mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-04 04:57:51 +00:00 
			
		
		
		
	This PR addresses an issue with the `createNotificationBubble` function, which generates an empty `span` element with the class `woot--notification`. This `span` element is currently not utilized anywhere in the code and lacks associated CSS, leading to an overflow issue, specifically in the Firefox browser. It solves the website overflow issue by removing this unused `span` element. This change is unrelated to the unread notification dot, which is working as before. Fixes https://linear.app/chatwoot/issue/PR-1098/missing-css-for-woot-notification-div
		
			
				
	
	
		
			327 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			327 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import Cookies from 'js-cookie';
 | 
						|
import {
 | 
						|
  addClasses,
 | 
						|
  loadCSS,
 | 
						|
  removeClasses,
 | 
						|
  onLocationChangeListener,
 | 
						|
} from './DOMHelpers';
 | 
						|
import {
 | 
						|
  body,
 | 
						|
  widgetHolder,
 | 
						|
  createBubbleHolder,
 | 
						|
  createBubbleIcon,
 | 
						|
  bubbleSVG,
 | 
						|
  chatBubble,
 | 
						|
  closeBubble,
 | 
						|
  bubbleHolder,
 | 
						|
  onClickChatBubble,
 | 
						|
  onBubbleClick,
 | 
						|
  setBubbleText,
 | 
						|
  addUnreadClass,
 | 
						|
  removeUnreadClass,
 | 
						|
} from './bubbleHelpers';
 | 
						|
import { isWidgetColorLighter } from 'shared/helpers/colorHelper';
 | 
						|
import { dispatchWindowEvent } from 'shared/helpers/CustomEventHelper';
 | 
						|
import { CHATWOOT_ERROR, CHATWOOT_READY } from '../widget/constants/sdkEvents';
 | 
						|
import { SET_USER_ERROR } from '../widget/constants/errorTypes';
 | 
						|
import { getUserCookieName, setCookieWithDomain } from './cookieHelpers';
 | 
						|
import {
 | 
						|
  getAlertAudio,
 | 
						|
  initOnEvents,
 | 
						|
} from 'shared/helpers/AudioNotificationHelper';
 | 
						|
import { isFlatWidgetStyle } from './settingsHelper';
 | 
						|
import { popoutChatWindow } from '../widget/helpers/popoutHelper';
 | 
						|
import addHours from 'date-fns/addHours';
 | 
						|
 | 
						|
const updateAuthCookie = (cookieContent, baseDomain = '') =>
 | 
						|
  setCookieWithDomain('cw_conversation', cookieContent, {
 | 
						|
    baseDomain,
 | 
						|
  });
 | 
						|
 | 
						|
