import { useConfig } from 'domains/config/hooks' import { useVisibility } from 'domains/visibility/hooks' import { className } from 'lib/css' import { useCallback, useEffect, useRef, useState } from 'preact/hooks' import IdleDetachWarning from 'ui/components/warnings/idle-detach-warning' import ResumeConversationPrompt from 'ui/components/warnings/resume-conversation-prompt' import { useSeamlyEntry } from 'ui/hooks/seamly-entry-hooks' import { useFileUploadMeta, useSeamlyIdleDetachCountdown, useSeamlyResumeConversationPrompt, useSkiplinkTargetFocusing, } from 'ui/hooks/seamly-hooks' import { runIfElementContainsOrHasFocus } from 'ui/utils/general-utils' import { entryTypes } from 'ui/utils/seamly-utils' import TextEntry from './text-entry' import Upload from './upload' import UploadToggle from './upload-toggle' const EntryContainer = () => { const { isOpen } = useVisibility() const entryContainer = useRef(null) const { hasCountdown } = useSeamlyIdleDetachCountdown() const [showCountdown, setShowCountDown] = useState(hasCountdown) const { hasPrompt: hasResumeConversationPrompt } = useSeamlyResumeConversationPrompt() const [showResumeConversationPrompt, setShowResumeConversationPrompt] = useState(hasResumeConversationPrompt) const focusSkiplinkTarget = useSkiplinkTargetFocusing() const containedFocus = useRef(false) const { activeEntry, activeEntryOptions } = useSeamlyEntry() const [entryComponents, setEntryComponents] = useState({ text: TextEntry, upload: Upload, }) const [renderEntry, setRenderEntry] = useState(() => activeEntry) const config = useConfig() const { accountAllowsUploads } = useFileUploadMeta() const focusFn = useCallback(() => { runIfElementContainsOrHasFocus(entryContainer.current, focusSkiplinkTarget) }, [focusSkiplinkTarget]) useEffect(() => { const { customComponents } = config const { entry } = customComponents || {} if (entry) { setEntryComponents((c) => ({ ...c, ...entry, })) } }, [config]) useEffect(() => { // Focus the current target of the skip link if focus was inside the // container before this effect change. focusFn() setShowCountDown(hasCountdown) setShowResumeConversationPrompt(hasResumeConversationPrompt) }, [hasCountdown, hasResumeConversationPrompt, focusFn]) useEffect(() => { setRenderEntry(activeEntry) // This focus action is required for auto entry changes. User driven // changes should be handled in the originating components. focusFn() }, [activeEntry, focusFn, entryContainer]) // Check if the active element is inside this container and save it. containedFocus.current = !!( entryContainer.current && entryContainer.current.contains(document.activeElement) ) // Everything other than `text` and `upload` will fallback to `TextEntry` for now. // This is also done for `choice_prompt`, see comment above `allowManualInput` below. // At a later stage we could implement components like `DateTime` or `PhoneNumber`. const EntryComponent = entryComponents[renderEntry] || TextEntry // Currently we do not have an actual ChoicePrompt entry component. // If we ever do, this property should be moved to that component instead. // The current ChoicePrompt component is only responsible for the rendering of the buttons/choose again option. const { allowManualInput = true } = activeEntryOptions return (
{showCountdown && } {showResumeConversationPrompt && }
{renderEntry !== entryTypes.upload && accountAllowsUploads && isOpen ? ( ) : null}
) } export default EntryContainer