├── src ├── app.less ├── assets │ ├── .gitkeep │ ├── fonts │ │ ├── ionicons.eot │ │ ├── ionicons.ttf │ │ ├── ionicons.woff │ │ └── ionicons.woff2 │ ├── images │ │ ├── test2.jpg │ │ ├── no_image.png │ │ ├── f21-background.png │ │ ├── f21ico-support.png │ │ ├── file-alt-solid.png │ │ ├── f21-background2.jpg │ │ ├── f21-background_1.jpg │ │ ├── f21-background_2.png │ │ ├── f21_widget_icon_white.png │ │ ├── tiledesk_logo_white_small.png │ │ ├── f21-background_2.svg │ │ ├── f21ico-send.svg │ │ ├── f21ico-done.svg │ │ ├── c21-down-gray.svg │ │ ├── f21ico-close.svg │ │ ├── f21ico-done_all.svg │ │ ├── f21ico-schedule.svg │ │ ├── tiledesk-chat-close.svg │ │ ├── f21ico-photo.svg │ │ ├── tiledesk-chat-ballon.svg │ │ ├── f21ico-attached.svg │ │ ├── f21ico-widgetclose_white.svg │ │ ├── f21_widget_icon_white_1.svg │ │ ├── f21_widget_icon_white_2.svg │ │ ├── tiledesk-chat-close-dark-gray.svg │ │ ├── tiledesk-chat-ballon-with-badge.svg │ │ ├── tiledesk-chat-ballon-big-badge.svg │ │ ├── avatar_bot_tiledesk.svg │ │ ├── f21_widget_icon_white_0.svg │ │ ├── f21-chat21-logo-widget.svg │ │ └── line_avatar_bot_tiledesk.svg │ ├── sounds │ │ ├── Carme.mp3 │ │ ├── pling.mp3 │ │ └── justsaying.mp3 │ └── twp │ │ └── tiledesk_widget_files │ │ ├── logo.png │ │ ├── facebook.png │ │ ├── linkedin.png │ │ ├── telegram.png │ │ ├── twitter.png │ │ ├── whatsapp.png │ │ ├── logo-black.png │ │ ├── logo-short.png │ │ ├── logo-mobile.png │ │ ├── logo@2x-black.png │ │ └── icon ├── sass │ ├── _mixins.scss │ ├── styles.scss │ └── _variables.scss ├── styles.css ├── app │ ├── users │ │ ├── user-login │ │ │ ├── user-login.component.less │ │ │ ├── user-login.component.html │ │ │ ├── user-login.component.ts │ │ │ └── user-login.component.spec.ts │ │ └── user-profile │ │ │ ├── user-profile.component.less │ │ │ ├── user-profile.component.html │ │ │ ├── user-profile.component.ts │ │ │ └── user-profile.component.spec.ts │ ├── components │ │ ├── form │ │ │ ├── inputs │ │ │ │ ├── select │ │ │ │ │ ├── select.component.scss │ │ │ │ │ ├── select.component.html │ │ │ │ │ ├── select.component.ts │ │ │ │ │ └── select.component.spec.ts │ │ │ │ ├── radio-button │ │ │ │ │ ├── radio-button.component.scss │ │ │ │ │ ├── radio-button.component.ts │ │ │ │ │ ├── radio-button.component.html │ │ │ │ │ └── radio-button.component.spec.ts │ │ │ │ ├── form-label │ │ │ │ │ ├── form-label.component.html │ │ │ │ │ ├── form-label.component.scss │ │ │ │ │ ├── form-label.component.ts │ │ │ │ │ └── form-label.component.spec.ts │ │ │ │ ├── form-checkbox │ │ │ │ │ ├── form-checkbox.component.html │ │ │ │ │ ├── form-checkbox.component.spec.ts │ │ │ │ │ └── form-checkbox.component.ts │ │ │ │ ├── form-text │ │ │ │ │ ├── form-text.component.spec.ts │ │ │ │ │ └── form-text.component.html │ │ │ │ └── form-textarea │ │ │ │ │ ├── form-textarea.component.spec.ts │ │ │ │ │ └── form-textarea.component.html │ │ │ └── form-builder │ │ │ │ └── form-builder.component.spec.ts │ │ ├── preview-loading-files │ │ │ ├── preview-loading-files.component.scss │ │ │ ├── preview-loading-files.component.html │ │ │ ├── preview-loading-files.component.ts │ │ │ └── preview-loading-files.component.spec.ts │ │ ├── message │ │ │ ├── html │ │ │ │ ├── html.component.html │ │ │ │ ├── html.component.spec.ts │ │ │ │ └── html.component.ts │ │ │ ├── info-message │ │ │ │ ├── info-message.component.html │ │ │ │ ├── info-message.component.scss │ │ │ │ ├── info-message.component.spec.ts │ │ │ │ └── info-message.component.ts │ │ │ ├── text │ │ │ │ ├── text.component.html │ │ │ │ ├── text.component.scss │ │ │ │ ├── text.component.spec.ts │ │ │ │ └── text.component.ts │ │ │ ├── buttons │ │ │ │ ├── text-button │ │ │ │ │ ├── text-button.component.html │ │ │ │ │ ├── text-button.component.spec.ts │ │ │ │ │ └── text-button.component.scss │ │ │ │ ├── action-button │ │ │ │ │ ├── action-button.component.html │ │ │ │ │ └── action-button.component.spec.ts │ │ │ │ └── link-button │ │ │ │ │ ├── link-button.component.spec.ts │ │ │ │ │ ├── link-button.component.html │ │ │ │ │ └── link-button.component.scss │ │ │ ├── frame │ │ │ │ ├── frame.component.html │ │ │ │ ├── frame.component.scss │ │ │ │ ├── frame.component.spec.ts │ │ │ │ └── frame.component.ts │ │ │ ├── image │ │ │ │ ├── image.component.html │ │ │ │ ├── image.component.spec.ts │ │ │ │ ├── image.component.ts │ │ │ │ └── image.component.scss │ │ │ ├── return-receipt │ │ │ │ ├── return-receipt.component.scss │ │ │ │ ├── return-receipt.component.spec.ts │ │ │ │ └── return-receipt.component.ts │ │ │ ├── avatar │ │ │ │ ├── avatar.component.html │ │ │ │ ├── avatar.component.spec.ts │ │ │ │ ├── avatar.component.scss │ │ │ │ └── avatar.component.ts │ │ │ └── bubble-message │ │ │ │ └── bubble-message.component.scss │ │ ├── send-button │ │ │ ├── send-button.component.ts │ │ │ ├── send-button.component.spec.ts │ │ │ ├── send-button.component.scss │ │ │ └── send-button.component.html │ │ ├── menu-options │ │ │ ├── menu-options.component.spec.ts │ │ │ └── menu-options.component.ts │ │ ├── conversation-detail │ │ │ ├── conversation-preview │ │ │ │ └── conversation-preview.component.spec.ts │ │ │ ├── interlal-frame │ │ │ │ └── interlal-frame.component.spec.ts │ │ │ └── conversation-header │ │ │ │ └── conversation-header.component.spec.ts │ │ ├── home │ │ │ └── home.component.spec.ts │ │ ├── star-rating-widget │ │ │ ├── star-rating-widget.service.spec.ts │ │ │ └── star-rating-widget.component.spec.ts │ │ ├── list-conversations │ │ │ └── list-conversations.component.spec.ts │ │ ├── launcher-button │ │ │ ├── launcher-button.component.spec.ts │ │ │ ├── launcher-button.component.scss │ │ │ └── launcher-button.component.html │ │ ├── eyeeye-catcher-card │ │ │ └── eyeeye-catcher-card.component.spec.ts │ │ ├── prechat-form │ │ │ └── prechat-form.component.spec.ts │ │ ├── selection-department │ │ │ └── selection-department.component.spec.ts │ │ ├── message-attachment │ │ │ └── message-attachment.component.spec.ts │ │ ├── last-message │ │ │ └── last-message.component.spec.ts │ │ └── list-all-conversations │ │ │ └── list-all-conversations.component.spec.ts │ ├── _animations │ │ ├── index.ts │ │ ├── fade-in.animation.ts │ │ ├── slide-in-out-for-panel.animation.ts │ │ └── slide-in-out.animation.ts │ ├── directives │ │ ├── marked.pipe.spec.ts │ │ ├── safe-html.pipe.spec.ts │ │ ├── html-entites-encode.pipe.spec.ts │ │ ├── safe-html.pipe.ts │ │ ├── html-entities-encode.pipe.ts │ │ └── marked.pipe.ts │ └── providers │ │ ├── storage.service.spec.ts │ │ ├── webpack-translate-loader.ts │ │ ├── contact.service.spec.ts │ │ ├── chat-presence-handler.service.spec.ts │ │ ├── settings-saver.service.spec.ts │ │ ├── upload.service.spec.ts │ │ ├── waiting.service.spec.ts │ │ ├── conversations.service.spec.ts │ │ ├── agent-availability.service.spec.ts │ │ ├── auth.service.spec.ts │ │ ├── translator.service.spec.ts │ │ ├── global-settings.service.spec.ts │ │ ├── waiting.service.ts │ │ ├── messaging.service.spec.ts │ │ └── settings-saver.service.ts ├── favicon.ico ├── chat21-core │ ├── models │ │ ├── upload.ts │ │ ├── group.ts │ │ ├── formArray.ts │ │ ├── user.ts │ │ ├── message.ts │ │ └── conversation.ts │ ├── providers │ │ ├── abstract │ │ │ ├── conversation-handler-builder.service.ts │ │ │ ├── logger.service.spec.ts │ │ │ ├── typing.service.spec.ts │ │ │ ├── upload.service.spec.ts │ │ │ ├── presence.service.spec.ts │ │ │ ├── app-storage.service.spec.ts │ │ │ ├── image-repo.service.spec.ts │ │ │ ├── logger.service.ts │ │ │ ├── groups-handler.service.spec.ts │ │ │ ├── messagingAuth.service.spec.ts │ │ │ ├── notifications.service.spec.ts │ │ │ ├── conversation-handler.service.spec.ts │ │ │ ├── conversations-handler.service.spec.ts │ │ │ ├── conversation-handler-builder.service.spec.ts │ │ │ ├── archivedconversations-handler.service.spec.ts │ │ │ ├── app-storage.service.ts │ │ │ ├── image-repo.service.ts │ │ │ ├── notifications.service.ts │ │ │ ├── upload.service.ts │ │ │ ├── typing.service.ts │ │ │ ├── presence.service.ts │ │ │ ├── messagingAuth.service.ts │ │ │ ├── groups-handler.service.ts │ │ │ ├── conversation-handler.service.ts │ │ │ └── archivedconversations-handler.service.ts │ │ ├── logger │ │ │ ├── loggerInstance.ts │ │ │ └── customLogger.ts │ │ ├── custom-translate.service.spec.ts │ │ ├── firebase │ │ │ ├── firebase-conversation-handler-builder.service.ts │ │ │ ├── firebase-init-service.ts │ │ │ └── firebase-image-repo.ts │ │ ├── mqtt │ │ │ ├── mqtt-conversation-handler-builder.service.ts │ │ │ ├── mqtt-notifications.ts │ │ │ └── chat-service.ts │ │ ├── native │ │ │ └── native-image-repo.ts │ │ └── custom-translate.service.ts │ └── utils │ │ ├── user-typing │ │ ├── user-typing.component.html │ │ ├── user-typing.component.spec.ts │ │ └── user-typing.component.ts │ │ └── utils-user.ts ├── models │ ├── upload.ts │ ├── contact.ts │ ├── User.ts │ ├── department.ts │ ├── conversation.ts │ └── message.ts ├── tsconfig.app.json ├── typings.d.ts ├── tsconfig.spec.json ├── main.ts ├── index.html ├── widget-config.json ├── widget-config-template.json ├── test.ts ├── environments │ ├── environment.prod.ts │ ├── environment.ts │ └── environment.pre.ts ├── test-auth.html └── 404.html ├── deploy ├── deploy_pre.sh ├── deploy_prod.sh ├── publish_pre.sh └── publish_prod.sh ├── .vscode └── settings.json ├── bin └── chat21-web-widget ├── docs ├── authuser.png ├── tiledesk-project-settings.png ├── tiledesk-dashboard-widget-screenshots.png └── autoinstall.md ├── current_version.ts ├── current_version.ts-e ├── .npmignore ├── firebase.json ├── e2e ├── app.po.ts ├── tsconfig.e2e.json └── app.e2e-spec.ts ├── .editorconfig ├── deploy_beta.sh ├── deploy_prod.sh ├── tsconfig.json ├── env.sample ├── server.js ├── .github └── workflows │ ├── docker-community-push-latest.yml │ └── docker-image-tag-community-tag-push.yml ├── nginx.conf ├── protractor.conf.js ├── deploy_amazon_prod.sh ├── .gitignore ├── .README.md.swp ├── karma.conf.js ├── LICENSE ├── Dockerfile └── deploy_amazon_beta.sh /src/app.less: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /deploy/deploy_pre.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /deploy/deploy_prod.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /deploy/publish_pre.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /deploy/publish_prod.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sass/_mixins.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/users/user-login/user-login.component.less: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/users/user-profile/user-profile.component.less: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/select/select.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /bin/chat21-web-widget: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../server'); 3 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/radio-button/radio-button.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/preview-loading-files/preview-loading-files.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sass/styles.scss: -------------------------------------------------------------------------------- 1 | @import './variables'; 2 | @import './mixins'; 3 | 4 | -------------------------------------------------------------------------------- /src/app/users/user-login/user-login.component.html: -------------------------------------------------------------------------------- 1 |

2 | user-login works! 3 |

4 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /docs/authuser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/docs/authuser.png -------------------------------------------------------------------------------- /src/app/components/form/inputs/select/select.component.html: -------------------------------------------------------------------------------- 1 |

2 | select works! 3 |

4 | -------------------------------------------------------------------------------- /src/app/users/user-profile/user-profile.component.html: -------------------------------------------------------------------------------- 1 |

2 | user-profile works! 3 |