const updateCampaignReadStatus = baseDomain => {
 | 
						|
  const expireBy = addHours(new Date(), 1);
 | 
						|
  setCookieWithDomain('cw_snooze_campaigns_till', Number(expireBy), {
 | 
						|
    expires: expireBy,
 | 
						|
    baseDomain,
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
export const IFrameHelper = {
 | 
						|
  getUrl({ baseUrl, websiteToken }) {
 | 
						|
    return `${baseUrl}/widget?website_token=${websiteToken}`;
 | 
						|
  },
 | 
						|
  createFrame: ({ baseUrl, websiteToken }) => {
 | 
						|
    if (IFrameHelper.getAppFrame()) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    loadCSS();
 | 
						|
    const iframe = document.createElement('iframe');
 | 
						|
    const cwCookie = Cookies.get('cw_conversation');
 | 
						|
    let widgetUrl = IFrameHelper.getUrl({ baseUrl, websiteToken });
 | 
						|
    if (cwCookie) {
 | 
						|
      widgetUrl = `${widgetUrl}&cw_conversation=${cwCookie}`;
 | 
						|
    }
 | 
						|
    iframe.src = widgetUrl;
 | 
						|
    iframe.allow =
 | 
						|
      'camera;microphone;fullscreen;display-capture;picture-in-picture;clipboard-write;';
 | 
						|
    iframe.id = 'chatwoot_live_chat_widget';
 | 
						|
    iframe.style.visibility = 'hidden';
 | 
						|
 | 
						|
    let holderClassName = `woot-widget-holder woot--hide woot-elements--${window.$chatwoot.position}`;
 | 
						|
    if (window.$chatwoot.hideMessageBubble) {
 | 
						|
      holderClassName += ` woot-widget--without-bubble`;
 | 
						|
    }
 | 
						|
    if (isFlatWidgetStyle(window.$chatwoot.widgetStyle)) {
 | 
						|
      holderClassName += ` woot-widget-holder--flat`;
 | 
						|
    }
 | 
						|
 | 
						|
    addClasses(widgetHolder, holderClassName);
 | 
						|
    widgetHolder.id = 'cw-widget-holder';
 | 
						|
    widgetHolder.appendChild(iframe);
 | 
						|
    body.appendChild(widgetHolder);
 | 
						|
    IFrameHelper.initPostMessageCommunication();
 | 
						|
    IFrameHelper.initWindowSizeListener();
 | 
						|
    IFrameHelper.preventDefaultScroll();
 | 
						|
  },
 | 
						|
  getAppFrame: () => document.getElementById('chatwoot_live_chat_widget'),
 | 
						|
  getBubbleHolder: () => document.getElementsByClassName('woot--bubble-holder'),
 | 
						|
  sendMessage: (key, value) => {
 | 
						|
    const element = IFrameHelper.getAppFrame();
 | 
						|
    element.contentWindow.postMessage(
 | 
						|
      `chatwoot-widget:${JSON.stringify({ event: key, ...value })}`,
 | 
						|
      '*'
 | 
						|
    );
 | 
						|
  },
 | 
						|
  initPostMessageCommunication: () => {
 | 
						|
    window.onmessage = e => {
 | 
						|
      if (
 | 
						|
        typeof e.data !== 'string' ||
 | 
						|
        e.data.indexOf('chatwoot-widget:') !== 0
 | 
						|
      ) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      const message = JSON.parse(e.data.replace('chatwoot-widget:', ''));
 | 
						|
      if (typeof IFrameHelper.events[message.event] === 'function') {
 | 
						|
        IFrameHelper.events[message.event](message);
 | 
						|
      }
 | 
						|
    };
 | 
						|
  },
 | 
						|
  initWindowSizeListener: () => {
 | 
						|
    window.addEventListener('resize', () => IFrameHelper.toggleCloseButton());
 | 
						|
  },
 | 
						|
  preventDefaultScroll: () => {
 | 
						|
    widgetHolder.addEventListener('wheel', event => {
 | 
						|
      const deltaY = event.deltaY;
 | 
						|
      const contentHeight = widgetHolder.scrollHeight;
 | 
						|
      const visibleHeight = widgetHolder.offsetHeight;
 | 
						|
      const scrollTop = widgetHolder.scrollTop;
 | 
						|
 | 
						|
      if (
 | 
						|
        (scrollTop === 0 && deltaY < 0) ||
 | 
						|
        (visibleHeight + scrollTop === contentHeight && deltaY > 0)
 | 
						|
      ) {
 | 
						|
        event.preventDefault();
 | 
						|
      }
 | 
						|
    });
 | 
						|
  },
 | 
						|
 | 
						|
  setFrameHeightToFitContent: (extraHeight, isFixedHeight) => {
 | 
						|
    const iframe = IFrameHelper.getAppFrame();
 | 
						|
    const updatedIframeHeight = isFixedHeight ? `${extraHeight}px` : '100%';
 | 
						|
 | 
						|
    if (iframe)
 | 
						|
      iframe.setAttribute('style', `height: ${updatedIframeHeight} !important`);
 | 
						|
  },
 | 
						|
 | 
						|
  setupAudioListeners: () => {
 | 
						|
    const { baseUrl = '' } = window.$chatwoot;
 | 
						|
    getAlertAudio(baseUrl, { type: 'widget', alertTone: 'ding' }).then(() =>
 | 
						|
      initOnEvents.forEach(event => {
 | 
						|
        document.removeEventListener(
 | 
						|
          event,
 | 
						|
          IFrameHelper.setupAudioListeners,
 | 
						|
          false
 | 
						|
        );
 | 
						|
      })
 | 
						|
    );
 | 
						|
  },
 | 
						|
 | 
						|
  events: {
 | 
						|
    loaded: message => {
 | 
						|
      updateAuthCookie(message.config.authToken, window.$chatwoot.baseDomain);
 | 
						|
      window.$chatwoot.hasLoaded = true;
 | 
						|
      const campaignsSnoozedTill = Cookies.get('cw_snooze_campaigns_till');
 | 
						|
      IFrameHelper.sendMessage('config-set', {
 | 
						|
        locale: window.$chatwoot.locale,
 | 
						|
        position: window.$chatwoot.position,
 | 
						|
        hideMessageBubble: window.$chatwoot.hideMessageBubble,
 | 
						|
        showPopoutButton: window.$chatwoot.showPopoutButton,
 | 
						|
        widgetStyle: window.$chatwoot.widgetStyle,
 | 
						|
        darkMode: window.$chatwoot.darkMode,
 | 
						|
        showUnreadMessagesDialog: window.$chatwoot.showUnreadMessagesDialog,
 | 
						|
        campaignsSnoozedTill,
 | 
						|
      });
 | 
						|
      IFrameHelper.onLoad({
 | 
						|
        widgetColor: message.config.channelConfig.widgetColor,
 | 
						|
      });
 | 
						|
      IFrameHelper.toggleCloseButton();
 | 
						|
 | 
						|
      if (window.$chatwoot.user) {
 | 
						|
        IFrameHelper.sendMessage('set-user', window.$chatwoot.user);
 | 
						|
      }
 | 
						|
 | 
						|
      window.playAudioAlert = () => {};
 | 
						|
 | 
						|
      initOnEvents.forEach(e => {
 | 
						|
        document.addEventListener(e, IFrameHelper.setupAudioListeners, false);
 | 
						|
      });
 | 
						|
 | 
						|
      if (!window.$chatwoot.resetTriggered) {
 | 
						|
        dispatchWindowEvent({ eventName: CHATWOOT_READY });
 | 
						|
      }
 | 
						|
    },
 | 
						|
    error: ({ errorType, data }) => {
 | 
						|
      dispatchWindowEvent({ eventName: CHATWOOT_ERROR, data: data });
 | 
						|
 | 
						|
      if (errorType === SET_USER_ERROR) {
 | 
						|
        Cookies.remove(getUserCookieName());
 | 
						|
      }
 | 
						|
    },
 | 
						|
    onEvent({ eventIdentifier: eventName, data }) {
 | 
						|
      dispatchWindowEvent({ eventName, data });
 | 
						|
    },
 | 
						|
    setBubbleLabel(message) {
 | 
						|
      setBubbleText(window.$chatwoot.launcherTitle || message.label);
 | 
						|
    },
 | 
						|
 | 
						|
    setAuthCookie({ data: { widgetAuthToken } }) {
 | 
						|
      updateAuthCookie(widgetAuthToken, window.$chatwoot.baseDomain);
 | 
						|
    },
 | 
						|
 | 
						|
    setCampaignReadOn() {
 | 
						|
      updateCampaignReadStatus(window.$chatwoot.baseDomain);
 | 
						|
    },
 | 
						|
 | 
						|
    toggleBubble: state => {
 | 
						|
      let bubbleState = {};
 | 
						|
      if (state === 'open') {
 | 
						|
        bubbleState.toggleValue = true;
 | 
						|
      } else if (state === 'close') {
 | 
						|
        bubbleState.toggleValue = false;
 | 
						|
      }
 | 
						|
 | 
						|
      onBubbleClick(bubbleState);
 | 
						|
    },
 | 
						|
 | 
						|
    popoutChatWindow: ({ baseUrl, websiteToken, locale }) => {
 | 
						|
      const cwCookie = Cookies.get('cw_conversation');
 | 
						|
      window.$chatwoot.toggle('close');
 | 
						|
      popoutChatWindow(baseUrl, websiteToken, locale, cwCookie);
 | 
						|
    },
 | 
						|
 | 
						|
    closeWindow: () => {
 | 
						|
      onBubbleClick({ toggleValue: false });
 | 
						|
      removeUnreadClass();
 | 
						|
    },
 | 
						|
 | 
						|
    onBubbleToggle: isOpen => {
 | 
						|
      IFrameHelper.sendMessage('toggle-open', { isOpen });
 | 
						|
      if (isOpen) {
 | 
						|
        IFrameHelper.pushEvent('webwidget.triggered');
 | 
						|
      }
 | 
						|
    },
 | 
						|
    onLocationChange: ({ referrerURL, referrerHost }) => {
 | 
						|
      IFrameHelper.sendMessage('change-url', {
 | 
						|
        referrerURL,
 | 
						|
        referrerHost,
 | 
						|
      });
 | 
						|
    },
 | 
						|
    updateIframeHeight: message => {
 | 
						|
      const { extraHeight = 0, isFixedHeight } = message;
 | 
						|
 | 
						|
      IFrameHelper.setFrameHeightToFitContent(extraHeight, isFixedHeight);
 | 
						|
    },
 | 
						|
 | 
						|
    setUnreadMode: () => {
 | 
						|
      addUnreadClass();
 | 
						|
      onBubbleClick({ toggleValue: true });
 | 
						|
    },
 | 
						|
 | 
						|
    resetUnreadMode: () => removeUnreadClass(),
 | 
						|
    handleNotificationDot: event => {
 | 
						|
      if (window.$chatwoot.hideMessageBubble) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      const bubbleElement = document.querySelector('.woot-widget-bubble');
 | 
						|
      if (
 | 
						|
        event.unreadMessageCount > 0 &&
 | 
						|
        !bubbleElement.classList.contains('unread-notification')
 | 
						|
      ) {
 | 
						|
        addClasses(bubbleElement, 'unread-notification');
 | 
						|
      } else if (event.unreadMessageCount === 0) {
 | 
						|
        removeClasses(bubbleElement, 'unread-notification');
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    closeChat: () => {
 | 
						|
      onBubbleClick({ toggleValue: false });
 | 
						|
    },
 | 
						|
 | 
						|
    playAudio: () => {
 | 
						|
      window.playAudioAlert();
 | 
						|
    },
 | 
						|
  },
 | 
						|
  pushEvent: eventName => {
 | 
						|
    IFrameHelper.sendMessage('push-event', { eventName });
 | 
						|
  },
 | 
						|
 | 
						|
  onLoad: ({ widgetColor }) => {
 | 
						|
    const iframe = IFrameHelper.getAppFrame();
 | 
						|
    iframe.style.visibility = '';
 | 
						|
    iframe.setAttribute('id', `chatwoot_live_chat_widget`);
 | 
						|
 | 
						|
    if (IFrameHelper.getBubbleHolder().length) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    createBubbleHolder(window.$chatwoot.hideMessageBubble);
 | 
						|
    onLocationChangeListener();
 | 
						|
 | 
						|
    let className = 'woot-widget-bubble';
 | 
						|
    let closeBtnClassName = `woot-elements--${window.$chatwoot.position} woot-widget-bubble woot--close woot--hide`;
 | 
						|
 | 
						|
    if (isFlatWidgetStyle(window.$chatwoot.widgetStyle)) {
 | 
						|
      className += ' woot-widget-bubble--flat';
 | 
						|
      closeBtnClassName += ' woot-widget-bubble--flat';
 | 
						|
    }
 | 
						|
 | 
						|
    if (isWidgetColorLighter(widgetColor)) {
 | 
						|
      className += ' woot-widget-bubble-color--lighter';
 | 
						|
      closeBtnClassName += ' woot-widget-bubble-color--lighter';
 | 
						|
    }
 | 
						|
 | 
						|
    const chatIcon = createBubbleIcon({
 | 
						|
      className,
 | 
						|
      path: bubbleSVG,
 | 
						|
      target: chatBubble,
 | 
						|
    });
 | 
						|
 | 
						|
    addClasses(closeBubble, closeBtnClassName);
 | 
						|
 | 
						|
    chatIcon.style.background = widgetColor;
 | 
						|
    closeBubble.style.background = widgetColor;
 | 
						|
 | 
						|
    bubbleHolder.appendChild(chatIcon);
 | 
						|
    bubbleHolder.appendChild(closeBubble);
 | 
						|
    onClickChatBubble();
 | 
						|
  },
 | 
						|
  toggleCloseButton: () => {
 | 
						|
    let isMobile = false;
 | 
						|
    if (window.matchMedia('(max-width: 668px)').matches) {
 | 
						|
      isMobile = true;
 | 
						|
    }
 | 
						|
    IFrameHelper.sendMessage('toggle-close-button', { isMobile });
 | 
						|
  },
 | 
						|
};
 |