mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 19:17:48 +00:00 
			
		
		
		
	 b474929f5e
			
		
	
	b474929f5e
	
	
	
		
			
			# Replace the deprecated `eventBus` with mitt.js ## Description Since eventBus and it's respective methods are deprecated and removed from all future releases of vue, this was blocking us from migrating. This PR replaces eventBus with [mitt](https://github.com/developit/mitt). I have created a wrapper mitt.js to simulate the same old event names so it's backwards compatible, without making a lot of changes. Fixes # (issue) ## Type of change Please delete options that are not relevant. - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected) - [ ] This change requires a documentation update ## How Has This Been Tested? 1. Made sure all the places we're listening to bus events are working as expected. 2. Respective specsf or the events from mitt. ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented on my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] Any dependent changes have been merged and published in downstream modules
		
			
				
	
	
		
			354 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			354 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
	
	
| <template>
 | |
|   <div
 | |
|     v-if="!conversationSize && isFetchingList"
 | |
|     class="flex flex-1 items-center h-full bg-black-25 justify-center"
 | |
|     :class="{ dark: prefersDarkMode }"
 | |
|   >
 | |
|     <spinner size="" />
 | |
|   </div>
 | |
|   <div
 | |
|     v-else
 | |
|     class="flex flex-col justify-end h-full"
 | |
|     :class="{
 | |
|       'is-mobile': isMobile,
 | |
|       'is-widget-right': isRightAligned,
 | |
|       'is-bubble-hidden': hideMessageBubble,
 | |
|       'is-flat-design': isWidgetStyleFlat,
 | |
|       dark: prefersDarkMode,
 | |
|     }"
 | |
|   >
 | |
|     <router-view />
 | |
|   </div>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| import { mapGetters, mapActions } from 'vuex';
 | |
| import { setHeader } from 'widget/helpers/axios';
 | |
| import addHours from 'date-fns/addHours';
 | |
| import { IFrameHelper, RNHelper } from 'widget/helpers/utils';
 | |
| import configMixin from './mixins/configMixin';
 | |
| import availabilityMixin from 'widget/mixins/availability';
 | |
| import { getLocale } from './helpers/urlParamsHelper';
 | |
| import { isEmptyObject } from 'widget/helpers/utils';
 | |
| import Spinner from 'shared/components/Spinner.vue';
 | |
| import routerMixin from './mixins/routerMixin';
 | |
| import {
 | |
|   getExtraSpaceToScroll,
 | |
|   loadedEventConfig,
 | |
| } from './helpers/IframeEventHelper';
 | |
| import {
 | |
|   ON_AGENT_MESSAGE_RECEIVED,
 | |
|   ON_CAMPAIGN_MESSAGE_CLICK,
 | |
|   ON_UNREAD_MESSAGE_CLICK,
 | |
| } from './constants/widgetBusEvents';
 | |
| import darkModeMixin from 'widget/mixins/darkModeMixin';
 | |
| import { SDK_SET_BUBBLE_VISIBILITY } from '../shared/constants/sharedFrameEvents';
 | |
| import { emitter } from 'shared/helpers/mitt';
 | |
| 
 | |