4 | -------------------------------------------------------------------------------- /current_version.ts: -------------------------------------------------------------------------------- 1 | export const CURR_VER_DEV = 'test.002'; 2 | export const CURR_VER_PROD = '1.009'; 3 | -------------------------------------------------------------------------------- /current_version.ts-e: -------------------------------------------------------------------------------- 1 | export const CURR_VER_DEV = 'test.001'; 2 | export const CURR_VER_PROD = '1.009'; 3 | -------------------------------------------------------------------------------- /src/assets/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/fonts/ionicons.eot -------------------------------------------------------------------------------- /src/assets/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/fonts/ionicons.ttf -------------------------------------------------------------------------------- /src/assets/images/test2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/images/test2.jpg -------------------------------------------------------------------------------- /src/assets/sounds/Carme.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/sounds/Carme.mp3 -------------------------------------------------------------------------------- /src/assets/sounds/pling.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/sounds/pling.mp3 -------------------------------------------------------------------------------- /src/app/components/message/html/html.component.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /src/assets/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/fonts/ionicons.woff -------------------------------------------------------------------------------- /src/assets/fonts/ionicons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/fonts/ionicons.woff2 -------------------------------------------------------------------------------- /src/assets/images/no_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/images/no_image.png -------------------------------------------------------------------------------- /docs/tiledesk-project-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/docs/tiledesk-project-settings.png -------------------------------------------------------------------------------- /src/assets/sounds/justsaying.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/sounds/justsaying.mp3 -------------------------------------------------------------------------------- /src/assets/images/f21-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/images/f21-background.png -------------------------------------------------------------------------------- /src/assets/images/f21ico-support.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/images/f21ico-support.png -------------------------------------------------------------------------------- /src/assets/images/file-alt-solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/images/file-alt-solid.png -------------------------------------------------------------------------------- /src/assets/images/f21-background2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/images/f21-background2.jpg -------------------------------------------------------------------------------- /src/assets/images/f21-background_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/images/f21-background_1.jpg -------------------------------------------------------------------------------- /src/assets/images/f21-background_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/images/f21-background_2.png -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | #f you want to include something that is excluded by your .gitignore file, you can create an empty .npmignore file to override it. -------------------------------------------------------------------------------- /src/app/components/message/info-message/info-message.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/images/f21_widget_icon_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/images/f21_widget_icon_white.png -------------------------------------------------------------------------------- /docs/tiledesk-dashboard-widget-screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/docs/tiledesk-dashboard-widget-screenshots.png -------------------------------------------------------------------------------- /src/assets/twp/tiledesk_widget_files/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/twp/tiledesk_widget_files/logo.png -------------------------------------------------------------------------------- /src/assets/images/tiledesk_logo_white_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/images/tiledesk_logo_white_small.png -------------------------------------------------------------------------------- /src/assets/twp/tiledesk_widget_files/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/twp/tiledesk_widget_files/facebook.png -------------------------------------------------------------------------------- /src/assets/twp/tiledesk_widget_files/linkedin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/twp/tiledesk_widget_files/linkedin.png -------------------------------------------------------------------------------- /src/assets/twp/tiledesk_widget_files/telegram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/twp/tiledesk_widget_files/telegram.png -------------------------------------------------------------------------------- /src/assets/twp/tiledesk_widget_files/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/twp/tiledesk_widget_files/twitter.png -------------------------------------------------------------------------------- /src/assets/twp/tiledesk_widget_files/whatsapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/twp/tiledesk_widget_files/whatsapp.png -------------------------------------------------------------------------------- /src/assets/twp/tiledesk_widget_files/logo-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/twp/tiledesk_widget_files/logo-black.png -------------------------------------------------------------------------------- /src/assets/twp/tiledesk_widget_files/logo-short.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/twp/tiledesk_widget_files/logo-short.png -------------------------------------------------------------------------------- /src/assets/twp/tiledesk_widget_files/logo-mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/twp/tiledesk_widget_files/logo-mobile.png -------------------------------------------------------------------------------- /src/assets/twp/tiledesk_widget_files/logo@2x-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chat21/chat21-web-widget/HEAD/src/assets/twp/tiledesk_widget_files/logo@2x-black.png -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "dist", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/assets/images/f21-background_2.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/_animations/index.ts: -------------------------------------------------------------------------------- 1 | export * from './fade-in.animation'; 2 | export * from './slide-in-out.animation'; 3 | export * from './slide-in-out-for-panel.animation'; 4 | export * from './slide-in.animation'; 5 | -------------------------------------------------------------------------------- /docs/autoinstall.md: -------------------------------------------------------------------------------- 1 | https://medium.com/@svsh227/add-node-server-with-angular-app-run-angularjs-app-with-node-server-a3c472ef8997 2 | 3 | 4 | https://blog.devget.net/development/how-to-deploy-angular-6-project-to-heroku/ -------------------------------------------------------------------------------- /src/app/components/form/inputs/form-label/form-label.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /src/app/components/preview-loading-files/preview-loading-files.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | anteprima immagine -> cancel : send 4 | vedi telegram desktop 5 |
-------------------------------------------------------------------------------- /src/app/directives/marked.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { MarkedPipe } from './marked.pipe'; 2 | 3 | describe('MarkedPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new MarkedPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/components/message/text/text.component.html: -------------------------------------------------------------------------------- 1 |

5 | -------------------------------------------------------------------------------- /src/app/components/message/buttons/text-button/text-button.component.html: -------------------------------------------------------------------------------- 1 |
3 | {{button?.value}} 4 |
5 | -------------------------------------------------------------------------------- /src/app/directives/safe-html.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { SafeHtmlPipe } from './safe-html.pipe'; 2 | 3 | describe('SafeHtmlPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new SafeHtmlPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/chat21-core/models/upload.ts: -------------------------------------------------------------------------------- 1 | export class UploadModel { 2 | $key: string; 3 | file: File; 4 | name: string; 5 | url: string; 6 | progress: number; 7 | createdAt: Date = new Date(); 8 | constructor(file: File) { 9 | this.file = file; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/models/upload.ts: -------------------------------------------------------------------------------- 1 | export class UploadModel { 2 | $key: string; 3 | file: File; 4 | name: string; 5 | url: string; 6 | progress: number; 7 | createdAt: Date = new Date(); 8 | 9 | constructor(file: File) { 10 | this.file = file; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": ["node"] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/app/components/message/buttons/action-button/action-button.component.html: -------------------------------------------------------------------------------- 1 |
4 | {{button?.value}} 5 |
6 | -------------------------------------------------------------------------------- /src/app/directives/html-entites-encode.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { HtmlEntitiesEncodePipe } from './html-entities-encode.pipe'; 2 | 3 | describe('HtmlEntitiesEncodePipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new HtmlEntitiesEncodePipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/models/contact.ts: -------------------------------------------------------------------------------- 1 | export class ContactModel { 2 | constructor( 3 | public uid: string, 4 | public email: string, 5 | public firstname: string, 6 | public imageurl: string, 7 | public lastname: string, 8 | public timestamp: string, 9 | ) { } 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "jasminewd2", 11 | "node" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/images/f21ico-send.svg: -------------------------------------------------------------------------------- 1 | ic-send-black -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/conversation-handler-builder.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | // @Injectable({ 4 | // providedIn: 'root' 5 | // }) 6 | @Injectable() 7 | export abstract class ConversationHandlerBuilderService { 8 | 9 | constructor() { } 10 | 11 | abstract build(): any; 12 | } 13 | -------------------------------------------------------------------------------- /deploy_beta.sh: -------------------------------------------------------------------------------- 1 | # npm version prerelease --preid=beta 2 | version=`node -e 'console.log(require("./package.json").version)'` 3 | echo "version $version" 4 | 5 | if [ "$version" != "" ]; then 6 | git tag -a "$version" -m "`git log -1 --format=%s`" 7 | echo "Created a new tag, $version" 8 | git push --tags 9 | npm publish 10 | fi -------------------------------------------------------------------------------- /src/assets/images/f21ico-done.svg: -------------------------------------------------------------------------------- 1 | ic_done -------------------------------------------------------------------------------- /e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('my-app App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to app!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/models/User.ts: -------------------------------------------------------------------------------- 1 | export interface User { 2 | id: string; 3 | firstname: string; 4 | updatedAt: any; 5 | createdAt: any; 6 | id_project: string; 7 | id_user: string; 8 | user_available?: boolean; 9 | role: string; 10 | createdBy: string; 11 | is_group_member: boolean; 12 | __v: any; 13 | imageurl: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | 7 | // // source : https://github.com/ngx-translate/http-loader#angular-cliwebpack-translateloader-example 8 | // declare var System: System; 9 | // interface System { 10 | // import(request: string): Promise; 11 | // } -------------------------------------------------------------------------------- /src/chat21-core/utils/user-typing/user-typing.component.html: -------------------------------------------------------------------------------- 1 | 5 |
6 |
7 |
8 |
9 |
10 | -------------------------------------------------------------------------------- /src/assets/images/c21-down-gray.svg: -------------------------------------------------------------------------------- 1 | ic-down-gray -------------------------------------------------------------------------------- /src/app/components/form/inputs/select/select.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'chat-select', 5 | templateUrl: './select.component.html', 6 | styleUrls: ['./select.component.scss'] 7 | }) 8 | export class SelectComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/models/department.ts: -------------------------------------------------------------------------------- 1 | export class DepartmentModel { 2 | constructor( 3 | public appId: string, 4 | public createdAt: string, 5 | public createdBy: string, 6 | public name: string, 7 | public updatedAt: string, 8 | public _id: string, 9 | public offline_msg: string, 10 | public online_msg: string 11 | ) { } 12 | } 13 | -------------------------------------------------------------------------------- /src/app/users/user-login/user-login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-user-login', 5 | templateUrl: './user-login.component.html', 6 | styleUrls: ['./user-login.component.less'] 7 | }) 8 | export class UserLoginComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/images/f21ico-close.svg: -------------------------------------------------------------------------------- 1 | ic-close-black -------------------------------------------------------------------------------- /src/app/users/user-profile/user-profile.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-user-profile', 5 | templateUrl: './user-profile.component.html', 6 | styleUrls: ['./user-profile.component.less'] 7 | }) 8 | export class UserProfileComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/chat21-core/models/group.ts: -------------------------------------------------------------------------------- 1 | export class GroupModel { 2 | constructor( 3 | public uid: string, 4 | public createdOn: any, 5 | public iconURL: string, 6 | public members: any[], 7 | public membersinfo: any[], 8 | public name: string, 9 | public owner: string, 10 | public color: string, 11 | public avatar: string 12 | ) { } 13 | } 14 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/chat21-core/models/formArray.ts: -------------------------------------------------------------------------------- 1 | export class FormArray { 2 | constructor( 3 | public label?: string | {}, 4 | public errorLabel?: string | {}, 5 | public name?: string, 6 | public type?: string, 7 | public mandatory?: boolean, 8 | public regex?: string, 9 | public value?: any, 10 | public options?: Array, 11 | public tabIndex?: number 12 | ) { } 13 | } -------------------------------------------------------------------------------- /deploy_prod.sh: -------------------------------------------------------------------------------- 1 | # npm version patch 2 | version=`node -e 'console.log(require("./package.json").version)'` 3 | ECHO "____________WIDGET-V5______________" 4 | echo "CREATING TAG ON GIT FOR version: $version" 5 | # echo "version $version" 6 | 7 | if [ "$version" != "" ]; then 8 | git tag -a "$version" -m "`git log -1 --format=%s`" 9 | echo "Created a new tag, $version" 10 | git push --tags 11 | npm publish 12 | fi -------------------------------------------------------------------------------- /src/app/components/form/inputs/radio-button/radio-button.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'chat-radio-button', 5 | templateUrl: './radio-button.component.html', 6 | styleUrls: ['./radio-button.component.scss'] 7 | }) 8 | export class RadioButtonComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.log(err)); 13 | -------------------------------------------------------------------------------- /src/assets/images/f21ico-done_all.svg: -------------------------------------------------------------------------------- 1 | ic_done_all -------------------------------------------------------------------------------- /src/assets/images/f21ico-schedule.svg: -------------------------------------------------------------------------------- 1 | ic_schedule -------------------------------------------------------------------------------- /src/assets/images/tiledesk-chat-close.svg: -------------------------------------------------------------------------------- 1 | tiledesk-chat-close -------------------------------------------------------------------------------- /src/app/directives/safe-html.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { DomSanitizer } from '@angular/platform-browser'; 3 | 4 | @Pipe({ 5 | name: 'safeHtml' 6 | }) 7 | export class SafeHtmlPipe implements PipeTransform { 8 | 9 | constructor(protected sanitizer: DomSanitizer) {} 10 | 11 | transform(value: any, args?: any): any { 12 | return this.sanitizer.bypassSecurityTrustHtml(value);; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/form-label/form-label.component.scss: -------------------------------------------------------------------------------- 1 | .c21-header-label{ 2 | padding: 10px 0px; 3 | // margin: 0px 12px; 4 | position: relative; 5 | left: 0; 6 | right: 0; 7 | .c21-form-message-field { 8 | padding: 0; 9 | margin: 0; 10 | line-height: 1.2em; 11 | color: #616161; 12 | font-size: 1.5em; 13 | text-align: center; 14 | word-wrap: break-word; 15 | } 16 | } -------------------------------------------------------------------------------- /src/assets/images/f21ico-photo.svg: -------------------------------------------------------------------------------- 1 | ic-photo-black -------------------------------------------------------------------------------- /src/assets/images/tiledesk-chat-ballon.svg: -------------------------------------------------------------------------------- 1 | tiledesk-chat-ballon -------------------------------------------------------------------------------- /src/chat21-core/models/user.ts: -------------------------------------------------------------------------------- 1 | export class UserModel { 2 | constructor( 3 | public uid: string, 4 | public email?: string, 5 | public firstname?: string, 6 | public lastname?: string, 7 | public fullname?: string, 8 | public imageurl?: string, 9 | public avatar?: string, 10 | public color?: string, 11 | public checked?: boolean, 12 | public online?: boolean, 13 | public lastConnection?: string, 14 | public decoded?: any 15 | ) { } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/components/message/frame/frame.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 9 |
10 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/logger.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { LoggerService } from './logger.service'; 3 | 4 | 5 | describe('LoggerService', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [LoggerService] 9 | }) 10 | ); 11 | 12 | it('should be created', () => { 13 | const service: LoggerService = TestBed.get(LoggerService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/typing.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { TypingService } from './typing.service'; 4 | 5 | describe('TypingService', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [TypingService] 9 | }) 10 | ); 11 | 12 | it('should be created', () => { 13 | const service: TypingService = TestBed.get(TypingService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/upload.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { UploadService } from './upload.service'; 4 | 5 | describe('UploadService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [UploadService] 9 | }); 10 | }); 11 | 12 | it('should be created', () => { 13 | const service: UploadService = TestBed.get(UploadService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/directives/html-entities-encode.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { htmlEntities, replaceEndOfLine } from '../../chat21-core/utils/utils'; 3 | 4 | @Pipe({ 5 | name: 'htmlEntitiesEncode' 6 | }) 7 | 8 | export class HtmlEntitiesEncodePipe implements PipeTransform { 9 | 10 | transform(text: any, args?: any): any { 11 | text = htmlEntities(text); 12 | text = replaceEndOfLine(text); 13 | text = text.trim(); 14 | return text; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/presence.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { PresenceService } from './presence.service'; 4 | 5 | describe('PresenceService', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [PresenceService] 9 | }) 10 | ); 11 | 12 | it('should be created', () => { 13 | const service: PresenceService = TestBed.get(PresenceService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/_animations/fade-in.animation.ts: -------------------------------------------------------------------------------- 1 | import { trigger, state, animate, transition, style } from '@angular/animations'; 2 | 3 | export const fadeInAnimation = 4 | trigger('fadeInAnimation', [ 5 | // route 'enter' transition 6 | transition(':enter', [ 7 | 8 | // styles at start of transition 9 | style({ opacity: 0 }), 10 | 11 | // animation and styles at end of transition 12 | animate('.3s', style({ opacity: 1 })) 13 | ]), 14 | ]); 15 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/app-storage.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { AppStorageService } from './app-storage.service'; 4 | 5 | describe('AppStorageService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [AppStorageService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([AppStorageService], (service: AppStorageService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/image-repo.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ImageRepoService } from './image-repo.service'; 4 | 5 | describe('ImageRepoService', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [ImageRepoService] 9 | }) 10 | ); 11 | 12 | it('should be created', () => { 13 | const service: ImageRepoService = TestBed.get(ImageRepoService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "resolveJsonModule": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2018", 17 | "dom" 18 | ], 19 | "skipLibCheck": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/logger.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | // @Injectable({ 4 | // providedIn: 'root' 5 | // }) 6 | @Injectable() 7 | export abstract class LoggerService { 8 | 9 | constructor() { } 10 | 11 | abstract setLoggerConfig(isLogEnabled: boolean, logLevel: string); 12 | abstract debug(...message: any[]) 13 | abstract log(...message: any[]) 14 | abstract warn(...message: any[]) 15 | abstract info(...message: any[]) 16 | abstract error(...message: any[]) 17 | } 18 | -------------------------------------------------------------------------------- /src/app/providers/storage.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Globals } from './../utils/globals'; 2 | import { TestBed, inject } from '@angular/core/testing'; 3 | 4 | import { StorageService } from './storage.service'; 5 | 6 | describe('StorageService', () => { 7 | beforeEach(() => { 8 | TestBed.configureTestingModule({ 9 | providers: [StorageService, Globals] 10 | }); 11 | }); 12 | 13 | it('should be created', inject([StorageService], (service: StorageService) => { 14 | expect(service).toBeTruthy(); 15 | })); 16 | }); 17 | -------------------------------------------------------------------------------- /src/assets/images/f21ico-attached.svg: -------------------------------------------------------------------------------- 1 | ic-attached-flipped-black -------------------------------------------------------------------------------- /src/app/providers/webpack-translate-loader.ts: -------------------------------------------------------------------------------- 1 | // // webpack-translate-loader.ts 2 | // import { TranslateLoader } from '@ngx-translate/core'; 3 | // // import { Observable } from 'rxjs/Observable'; 4 | // import { Observable } from 'rxjs/Rx'; 5 | // import 'rxjs/add/observable/fromEvent'; 6 | 7 | // export class WebpackTranslateLoader implements TranslateLoader { 8 | // getTranslation(lang: string): Observable { 9 | 10 | // return Observable.fromPromise(System.import(`../../assets/i18n/${lang}.json`)); 11 | // } 12 | // } 13 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/groups-handler.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { GroupsHandlerService } from './groups-handler.service'; 4 | 5 | describe('GroupsHandlerService', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [GroupsHandlerService] 9 | }) 10 | ); 11 | 12 | it('should be created', () => { 13 | const service: GroupsHandlerService = TestBed.get(GroupsHandlerService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/messagingAuth.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { MessagingAuthService } from './messagingAuth.service'; 4 | 5 | describe('MessagingAuthService', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [MessagingAuthService] 9 | }) 10 | ); 11 | 12 | it('should be created', () => { 13 | const service: MessagingAuthService = TestBed.get(MessagingAuthService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/notifications.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { NotificationsService } from './notifications.service'; 4 | 5 | describe('NotificationsService', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [NotificationsService] 9 | }) 10 | ); 11 | 12 | it('should be created', () => { 13 | const service: NotificationsService = TestBed.get(NotificationsService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/radio-button/radio-button.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 |
7 |
8 | 9 | 12 |
13 | -------------------------------------------------------------------------------- /src/app/components/message/info-message/info-message.component.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../sass/variables'; 2 | 3 | .base_info { 4 | border-radius: 14px; 5 | border: 1px solid #C9E4F6; 6 | padding-left: 4px; 7 | padding-right: 4px; 8 | padding: 6px 10px; 9 | display: inline-block; 10 | background: #C9E4F6; 11 | font-size: 10px; 12 | color: $base-gray; 13 | margin-left: 32px; 14 | margin-right: 32px; 15 | } 16 | 17 | .base_info ::ng-deep > p { 18 | margin-top: 0 !important; 19 | margin-bottom: 0 !important; 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/images/f21ico-widgetclose_white.svg: -------------------------------------------------------------------------------- 1 | chat21-close -------------------------------------------------------------------------------- /src/app/providers/contact.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Globals } from './../utils/globals'; 2 | import { TestBed, inject } from '@angular/core/testing'; 3 | 4 | import { ContactService } from './contact.service'; 5 | 6 | describe('ContactService', () => { 7 | beforeEach(() => { 8 | TestBed.configureTestingModule({ 9 | providers: [ 10 | ContactService, 11 | Globals 12 | ] 13 | }); 14 | }); 15 | 16 | it('should be created', inject([ContactService], (service: ContactService) => { 17 | expect(service).toBeTruthy(); 18 | })); 19 | }); 20 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/conversation-handler.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ConversationHandlerService } from './conversation-handler.service'; 4 | 5 | describe('ConversationHandlerService', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [ConversationHandlerService] 9 | }) 10 | ); 11 | 12 | it('should be created', () => { 13 | const service: ConversationHandlerService = TestBed.get(ConversationHandlerService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/chat21-core/providers/logger/loggerInstance.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core' 2 | import { LoggerService } from '../abstract/logger.service'; 3 | import { CustomLogger } from './customLogger'; 4 | 5 | @Injectable() 6 | export class LoggerInstance { 7 | 8 | 9 | //private variables 10 | private static instance: LoggerService; 11 | 12 | static getInstance() { 13 | return LoggerInstance.instance; 14 | } 15 | 16 | static setInstance(loggerService: LoggerService) { 17 | LoggerInstance.instance = loggerService 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/conversations-handler.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ConversationsHandlerService } from './conversations-handler.service'; 4 | 5 | describe('ConversationsHandlerService', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [ConversationsHandlerService] 9 | }) 10 | ); 11 | 12 | it('should be created', () => { 13 | const service: ConversationsHandlerService = TestBed.get(ConversationsHandlerService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tilechat Widget 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /env.sample: -------------------------------------------------------------------------------- 1 | CHAT21_ENGINE=mqtt 2 | UPLOAD_ENGINE=native 3 | PUSH_ENGINE=none 4 | TENANT=tilechat 5 | FILE_UPLOAD_ACCEPT=*/* 6 | LOG_LEVEL=INFO 7 | TRANSLATIONS_URL=CHANGEIT 8 | FIREBASE_APIKEY=CHANGEIT 9 | FIREBASE_AUTHDOMAIN=CHANGEIT.firebaseapp.com 10 | FIREBASE_DATABASEURL=https://CHANGEIT.firebaseio.com 11 | FIREBASE_PROJECT_ID=CHANGEIT 12 | FIREBASE_STORAGEBUCKET=CHANGEIT.appspot.com 13 | FIREBASE_APP_ID=CHANGEIT 14 | FIREBASE_MESSAGINGSENDERID=******** 15 | MQTT_APPID=tilechat 16 | MQTT_ENDPOINT=CHANGEIT 17 | MQTT_APIENDPOINT=CHANGEIT 18 | API_URL=CHANGEIT 19 | API_BASEIMAGE_URL=CHANGEIT 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/sass/_variables.scss: -------------------------------------------------------------------------------- 1 | // =========== COLORS =============== // 2 | $black: #1a1a1a; 3 | $light-white: #f7f7f7; 4 | $gray: #aaaaaa; 5 | $light-gray: #eeeeee; 6 | $base-gray: #666666; 7 | $red: red; 8 | $danger: #a94442; 9 | $blue: rgb(42, 106, 193); 10 | 11 | $trasp-light-gray: rgba(191, 191, 191, 0.2); 12 | $trasp-black:rgba(0,0,0,0.8); 13 | $trasp-light-black:rgba(0,0,0,0.2); 14 | 15 | // $theme-color: rgb(42, 106, 193); 16 | /** conversation **/ 17 | $bck-msg-sent: rgb(98, 168, 234); 18 | $col-msg-sent: #ffffff; 19 | 20 | $border-radius-bubble-message: 20px; 21 | $button-in-msg-font-size: 15px; 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/conversation-handler-builder.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ConversationHandlerBuilderService } from './conversation-handler-builder.service'; 4 | 5 | describe('ConversationHandlerBuilderService', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [ConversationHandlerBuilderService] 9 | }) 10 | ); 11 | 12 | it('should be created', () => { 13 | const service: ConversationHandlerBuilderService = TestBed.get(ConversationHandlerBuilderService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | //Install express server 2 | const express = require('express'); 3 | const path = require('path'); 4 | 5 | const app = express(); 6 | 7 | // Serve only the static files form the dist directory 8 | app.use(express.static(__dirname + '/dist')); 9 | 10 | app.get('/*', function(req,res) { 11 | // console.log("other res"); 12 | res.sendFile(path.join(__dirname,'/dist/index.html')); 13 | }); 14 | 15 | // Start the app by listening on the default Heroku port 16 | var listener = app.listen(process.env.PORT || 4200, function(){ 17 | // console.log('Listening on port ' + listener.address().port); //Listening on port 8888 18 | }); 19 | -------------------------------------------------------------------------------- /src/chat21-core/providers/custom-translate.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TranslateModule } from '@ngx-translate/core'; 2 | import { TestBed } from '@angular/core/testing'; 3 | 4 | import { CustomTranslateService } from './custom-translate.service'; 5 | 6 | describe('CustomTranslateService', () => { 7 | beforeEach(() => 8 | TestBed.configureTestingModule({ 9 | imports: [ TranslateModule.forRoot()], 10 | providers: [CustomTranslateService] 11 | }) 12 | ); 13 | 14 | it('should be created', () => { 15 | const service: CustomTranslateService = TestBed.get(CustomTranslateService); 16 | expect(service).toBeTruthy(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /.github/workflows/docker-community-push-latest.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image Community latest CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | push_to_registry: 11 | name: Push Docker image to Docker Hub 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | name: Check out the repo 17 | - uses: docker/build-push-action@v1 18 | with: 19 | username: ${{ secrets.DOCKERHUB_USERNAME }} 20 | password: ${{ secrets.DOCKERHUB_TOKEN }} 21 | repository: chat21/chat21-web-widget 22 | tags: latest 23 | -------------------------------------------------------------------------------- /src/app/components/message/frame/frame.component.scss: -------------------------------------------------------------------------------- 1 | .loader { 2 | float: left; 3 | // position: absolute; 4 | z-index: 1000; 5 | background-color: #ccc; 6 | border-radius: 8px; 7 | background-image: linear-gradient(90deg, #f7f4f4 0px, #e8e8e8 40px, #f7f4f4 80px); 8 | background-size: 600px; 9 | animation: shine-loader 1.6s infinite linear; 10 | } 11 | 12 | .isLoadingImage { 13 | // position: relative; 14 | // top: 6px; 15 | display: none; 16 | } 17 | 18 | @keyframes shine-loader { 19 | 0% { 20 | background-position: -32px; 21 | } 22 | 40%, 100% { 23 | background-position: 208px; 24 | } 25 | } -------------------------------------------------------------------------------- /src/app/providers/chat-presence-handler.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Globals } from './../utils/globals'; 2 | import { TestBed, inject } from '@angular/core/testing'; 3 | 4 | import { ChatPresenceHandlerService } from './chat-presence-handler.service'; 5 | 6 | describe('ChatPresenceHandlerService', () => { 7 | beforeEach(() => { 8 | TestBed.configureTestingModule({ 9 | providers: [ 10 | ChatPresenceHandlerService, 11 | Globals 12 | ] 13 | }); 14 | }); 15 | 16 | it('should be created', inject([ChatPresenceHandlerService], (service: ChatPresenceHandlerService) => { 17 | expect(service).toBeTruthy(); 18 | })); 19 | }); 20 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/archivedconversations-handler.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { ArchivedConversationsHandlerService } from './archivedconversations-handler.service'; 4 | 5 | describe('ArchivedconversationsHandlerService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [ArchivedConversationsHandlerService] 9 | }); 10 | }); 11 | 12 | it('should be created', () => { 13 | const service: ArchivedConversationsHandlerService = TestBed.get(ArchivedConversationsHandlerService); 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/app-storage.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable() 4 | export abstract class AppStorageService { 5 | 6 | 7 | constructor() { } 8 | 9 | abstract initialize(storagePrefix: string, persistence: string, projectID?: string): void; 10 | abstract getItem(key: string): any; 11 | abstract setItem(key: string, value: any): void; 12 | /** @deprecated */ 13 | abstract getItemWithoutProjectID(key: string): any; 14 | /** @deprecated */ 15 | abstract setItemWithoutProjectID(key: string, value: any): void; 16 | abstract removeItem(key: string): void; 17 | abstract clear(): void; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/app/components/message/text/text.component.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../sass/variables'; 2 | 3 | .message_innerhtml { 4 | margin: 0px; 5 | // padding: 0px 14px; 6 | &.marked{ 7 | padding:8px; 8 | margin-block-start: -1em!important; 9 | margin-block-end: -1em!important; 10 | } 11 | 12 | .text-message { 13 | padding-top: 14px; 14 | } 15 | } 16 | 17 | p { 18 | font-size: 1.4em; 19 | margin: 0; 20 | padding: 14px; 21 | line-height: 1.4em; 22 | font-style: normal; 23 | letter-spacing: normal; 24 | font-stretch: normal; 25 | font-variant: normal; 26 | font-weight: 300; 27 | overflow: hidden; 28 | } -------------------------------------------------------------------------------- /src/app/providers/settings-saver.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Globals } from './../utils/globals'; 2 | import { TestBed, inject } from '@angular/core/testing'; 3 | 4 | import { SettingsSaverService } from './settings-saver.service'; 5 | import { AppStorageService } from '../../chat21-core/providers/abstract/app-storage.service'; 6 | 7 | describe('SettingsSaverService', () => { 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({ 10 | providers: [SettingsSaverService, Globals, AppStorageService] 11 | }); 12 | }); 13 | 14 | it('should be created', inject([SettingsSaverService], (service: SettingsSaverService) => { 15 | expect(service).toBeTruthy(); 16 | })); 17 | }); 18 | -------------------------------------------------------------------------------- /src/chat21-core/models/message.ts: -------------------------------------------------------------------------------- 1 | export class MessageModel { 2 | constructor( 3 | public uid: string, 4 | public language: string, 5 | public recipient: string, 6 | public recipient_fullname: string, 7 | public sender: string, 8 | public sender_fullname: string, 9 | public status: number, 10 | public metadata: any, 11 | public text: string, 12 | public timestamp: any, 13 | //public headerDate: string, 14 | public type: string, 15 | public attributes: any, 16 | public channel_type: string, 17 | public isSender: boolean, 18 | public emoticon?: boolean 19 | ) { } 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/docker-image-tag-community-tag-push.yml: -------------------------------------------------------------------------------- 1 | name: Publish Docker Community image tags 2 | 3 | on: 4 | push: 5 | tags: 6 | - '**' # Push events to every tag including hierarchical tags like 7 | jobs: 8 | 9 | push_to_registry: 10 | name: Push Docker image to Docker Hub 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Check out the repo 14 | uses: actions/checkout@v2 15 | - name: Push to Docker Hub 16 | uses: docker/build-push-action@v1 17 | with: 18 | username: ${{ secrets.DOCKERHUB_USERNAME }} 19 | password: ${{ secrets.DOCKERHUB_TOKEN }} 20 | repository: chat21/chat21-web-widget 21 | tag_with_ref: true 22 | -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | http { 8 | server { 9 | listen 80; 10 | server_name localhost; 11 | 12 | root /usr/share/nginx/html; 13 | index index.html index.htm; 14 | include /etc/nginx/mime.types; 15 | 16 | gzip on; 17 | gzip_min_length 1000; 18 | gzip_proxied expired no-cache no-store private auth; 19 | gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; 20 | 21 | location / { 22 | try_files $uri $uri/ /index.html; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/components/preview-loading-files/preview-loading-files.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; 2 | import { Globals } from '../../utils/globals'; 3 | 4 | @Component({ 5 | selector: 'tiledeskwidget-preview-loading-files', 6 | templateUrl: './preview-loading-files.component.html', 7 | styleUrls: ['./preview-loading-files.component.scss'] 8 | }) 9 | export class PreviewLoadingFilesComponent implements OnInit { 10 | @Input() arrayFilesLoad: [any]; 11 | @Output() eventClose = new EventEmitter(); 12 | @Output() eventSend = new EventEmitter(); 13 | 14 | constructor( 15 | public g: Globals 16 | ) { } 17 | 18 | ngOnInit() { 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/app/components/message/image/image.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 11 | 12 | {{ tooltipMessage }} 13 | 14 |
15 | -------------------------------------------------------------------------------- /src/chat21-core/providers/firebase/firebase-conversation-handler-builder.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | // services 3 | import { ConversationHandlerBuilderService } from '../abstract/conversation-handler-builder.service'; 4 | import { FirebaseConversationHandler } from './firebase-conversation-handler'; 5 | 6 | // @Injectable({ 7 | // providedIn: 'root' 8 | // }) 9 | @Injectable() 10 | export class FirebaseConversationHandlerBuilderService extends ConversationHandlerBuilderService { 11 | 12 | constructor() { 13 | super(); 14 | } 15 | 16 | public build(): any { 17 | const conversationHandlerService = new FirebaseConversationHandler(true); 18 | return conversationHandlerService; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/app/components/message/return-receipt/return-receipt.component.scss: -------------------------------------------------------------------------------- 1 | .status-message { 2 | width: 16px; 3 | height: 16px; 4 | margin-left: 4px; 5 | .icon { 6 | width: 13px; 7 | height: 13px; 8 | background-repeat: no-repeat; 9 | background-position: center; 10 | background-size: cover; 11 | overflow-x: hidden; 12 | } 13 | .c21-ico-schedule { 14 | background-image: url("../../../../assets/images/f21ico-schedule.svg"); 15 | } 16 | .c21-ico-done { 17 | background-image: url("../../../../assets/images/f21ico-done.svg"); 18 | } 19 | .c21-ico-done_all { 20 | background-image: url("../../../../assets/images/f21ico-done_all.svg"); 21 | } 22 | } -------------------------------------------------------------------------------- /src/assets/twp/tiledesk_widget_files/icon: -------------------------------------------------------------------------------- 1 | /* fallback */ 2 | @font-face { 3 | font-family: 'Material Icons Extended'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: url(https://fonts.gstatic.com/s/materialiconsextended/v53/kJEjBvgX7BgnkSrUwT8UnLVc38YydejYY-oE_LvJHMXBBA.woff2) format('woff2'); 7 | } 8 | 9 | .material-icons-extended { 10 | font-family: 'Material Icons Extended'; 11 | font-weight: normal; 12 | font-style: normal; 13 | font-size: 24px; 14 | line-height: 1; 15 | letter-spacing: normal; 16 | text-transform: none; 17 | display: inline-block; 18 | white-space: nowrap; 19 | word-wrap: normal; 20 | direction: ltr; 21 | -webkit-font-feature-settings: 'liga'; 22 | -webkit-font-smoothing: antialiased; 23 | } 24 | -------------------------------------------------------------------------------- /src/app/directives/marked.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import * as marked from 'marked'; 3 | 4 | 5 | @Pipe({ 6 | name: 'marked' 7 | }) 8 | 9 | export class MarkedPipe implements PipeTransform { 10 | transform(value: any): any { 11 | const renderer = new marked.Renderer(); 12 | renderer.link = function(href, title, text) { 13 | const link = marked.Renderer.prototype.link.call(this, href, title, text); 14 | return link.replace(' 0) { 20 | const text = marked(value); 21 | return text; 22 | } 23 | return value; 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/app/components/message/html/html.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HtmlComponent } from './html.component'; 4 | 5 | describe('HtmlComponent', () => { 6 | let component: HtmlComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HtmlComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HtmlComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/form-checkbox/form-checkbox.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 10 | 11 |
12 | {{translationErrorLabelMap.get('LABEL_ERROR_FIELD_REQUIRED')}} 13 |
14 |
15 |
-------------------------------------------------------------------------------- /src/app/components/message/frame/frame.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FrameComponent } from './frame.component'; 4 | 5 | describe('FrameComponent', () => { 6 | let component: FrameComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FrameComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FrameComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/assets/images/f21_widget_icon_white_1.svg: -------------------------------------------------------------------------------- 1 | chat21-thik-balloon -------------------------------------------------------------------------------- /src/models/conversation.ts: -------------------------------------------------------------------------------- 1 | export class ConversationModel { 2 | constructor( 3 | public uid: string, 4 | public attributes: any, 5 | public channel_type: string, 6 | public is_new: boolean, 7 | public last_message_text: string, 8 | public recipient: string, 9 | public recipient_fullname: string, 10 | public sender: string, 11 | public sender_fullname: string, 12 | public status: string, 13 | public timestamp: number, 14 | public type: string, 15 | public time_last_message: string, 16 | public color: string, 17 | public avatar: string, 18 | public image: string, 19 | public badge: number, 20 | public archived: boolean 21 | ) {} 22 | } 23 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/form-label/form-label.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | import { FormGroup, FormGroupDirective } from '@angular/forms'; 3 | import { FormArray } from '../../../../../chat21-core/models/formArray'; 4 | 5 | @Component({ 6 | selector: 'chat-form-label', 7 | templateUrl: './form-label.component.html', 8 | styleUrls: ['./form-label.component.scss'] 9 | }) 10 | export class FormLabelComponent implements OnInit { 11 | 12 | @Input() element: FormArray; 13 | @Input() controlName: string; 14 | @Input() hasSubmitted: boolean; 15 | 16 | form: FormGroup; 17 | constructor(private rootFormGroup: FormGroupDirective) { } 18 | 19 | ngOnInit() { 20 | this.form = this.rootFormGroup.control; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/select/select.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SelectComponent } from './select.component'; 4 | 5 | describe('SelectComponent', () => { 6 | let component: SelectComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SelectComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SelectComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/send-button/send-button.component.ts: -------------------------------------------------------------------------------- 1 | import { ConversationFooterComponent } from './../conversation-detail/conversation-footer/conversation-footer.component'; 2 | import { Component, OnInit, EventEmitter, Output } from '@angular/core'; 3 | import { Globals } from '../../utils/globals'; 4 | 5 | @Component({ 6 | selector: 'chat-send-button', 7 | templateUrl: './send-button.component.html', 8 | styleUrls: ['./send-button.component.scss'] 9 | }) 10 | export class SendButtonComponent implements OnInit { 11 | 12 | @Output() onSendButtonClicked = new EventEmitter() 13 | constructor(public g: Globals) { } 14 | 15 | ngOnInit() { 16 | } 17 | 18 | onSendPressed(event){ 19 | console.log('send pressed') 20 | this.onSendButtonClicked.emit(true) 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/app/providers/upload.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientModule } from '@angular/common/http'; 2 | import { AppConfigService } from './app-config.service'; 3 | import { Globals } from './../utils/globals'; 4 | import { TestBed, inject } from '@angular/core/testing'; 5 | 6 | import { UploadService_old } from './upload.service'; 7 | 8 | describe('UploadService_old', () => { 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | imports: [ 12 | HttpClientModule 13 | ], 14 | providers: [ 15 | UploadService_old, 16 | Globals, 17 | AppConfigService 18 | ] 19 | }); 20 | }); 21 | 22 | it('should be created', inject([UploadService_old], (service: UploadService_old) => { 23 | expect(service).toBeTruthy(); 24 | })); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/users/user-login/user-login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserLoginComponent } from './user-login.component'; 4 | 5 | describe('UserLoginComponent', () => { 6 | let component: UserLoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ UserLoginComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(UserLoginComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/form-text/form-text.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FormTextComponent } from './form-text.component'; 4 | 5 | describe('FormTextComponent', () => { 6 | let component: FormTextComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FormTextComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FormTextComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/send-button/send-button.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SendButtonComponent } from './send-button.component'; 4 | 5 | describe('SendButtonComponent', () => { 6 | let component: SendButtonComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SendButtonComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SendButtonComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/assets/images/f21_widget_icon_white_2.svg: -------------------------------------------------------------------------------- 1 | chat21-balloon -------------------------------------------------------------------------------- /src/app/components/form/inputs/form-label/form-label.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FormLabelComponent } from './form-label.component'; 4 | 5 | describe('FormLabelComponent', () => { 6 | let component: FormLabelComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FormLabelComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FormLabelComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/users/user-profile/user-profile.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserProfileComponent } from './user-profile.component'; 4 | 5 | describe('UserProfileComponent', () => { 6 | let component: UserProfileComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ UserProfileComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(UserProfileComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/assets/images/tiledesk-chat-close-dark-gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | tiledesk-chat-close 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/app/components/form/form-builder/form-builder.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FormBuilderComponent } from './form-builder.component'; 4 | 5 | describe('FormBuilderComponent', () => { 6 | let component: FormBuilderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FormBuilderComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FormBuilderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/message/buttons/link-button/link-button.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LinkButtonComponent } from './link-button.component'; 4 | 5 | describe('LinkButtonComponent', () => { 6 | let component: LinkButtonComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LinkButtonComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LinkButtonComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/message/buttons/text-button/text-button.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TextButtonComponent } from './text-button.component'; 4 | 5 | describe('TextButtonComponent', () => { 6 | let component: TextButtonComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TextButtonComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TextButtonComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/radio-button/radio-button.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RadioButtonComponent } from './radio-button.component'; 4 | 5 | describe('RadioButtonComponent', () => { 6 | let component: RadioButtonComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RadioButtonComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RadioButtonComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/chat21-core/models/conversation.ts: -------------------------------------------------------------------------------- 1 | export class ConversationModel { 2 | constructor( 3 | public uid: string, 4 | public attributes: any, 5 | public channel_type: string, 6 | public conversation_with_fullname: string, 7 | public conversation_with: string, 8 | public recipient: string, 9 | public recipient_fullname: string, 10 | public image: string, 11 | public is_new: boolean, 12 | public last_message_text: string, 13 | public text: string, 14 | public sender: string, 15 | public senderAuthInfo: any, 16 | public sender_fullname: string, 17 | public status: string, 18 | public timestamp: string, 19 | public selected: boolean, 20 | public color: string, 21 | public avatar: string, 22 | public archived: boolean, 23 | public type: string, 24 | ) { } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/form-checkbox/form-checkbox.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FormCheckboxComponent } from './form-checkbox.component'; 4 | 5 | describe('FormCheckboxComponent', () => { 6 | let component: FormCheckboxComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FormCheckboxComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FormCheckboxComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/form-textarea/form-textarea.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FormTextareaComponent } from './form-textarea.component'; 4 | 5 | describe('FormTextareaComponent', () => { 6 | let component: FormTextareaComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FormTextareaComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FormTextareaComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/message/buttons/action-button/action-button.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ActionButtonComponent } from './action-button.component'; 4 | 5 | describe('ActionButtonComponent', () => { 6 | let component: ActionButtonComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ActionButtonComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ActionButtonComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/message/return-receipt/return-receipt.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ReturnReceiptComponent } from './return-receipt.component'; 4 | 5 | describe('ReturnReceiptComponent', () => { 6 | let component: ReturnReceiptComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ReturnReceiptComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ReturnReceiptComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/message/return-receipt/return-receipt.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | import { MSG_STATUS_RETURN_RECEIPT, MSG_STATUS_SENT, MSG_STATUS_SENT_SERVER } from '../../../utils/constants'; 3 | 4 | @Component({ 5 | selector: 'chat-return-receipt', 6 | templateUrl: './return-receipt.component.html', 7 | styleUrls: ['./return-receipt.component.scss'] 8 | }) 9 | export class ReturnReceiptComponent implements OnInit { 10 | 11 | @Input() status: number; 12 | 13 | // ========== begin:: set icon status message 14 | MSG_STATUS_SENT = MSG_STATUS_SENT; 15 | MSG_STATUS_SENT_SERVER = MSG_STATUS_SENT_SERVER; 16 | MSG_STATUS_RETURN_RECEIPT = MSG_STATUS_RETURN_RECEIPT; 17 | // ========== end:: icon status message 18 | 19 | constructor() { } 20 | 21 | ngOnInit() { 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/image-repo.service.ts: -------------------------------------------------------------------------------- 1 | import { environment } from '../../../environments/environment'; 2 | import { Injectable } from '@angular/core'; 3 | 4 | // @Injectable({providedIn: 'root'}) 5 | @Injectable() 6 | export abstract class ImageRepoService { 7 | 8 | 9 | 10 | //params 11 | private DEFAULT_URL: string = environment.baseImageUrl; 12 | private baseImageUrl; 13 | 14 | public setImageBaseUrl(baseUrl): void { 15 | this.baseImageUrl = baseUrl; 16 | } 17 | public getImageBaseUrl(): string { 18 | if (this.baseImageUrl) { 19 | return this.baseImageUrl; 20 | } else { 21 | return this.DEFAULT_URL; 22 | } 23 | } 24 | 25 | // functions 26 | abstract getImagePhotoUrl(uid: string): string; 27 | abstract checkImageExists(uid: string, callback:(exist: boolean)=>void): void; 28 | } 29 | -------------------------------------------------------------------------------- /src/chat21-core/utils/user-typing/user-typing.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { IonicModule } from '@ionic/angular'; 3 | 4 | import { UserTypingComponent } from './user-typing.component'; 5 | 6 | describe('UserTypingComponent', () => { 7 | let component: UserTypingComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [ UserTypingComponent ], 13 | imports: [] 14 | }).compileComponents(); 15 | 16 | fixture = TestBed.createComponent(UserTypingComponent); 17 | component = fixture.componentInstance; 18 | fixture.detectChanges(); 19 | })); 20 | 21 | it('should create', () => { 22 | expect(component).toBeTruthy(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/chat21-core/providers/mqtt/mqtt-conversation-handler-builder.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | // services 3 | import { ConversationHandlerBuilderService } from '../abstract/conversation-handler-builder.service'; 4 | import { MQTTConversationHandler } from './mqtt-conversation-handler'; 5 | import { Chat21Service } from './chat-service'; 6 | 7 | // @Injectable({ providedIn: 'root' }) 8 | @Injectable() 9 | export class MQTTConversationHandlerBuilderService extends ConversationHandlerBuilderService { 10 | 11 | constructor( 12 | public chat21Service: Chat21Service 13 | ) { 14 | super(); 15 | } 16 | 17 | public build(): any { 18 | const conversationHandlerService = new MQTTConversationHandler( 19 | this.chat21Service, 20 | true 21 | ); 22 | return conversationHandlerService; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/chat21-core/providers/mqtt/mqtt-notifications.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Injectable } from '@angular/core'; 3 | // services 4 | import { NotificationsService } from '../abstract/notifications.service'; 5 | 6 | // @Injectable({ providedIn: 'root' }) 7 | @Injectable() 8 | export class MQTTNotifications extends NotificationsService { 9 | 10 | public BUILD_VERSION: string; 11 | constructor( ) { 12 | super(); 13 | } 14 | 15 | initialize(tenant: string): void { 16 | console.log('Method not implemented.'); 17 | return; 18 | } 19 | 20 | getNotificationPermissionAndSaveToken(currentUser: string) { 21 | console.log('Method not implemented.'); 22 | return; 23 | } 24 | 25 | 26 | removeNotificationsInstance(callback: (string) => void) { 27 | console.log('Method not implemented.'); 28 | return; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /deploy_amazon_prod.sh: -------------------------------------------------------------------------------- 1 | # npm version patch 2 | version=`node -e 'console.log(require("./package.json").version)'` 3 | echo "version $version" 4 | 5 | # --build-optimizer=false if localstorage is disabled (webview) appears https://github.com/firebase/angularfire/issues/970 6 | ng build --prod --env=prod --base-href --output-hashing none --build-optimizer=false 7 | 8 | cd dist 9 | aws s3 sync . s3://tiledesk-widget/v5/$version/ 10 | aws s3 sync . s3://tiledesk-widget/v5/ 11 | # --cache-control max-age=604800 12 | cd .. 13 | 14 | aws cloudfront create-invalidation --distribution-id E3EJDWEHY08CZZ --paths "/*" 15 | echo new version deployed $version on s3://tiledesk-widget/v5 16 | echo available on https://s3.eu-west-1.amazonaws.com/tiledesk-widget/v5/index.html 17 | echo https://widget.tiledesk.com/v5/index.html 18 | echo https://widget.tiledesk.com/v5/$version/index.html -------------------------------------------------------------------------------- /src/app/providers/waiting.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientModule } from '@angular/common/http'; 2 | import { AppConfigService } from './app-config.service'; 3 | import { Globals } from './../utils/globals'; 4 | import { HttpModule } from '@angular/http'; 5 | import { TestBed, inject } from '@angular/core/testing'; 6 | 7 | import { WaitingService } from './waiting.service'; 8 | 9 | describe('WaitingService', () => { 10 | beforeEach(() => { 11 | TestBed.configureTestingModule({ 12 | imports: [ 13 | HttpModule, 14 | HttpClientModule 15 | ], 16 | providers: [ 17 | WaitingService, 18 | Globals, 19 | AppConfigService 20 | ] 21 | }); 22 | }); 23 | 24 | it('should be created', inject([WaitingService], (service: WaitingService) => { 25 | expect(service).toBeTruthy(); 26 | })); 27 | }); 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | 9 | # dependencies 10 | /node_modules 11 | 12 | # IDEs and editors 13 | /.idea 14 | .project 15 | .classpath 16 | .c9/ 17 | *.launch 18 | .settings/ 19 | *.sublime-workspace 20 | 21 | # IDE - VSCode 22 | .vscode/* 23 | !.vscode/settings.json 24 | !.vscode/tasks.json 25 | !.vscode/launch.json 26 | !.vscode/extensions.json 27 | 28 | # misc 29 | /.sass-cache 30 | /connect.lock 31 | /coverage 32 | /libpeerconnection.log 33 | npm-debug.log 34 | testem.log 35 | /typings 36 | 37 | # e2e 38 | /e2e/*.js 39 | /e2e/*.map 40 | 41 | # System Files 42 | .DS_Store 43 | Thumbs.db 44 | test_widget.php 45 | 46 | src/environments 47 | src/environments_dati_reali 48 | src/widget-config-docker.json 49 | src/widget-config-native-mqtt.json 50 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/notifications.service.ts: -------------------------------------------------------------------------------- 1 | import { environment } from './../../../environments/environment'; 2 | import { Injectable } from '@angular/core'; 3 | 4 | // @Injectable({ providedIn: 'root' }) 5 | @Injectable() 6 | export abstract class NotificationsService { 7 | 8 | private _tenant: string; 9 | abstract BUILD_VERSION = environment.version 10 | 11 | public setTenant(tenant): void { 12 | this._tenant = tenant; 13 | } 14 | public getTenant(): string { 15 | if (this._tenant) { 16 | return this._tenant; 17 | } 18 | } 19 | 20 | abstract initialize(tenant: string, vapidKey: string): void; 21 | abstract getNotificationPermissionAndSaveToken(currentUserUid: string): void; 22 | abstract removeNotificationsInstance(callback: (string) => void): void; 23 | 24 | constructor( ) { 25 | 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/widget-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "chatEngine": "mqtt", 3 | "uploadEngine": "native", 4 | "pushEngine":"none", 5 | "fileUploadAccept":"*/*", 6 | "logLevel":"INFO", 7 | "remoteTranslationsUrl": "http://localhost:3000/", 8 | "firebaseConfig": { 9 | "apiKey": "CHANGEIT", 10 | "authDomain": "CHANGEIT", 11 | "databaseURL": "CHANGEIT", 12 | "projectId": "CHANGEIT", 13 | "storageBucket": "CHANGEIT", 14 | "messagingSenderId": "CHANGEIT", 15 | "appId": "CHANGEIT", 16 | "tenant": "CHANGEIT" 17 | }, 18 | "chat21Config": { 19 | "appId": "tilechat", 20 | "MQTTendpoint": "ws://localhost:15675/ws", 21 | "APIendpoint": "http://localhost:8004/api" 22 | }, 23 | "apiUrl": "http://localhost:3000/", 24 | "baseImageUrl": "http://localhost:3000/", 25 | "authPersistence": "LOCAL" 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/app/providers/conversations.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { SettingsSaverService } from './settings-saver.service'; 2 | import { Globals } from './../utils/globals'; 3 | import { TestBed, inject } from '@angular/core/testing'; 4 | 5 | import { ConversationsService } from './conversations.service'; 6 | import { HttpClientModule } from '@angular/common/http'; 7 | import { AppStorageService } from '../../chat21-core/providers/abstract/app-storage.service'; 8 | 9 | describe('ConversationsService', () => { 10 | beforeEach(() => { 11 | TestBed.configureTestingModule({ 12 | providers: [ 13 | ConversationsService, 14 | Globals, 15 | SettingsSaverService, 16 | AppStorageService 17 | ] 18 | }); 19 | }); 20 | 21 | it('should be created', inject([ConversationsService], (service: ConversationsService) => { 22 | expect(service).toBeTruthy(); 23 | })); 24 | }); 25 | -------------------------------------------------------------------------------- /src/app/components/menu-options/menu-options.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { Globals } from '../../utils/globals'; 3 | 4 | import { MenuOptionsComponent } from './menu-options.component'; 5 | 6 | describe('MenuOptionsComponent', () => { 7 | let component: MenuOptionsComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [ MenuOptionsComponent ], 13 | providers: [ Globals ] 14 | }) 15 | .compileComponents(); 16 | })); 17 | 18 | beforeEach(() => { 19 | fixture = TestBed.createComponent(MenuOptionsComponent); 20 | component = fixture.componentInstance; 21 | fixture.detectChanges(); 22 | }); 23 | 24 | it('should create', () => { 25 | expect(component).toBeTruthy(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/app/components/message/avatar/avatar.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 | 7 |
8 |
9 | 10 | 16 | 17 | -------------------------------------------------------------------------------- /src/app/components/message/info-message/info-message.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { MarkedPipe } from '../../../directives/marked.pipe'; 3 | 4 | import { InfoMessageComponent } from './info-message.component'; 5 | 6 | describe('InfoMessageComponent', () => { 7 | let component: InfoMessageComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [ InfoMessageComponent, MarkedPipe ] 13 | }) 14 | .compileComponents(); 15 | })); 16 | 17 | beforeEach(() => { 18 | fixture = TestBed.createComponent(InfoMessageComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/app/components/conversation-detail/conversation-preview/conversation-preview.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ConversationPreviewComponent } from './conversation-preview.component'; 4 | 5 | describe('ConversationPreviewImageComponent', () => { 6 | let component: ConversationPreviewComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ConversationPreviewComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ConversationPreviewComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/message/avatar/avatar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { ImageRepoService } from '../../../../chat21-core/providers/abstract/image-repo.service'; 3 | 4 | import { AvatarComponent } from './avatar.component'; 5 | 6 | describe('AvatarComponent', () => { 7 | let component: AvatarComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [ AvatarComponent ], 13 | providers: [ ImageRepoService ] 14 | }) 15 | .compileComponents(); 16 | })); 17 | 18 | beforeEach(() => { 19 | fixture = TestBed.createComponent(AvatarComponent); 20 | component = fixture.componentInstance; 21 | fixture.detectChanges(); 22 | }); 23 | 24 | it('should create', () => { 25 | expect(component).toBeTruthy(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/app/providers/agent-availability.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Globals } from './../utils/globals'; 2 | import { AppConfigService } from './app-config.service'; 3 | import { HttpClientModule } from '@angular/common/http'; 4 | import { TestBed, inject } from '@angular/core/testing'; 5 | import { HttpModule } from '@angular/http'; 6 | 7 | import { AgentAvailabilityService } from './agent-availability.service'; 8 | 9 | describe('AgentAvailabilityService', () => { 10 | beforeEach(() => { 11 | TestBed.configureTestingModule({ 12 | imports: [ 13 | HttpModule, 14 | HttpClientModule 15 | ], 16 | providers: [ 17 | AgentAvailabilityService, 18 | AppConfigService, 19 | Globals 20 | ] 21 | }); 22 | }); 23 | 24 | it('should be created', inject([AgentAvailabilityService], (service: AgentAvailabilityService) => { 25 | expect(service).toBeTruthy(); 26 | })); 27 | }); 28 | -------------------------------------------------------------------------------- /src/app/providers/auth.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { StorageService } from './storage.service'; 2 | import { AppConfigService } from './app-config.service'; 3 | import { Globals } from './../utils/globals'; 4 | import { TestBed, inject } from '@angular/core/testing'; 5 | import { HttpModule } from '@angular/http'; 6 | 7 | import { AuthService_old } from './auth.service'; 8 | import { HttpClientModule } from '@angular/common/http'; 9 | 10 | describe('AuthService_old', () => { 11 | beforeEach(() => { 12 | TestBed.configureTestingModule({ 13 | imports: [ 14 | HttpModule, 15 | HttpClientModule 16 | ], 17 | providers: [ 18 | AuthService_old, 19 | Globals, 20 | AppConfigService, 21 | StorageService 22 | ] 23 | }); 24 | }); 25 | 26 | it('should be created', inject([AuthService_old], (service: AuthService_old) => { 27 | expect(service).toBeTruthy(); 28 | })); 29 | }); 30 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/upload.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { BehaviorSubject } from 'rxjs'; 3 | import { environment } from '../../../environments/environment'; 4 | 5 | // models 6 | import { UploadModel } from '../../models/upload'; 7 | 8 | @Injectable() 9 | export abstract class UploadService { 10 | 11 | //params 12 | private DEFAULT_URL: string = environment.apiUrl; 13 | private baseUrl; 14 | 15 | public setBaseUrl(baseUrl): void { 16 | this.baseUrl = baseUrl; 17 | } 18 | public getBaseUrl(): string { 19 | if (this.baseUrl) { 20 | return this.baseUrl; 21 | } else { 22 | return this.DEFAULT_URL; 23 | } 24 | } 25 | 26 | //BehaviorSubject 27 | abstract BSStateUpload: BehaviorSubject = new BehaviorSubject(null); 28 | 29 | // functions 30 | abstract initialize(): void; 31 | abstract upload(userId: string, upload: UploadModel): Promise; 32 | } -------------------------------------------------------------------------------- /src/app/components/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { NO_ERRORS_SCHEMA } from '@angular/core'; 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { Globals } from '../../utils/globals'; 4 | 5 | import { HomeComponent } from './home.component'; 6 | 7 | describe('HomeComponent', () => { 8 | let component: HomeComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(async(() => { 12 | TestBed.configureTestingModule({ 13 | declarations: [ HomeComponent ], 14 | providers: [ 15 | Globals 16 | ], 17 | schemas: [NO_ERRORS_SCHEMA] 18 | }) 19 | .compileComponents(); 20 | })); 21 | 22 | beforeEach(() => { 23 | fixture = TestBed.createComponent(HomeComponent); 24 | component = fixture.componentInstance; 25 | fixture.detectChanges(); 26 | }); 27 | 28 | it('should create', () => { 29 | expect(component).toBeTruthy(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/app/components/star-rating-widget/star-rating-widget.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { AppConfigService } from './../../providers/app-config.service'; 2 | import { Globals } from './../../utils/globals'; 3 | import { TestBed, inject } from '@angular/core/testing'; 4 | import { HttpModule } from '@angular/http'; 5 | 6 | import { StarRatingWidgetService } from './star-rating-widget.service'; 7 | import { HttpClientModule } from '@angular/common/http'; 8 | 9 | describe('StarRatingWidgetService', () => { 10 | beforeEach(() => { 11 | TestBed.configureTestingModule({ 12 | imports: [ 13 | HttpModule, 14 | HttpClientModule 15 | ], 16 | providers: [ 17 | StarRatingWidgetService, 18 | Globals, 19 | AppConfigService 20 | ] 21 | }); 22 | }); 23 | 24 | it('should be created', inject([StarRatingWidgetService], (service: StarRatingWidgetService) => { 25 | expect(service).toBeTruthy(); 26 | })); 27 | }); 28 | -------------------------------------------------------------------------------- /src/app/components/list-conversations/list-conversations.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { NO_ERRORS_SCHEMA } from '@angular/core'; 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | 4 | import { ListConversationsComponent } from './list-conversations.component'; 5 | 6 | describe('ListConversationsComponent', () => { 7 | let component: ListConversationsComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [ ListConversationsComponent ], 13 | schemas: [NO_ERRORS_SCHEMA] 14 | }) 15 | .compileComponents(); 16 | })); 17 | 18 | beforeEach(() => { 19 | fixture = TestBed.createComponent(ListConversationsComponent); 20 | component = fixture.componentInstance; 21 | fixture.detectChanges(); 22 | }); 23 | 24 | it('should create', () => { 25 | expect(component).toBeTruthy(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/app/components/preview-loading-files/preview-loading-files.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { Globals } from '../../utils/globals'; 3 | 4 | import { PreviewLoadingFilesComponent } from './preview-loading-files.component'; 5 | 6 | describe('PreviewLoadingFilesComponent', () => { 7 | let fixture: ComponentFixture; 8 | let component: PreviewLoadingFilesComponent; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [ PreviewLoadingFilesComponent ], 13 | providers: [ Globals ] 14 | }) 15 | .compileComponents(); 16 | })); 17 | 18 | beforeEach(() => { 19 | fixture = TestBed.createComponent(PreviewLoadingFilesComponent); 20 | component = fixture.componentInstance; 21 | fixture.detectChanges(); 22 | }); 23 | 24 | it('should create', () => { 25 | expect(component).toBeTruthy(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/app/providers/translator.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientModule } from '@angular/common/http'; 2 | import { AppConfigService } from './app-config.service'; 3 | import { Globals } from './../utils/globals'; 4 | import { HttpModule } from '@angular/http'; 5 | import { TranslateModule, TranslateService } from '@ngx-translate/core'; 6 | import { TestBed, inject } from '@angular/core/testing'; 7 | 8 | import { TranslatorService } from './translator.service'; 9 | 10 | describe('TranslatorService', () => { 11 | beforeEach(() => { 12 | TestBed.configureTestingModule({ 13 | imports: [ 14 | HttpModule, 15 | HttpClientModule, 16 | TranslateModule.forRoot(), 17 | ], 18 | providers: [ 19 | TranslatorService, 20 | Globals, 21 | AppConfigService 22 | ] 23 | }); 24 | }); 25 | 26 | it('should be created', inject([TranslatorService], (service: TranslatorService) => { 27 | expect(service).toBeTruthy(); 28 | })); 29 | }); 30 | -------------------------------------------------------------------------------- /.README.md.swp: -------------------------------------------------------------------------------- 1 | b0nano 2.5.3Rparallelsubuntu/home/parallels/dev/chat21-web-widget/README.mdU -------------------------------------------------------------------------------- /src/chat21-core/utils/user-typing/user-typing.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, OnDestroy, Input, ElementRef } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'user-typing', 5 | templateUrl: './user-typing.component.html', 6 | styleUrls: ['./user-typing.component.scss'], 7 | }) 8 | export class UserTypingComponent implements OnInit, OnDestroy { 9 | 10 | // @Input() idConversation: string; 11 | // @Input() idCurrentUser: string; 12 | // @Input() isDirect: boolean; 13 | @Input() translationMap: Map; 14 | @Input() themeColor: string; 15 | @Input() idUserTypingNow: string; 16 | @Input() nameUserTypingNow: string; 17 | // @Input() membersConversation: [string]; 18 | 19 | constructor(private elementRef: ElementRef ) { } 20 | 21 | /** */ 22 | ngOnInit() { 23 | this.elementRef.nativeElement.style.setProperty('--themeColor', this.themeColor); 24 | } 25 | 26 | /** */ 27 | ngOnDestroy() { 28 | // this.unsubescribeAll(); 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/app/components/conversation-detail/interlal-frame/interlal-frame.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | 4 | import { InterlalFrameComponent } from './interlal-frame.component'; 5 | 6 | describe('InterlalFrameComponent', () => { 7 | let component: InterlalFrameComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [ InterlalFrameComponent ], 13 | imports: [ 14 | BrowserAnimationsModule 15 | ] 16 | }) 17 | .compileComponents(); 18 | })); 19 | 20 | beforeEach(() => { 21 | fixture = TestBed.createComponent(InterlalFrameComponent); 22 | component = fixture.componentInstance; 23 | fixture.detectChanges(); 24 | }); 25 | 26 | it('should create', () => { 27 | expect(component).toBeTruthy(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/app/components/message/frame/frame.component.ts: -------------------------------------------------------------------------------- 1 | import { DomSanitizer } from '@angular/platform-browser'; 2 | import { Component, Input, OnInit } from '@angular/core'; 3 | 4 | @Component({ 5 | selector: 'chat-frame', 6 | templateUrl: './frame.component.html', 7 | styleUrls: ['./frame.component.scss'] 8 | }) 9 | export class FrameComponent implements OnInit { 10 | 11 | @Input() metadata: any; 12 | @Input() width: string; 13 | @Input() height: string; 14 | 15 | url: any; 16 | loading: boolean = true 17 | constructor(private sanitizer: DomSanitizer) { } 18 | 19 | ngOnInit() { 20 | if(this.metadata && this.metadata.src){ 21 | this.url = this.sanitizer.bypassSecurityTrustResourceUrl(this.metadata.src); 22 | } 23 | // this.width = this.getSizeImg(this.metadata).width; 24 | // this.height = this.getSizeImg(this.metadata).height; 25 | } 26 | 27 | ngOnDestroy(){ 28 | this.url = null; 29 | } 30 | 31 | onLoaded(event){ 32 | this.loading = false 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/app/providers/global-settings.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Globals } from './../utils/globals'; 2 | import { HttpClientModule } from '@angular/common/http'; 3 | import { TestBed, inject } from '@angular/core/testing'; 4 | import { Http, HttpModule } from '@angular/http'; 5 | import { AppStorageService } from '../../chat21-core/providers/abstract/app-storage.service'; 6 | import { AppConfigService } from './app-config.service'; 7 | 8 | import { GlobalSettingsService } from './global-settings.service'; 9 | 10 | describe('GlobalSettingsService', () => { 11 | beforeEach(() => { 12 | TestBed.configureTestingModule({ 13 | imports: [ 14 | HttpModule, 15 | HttpClientModule, 16 | ], 17 | providers: [ 18 | GlobalSettingsService, 19 | AppStorageService, 20 | AppConfigService, 21 | Globals 22 | ] 23 | }); 24 | }); 25 | 26 | it('should be created', inject([GlobalSettingsService], (service: GlobalSettingsService) => { 27 | expect(service).toBeTruthy(); 28 | })); 29 | }); 30 | -------------------------------------------------------------------------------- /src/app/components/launcher-button/launcher-button.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { AppStorageService } from '../../../chat21-core/providers/abstract/app-storage.service'; 3 | import { Globals } from '../../utils/globals'; 4 | 5 | import { LauncherButtonComponent } from './launcher-button.component'; 6 | 7 | describe('LauncherButtonComponent', () => { 8 | let component: LauncherButtonComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(async(() => { 12 | TestBed.configureTestingModule({ 13 | declarations: [ LauncherButtonComponent ], 14 | providers: [ Globals, AppStorageService] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(LauncherButtonComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular/cli'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular/cli/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | reports: [ 'html', 'lcovonly' ], 20 | fixWebpackSourcePaths: true 21 | }, 22 | angularCli: { 23 | environment: 'dev' 24 | }, 25 | reporters: ['progress', 'kjhtml'], 26 | port: 9876, 27 | colors: true, 28 | logLevel: config.LOG_INFO, 29 | autoWatch: true, 30 | browsers: ['Chrome'], 31 | singleRun: false 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /src/chat21-core/providers/firebase/firebase-init-service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | // firebase 3 | import * as firebase from 'firebase/app'; 4 | import 'firebase/app'; 5 | /* 6 | Generated class for the AuthService provider. 7 | See https://angular.io/docs/ts/latest/guide/dependency-injection.html 8 | for more info on providers and Angular 2 DI. 9 | */ 10 | @Injectable() 11 | /** 12 | * DESC PROVIDER 13 | */ 14 | export class FirebaseInitService { 15 | 16 | public static firebaseInit: any; 17 | 18 | constructor() { 19 | } 20 | 21 | public static initFirebase(firebaseConfig: any) { 22 | if(!FirebaseInitService.firebaseInit){ 23 | if (!firebaseConfig || firebaseConfig.apiKey === 'CHANGEIT') { 24 | throw new Error('Firebase config is not defined. Please create your widget-config.json. See the Chat21-Web_widget Installation Page'); 25 | } 26 | FirebaseInitService.firebaseInit = firebase.initializeApp(firebaseConfig); 27 | } 28 | return FirebaseInitService.firebaseInit 29 | } 30 | } -------------------------------------------------------------------------------- /src/widget-config-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "chatEngine": "${CHAT21_ENGINE}", 3 | "uploadEngine": "${UPLOAD_ENGINE}", 4 | "pushEngine": "${PUSH_ENGINE}", 5 | "fileUploadAccept":"${FILE_UPLOAD_ACCEPT}", 6 | "logLevel": "${LOG_LEVEL}" , 7 | "remoteTranslationsUrl": "${TRANSLATIONS_URL}", 8 | "firebaseConfig": { 9 | "apiKey": "${FIREBASE_APIKEY}", 10 | "authDomain": "${FIREBASE_AUTHDOMAIN}", 11 | "databaseURL": "${FIREBASE_DATABASEURL}", 12 | "projectId": "${FIREBASE_PROJECT_ID}", 13 | "storageBucket": "${FIREBASE_STORAGEBUCKET}", 14 | "messagingSenderId": "${FIREBASE_MESSAGINGSENDERID}", 15 | "appId": "${FIREBASE_APP_ID}", 16 | "tenant": "${FIREBASE_TENANT}" 17 | }, 18 | "chat21Config": { 19 | "appId": "${MQTT_APPID}", 20 | "MQTTendpoint": "${MQTT_ENDPOINT}", 21 | "APIendpoint": "${MQTT_APIENDPOINT}" 22 | }, 23 | "apiUrl": "${API_URL}", 24 | "baseImageUrl": "${API_BASEIMAGE_URL}", 25 | "authPersistence": "${AUTH_PERSISTENCE}" 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/app/providers/waiting.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { environment } from '../../environments/environment'; 3 | import { Observable } from 'rxjs/Observable'; 4 | import { Globals } from '../utils/globals'; 5 | import { Headers, Http } from '@angular/http'; 6 | import { AppConfigService } from '../providers/app-config.service'; 7 | 8 | @Injectable() 9 | export class WaitingService { 10 | API_URL: string; 11 | 12 | constructor( 13 | public http: Http, 14 | public g: Globals, 15 | public appConfigService: AppConfigService 16 | ) { 17 | 18 | this.API_URL = appConfigService.getConfig().apiUrl; 19 | } 20 | 21 | public getCurrent(projectId): Observable { 22 | const url = this.API_URL + projectId + '/publicanalytics/waiting/current'; 23 | const headers = new Headers(); 24 | headers.append('Content-Type', 'application/json'); 25 | // headers.append('Authorization', TOKEN); 26 | return this.http 27 | .get(url, { headers }) 28 | .map((response) => response.json()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/app/components/message/text/text.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { HtmlEntitiesEncodePipe } from './../../../directives/html-entities-encode.pipe'; 2 | import { MarkedPipe } from './../../../directives/marked.pipe'; 3 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 4 | 5 | import { TextComponent } from './text.component'; 6 | 7 | describe('TextComponent', () => { 8 | let component: TextComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(async(() => { 12 | TestBed.configureTestingModule({ 13 | declarations: [ 14 | TextComponent, 15 | MarkedPipe, 16 | HtmlEntitiesEncodePipe 17 | ] 18 | }) 19 | .compileComponents(); 20 | })); 21 | 22 | beforeEach(() => { 23 | fixture = TestBed.createComponent(TextComponent); 24 | component = fixture.componentInstance; 25 | component.text = 'Msg text' 26 | component.color= 'black' 27 | fixture.detectChanges(); 28 | }); 29 | 30 | it('should create', () => { 31 | expect(component).toBeTruthy(); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/app/components/eyeeye-catcher-card/eyeeye-catcher-card.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { Globals } from '../../utils/globals'; 4 | 5 | import { EyeeyeCatcherCardComponent } from './eyeeye-catcher-card.component'; 6 | 7 | describe('EyeeyeCatcherCardComponent', () => { 8 | let component: EyeeyeCatcherCardComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(async(() => { 12 | TestBed.configureTestingModule({ 13 | declarations: [ EyeeyeCatcherCardComponent ], 14 | imports: [ 15 | BrowserAnimationsModule 16 | ], 17 | providers: [ Globals ] 18 | }) 19 | .compileComponents(); 20 | })); 21 | 22 | beforeEach(() => { 23 | fixture = TestBed.createComponent(EyeeyeCatcherCardComponent); 24 | component = fixture.componentInstance; 25 | fixture.detectChanges(); 26 | }); 27 | 28 | it('should create', () => { 29 | expect(component).toBeTruthy(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/form-text/form-text.component.html: -------------------------------------------------------------------------------- 1 |
2 |
5 | 8 | 16 |
17 |
18 | {{translationErrorLabelMap.get('LABEL_ERROR_FIELD_REQUIRED')}} 19 |
20 |
21 | {{element.errorLabel}} 22 |
23 |
24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-present Tiledesk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/app/providers/messaging.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientModule } from '@angular/common/http'; 2 | import { AppConfigService } from './app-config.service'; 3 | import { Globals } from './../utils/globals'; 4 | import { StarRatingWidgetService } from './../components/star-rating-widget/star-rating-widget.service'; 5 | import { TestBed, inject } from '@angular/core/testing'; 6 | 7 | import { MessagingService } from './messaging.service'; 8 | import { HttpModule } from '@angular/http'; 9 | import { AppStorageService } from '../../chat21-core/providers/abstract/app-storage.service'; 10 | 11 | describe('MessagingService', () => { 12 | beforeEach(() => { 13 | TestBed.configureTestingModule({ 14 | imports: [ 15 | HttpModule, 16 | HttpClientModule 17 | ], 18 | providers: [ 19 | MessagingService, 20 | StarRatingWidgetService, 21 | Globals, 22 | AppConfigService, 23 | AppStorageService 24 | ] 25 | }); 26 | }); 27 | 28 | it('should be created', inject([MessagingService], (service: MessagingService) => { 29 | expect(service).toBeTruthy(); 30 | })); 31 | }); 32 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/typing.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { BehaviorSubject } from 'rxjs'; 3 | 4 | 5 | // @Injectable({ 6 | // providedIn: 'root' 7 | // }) 8 | @Injectable() 9 | export abstract class TypingService { 10 | 11 | // BehaviorSubject 12 | BSIsTyping: BehaviorSubject = new BehaviorSubject(null); 13 | BSSetTyping: BehaviorSubject = new BehaviorSubject(null); 14 | 15 | // params 16 | // private DEFAULT_TENANT: string = environment.firebaseConfig.tenant; 17 | // private _tenant: string; 18 | 19 | // public setTenant(tenant): void { 20 | // this._tenant = tenant; 21 | // } 22 | // public getTenant(): string { 23 | // if (this._tenant) { 24 | // return this._tenant; 25 | // } else { 26 | // return this.DEFAULT_TENANT 27 | // } 28 | // } 29 | 30 | // functions 31 | abstract initialize(tenant: string): void; 32 | abstract isTyping(idConversation: string, idCurrentUser: string, isDirect: boolean): void; 33 | abstract setTyping(idConversation: string, message: string, idUser: string, userFullname: string): void; 34 | } 35 | -------------------------------------------------------------------------------- /src/app/components/prechat-form/prechat-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { Globals } from './../../utils/globals'; 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | 5 | import { PrechatFormComponent } from './prechat-form.component'; 6 | import { AppStorageService } from '../../../chat21-core/providers/abstract/app-storage.service'; 7 | 8 | describe('PrechatFormComponent', () => { 9 | let component: PrechatFormComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ PrechatFormComponent ], 15 | imports: [ FormsModule, ReactiveFormsModule ], 16 | providers: [ Globals, AppStorageService] 17 | }) 18 | .compileComponents(); 19 | })); 20 | 21 | beforeEach(() => { 22 | fixture = TestBed.createComponent(PrechatFormComponent); 23 | component = fixture.componentInstance; 24 | fixture.detectChanges(); 25 | }); 26 | 27 | it('should create', () => { 28 | expect(component).toBeTruthy(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /src/assets/images/tiledesk-chat-ballon-with-badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | tiledesk-chat-ballon 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/presence.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { BehaviorSubject, Observable } from 'rxjs'; 3 | 4 | // @Injectable({ 5 | // providedIn: 'root' 6 | // }) 7 | @Injectable() 8 | export abstract class PresenceService { 9 | 10 | // BehaviorSubject 11 | abstract BSIsOnline: BehaviorSubject = new BehaviorSubject(null); 12 | abstract BSLastOnline: BehaviorSubject = new BehaviorSubject(null); 13 | 14 | // params 15 | // private DEFAULT_TENANT: string = environment.firebaseConfig.tenant; 16 | // private _tenant: string; 17 | 18 | // public setTenant(tenant): void { 19 | // this._tenant = tenant; 20 | // } 21 | // public getTenant(): string { 22 | // if (this._tenant) { 23 | // return this._tenant; 24 | // } else { 25 | // return this.DEFAULT_TENANT 26 | // } 27 | // } 28 | 29 | // functions 30 | abstract initialize(tenant: string): void; 31 | abstract userIsOnline(userid: string): Observable 32 | abstract lastOnlineForUser(userid: string): void; 33 | abstract setPresence(userid: string): void; 34 | abstract removePresence(): void; 35 | } 36 | -------------------------------------------------------------------------------- /src/assets/images/tiledesk-chat-ballon-big-badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | tiledesk-chat-ballon 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ### STAGE 1: Build ### 2 | 3 | # We label our stage as ‘builder’ 4 | FROM node:10-alpine as builder 5 | 6 | COPY package.json package-lock.json ./ 7 | 8 | ## Storing node modules on a separate layer will prevent unnecessary npm installs at each build 9 | 10 | RUN npm ci && mkdir /ng-app && mv ./node_modules ./ng-app 11 | 12 | WORKDIR /ng-app 13 | 14 | COPY . . 15 | 16 | ## Build the angular app in production mode and store the artifacts in dist folder 17 | 18 | RUN npm run ng build -- --prod --output-path=dist --base-href ./ --output-hashing none --build-optimizer=false 19 | 20 | 21 | ### STAGE 2: Setup ### 22 | 23 | FROM nginx:1.14.1-alpine 24 | 25 | ## Copy our default nginx config 26 | COPY nginx.conf /etc/nginx/nginx.conf 27 | 28 | ## Remove default nginx website 29 | RUN rm -rf /usr/share/nginx/html/* 30 | 31 | ## From ‘builder’ stage copy over the artifacts in dist folder to default nginx public folder 32 | COPY --from=builder /ng-app/dist /usr/share/nginx/html 33 | 34 | RUN echo "Chat21 Web Widget Started!!" 35 | 36 | CMD ["/bin/sh", "-c", "envsubst < /usr/share/nginx/html/widget-config-template.json > /usr/share/nginx/html/widget-config.json && exec nginx -g 'daemon off;'"] 37 | -------------------------------------------------------------------------------- /src/app/components/message/text/text.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, OnInit, Output, Sanitizer } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'chat-text', 5 | templateUrl: './text.component.html', 6 | styleUrls: ['./text.component.scss'] 7 | }) 8 | export class TextComponent implements OnInit { 9 | 10 | @Input() text: string; 11 | @Input() htmlEnabled: boolean = false; 12 | @Input() color: string; 13 | @Input() fontSize: string; 14 | @Input() fontFamily: string; 15 | @Output() onBeforeMessageRender = new EventEmitter(); 16 | @Output() onAfterMessageRender = new EventEmitter(); 17 | 18 | constructor() { } 19 | 20 | ngOnInit() { 21 | } 22 | 23 | 24 | printMessage(text, messageEl, component) { 25 | const messageOBJ = { messageEl: messageEl, component: component} 26 | this.onBeforeMessageRender.emit(messageOBJ) 27 | const messageText = text; 28 | this.onAfterMessageRender.emit(messageOBJ) 29 | // this.triggerBeforeMessageRender(message, messageEl, component); 30 | // const messageText = message.text; 31 | // this.triggerAfterMessageRender(message, messageEl, component); 32 | return messageText; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/assets/images/avatar_bot_tiledesk.svg: -------------------------------------------------------------------------------- 1 | ic_widget_bot_gray_03 -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | import { getTestBed } from '@angular/core/testing'; 10 | import { 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting 13 | } from '@angular/platform-browser-dynamic/testing'; 14 | 15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 16 | declare const __karma__: any; 17 | declare const require: any; 18 | 19 | // Prevent Karma from running prematurely. 20 | __karma__.loaded = function () {}; 21 | 22 | // First, initialize the Angular testing environment. 23 | getTestBed().initTestEnvironment( 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting() 26 | ); 27 | // Then we find all the tests. 28 | const context = require.context('./', true, /\.spec\.ts$/); 29 | // And load the modules. 30 | context.keys().map(context); 31 | // Finally, start Karma to run the tests. 32 | __karma__.start(); 33 | -------------------------------------------------------------------------------- /src/chat21-core/providers/mqtt/chat-service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | import { Chat21Client } from '../../../assets/js/chat21client'; 4 | // declare var Chat21Client: any; 5 | 6 | /* 7 | Generated class for the AuthService provider. 8 | See https://angular.io/docs/ts/latest/guide/dependency-injection.html 9 | for more info on providers and Angular 2 DI. 10 | */ 11 | @Injectable() 12 | /** 13 | * DESC PROVIDER 14 | */ 15 | export class Chat21Service { 16 | 17 | public chatClient: any; 18 | private _config: any; 19 | 20 | constructor() { 21 | } 22 | 23 | public set config(config: any) { 24 | this._config = config; 25 | } 26 | 27 | public get config() : any { 28 | return this._config; 29 | } 30 | 31 | initChat() { 32 | if (!this._config || this._config.appId === 'CHANGEIT') { 33 | throw new Error('chat21Config is not defined. Please setup your environment'); 34 | } 35 | if (!this.chatClient) { 36 | this.chatClient = new Chat21Client(this._config); 37 | } 38 | else { 39 | console.log("Did you try again to create a Chat21Client istance?"); 40 | } 41 | // console.log("chatClient init. ID:", this.chatClient.client_id) 42 | } 43 | } -------------------------------------------------------------------------------- /src/app/components/message/html/html.component.ts: -------------------------------------------------------------------------------- 1 | import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; 2 | import { Component, ElementRef, Input, OnInit, SimpleChange, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core'; 3 | 4 | @Component({ 5 | selector: 'chat-html', 6 | templateUrl: './html.component.html', 7 | styleUrls: ['./html.component.scss'] 8 | }) 9 | export class HtmlComponent implements OnInit { 10 | 11 | @Input() htmlText: string; 12 | @Input() fontSize: string; 13 | @Input() themeColor: string; 14 | @Input() foregroundColor: string; 15 | 16 | @ViewChild('htmlCode') container; 17 | 18 | constructor(private elementRef: ElementRef) { } 19 | 20 | ngOnInit(){ 21 | 22 | } 23 | 24 | ngOnChanges(changes: SimpleChanges){ 25 | //decomment if element should have same color of themeColor and fregroundColor 26 | if(this.fontSize) this.elementRef.nativeElement.style.setProperty('--buttonFontSize', this.fontSize); 27 | if(this.themeColor) this.elementRef.nativeElement.style.setProperty('--themeColor', this.themeColor); 28 | if(this.foregroundColor) this.elementRef.nativeElement.style.setProperty('--foregroundColor', this.foregroundColor); 29 | } 30 | 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/app/components/message/image/image.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ImageComponent } from './image.component'; 4 | 5 | describe('ImageComponent', () => { 6 | let component: ImageComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ImageComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ImageComponent); 18 | component = fixture.componentInstance; 19 | component.metadata = { 20 | height: 650, 21 | name: "logo_fb.png", 22 | src: "https://firebasestorage.googleapis.com/v0/b/chat21-pre-01.appspot.com/o/public%2Fimages%2F42083ab3-3aa6-4507-831c-41c84b09dd83%2F0e8e8562-360e-4407-aa20-a0ccbe99b62d%2Flogo_fb.png?alt=media&token=8125435a-76ac-42f0-9017-cf3d8fb4e8a1", 23 | type: "image/png", 24 | uid: "ksg7sxnt", 25 | width: 650 26 | } 27 | component.width = '650px' 28 | component.height = 650 29 | fixture.detectChanges(); 30 | }); 31 | 32 | it('should create', () => { 33 | expect(component).toBeTruthy(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/app/components/selection-department/selection-department.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ElementRef } from '@angular/core'; 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { AppStorageService } from '../../../chat21-core/providers/abstract/app-storage.service'; 4 | import { Globals } from '../../utils/globals'; 5 | 6 | import { SelectionDepartmentComponent } from './selection-department.component'; 7 | 8 | describe('SelectionDepartmentComponent', () => { 9 | let component: SelectionDepartmentComponent; 10 | let fixture: ComponentFixture; 11 | class MockElementRef {} 12 | 13 | beforeEach(async(() => { 14 | TestBed.configureTestingModule({ 15 | declarations: [ SelectionDepartmentComponent ], 16 | providers: [ 17 | Globals, 18 | { provide: ElementRef, useClass: MockElementRef }, 19 | AppStorageService 20 | ] 21 | }) 22 | .compileComponents(); 23 | })); 24 | 25 | beforeEach(() => { 26 | fixture = TestBed.createComponent(SelectionDepartmentComponent); 27 | component = fixture.componentInstance; 28 | fixture.detectChanges(); 29 | }); 30 | 31 | it('should create', () => { 32 | expect(component).toBeTruthy(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/app/components/message-attachment/message-attachment.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ActionButtonComponent } from './../message/buttons/action-button/action-button.component'; 2 | import { TextButtonComponent } from './../message/buttons/text-button/text-button.component'; 3 | import { LinkButtonComponent } from './../message/buttons/link-button/link-button.component'; 4 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 5 | 6 | import { MessageAttachmentComponent } from './message-attachment.component'; 7 | 8 | describe('MessageAttachmentComponent', () => { 9 | let component: MessageAttachmentComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ 15 | MessageAttachmentComponent, 16 | LinkButtonComponent, 17 | TextButtonComponent, 18 | ActionButtonComponent 19 | ] 20 | }) 21 | .compileComponents(); 22 | })); 23 | 24 | beforeEach(() => { 25 | fixture = TestBed.createComponent(MessageAttachmentComponent); 26 | component = fixture.componentInstance; 27 | fixture.detectChanges(); 28 | }); 29 | 30 | it('should create', () => { 31 | expect(component).toBeTruthy(); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/app/components/message/info-message/info-message.component.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Component, Input, OnInit } from '@angular/core'; 3 | import { MessageModel } from '../../../../chat21-core/models/message'; 4 | import { LoggerService } from '../../../../chat21-core/providers/abstract/logger.service'; 5 | import { LoggerInstance } from '../../../../chat21-core/providers/logger/loggerInstance'; 6 | 7 | @Component({ 8 | selector: 'chat-info-message', 9 | templateUrl: './info-message.component.html', 10 | styleUrls: ['./info-message.component.scss'] 11 | }) 12 | export class InfoMessageComponent implements OnInit { 13 | 14 | @Input() message: MessageModel 15 | 16 | public message_text: string 17 | private logger: LoggerService = LoggerInstance.getInstance() 18 | constructor() { } 19 | 20 | ngOnInit() { 21 | this.logger.debug('[INFO-COMP] message ', this.message) 22 | // Fixes the bug: if a snippet of code is pasted and sent it is not displayed correctly info message 23 | if(this.message && this.message.text) { 24 | var regex = //gi; 25 | this.message.text = this.message.text.replace(regex, "\n") 26 | // this.message.text = replaceEndOfLine(this.message.text); 27 | this.logger.debug('[INFO-COMP] message .text ', this.message.text ) 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/assets/images/f21_widget_icon_white_0.svg: -------------------------------------------------------------------------------- 1 | chat21-full -------------------------------------------------------------------------------- /src/app/components/send-button/send-button.component.scss: -------------------------------------------------------------------------------- 1 | #c21-launcher-button { 2 | // border-radius: 50%; //--> now retrived from settings 3 | position: fixed; 4 | bottom: 0px; 5 | // width: 60px; //--> now retrived from settings 6 | // height: 60px; //--> now retrived from settings 7 | cursor: pointer; 8 | display: block; 9 | margin: 20px; 10 | z-index: 1; 11 | box-shadow: rgba(0, 18, 46, 0.16) 0px 0px 16px 0px; /* NEW GAB */ 12 | 13 | .launcher-button{ 14 | width:100%; 15 | height:100%; 16 | padding:0px; 17 | margin: 0px; 18 | display: flex; 19 | } 20 | } 21 | .c21-divBudge { 22 | position: absolute; 23 | top: 0; 24 | width: 16px; 25 | height: 16px; 26 | min-width: 12px; 27 | font-size: 1.2em; 28 | line-height: 16px; 29 | border-radius: 50%; 30 | background-color: red; 31 | color: white; 32 | font-weight: bold; 33 | padding: 5px 5px; 34 | text-align: center; 35 | margin-top: -10px; 36 | display: inline-block; 37 | } 38 | 39 | @media (max-width: 451px) { 40 | #c21-launcher-button { 41 | //display: none; 42 | &.c21-align-right { 43 | right: 0; 44 | } 45 | &.c21-align-left { 46 | left: 0; 47 | } 48 | 49 | } 50 | } -------------------------------------------------------------------------------- /src/app/components/launcher-button/launcher-button.component.scss: -------------------------------------------------------------------------------- 1 | #c21-launcher-button { 2 | // border-radius: 50%; //--> now retrived from settings 3 | position: fixed; 4 | bottom: 0px; 5 | // width: 60px; //--> now retrived from settings 6 | // height: 60px; //--> now retrived from settings 7 | cursor: pointer; 8 | display: block; 9 | margin: 20px; 10 | z-index: 1; 11 | box-shadow: rgba(0, 18, 46, 0.16) 0px 0px 16px 0px; /* NEW GAB */ 12 | 13 | .launcher-button{ 14 | width:100%; 15 | height:100%; 16 | padding:0px; 17 | margin: 0px; 18 | display: flex; 19 | } 20 | } 21 | .c21-divBudge { 22 | position: absolute; 23 | top: 0; 24 | width: 16px; 25 | height: 16px; 26 | min-width: 12px; 27 | font-size: 1.2em; 28 | line-height: 16px; 29 | border-radius: 50%; 30 | background-color: red; 31 | color: white; 32 | font-weight: bold; 33 | padding: 5px 5px; 34 | text-align: center; 35 | margin-top: -10px; 36 | display: inline-block; 37 | } 38 | 39 | @media (max-width: 451px) { 40 | #c21-launcher-button { 41 | //display: none; 42 | &.c21-align-right { 43 | right: 0; 44 | } 45 | &.c21-align-left { 46 | left: 0; 47 | } 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/chat21-core/providers/native/native-image-repo.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { ImageRepoService } from '../abstract/image-repo.service'; 4 | 5 | // @Injectable({ providedIn: 'root' }) 6 | @Injectable() 7 | export class NativeImageRepoService extends ImageRepoService { 8 | 9 | private baseImageURL: string; 10 | 11 | constructor(public http: HttpClient) { 12 | super(); 13 | } 14 | 15 | /** 16 | * @param uid 17 | */ 18 | getImagePhotoUrl(uid: string): string { 19 | this.baseImageURL = this.getImageBaseUrl() + 'images' 20 | let sender_id = ''; 21 | if (uid.includes('bot_')) { 22 | sender_id = uid.slice(4) 23 | } else { 24 | sender_id = uid 25 | } 26 | const filename_photo = '?path=uploads/users/'+ sender_id + '/images/photo.jpg' 27 | const filename_thumbnail = '?path=uploads/users/'+ sender_id + '/images/thumbnails_200_200-photo.jpg' 28 | return this.baseImageURL + filename_photo 29 | } 30 | 31 | checkImageExists(url: string, callback: (exist: boolean) => void): void { 32 | this.http.get(url).subscribe( res => { 33 | callback(true) 34 | },(error) => { console.log('errorrrrrr', url, error);callback(false)}) 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/chat21-core/providers/custom-translate.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | // https://enappd.com/blog/how-to-translate-in-ionic-internationalization-and-localization/143/ 3 | // https://phrase.com/blog/posts/localizing-ionic-applications-with-ngx-translate/ 4 | import { TranslateService } from '@ngx-translate/core'; 5 | 6 | // @Injectable({ 7 | // providedIn: 'root' 8 | // }) 9 | @Injectable() 10 | export class CustomTranslateService { 11 | 12 | 13 | public language: string; 14 | 15 | constructor( 16 | private translateService: TranslateService 17 | ) { 18 | //this.translateService.setDefaultLang('en'); 19 | } 20 | 21 | /** */ 22 | public translateLanguage(keys: any, lang?: string): Map { 23 | // if (!lang || lang === '') { 24 | // this.language = this.translateService.currentLang; 25 | // } else { 26 | // this.language = lang; 27 | // } 28 | // this.translateService.use(this.language); 29 | return this.initialiseTranslation(keys); 30 | } 31 | 32 | /** */ 33 | private initialiseTranslation(keys): Map { 34 | const mapTranslate = new Map(); 35 | keys.forEach((key: string) => { 36 | this.translateService.get(key).subscribe((res: string) => { 37 | mapTranslate.set(key, res); 38 | }); 39 | }); 40 | return mapTranslate; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/app/components/star-rating-widget/star-rating-widget.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { AppConfigService } from './../../providers/app-config.service'; 2 | import { StarRatingWidgetService } from './star-rating-widget.service'; 3 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 4 | 5 | import { StarRatingWidgetComponent } from './star-rating-widget.component'; 6 | import { HttpModule } from '@angular/http'; 7 | import { Globals } from '../../utils/globals'; 8 | import { HttpClientModule } from '@angular/common/http'; 9 | 10 | describe('StarRatingWidgetComponent', () => { 11 | let component: StarRatingWidgetComponent; 12 | let fixture: ComponentFixture; 13 | 14 | beforeEach(async(() => { 15 | TestBed.configureTestingModule({ 16 | declarations: [ StarRatingWidgetComponent ], 17 | imports: [ 18 | HttpModule, 19 | HttpClientModule 20 | ], 21 | providers: [ 22 | Globals, 23 | AppConfigService, 24 | StarRatingWidgetService 25 | ] 26 | }) 27 | .compileComponents(); 28 | })); 29 | 30 | beforeEach(() => { 31 | fixture = TestBed.createComponent(StarRatingWidgetComponent); 32 | component = fixture.componentInstance; 33 | fixture.detectChanges(); 34 | }); 35 | 36 | it('should create', () => { 37 | expect(component).toBeTruthy(); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/app/components/message/buttons/text-button/text-button.component.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../../sass/variables'; 2 | 3 | :host { 4 | --backgroundColor: #{$blue}; 5 | --textColor: #{$bck-msg-sent}; 6 | --hoverBackgroundColor: #{$bck-msg-sent}; 7 | --hoverTextColor: #{$blue}; 8 | --buttonFontSize: #{$button-in-msg-font-size}; 9 | } 10 | 11 | 12 | .button-in-msg { 13 | 14 | padding: 8px 16px!important; 15 | position: relative; 16 | max-width: 300px; 17 | min-width: inherit; 18 | cursor: pointer; 19 | border: 1px solid var(--textColor); //$blue 20 | border-radius: 20px; 21 | margin: 3px; 22 | background: var(--backgroundColor); 23 | overflow: hidden; 24 | font-family: 'Muli', sans-serif; 25 | font-size: var(--buttonFontSize); 26 | -o-text-overflow: ellipsis; 27 | text-overflow: ellipsis; 28 | white-space: nowrap; 29 | letter-spacing: -0.24px; 30 | -webkit-font-smoothing: antialiased; 31 | color: var(--textColor); //$blue 32 | line-height: 16px; 33 | } 34 | 35 | .text { 36 | // color: rgb(42, 106, 193); 37 | transition: background-color .6s ease; 38 | &:focus, 39 | &:hover { 40 | color: var(--hoverTextColor); 41 | background: var(--hoverBackgroundColor); 42 | .icon-button-action { 43 | svg { 44 | fill: $black; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/messagingAuth.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { BehaviorSubject } from 'rxjs'; 3 | 4 | 5 | // @Injectable({ 6 | // providedIn: 'root' 7 | // }) 8 | @Injectable() 9 | export abstract class MessagingAuthService { 10 | 11 | // BehaviorSubject 12 | abstract BSAuthStateChanged: BehaviorSubject = new BehaviorSubject(null); 13 | abstract BSSignOut: BehaviorSubject = new BehaviorSubject(null); 14 | 15 | // params 16 | public DEFAULT_PERSISTENCE: string = 'NONE'; 17 | public DEFAULT_URL: string = 'https://api.tiledesk.com/v2/auth/'; 18 | 19 | private persistence; 20 | private baseUrl; 21 | 22 | public setPersistence(persistence): void { 23 | this.persistence = persistence; 24 | } 25 | 26 | public getPersistence(): string { 27 | if (this.persistence) { 28 | return this.persistence; 29 | } else { 30 | return this.DEFAULT_PERSISTENCE; 31 | } 32 | } 33 | 34 | public setBaseUrl(baseUrl): void { 35 | this.baseUrl = baseUrl; 36 | } 37 | public getBaseUrl(): string { 38 | if (this.baseUrl) { 39 | return this.baseUrl; 40 | } else { 41 | return this.DEFAULT_URL; 42 | } 43 | } 44 | 45 | // functions 46 | abstract initialize(): void; 47 | abstract getToken(): string; 48 | abstract createCustomToken(tiledeskToken): void; 49 | abstract logout(): Promise; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/app/components/conversation-detail/conversation-header/conversation-header.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientModule } from '@angular/common/http'; 2 | import { AppConfigService } from './../../../providers/app-config.service'; 3 | import { Globals } from './../../../utils/globals'; 4 | import { NO_ERRORS_SCHEMA } from '@angular/core'; 5 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 6 | 7 | import { ConversationHeaderComponent } from './conversation-header.component'; 8 | import { TypingService } from '../../../../chat21-core/providers/abstract/typing.service'; 9 | 10 | describe('ConversationHeaderComponent', () => { 11 | let component: ConversationHeaderComponent; 12 | let fixture: ComponentFixture; 13 | 14 | beforeEach(async(() => { 15 | TestBed.configureTestingModule({ 16 | declarations: [ ConversationHeaderComponent ], 17 | imports: [ 18 | HttpClientModule 19 | ], 20 | providers: [ 21 | Globals, 22 | TypingService, 23 | AppConfigService 24 | ], 25 | schemas: [NO_ERRORS_SCHEMA], 26 | }) 27 | .compileComponents(); 28 | })); 29 | 30 | beforeEach(() => { 31 | fixture = TestBed.createComponent(ConversationHeaderComponent); 32 | component = fixture.componentInstance; 33 | fixture.detectChanges(); 34 | }); 35 | 36 | it('should create', () => { 37 | expect(component).toBeTruthy(); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/app/components/message/bubble-message/bubble-message.component.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../sass/variables'; 2 | /* ====== SET MESSAGES ====== */ 3 | 4 | .messages { 5 | border-radius: $border-radius-bubble-message; 6 | padding: 0; 7 | word-wrap: break-word; 8 | // padding: 14px; 9 | // padding: 6px 6px 6px 6px; 10 | // box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); 11 | // -webkit-animation: heartbeat 1.5s ease-in-out both; 12 | // animation: heartbeat 1.5s ease-in-out both; 13 | 14 | // p { 15 | // font-size: 1.4em; 16 | // margin: 0; 17 | // padding: 14px; 18 | // font-style: normal; 19 | // letter-spacing: normal; 20 | // font-stretch: normal; 21 | // font-variant: normal; 22 | // font-weight: 300; 23 | // overflow: hidden; 24 | // } 25 | 26 | img { 27 | border-radius: $border-radius-bubble-message; 28 | padding: 3px; 29 | margin-bottom: 0px; 30 | max-width: calc(100% - 6px); 31 | width: auto; 32 | height: auto; 33 | object-fit: cover; 34 | } 35 | .message_innerhtml { 36 | margin: 0px; 37 | // padding: 0px 14px; 38 | &.marked{ 39 | padding:8px; 40 | margin-block-start: -1em!important; 41 | margin-block-end: -1em!important; 42 | } 43 | 44 | .text-message { 45 | padding-top: 14px; 46 | } 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/app/components/send-button/send-button.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/groups-handler.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { BehaviorSubject, Observable, Subject } from 'rxjs'; 4 | import { GroupModel } from '../../models/group'; 5 | 6 | // @Injectable({ providedIn: 'root' }) 7 | @Injectable() 8 | export abstract class GroupsHandlerService { 9 | 10 | // BehaviorSubject 11 | abstract BSgroupDetail: BehaviorSubject = new BehaviorSubject(null); 12 | abstract SgroupDetail: Subject = new Subject(); 13 | abstract groupAdded: BehaviorSubject = new BehaviorSubject(null); 14 | abstract groupChanged: BehaviorSubject = new BehaviorSubject(null); 15 | abstract groupRemoved: BehaviorSubject = new BehaviorSubject(null); 16 | 17 | abstract initialize(tenant: string, loggedUserId: string): void; 18 | abstract connect(): void; 19 | abstract getDetail(groupId: string, callback?:(group: GroupModel)=>void): Promise; 20 | abstract onGroupChange(groupId: string): Observable; 21 | abstract create(groupName: string, members: [string], callback?:(res: any, error: any)=>void): Promise; 22 | abstract leave(groupId: string, callback?:(res: any, error: any)=>void): Promise; 23 | abstract join(groupId: string, member: string, callback?:(res: any, error: any)=>void) 24 | abstract dispose(): void; 25 | } 26 | -------------------------------------------------------------------------------- /src/app/components/last-message/last-message.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { MarkedPipe } from './../../directives/marked.pipe'; 2 | import { NO_ERRORS_SCHEMA } from '@angular/core'; 3 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 4 | import { ImageRepoService } from '../../../chat21-core/providers/abstract/image-repo.service'; 5 | import { Globals } from '../../utils/globals'; 6 | 7 | import { LastMessageComponent } from './last-message.component'; 8 | import { HtmlEntitiesEncodePipe } from '../../directives/html-entities-encode.pipe'; 9 | import { MomentModule } from 'angular2-moment'; 10 | 11 | describe('LastMessageComponent', () => { 12 | let component: LastMessageComponent; 13 | let fixture: ComponentFixture; 14 | 15 | beforeEach(async(() => { 16 | TestBed.configureTestingModule({ 17 | declarations: [ 18 | LastMessageComponent, 19 | MarkedPipe, 20 | HtmlEntitiesEncodePipe 21 | ], 22 | imports: [ 23 | MomentModule 24 | ], 25 | providers: [ 26 | Globals, 27 | ImageRepoService, 28 | ], 29 | schemas: [NO_ERRORS_SCHEMA] 30 | }) 31 | .compileComponents(); 32 | })); 33 | 34 | beforeEach(() => { 35 | fixture = TestBed.createComponent(LastMessageComponent); 36 | component = fixture.componentInstance; 37 | fixture.detectChanges(); 38 | }); 39 | 40 | it('should create', () => { 41 | expect(component).toBeTruthy(); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/form-checkbox/form-checkbox.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit, ElementRef, EventEmitter, Output } from '@angular/core'; 2 | import { FormGroupDirective } from '@angular/forms'; 3 | import { FormGroup } from '@angular/forms'; 4 | import { FormArray } from '../../../../../chat21-core/models/formArray'; 5 | 6 | @Component({ 7 | selector: 'chat-form-checkbox', 8 | templateUrl: './form-checkbox.component.html', 9 | styleUrls: ['./form-checkbox.component.scss'] 10 | }) 11 | export class FormCheckboxComponent implements OnInit { 12 | 13 | @Input() element: FormArray; 14 | @Input() controlName: string; 15 | @Input() translationErrorLabelMap: Map; 16 | @Input() stylesMap: Map; 17 | @Input() hasSubmitted: boolean; 18 | @Output() onKeyEnterPressed = new EventEmitter(); 19 | 20 | form: FormGroup; 21 | constructor(private rootFormGroup: FormGroupDirective, 22 | private elementRef: ElementRef) { } 23 | 24 | ngOnInit() { 25 | this.form = this.rootFormGroup.control; 26 | this.elementRef.nativeElement.style.setProperty('--themeColor', this.stylesMap.get('themeColor')); 27 | this.elementRef.nativeElement.style.setProperty('--foregroundColor', this.stylesMap.get('foregroundColor')); 28 | 29 | } 30 | 31 | /** 32 | * FIRED when user press ENTER button on keyboard 33 | * @param event 34 | */ 35 | onEnterPressed(event){ 36 | this.onKeyEnterPressed.emit(event) 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/app/components/message/buttons/link-button/link-button.component.html: -------------------------------------------------------------------------------- 1 |
3 | 4 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | {{button?.value}} 24 |
25 |
26 | 27 | -------------------------------------------------------------------------------- /src/app/components/message/image/image.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit, SimpleChanges, EventEmitter, Output } from '@angular/core'; 2 | import { popupUrl } from '../../../../chat21-core/utils/utils'; 3 | 4 | @Component({ 5 | selector: 'chat-image', 6 | templateUrl: './image.component.html', 7 | styleUrls: ['./image.component.scss'] 8 | }) 9 | export class ImageComponent implements OnInit { 10 | 11 | @Input() metadata: any; 12 | @Input() width: string; 13 | @Input() height: number; 14 | @Output() onImageRendered = new EventEmitter(); 15 | 16 | loading: boolean = true 17 | tooltipMessage: string; 18 | tooltipOptions = { 19 | 'show-delay': 0, 20 | 'tooltip-class': 'chat-tooltip', 21 | 'theme': 'light', 22 | 'shadow': false, 23 | 'hide-delay-mobile': 0, 24 | 'hideDelayAfterClick': 3000, 25 | 'hide-delay': 200 26 | }; 27 | 28 | popupUrl = popupUrl; 29 | 30 | constructor() { } 31 | 32 | ngOnInit() { 33 | } 34 | 35 | onLoaded(event){ 36 | this.loading = false 37 | this.onImageRendered.emit(true) 38 | } 39 | 40 | downloadImage(url: string, fileName: string) { 41 | // console.log('Image COMP - IMAGE URL ', url) 42 | // console.log('Image COMP - IMAGE FILENAME ', fileName) 43 | const a: any = document.createElement('a'); 44 | a.href = url; 45 | a.download = fileName; 46 | document.body.appendChild(a); 47 | a.style = 'display: none'; 48 | a.click(); 49 | a.remove(); 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/chat21-core/utils/utils-user.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * getColorBck 3 | * @param str 4 | */ 5 | export function getColorBck(str: string): string { 6 | const arrayBckColor = ['#E17076', '#7BC862', '#65aadd', '#a695e7', '#ee7aae', '#6ec9cb', '#faa774']; 7 | let num = 0; 8 | if (str) { 9 | const code = str.charCodeAt((str.length - 1)); 10 | num = Math.round(code % arrayBckColor.length); 11 | } 12 | return arrayBckColor[num]; 13 | } 14 | 15 | /** 16 | * avatarPlaceholder 17 | * @param name 18 | */ 19 | export function avatarPlaceholder(name: string): string { 20 | let initials = ''; 21 | if (name) { 22 | const arrayName = name.split(' '); 23 | arrayName.forEach(member => { 24 | if (member.trim().length > 1 && initials.length < 3) { 25 | initials += member.substring(0, 1).toUpperCase(); 26 | } 27 | if(member.trim().length == 1){ 28 | initials+= member.substring(0, 1).toUpperCase(); 29 | } 30 | }); 31 | } 32 | return initials; 33 | } 34 | 35 | /** 36 | * getImageUrlThumbFromFirebasestorage 37 | * @param uid 38 | * @param FIREBASESTORAGE_BASE_URL_IMAGE 39 | * @param urlStorageBucket 40 | */ 41 | export function getImageUrlThumbFromFirebasestorage( 42 | uid: string, 43 | FIREBASESTORAGE_BASE_URL_IMAGE: string, 44 | urlStorageBucket: string 45 | ): string { 46 | const imageurl = FIREBASESTORAGE_BASE_URL_IMAGE + urlStorageBucket + uid + '%2Fthumb_photo.jpg?alt=media'; 47 | return imageurl; 48 | } 49 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build2. 2 | // The build2 system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build2 --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: true, 8 | version: require('../../package.json').version, // https://stackoverflow.com/questions/34907682/how-to-display-app-version-in-angular2 9 | remoteConfig: true, 10 | remoteConfigUrl: '/widget-config.json', 11 | loadRemoteTranslations: true, 12 | remoteTranslationsUrl: 'http://localhost:3000/', 13 | chatEngine: 'CHANGEIT', 14 | uploadEngine: 'CHANGEIT', 15 | fileUploadAccept:"*/*", 16 | logLevel: 'INFO', 17 | firebaseConfig: { 18 | apiKey: 'CHANGEIT', 19 | authDomain: 'CHANGEIT', 20 | databaseURL: 'CHANGEIT', 21 | projectId: 'CHANGEIT', 22 | storageBucket: 'CHANGEIT', 23 | messagingSenderId: 'CHANGEIT', 24 | appId: 'CHANGEIT', 25 | tenant: 'CHANGEIT', 26 | }, 27 | chat21Config: { 28 | appId: 'tilechat', 29 | MQTTendpoint: 'mqtt://localhost:15675/ws', // MQTT endpoint 30 | APIendpoint: 'http://localhost:8004/api' 31 | }, 32 | apiUrl: 'http://localhost:3000/', 33 | baseImageUrl: 'https://firebasestorage.googleapis.com/v0/b/', 34 | defaultLang : 'en', 35 | storage_prefix : 'widget_sv5', 36 | authPersistence: 'LOCAL', 37 | supportMode: true, 38 | }; -------------------------------------------------------------------------------- /src/assets/images/f21-chat21-logo-widget.svg: -------------------------------------------------------------------------------- 1 | chat21-logo-widget -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build2. 2 | // The build2 system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build2 --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false, 8 | version: require('../../package.json').version, // https://stackoverflow.com/questions/34907682/how-to-display-app-version-in-angular2 9 | remoteConfig: true, 10 | remoteConfigUrl: '/widget-config.json', 11 | loadRemoteTranslations: true, 12 | remoteTranslationsUrl: 'http://localhost:3000/', 13 | chatEngine: 'mqtt', 14 | uploadEngine: 'native', 15 | tenant: 'tilechat', 16 | fileUploadAccept:"*/*", 17 | logLevel: 'INFO', 18 | firebaseConfig: { 19 | apiKey: 'CHANGEIT', 20 | authDomain: 'CHANGEIT', 21 | databaseURL: 'CHANGEIT', 22 | projectId: 'CHANGEIT', 23 | storageBucket: 'CHANGEIT', 24 | messagingSenderId: 'CHANGEIT', 25 | appId: 'CHANGEIT', 26 | tenant: 'tilechat' 27 | }, 28 | chat21Config: { 29 | appId: 'tilechat', 30 | MQTTendpoint: 'mqtt://localhost:15675/ws', // MQTT endpoint 31 | APIendpoint: 'http://localhost:8004/api' 32 | }, 33 | apiUrl: 'http://localhost:3000/', 34 | baseImageUrl: 'https://firebasestorage.googleapis.com/v0/b/', 35 | defaultLang : 'en', 36 | storage_prefix : 'widget_sv5', 37 | authPersistence: 'LOCAL', 38 | supportMode: true, 39 | }; 40 | -------------------------------------------------------------------------------- /src/models/message.ts: -------------------------------------------------------------------------------- 1 | // firebase 2 | import * as firebase from 'firebase/app'; 3 | import 'firebase/database'; 4 | 5 | export class MessageModel { 6 | public sender_urlImage: string; 7 | constructor( 8 | public uid: string, 9 | public language: string, 10 | public recipient: string, 11 | public recipient_fullname: string, 12 | public sender: string, 13 | public sender_fullname: string, 14 | public status: string, 15 | public metadata: any, 16 | public text: any, 17 | public timestamp: any, 18 | public headerDate: string, 19 | public type: string, 20 | public attributes: any, 21 | public channel_type: string, 22 | public projectid: string, 23 | public emoticon?: boolean 24 | ) { } 25 | 26 | asFirebaseMessage(): Object { 27 | const message = { 28 | language: this.language, 29 | recipient: this.recipient, 30 | recipient_fullname: this.recipient_fullname, 31 | sender: this.sender, 32 | sender_fullname: this.sender_fullname, 33 | status: this.status, 34 | metadata: this.metadata, 35 | text: this.text, 36 | timestamp: firebase.database.ServerValue.TIMESTAMP, 37 | // headerDate: this.headerDate, 38 | type: this.type, 39 | attributes: this.attributes, 40 | channel_type: this.channel_type 41 | // projectid: this.projectid // removed by sponziello 42 | }; 43 | 44 | return message; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/conversation-handler.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { BehaviorSubject } from 'rxjs'; 3 | 4 | // models 5 | import { MessageModel } from '../../models/message'; 6 | import { UserModel } from '../../models/user'; 7 | 8 | // @Injectable({ 9 | // providedIn: 'root' 10 | // }) 11 | @Injectable() 12 | export abstract class ConversationHandlerService { 13 | 14 | // BehaviorSubject 15 | abstract messageAdded: BehaviorSubject = new BehaviorSubject(null); 16 | abstract messageChanged: BehaviorSubject = new BehaviorSubject(null); 17 | abstract messageRemoved: BehaviorSubject = new BehaviorSubject(null); 18 | abstract messageWait: BehaviorSubject = new BehaviorSubject(null); 19 | 20 | // params 21 | abstract attributes: any; 22 | abstract messages: Array = []; 23 | abstract conversationWith: string; 24 | 25 | constructor() {} 26 | 27 | // functions 28 | abstract initialize( 29 | recipientId: string, 30 | recipientFullName: string, 31 | loggedUser: UserModel, 32 | tenant: string, 33 | translationMap: Map 34 | ): void; 35 | abstract connect(): void; 36 | abstract sendMessage( 37 | msg: string, 38 | type: string, 39 | metadata: string, 40 | conversationWith: string, 41 | conversationWithFullname: string, 42 | sender: string, 43 | senderFullname: string, 44 | channelType: string, 45 | attributes: any 46 | ): MessageModel; 47 | abstract dispose(): void; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/app/components/menu-options/menu-options.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Output, EventEmitter } from '@angular/core'; 2 | import { Globals } from '../../utils/globals'; 3 | import { convertColorToRGBA } from '../../utils/utils'; 4 | 5 | 6 | 7 | @Component({ 8 | selector: 'chat-menu-options', 9 | templateUrl: './menu-options.component.html', 10 | styleUrls: ['./menu-options.component.scss'] 11 | }) 12 | export class MenuOptionsComponent implements OnInit { 13 | // ========= begin:: Input/Output values ============// 14 | @Output() onSignOut = new EventEmitter(); 15 | // ========= end:: Input/Output values ============// 16 | themeColor50: string; 17 | hover: boolean; 18 | 19 | constructor( 20 | public g: Globals 21 | ) { } 22 | 23 | ngOnInit() { 24 | const themeColor = this.g.themeColor; 25 | this.themeColor50 = convertColorToRGBA(themeColor, 50); 26 | // this.themeColor50 = this.g.themeColor + '7F'; 27 | } 28 | 29 | f21_toggle_options() { 30 | this.g.setParameter('isOpenMenuOptions', !this.g.isOpenMenuOptions, true); 31 | } 32 | 33 | toggleSound() { 34 | this.g.setParameter('soundEnabled', !this.g.soundEnabled, true); 35 | this.g.setParameter('isOpenMenuOptions', false, true); 36 | // this.g.soundEnabled = !this.g.soundEnabled; 37 | // if ( this.g.soundEnabled === false ) { 38 | // this.storageService.setItem('soundEnabled', false); 39 | // } else { 40 | // this.storageService.setItem('soundEnabled', true); 41 | // } 42 | } 43 | 44 | signOut() { 45 | this.g.setParameter('isOpenMenuOptions', false, true); 46 | this.onSignOut.emit(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/app/components/form/inputs/form-textarea/form-textarea.component.html: -------------------------------------------------------------------------------- 1 |
2 | 15 |
17 | 20 | 31 |
32 |
33 | {{translationErrorLabelMap.get('LABEL_ERROR_FIELD_REQUIRED')}} 34 |
35 |
36 | {{element.errorLabel}} 37 |
38 |
39 | -------------------------------------------------------------------------------- /src/test-auth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tilechat Widget 6 | 7 | 8 | 9 | 10 | 11 | 30 | 31 | 32 | 33 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/chat21-core/providers/logger/customLogger.ts: -------------------------------------------------------------------------------- 1 | import { LogLevel } from './../../utils/constants'; 2 | import { Inject, Injectable } from '@angular/core'; 3 | import { LoggerService } from './../abstract/logger.service'; 4 | @Injectable() 5 | export class CustomLogger extends LoggerService{ 6 | 7 | 8 | //private variables 9 | private logLevel: number = LogLevel.DEBUG 10 | private isLogEnabled: boolean = true; 11 | constructor() { 12 | super(); 13 | } 14 | 15 | setLoggerConfig(isLogEnabled: boolean, logLevel: string){ 16 | this.isLogEnabled = isLogEnabled; 17 | if (typeof logLevel === 'string') { 18 | this.logLevel = LogLevel[logLevel.toUpperCase()]; 19 | } else { 20 | console.error('logLevel is not a string. See the chat21-ionic README.md') 21 | } 22 | } 23 | 24 | info(...message) { 25 | if (this.isLogEnabled && this.logLevel >= LogLevel.INFO) { 26 | console.info(message) 27 | } 28 | } 29 | debug(...message: any[]) { 30 | if (this.isLogEnabled && this.logLevel >= LogLevel.DEBUG) { 31 | console.debug(message) 32 | } 33 | } 34 | warn(...message: any[]) { 35 | if (this.isLogEnabled && this.logLevel >= LogLevel.WARN) { 36 | console.warn(message) 37 | } 38 | } 39 | error(...message: any[]) { 40 | if(this.isLogEnabled && this.logLevel >= LogLevel.ERROR){ 41 | console.error(message) 42 | } 43 | } 44 | 45 | log(...message: any[]) { 46 | if (this.isLogEnabled && this.logLevel >= LogLevel.DEBUG) { 47 | console.log(message) 48 | } 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /src/app/components/message/buttons/link-button/link-button.component.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../../sass/variables'; 2 | 3 | :root { 4 | --backgroundColor: #{$blue}; 5 | --textColor: #{$bck-msg-sent}; 6 | --hoverBackgroundColor: #{$bck-msg-sent}; 7 | --hoverTextColor: #{$blue}; 8 | --buttonFontSize: #{$button-in-msg-font-size}; 9 | } 10 | 11 | .button-in-msg { 12 | padding: 8px 16px!important; 13 | position: relative; 14 | max-width: 300px; 15 | min-width: inherit; 16 | cursor: pointer; 17 | border: 1px solid var(--textColor); 18 | border-radius: 20px; 19 | margin: 3px; 20 | background: var(--backgroundColor); 21 | overflow: hidden; 22 | font-family: 'Muli', sans-serif; 23 | font-size: var(--buttonFontSize); 24 | -o-text-overflow: ellipsis; 25 | text-overflow: ellipsis; 26 | white-space: nowrap; 27 | letter-spacing: -0.24px; 28 | -webkit-font-smoothing: antialiased; 29 | color: var(--textColor); 30 | line-height: 16px; 31 | } 32 | 33 | .url { 34 | transition: background-color .6s ease; 35 | .icon-button-action { 36 | position: absolute; 37 | top: -1px; 38 | right: 1px; 39 | svg { 40 | fill: var(--textColor); 41 | } 42 | } 43 | .icon-button-action-self{ 44 | position: absolute; 45 | right: 1px; 46 | svg { 47 | fill: var(--textColor); 48 | } 49 | } 50 | &:focus, 51 | &:hover { 52 | color: var(--hoverTextColor); 53 | background: var(--hoverBackgroundColor); 54 | .icon-button-action, .icon-button-action-self { 55 | svg { 56 | fill: var(--hoverTextColor); 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/environments/environment.pre.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build2. 2 | // The build2 system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build2 --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | // tslint:disable-next-line:max-line-length 6 | // import { firebasePreConfig } from '../environments/firebase-config'; // please comment on this line when changing the values ​​of firebase {} 7 | 8 | export const environment = { 9 | production: true, 10 | version: require('../../package.json').version, // https://stackoverflow.com/questions/34907682/how-to-display-app-version-in-angular2 11 | remoteConfig: true, 12 | remoteConfigUrl: '/widget-config.json', 13 | remoteTranslationsUrl: 'http://localhost:3000/', 14 | loadRemoteTranslations: true, 15 | chatEngine: 'mqtt', 16 | uploadEngine: 'native', 17 | fileUploadAccept:"*/*", 18 | logLevel: 'INFO', 19 | firebaseConfig: { 20 | apiKey: 'CHANGEIT', 21 | authDomain: 'CHANGEIT', 22 | databaseURL: 'CHANGEIT', 23 | projectId: 'CHANGEIT', 24 | storageBucket: 'CHANGEIT', 25 | messagingSenderId: 'CHANGEIT', 26 | appId: 'CHANGEIT', 27 | tenant: 'tilechat', 28 | }, 29 | chat21Config: { 30 | appId: 'tilechat', 31 | MQTTendpoint: 'mqtt://localhost:15675/ws', // MQTT endpoint 32 | APIendpoint: 'http://localhost:8004/api' 33 | }, 34 | apiUrl: 'http://localhost:3000/', 35 | baseImageUrl: 'https://firebasestorage.googleapis.com/v0/b/', 36 | defaultLang : 'en', 37 | storage_prefix : 'widget_sv5', 38 | authPersistence: 'LOCAL', 39 | supportMode: true, 40 | }; 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/app/components/list-all-conversations/list-all-conversations.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { CustomTranslateService } from './../../../chat21-core/providers/custom-translate.service'; 2 | import { NO_ERRORS_SCHEMA, IterableDiffers, IterableDifferFactory } from '@angular/core'; 3 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 4 | import { Globals } from '../../utils/globals'; 5 | 6 | import { ListAllConversationsComponent } from './list-all-conversations.component'; 7 | import { TranslateModule, TranslateService } from '@ngx-translate/core'; 8 | 9 | describe('ListAllConversationsComponent', () => { 10 | let component: ListAllConversationsComponent; 11 | let fixture: ComponentFixture; 12 | 13 | class MockIterableDiffers implements IterableDiffers { 14 | factories: IterableDifferFactory[]; 15 | find(iterable: any): IterableDifferFactory { 16 | return 17 | } 18 | create(factories: IterableDifferFactory[], parent?: IterableDiffers): IterableDiffers { 19 | return 20 | } 21 | } 22 | 23 | beforeEach(async(() => { 24 | TestBed.configureTestingModule({ 25 | declarations: [ ListAllConversationsComponent ], 26 | imports: [ 27 | TranslateModule.forRoot(), 28 | ], 29 | providers: [ 30 | Globals, 31 | { provide: IterableDiffers, useClass: MockIterableDiffers }, 32 | CustomTranslateService, 33 | TranslateService 34 | ], 35 | schemas: [NO_ERRORS_SCHEMA] 36 | }) 37 | .compileComponents(); 38 | })); 39 | 40 | beforeEach(() => { 41 | fixture = TestBed.createComponent(ListAllConversationsComponent); 42 | component = fixture.componentInstance; 43 | fixture.detectChanges(); 44 | }); 45 | 46 | it('should create', () => { 47 | expect(component).toBeTruthy(); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/app/providers/settings-saver.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { AppStorageService } from '../../chat21-core/providers/abstract/app-storage.service'; 3 | import { Globals } from '../utils/globals'; 4 | import { stringToBoolean } from '../utils/utils'; 5 | 6 | 7 | @Injectable() 8 | export class SettingsSaverService { 9 | 10 | constructor( 11 | private g: Globals, 12 | private appStorageService: AppStorageService 13 | ) {} 14 | 15 | /** 16 | * recupero dallo storage globals e lo assegno a globalsParameters 17 | * ogni successiva modifica di globals verrà salvata in appStorageService 18 | */ 19 | initialize() { 20 | // if (this.appStorageService.getItem('globals')) { 21 | // this.globalsParameters = this.appStorageService.getItem('globals'); 22 | // } 23 | this.setGlobalsSubscription(); 24 | } 25 | 26 | /** 27 | * 28 | */ 29 | public setGlobalsSubscription() { 30 | const that = this; 31 | this.g.obsObjChanged.subscribe((obj) => { 32 | if (obj) { 33 | that.setVariable(obj.key, obj.val); 34 | } 35 | }); 36 | } 37 | 38 | /** 39 | * modifico il valore di un parametro e lo salvo nel dizionario 40 | * pubblico il dizionario modificato 41 | * salvo il dictionary in local 42 | * @param key 43 | * @param value 44 | */ 45 | public setVariable(key: string, value: any) { 46 | const val = JSON.stringify(value); 47 | // console.log('========================================'); 48 | // console.log('key: ', key); 49 | // console.log('val: ', val); 50 | // console.log('========================================'); 51 | this.appStorageService.setItem(key, stringToBoolean(value)); 52 | 53 | //this.g.wdLog(['SET key: ', key, ' - VAL: ', stringToBoolean(value), ' ---------->', JSON.stringify(value) ]); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/chat21-core/providers/firebase/firebase-image-repo.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { environment } from '../../../environments/environment'; 4 | 5 | // services 6 | import { ImageRepoService } from '../abstract/image-repo.service'; 7 | 8 | // firebase 9 | import * as firebase from 'firebase/app'; 10 | import 'firebase/storage'; 11 | 12 | // @Injectable({ providedIn: 'root' }) 13 | @Injectable() 14 | export class FirebaseImageRepoService extends ImageRepoService { 15 | 16 | // private params 17 | private urlStorageBucket = environment.firebaseConfig.storageBucket + '/o/profiles%2F'; 18 | private baseImageURL: string; 19 | 20 | constructor(public http: HttpClient) { 21 | super(); 22 | } 23 | 24 | /** 25 | * @param uid 26 | */ 27 | getImagePhotoUrl(uid: string): string { 28 | this.baseImageURL = this.getImageBaseUrl() 29 | let sender_id = ''; 30 | if (uid && uid.includes('bot_')) { 31 | sender_id = uid.slice(4) 32 | } else { 33 | sender_id = uid 34 | } 35 | const firebase_photo = '/o/profiles%2F'+ sender_id + '%2Fphoto.jpg?alt=media' 36 | const firebase_thumbnail = '/o/profiles%2F'+ sender_id + '%2Fthumb_photo.jpg?alt=media' 37 | const imageurl = this.baseImageURL + firebase.storage().ref().bucket + firebase_thumbnail 38 | 39 | return imageurl; 40 | } 41 | 42 | 43 | checkImageExists(url: string, callback: (exist: boolean) => void): void { 44 | console.log('urllll', url) 45 | this.http.get(url, { responseType: 'blob' }).subscribe( res => { 46 | callback(true) 47 | },(error) => { 48 | console.log('ressssssss errorr', error); 49 | callback(false) 50 | }) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/app/components/message/image/image.component.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../sass/variables'; 2 | 3 | :host{ 4 | // --borderRadius: #{$border-radius-bubble-message}; 5 | --borderRadius: 8px; 6 | } 7 | 8 | img { 9 | border-radius: var(--borderRadius); 10 | //padding: 3px; 11 | margin-bottom: 0px; 12 | max-width: calc(100% - 6px); 13 | width: auto; 14 | height: auto; 15 | object-fit: cover; 16 | 17 | } 18 | 19 | img:hover{ 20 | cursor: pointer; 21 | } 22 | 23 | 24 | .c21-img-container { 25 | text-align: center; 26 | width: 100%; 27 | // background-image: linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.5)), url("https://firebasestorage.googleapis.com/v0/b/chat21-pre-01.appspot.com/o/public%2Fimages%2Fb4361ea5-5e37-433c-b727-9034eb5586fe%2F6d74f795-5873-49a8-9165-38f48642df51%2Ffacebook_like%20(3).png?alt=media&token=79afcfe5-ba0c-4573-9263-0877e0225c84"); 28 | // background-repeat: no-repeat; 29 | // background-position: 50% 0; 30 | // background-size: cover; 31 | // border-top-left-radius: $border-radius-bubble-message; 32 | // border-top-right-radius: $border-radius-bubble-message; 33 | } 34 | 35 | .demo-content { 36 | position: relative; 37 | } 38 | 39 | .isLoadingImage { 40 | // position: relative; 41 | // top: 6px; 42 | display: none; 43 | } 44 | 45 | .loader { 46 | float: left; 47 | // position: absolute; 48 | z-index: 1000; 49 | background-color: #ccc; 50 | border-radius: var(--borderRadius); 51 | background-image: linear-gradient(90deg, #f7f4f4 0px, #e8e8e8 40px, #f7f4f4 80px); 52 | background-size: 600px; 53 | animation: shine-loader 1.6s infinite linear; 54 | } 55 | 56 | @keyframes shine-loader { 57 | 0% { 58 | background-position: -32px; 59 | } 60 | 40%, 100% { 61 | background-position: 208px; 62 | } 63 | } -------------------------------------------------------------------------------- /src/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Page Not Found 7 | 8 | 23 | 24 | 25 |
26 |

404

27 |

Page Not Found

28 |

The specified file was not found on this website. Please check the URL for mistakes and try again.

29 |

Why am I seeing this?

30 |

This page was generated by the Firebase Command-Line Interface. To modify it, edit the 404.html file in your project's configured public directory.

31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /src/chat21-core/providers/abstract/archivedconversations-handler.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { BehaviorSubject } from 'rxjs'; 3 | import { ConversationModel } from '../../models/conversation'; 4 | import { ImageRepoService } from './image-repo.service'; 5 | 6 | @Injectable() 7 | export abstract class ArchivedConversationsHandlerService { 8 | 9 | // BehaviorSubject 10 | abstract BSConversationDetail: BehaviorSubject = new BehaviorSubject(null); 11 | abstract archivedConversationAdded: BehaviorSubject = new BehaviorSubject(null); 12 | abstract archivedConversationChanged: BehaviorSubject = new BehaviorSubject(null); 13 | abstract archivedConversationRemoved: BehaviorSubject = new BehaviorSubject(null); 14 | abstract loadedConversationsStorage: BehaviorSubject = new BehaviorSubject([]); 15 | // abstract readAllMessages: BehaviorSubject = new BehaviorSubject(null); 16 | 17 | // params 18 | abstract archivedConversations: Array = []; 19 | abstract uidConvSelected: string; 20 | //abstract imageRepo: ImageRepoService; 21 | 22 | // functions 23 | abstract initialize(tenant: string, userId: string, translationMap: Map): void; 24 | // abstract connect(): void; 25 | abstract subscribeToConversations(callback: any): void; 26 | abstract countIsNew(): number; 27 | abstract setConversationRead(conversationId: string) 28 | abstract dispose(): void; 29 | abstract getConversationDetail(conversationId: string, callback:(conv: ConversationModel)=>void): void; 30 | abstract getClosingConversation(conversationId: string): boolean; 31 | abstract setClosingConversation(conversationId: string, status: boolean): void; 32 | abstract deleteClosingConversation(conversationId: string): void; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/app/components/message/avatar/avatar.component.scss: -------------------------------------------------------------------------------- 1 | /* SET ICON AVATAR */ 2 | .c21-icon-avatar { 3 | position: relative; 4 | padding: 0; 5 | margin: 0; 6 | height: 40px; 7 | width: 40px; 8 | min-height: 40px; 9 | min-width: 40px; 10 | line-height: 40px; 11 | border-radius: 50%; 12 | overflow: hidden; 13 | background-color: #ffffff; 14 | .c21-avatar-placeholder { 15 | position: absolute; 16 | top: 0; 17 | left: 0; 18 | width: 100%; 19 | height: 100%; 20 | border-radius: 50%; 21 | text-align: center; 22 | font-size: 1.4em; 23 | color: #ffffff; 24 | font-weight: 500; 25 | } 26 | .c21-avatar-image { 27 | position: absolute; 28 | top: 0; 29 | left: 0; 30 | width: 100%; 31 | height: 100%; 32 | margin: 0; 33 | background-repeat: no-repeat; 34 | background-position: center; 35 | background-size: cover; 36 | border-radius: 50%; 37 | } 38 | .c21-avatar-image img{ 39 | max-width: 100%; 40 | width: 100%; 41 | height: 100%; 42 | min-width: 25px; 43 | min-height: 25px; 44 | object-fit: cover; 45 | } 46 | } 47 | 48 | .c21-pallozzo{ 49 | display: inline; 50 | } 51 | 52 | 53 | .c21-ball { 54 | position: relative; 55 | border: 2px solid #ffffff; 56 | width: 52px; 57 | height: 52px; 58 | border-radius: 50%; 59 | margin: 0; 60 | display: inline-flex; 61 | align-items: center; 62 | text-align: center; 63 | margin-left: -10px; 64 | .c21-ball-label { 65 | color: #ffffff; 66 | margin: auto; 67 | font-size: 20px; 68 | user-select: none; 69 | font-weight: 500; 70 | } 71 | .c21-avatar-image { 72 | position: absolute; 73 | top: 0; 74 | left: 0; 75 | width: 100%; 76 | height: 100%; 77 | margin: 0; 78 | background-repeat: no-repeat; 79 | background-position: center; 80 | background-size: cover; 81 | border-radius: 50%; 82 | } 83 | } -------------------------------------------------------------------------------- /deploy_amazon_beta.sh: -------------------------------------------------------------------------------- 1 | # npm version prerelease --preid=beta 2 | version=`node -e 'console.log(require("./package.json").version)'` 3 | echo "version $version" 4 | 5 | ng build --prod --env=pre --base-href --output-hashing none --build-optimizer=false 6 | 7 | # ########## --->>>> NATIVE-MQTT folder START <<<<<------ ########## # 8 | 9 | # cd dist 10 | # aws s3 sync . s3://tiledesk-widget-pre/native-mqtt/widget/$version/ 11 | # aws s3 sync . s3://tiledesk-widget-pre/native-mqtt/widget/ 12 | # cd .. 13 | 14 | # #aws cloudfront create-invalidation --distribution-id E3EJDWEHY08CZZ --paths "/*" 15 | # # echo new version deployed $NEW_VER/$NEW_BUILD/ on s3://tiledesk-widget-pre/v2 16 | # echo new version deployed $version/ on s3://tiledesk-widget-pre/native-mqtt/widget/ and s3://tiledesk-widget-pre/native-mqtt/widget/$version/ 17 | # echo available on https://s3.eu-west-1.amazonaws.com/tiledesk-widget-pre/native-mqtt/widget/index.html 18 | # echo https://widget-pre.tiledesk.com/v5/index.html 19 | # echo https://widget-pre.tiledesk.com/v5/$version/index.html 20 | 21 | # ########## --->>>> NATIVE-MQTT folder END <<<<<------ ########## # 22 | 23 | 24 | # ########## --->>>> FIREBASE folder START <<<<<------ ########## # 25 | cd dist 26 | aws s3 sync . s3://tiledesk-widget-pre/v5/$version/ 27 | aws s3 sync . s3://tiledesk-widget-pre/v5/ 28 | cd .. 29 | 30 | #aws cloudfront create-invalidation --distribution-id E3EJDWEHY08CZZ --paths "/*" 31 | # echo new version deployed $NEW_VER/$NEW_BUILD/ on s3://tiledesk-widget-pre/v2 32 | echo new version deployed $version/ on s3://tiledesk-widget-pre/v5 and s3://tiledesk-widget-pre/v5/$version/ 33 | echo available on https://s3.eu-west-1.amazonaws.com/tiledesk-widget-pre/v5/index.html 34 | echo https://widget-pre.tiledesk.com/v5/index.html 35 | echo https://widget-pre.tiledesk.com/v5/$version/index.html 36 | 37 | # ########## --->>>> FIREBASE folder END <<<<<------ ########## # 38 | 39 | ## AZIONI per committare: 40 | ## 1) modificare package.json e package-lock.json aggiungendo il num di versione nuovo 41 | ## 2) aggiornare il CHANGELOG 42 | ## 3) fare il commit tramite sourcetree 43 | ## 4) da terminale richiamare ./deploy_pre.sh -------------------------------------------------------------------------------- /src/app/components/launcher-button/launcher-button.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/app/components/message/avatar/avatar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | import { ImageRepoService } from '../../../../chat21-core/providers/abstract/image-repo.service'; 3 | @Component({ 4 | selector: 'chat-avatar-image', 5 | templateUrl: './avatar.component.html', 6 | styleUrls: ['./avatar.component.scss'] 7 | }) 8 | export class AvatarComponent implements OnInit { 9 | 10 | @Input() senderID: string; 11 | @Input() senderFullname: string; 12 | @Input() baseLocation: string; 13 | url: string; 14 | constructor(private imageRepoService: ImageRepoService) { } 15 | 16 | ngOnInit() { 17 | if(this.senderID){ 18 | if(this.senderID.indexOf('bot_') !== -1 || this.senderFullname === 'Bot'){ 19 | this.url = this.baseLocation +'/assets/images/avatar_bot_tiledesk.svg' 20 | }else if( this.senderID.indexOf('bot_') == -1){ 21 | this.url = this.baseLocation +'/assets/images/light_avatar_placeholder.svg' 22 | } 23 | let url = this.imageRepoService.getImagePhotoUrl(this.senderID) 24 | // this.imageRepoService.checkImageExists(url, (existImage)=> { 25 | // existImage? this.url = url: null; 26 | // console.log('existttttt', existImage) 27 | // }) 28 | this.checkImageExists(url, (existImage)=> { 29 | existImage? this.url = url: null; 30 | }) 31 | } 32 | 33 | } 34 | 35 | onBotImgError(event){ 36 | event.target.src = this.baseLocation +'/assets/images/avatar_bot_tiledesk.svg' 37 | } 38 | onHumanImgError(event) { 39 | event.target.src = this.baseLocation + "/assets/images/light_avatar_placeholder.svg" 40 | } 41 | 42 | onLoadedBot(event){ 43 | // console.log('LOADED Bot avatar image...') 44 | } 45 | 46 | onLoadedHuman(event){ 47 | // console.log('LOADED Bot human image...') 48 | } 49 | 50 | 51 | checkImageExists(imageUrl, callBack) { 52 | var imageData = new Image(); 53 | imageData.onload = function () { 54 | callBack(true); 55 | }; 56 | imageData.onerror = function () { 57 | callBack(false); 58 | }; 59 | imageData.src = imageUrl; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/app/_animations/slide-in-out-for-panel.animation.ts: -------------------------------------------------------------------------------- 1 | import { trigger, state, animate, transition, style } from '@angular/animations'; 2 | 3 | 4 | 5 | export const slideInOutForPanelAnimation = 6 | trigger('slideInOutForPanelAnimation', [ 7 | 8 | // end state styles for route container (host) 9 | state('*', style({ 10 | // the view covers the whole screen with a semi tranparent background 11 | // position: 'fixed', 12 | position: 'absolute', 13 | top: 0 + 'px', 14 | left: 0, 15 | right: 0, 16 | bottom: 0, 17 | backgroundColor: 'rgba(0, 0, 0, 0.5)' 18 | })), 19 | 20 | // route 'enter' transition 21 | transition(':enter', [ 22 | 23 | // styles at start of transition 24 | style({ 25 | // start with the content positioned off the right of the screen, 26 | // -400% is required instead of -100% because the negative position adds to the width of the element 27 | right: '-400%', 28 | 29 | // start with background opacity set to 0 (invisible) 30 | backgroundColor: 'rgba(0, 0, 0, 0)' 31 | }), 32 | 33 | // animation and styles at end of transition 34 | animate('.3s ease-in-out', style({ 35 | // transition the right position to 0 which slides the content into view 36 | right: 0, 37 | 38 | // transition the background opacity to 0.8 to fade it in 39 | backgroundColor: 'rgba(0, 0, 0, 0.5)' 40 | })) 41 | ]), 42 | 43 | // route 'leave' transition 44 | transition(':leave', [ 45 | // animation and styles at end of transition 46 | animate('3s ease-in-out', style({ 47 | // transition the right position to -400% which slides the content out of view 48 | right: '-400%', 49 | 50 | // transition the background opacity to 0 to fade it out 51 | backgroundColor: 'rgba(0, 0, 0, 0)' 52 | })) 53 | ]) 54 | ]); 55 | -------------------------------------------------------------------------------- /src/app/_animations/slide-in-out.animation.ts: -------------------------------------------------------------------------------- 1 | import { trigger, state, animate, transition, style } from '@angular/animations'; 2 | 3 | 4 | 5 | export const slideInOutAnimation = 6 | trigger('slideInOutAnimation', [ 7 | 8 | // end state styles for route container (host) 9 | state('*', style({ 10 | // the view covers the whole screen with a semi tranparent background 11 | // position: 'fixed', 12 | position: 'absolute', 13 | // top: 60 + 'px', 14 | top:0, 15 | left: 0, 16 | right: 0, 17 | bottom: 0, 18 | backgroundColor: 'rgba(0, 0, 0, 0.5)' 19 | })), 20 | 21 | // route 'enter' transition 22 | transition(':enter', [ 23 | 24 | // styles at start of transition 25 | style({ 26 | // start with the content positioned off the right of the screen, 27 | // -400% is required instead of -100% because the negative position adds to the width of the element 28 | right: '-400%', 29 | 30 | // start with background opacity set to 0 (invisible) 31 | backgroundColor: 'rgba(0, 0, 0, 0)' 32 | }), 33 | 34 | // animation and styles at end of transition 35 | animate('.3s ease-in-out', style({ 36 | // transition the right position to 0 which slides the content into view 37 | right: 0, 38 | 39 | // transition the background opacity to 0.8 to fade it in 40 | backgroundColor: 'rgba(0, 0, 0, 0.5)' 41 | })) 42 | ]), 43 | 44 | // route 'leave' transition 45 | transition(':leave', [ 46 | // animation and styles at end of transition 47 | animate('3s ease-in-out', style({ 48 | // transition the right position to -400% which slides the content out of view 49 | right: '-400%', 50 | 51 | // transition the background opacity to 0 to fade it out 52 | backgroundColor: 'rgba(0, 0, 0, 0)' 53 | })) 54 | ]) 55 | ]); 56 | -------------------------------------------------------------------------------- /src/assets/images/line_avatar_bot_tiledesk.svg: -------------------------------------------------------------------------------- 1 | line_avatar_bot_tiledesk --------------------------------------------------------------------------------