import { useI18n } from 'domains/i18n/hooks' import { useVisibility } from 'domains/visibility/hooks' import { useCallback, useEffect, useRef } from 'preact/hooks' import { useSelector } from 'react-redux' import useSeamlyCommands from 'ui/hooks/use-seamly-commands' import { selectShowInlineView } from '../../domains/visibility/selectors' import { useLiveRegion } from './live-region-hooks' import { useSeamlyLayoutMode } from './seamly-state-hooks' import useSessionExpiredCommand from './use-session-expired-command' const useSeamlyChat = () => { const { t } = useI18n() const { isInline, isWindow, isApp } = useSeamlyLayoutMode() const { isOpen, isVisible } = useVisibility() const showInlineView = useSelector(selectShowInlineView) const { start, connect, apiConfigReady, apiConnected } = useSeamlyCommands() const connectCalled = useRef(false) const { sendAssertive } = useLiveRegion() // Automatically reset conversation if the session has expired useSessionExpiredCommand() useEffect(() => { if (isVisible) { // Wait for the live containers to stabilise in the DOM before injecting // the message or some screen readers will swallow it. setTimeout(() => { sendAssertive(t('window.srTexts.onLoad')) }, 500) } }, [isVisible, sendAssertive, t]) useEffect(() => { if (!isVisible) { return } if (isOpen) { sendAssertive(t('window.srTexts.onOpen')) } else { sendAssertive(t('window.srTexts.onClose')) } }, [isOpen, isVisible, sendAssertive, t]) useEffect(() => { // This is needed to reset the ref to allow connect and start to happen again. // Mostly due to Interrupt situations and a reset being called. // Only do this in case both are `false` (reset does this), because the websocket itself will automatically try to reconnect. if (!apiConfigReady && !apiConnected) { connectCalled.current = false } }, [apiConfigReady, apiConnected]) const connectAndStart = useCallback(async () => { // We don't connect if we are already connected to the api to avoid multiple in-flight connection processes. if (!apiConnected) { connectCalled.current = true await connect() } // We only start a conversation when the chat interface is either app, 'open' or if using the inline view if it's 'open' or 'minimized'. if (isApp || isOpen || (isVisible && isInline)) { start() } }, [apiConnected, connect, isApp, isInline, isOpen, isVisible, start]) useEffect(() => { // We dont't connect or start when the apiConfig is not ready yet. // We also keep track of whether start has been called to avoid multiple in-flight connection processes. // We check if the window view is not open and no conversation is started yet. // Lastly we check if the inline view is not scrolled in to view. if ( !apiConfigReady || connectCalled.current || (isWindow && !isOpen) || (isInline && (!isVisible || !showInlineView)) ) { return } connectAndStart() }, [ apiConfigReady, connectAndStart, isInline, isOpen, isVisible, isWindow, showInlineView, ]) } export default useSeamlyChat