| export default {
 | |
|   name: 'App',
 | |
|   components: {
 | |
|     Spinner,
 | |
|   },
 | |
|   mixins: [availabilityMixin, configMixin, routerMixin, darkModeMixin],
 | |
|   data() {
 | |
|     return {
 | |
|       isMobile: false,
 | |
|       campaignsSnoozedTill: undefined,
 | |
|     };
 | |
|   },
 | |
|   computed: {
 | |
|     ...mapGetters({
 | |
|       activeCampaign: 'campaign/getActiveCampaign',
 | |
|       campaigns: 'campaign/getCampaigns',
 | |
|       conversationSize: 'conversation/getConversationSize',
 | |
|       currentUser: 'contacts/getCurrentUser',
 | |
|       hasFetched: 'agent/getHasFetched',
 | |
|       hideMessageBubble: 'appConfig/getHideMessageBubble',
 | |
|       isFetchingList: 'conversation/getIsFetchingList',
 | |
|       isRightAligned: 'appConfig/isRightAligned',
 | |
|       isWidgetOpen: 'appConfig/getIsWidgetOpen',
 | |
|       messageCount: 'conversation/getMessageCount',
 | |
|       unreadMessageCount: 'conversation/getUnreadMessageCount',
 | |
|       isWidgetStyleFlat: 'appConfig/isWidgetStyleFlat',
 | |
|     }),
 | |
|     isIFrame() {
 | |
|       return IFrameHelper.isIFrame();
 | |
|     },
 | |
|     isRNWebView() {
 | |
|       return RNHelper.isRNWebView();
 | |
|     },
 | |
|   },
 | |
|   watch: {
 | |
|     activeCampaign() {
 | |
|       this.setCampaignView();
 | |
|     },
 | |
|   },
 | |
|   mounted() {
 | |
|     const { websiteToken, locale, widgetColor } = window.chatwootWebChannel;
 | |
|     this.setLocale(locale);
 | |
|     this.setWidgetColor(widgetColor);
 | |
|     setHeader(window.authToken);
 | |
|     if (this.isIFrame) {
 | |
|       this.registerListeners();
 | |
|       this.sendLoadedEvent();
 | |
|     } else {
 | |
|       this.fetchOldConversations();
 | |
|       this.fetchAvailableAgents(websiteToken);
 | |
|       this.setLocale(getLocale(window.location.search));
 | |
|     }
 | |
|     if (this.isRNWebView) {
 | |
|       this.registerListeners();
 | |
|       this.sendRNWebViewLoadedEvent();
 | |
|     }
 | |
|     this.$store.dispatch('conversationAttributes/getAttributes');
 | |
|     this.registerUnreadEvents();
 | |
|     this.registerCampaignEvents();
 | |
|   },
 | |
|   methods: {
 | |
|     ...mapActions('appConfig', [
 | |
|       'setAppConfig',
 | |
|       'setReferrerHost',
 | |
|       'setWidgetColor',
 | |
|       'setBubbleVisibility',
 | |
|       'setColorScheme',
 | |
|     ]),
 | |
|     ...mapActions('conversation', ['fetchOldConversations', 'setUserLastSeen']),
 | |
|     ...mapActions('campaign', [
 | |
|       'initCampaigns',
 | |
|       'executeCampaign',
 | |
|       'resetCampaign',
 | |
|     ]),
 | |
|     ...mapActions('agent', ['fetchAvailableAgents']),
 | |
|     scrollConversationToBottom() {
 | |
|       const container = this.$el.querySelector('.conversation-wrap');
 | |
|       container.scrollTop = container.scrollHeight;
 | |
|     },
 | |
|     setBubbleLabel() {
 | |
|       IFrameHelper.sendMessage({
 | |
|         event: 'setBubbleLabel',
 | |
|         label: this.$t('BUBBLE.LABEL'),
 | |
|       });
 | |
|     },
 | |
|     setIframeHeight(isFixedHeight) {
 | |
|       this.$nextTick(() => {
 | |
|         const extraHeight = getExtraSpaceToScroll();
 | |
|         IFrameHelper.sendMessage({
 | |
|           event: 'updateIframeHeight',
 | |
|           isFixedHeight,
 | |
|           extraHeight,
 | |
|         });
 | |
|       });
 | |
|     },
 | |
|     setLocale(localeWithVariation) {
 | |
|       if (!localeWithVariation) return;
 | |
|       const { enabledLanguages } = window.chatwootWebChannel;
 | |
|       const localeWithoutVariation = localeWithVariation.split('_')[0];
 | |
|       const hasLocaleWithoutVariation = enabledLanguages.some(
 | |
|         lang => lang.iso_639_1_code === localeWithoutVariation
 | |
|       );
 | |
|       const hasLocaleWithVariation = enabledLanguages.some(
 | |
|         lang => lang.iso_639_1_code === localeWithVariation
 | |
|       );
 | |
| 
 | |
|       if (hasLocaleWithVariation) {
 | |
|         this.$root.$i18n.locale = localeWithVariation;
 | |
|       } else if (hasLocaleWithoutVariation) {
 | |
|         this.$root.$i18n.locale = localeWithoutVariation;
 | |
|       }
 | |
|     },
 | |
|     registerUnreadEvents() {
 | |
|       emitter.on(ON_AGENT_MESSAGE_RECEIVED, () => {
 | |
|         const { name: routeName } = this.$route;
 | |
|         if ((this.isWidgetOpen || !this.isIFrame) && routeName === 'messages') {
 | |
|           this.$store.dispatch('conversation/setUserLastSeen');
 | |
|         }
 | |
|         this.setUnreadView();
 | |
|       });
 | |
|       emitter.on(ON_UNREAD_MESSAGE_CLICK, () => {
 | |
|         this.replaceRoute('messages').then(() => this.unsetUnreadView());
 | |
|       });
 | |
|     },
 | |
|     registerCampaignEvents() {
 | |
|       emitter.on(ON_CAMPAIGN_MESSAGE_CLICK, () => {
 | |
|         if (this.shouldShowPreChatForm) {
 | |
|           this.replaceRoute('prechat-form');
 | |
|         } else {
 | |
|           this.replaceRoute('messages');
 | |
|           emitter.emit('execute-campaign', {
 | |
|             campaignId: this.activeCampaign.id,
 | |
|           });
 | |
|         }
 | |
|         this.unsetUnreadView();
 | |
|       });
 | |
|       emitter.on('execute-campaign', campaignDetails => {
 | |
|         const { customAttributes, campaignId } = campaignDetails;
 | |
|         const { websiteToken } = window.chatwootWebChannel;
 | |
|         this.executeCampaign({ campaignId, websiteToken, customAttributes });
 | |
|         this.replaceRoute('messages');
 | |
|       });
 | |
|       emitter.on('snooze-campaigns', () => {
 | |
|         const expireBy = addHours(new Date(), 1);
 | |
|         this.campaignsSnoozedTill = Number(expireBy);
 | |
|       });
 | |
|     },
 | |
|     setCampaignView() {
 | |
|       const { messageCount, activeCampaign } = this;
 | |
|       const shouldSnoozeCampaign =
 | |
|         this.campaignsSnoozedTill && this.campaignsSnoozedTill > Date.now();
 | |
|       const isCampaignReadyToExecute =
 | |
|         !isEmptyObject(activeCampaign) &&
 | |
|         !messageCount &&
 | |
|         !shouldSnoozeCampaign;
 | |
|       if (this.isIFrame && isCampaignReadyToExecute) {
 | |
|         this.replaceRoute('campaigns').then(() => {
 | |
|           this.setIframeHeight(true);
 | |
|           IFrameHelper.sendMessage({ event: 'setUnreadMode' });
 | |
|         });
 | |
|       }
 | |
|     },
 | |
|     setUnreadView() {
 | |
|       const { unreadMessageCount } = this;
 | |
| 
 | |
|       if (this.isIFrame && unreadMessageCount > 0 && !this.isWidgetOpen) {
 | |
|         this.replaceRoute('unread-messages').then(() => {
 | |
|           this.setIframeHeight(true);
 | |
|           IFrameHelper.sendMessage({ event: 'setUnreadMode' });
 | |
|         });
 | |
|         this.handleUnreadNotificationDot();
 | |
|       }
 | |
|     },
 | |
|     unsetUnreadView() {
 | |
|       if (this.isIFrame) {
 | |
|         IFrameHelper.sendMessage({ event: 'resetUnreadMode' });
 | |
|         this.setIframeHeight(false);
 | |
|         this.handleUnreadNotificationDot();
 | |
|       }
 | |
|     },
 | |
|     handleUnreadNotificationDot() {
 | |
|       const { unreadMessageCount } = this;
 | |
|       if (this.isIFrame) {
 | |
|         IFrameHelper.sendMessage({
 | |
|           event: 'handleNotificationDot',
 | |
|           unreadMessageCount,
 | |
|         });
 | |
|       }
 | |
|     },
 | |
|     createWidgetEvents(message) {
 | |
|       const { eventName } = message;
 | |
|       const isWidgetTriggerEvent = eventName === 'webwidget.triggered';
 | |
|       if (
 | |
|         isWidgetTriggerEvent &&
 | |
|         ['unread-messages', 'campaigns'].includes(this.$route.name)
 | |
|       ) {
 | |
|         return;
 | |
|       }
 | |
|       this.$store.dispatch('events/create', { name: eventName });
 | |
|     },
 | |
|     registerListeners() {
 | |
|       const { websiteToken } = window.chatwootWebChannel;
 | |
|       window.addEventListener('message', e => {
 | |
|         if (!IFrameHelper.isAValidEvent(e)) {
 | |
|           return;
 | |
|         }
 | |
|         const message = IFrameHelper.getMessage(e);
 | |
|         if (message.event === 'config-set') {
 | |
|           this.setLocale(message.locale);
 | |
|           this.setBubbleLabel();
 | |
|           this.fetchOldConversations().then(() => this.setUnreadView());
 | |
|           this.fetchAvailableAgents(websiteToken);
 | |
|           this.setAppConfig(message);
 | |
|           this.$store.dispatch('contacts/get');
 | |
|           this.setCampaignReadData(message.campaignsSnoozedTill);
 | |
|         } else if (message.event === 'widget-visible') {
 | |
|           this.scrollConversationToBottom();
 | |
|         } else if (message.event === 'change-url') {
 | |
|           const { referrerURL, referrerHost } = message;
 | |
|           this.initCampaigns({
 | |
|             currentURL: referrerURL,
 | |
|             websiteToken,
 | |
|             isInBusinessHours: this.isInBusinessHours,
 | |
|           });
 | |
|           window.referrerURL = referrerURL;
 | |
|           this.setReferrerHost(referrerHost);
 | |
|         } else if (message.event === 'toggle-close-button') {
 | |
|           this.isMobile = message.isMobile;
 | |
|         } else if (message.event === 'push-event') {
 | |
|           this.createWidgetEvents(message);
 | |
|         } else if (message.event === 'set-label') {
 | |
|           this.$store.dispatch('conversationLabels/create', message.label);
 | |
|         } else if (message.event === 'remove-label') {
 | |
|           this.$store.dispatch('conversationLabels/destroy', message.label);
 | |
|         } else if (message.event === 'set-user') {
 | |
|           this.$store.dispatch('contacts/setUser', message);
 | |
|         } else if (message.event === 'set-custom-attributes') {
 | |
|           this.$store.dispatch(
 | |
|             'contacts/setCustomAttributes',
 | |
|             message.customAttributes
 | |
|           );
 | |
|         } else if (message.event === 'delete-custom-attribute') {
 | |
|           this.$store.dispatch(
 | |
|             'contacts/deleteCustomAttribute',
 | |
|             message.customAttribute
 | |
|           );
 | |
|         } else if (message.event === 'set-conversation-custom-attributes') {
 | |
|           this.$store.dispatch(
 | |
|             'conversation/setCustomAttributes',
 | |
|             message.customAttributes
 | |
|           );
 | |
|         } else if (message.event === 'delete-conversation-custom-attribute') {
 | |
|           this.$store.dispatch(
 | |
|             'conversation/deleteCustomAttribute',
 | |
|             message.customAttribute
 | |
|           );
 | |
|         } else if (message.event === 'set-locale') {
 | |
|           this.setLocale(message.locale);
 | |
|           this.setBubbleLabel();
 | |
|         } else if (message.event === 'set-color-scheme') {
 | |
|           this.setColorScheme(message.darkMode);
 | |
|         } else if (message.event === 'toggle-open') {
 | |
|           this.$store.dispatch('appConfig/toggleWidgetOpen', message.isOpen);
 | |
| 
 | |
|           const shouldShowMessageView =
 | |
|             ['home'].includes(this.$route.name) &&
 | |
|             message.isOpen &&
 | |
|             this.messageCount;
 | |
|           const shouldShowHomeView =
 | |
|             !message.isOpen &&
 | |
|             ['unread-messages', 'campaigns'].includes(this.$route.name);
 | |
| 
 | |
|           if (shouldShowMessageView) {
 | |
|             this.replaceRoute('messages');
 | |
|           }
 | |
|           if (shouldShowHomeView) {
 | |
|             this.$store.dispatch('conversation/setUserLastSeen');
 | |
|             this.unsetUnreadView();
 | |
|             this.replaceRoute('home');
 | |
|           }
 | |
|           if (!message.isOpen) {
 | |
|             this.resetCampaign();
 | |
|           }
 | |
|         } else if (message.event === SDK_SET_BUBBLE_VISIBILITY) {
 | |
|           this.setBubbleVisibility(message.hideMessageBubble);
 | |
|         }
 | |
|       });
 | |
|     },
 | |
|     sendLoadedEvent() {
 | |
|       IFrameHelper.sendMessage(loadedEventConfig());
 | |
|     },
 | |
|     sendRNWebViewLoadedEvent() {
 | |
|       RNHelper.sendMessage(loadedEventConfig());
 | |
|     },
 | |
|     setCampaignReadData(snoozedTill) {
 | |
|       if (snoozedTill) {
 | |
|         this.campaignsSnoozedTill = Number(snoozedTill);
 | |
|       }
 | |
|     },
 | |
|   },
 | |
| };
 | |
| </script>
 | |
| 
 | |
| <style lang="scss">
 | |
| @import '~widget/assets/scss/woot.scss';
 | |
| </style>
 |