import { resetApp } from 'domains/app/actions' import { useUserHasResponded } from 'domains/app/hooks' import { setHasResponded } from 'domains/app/slice' import { setInterrupt } from 'domains/interrupt/slice' import { useAppDispatch } from 'domains/store' import { addEvent, setEvents, setInitialState } from 'domains/store/slice' import type { MessageUpload } from 'domains/store/store.types' import { visibilityStates } from 'domains/visibility/constants' import { useVisibility } from 'domains/visibility/hooks' import { randomId } from 'lib/id' import { useCallback } from 'preact/hooks' import useSeamlyEventBusContext from './event-bus-hooks' import { useSeamlyApiContext, useSeamlyHasConversation, } from './seamly-api-hooks' import { useSeamlyUnreadCount } from './seamly-state-hooks' const useSeamlyCommands = () => { const api = useSeamlyApiContext() const dispatch = useAppDispatch() const eventBus = useSeamlyEventBusContext() const userHasResponded = useUserHasResponded() const hasConversation = useSeamlyHasConversation() const { visible: visibility, setVisibility } = useVisibility() const unreadMessageCount = useSeamlyUnreadCount() const emitEvent = useCallback( (...args) => { // @ts-ignore eventBus.emit(...args) }, [eventBus], ) const start = useCallback(() => { emitEvent('ui.beforeStart', { visibility, hasConversation: hasConversation(), hasResponded: userHasResponded, unreadMessageCount, }) api.send('start_conversation') emitEvent('ui.start', { visibility, hasConversation: hasConversation(), hasResponded: userHasResponded, unreadMessageCount, }) }, [ api, emitEvent, hasConversation, userHasResponded, unreadMessageCount, visibility, ]) const reset = useCallback(async () => { await dispatch(resetApp()) }, [dispatch]) const getMessageBase = useCallback( (type) => ({ type, id: randomId(), transactionId: randomId(), fromClient: true, participant: 'seamly-client-participant', occurredAt: Date.now() * 1000, }), [], ) const getTextMessageBase = useCallback( (bodyText: string) => { const base = getMessageBase('text') return { ...base, body: { text: bodyText, }, } }, [getMessageBase], ) const sendMessage = useCallback( ({ body, config = {} }) => { if (body.trim() === '') { return } const message = { ...getTextMessageBase(body), ...config, } api.send('message', message) emitEvent('message', message) dispatch( addEvent({ type: 'message', payload: { ...message, body: message.body, type: message.type, optimisticallyInjected: true, }, }), ) }, [api, dispatch, emitEvent, getTextMessageBase], ) const addMessageBubble = useCallback( (text, transactionId = randomId()) => { dispatch( addEvent({ type: 'message', payload: { ...getTextMessageBase(text), transactionId, }, }), ) }, [dispatch, getTextMessageBase], ) const addUploadBubble = useCallback( ( id: MessageUpload['payload']['id'], transactionId: MessageUpload['payload']['transactionId'], occurredAt: MessageUpload['payload']['occurredAt'], contentType: MessageUpload['payload']['body']['contentType'], filename: MessageUpload['payload']['body']['filename'], filesize: MessageUpload['payload']['body']['filesize'], ) => { dispatch( addEvent({ type: 'message', payload: { type: 'upload', id, transactionId, fromClient: true, participant: 'seamly-client-participant', occurredAt, body: { contentType, filename, filesize, id: id || '', isDeleted: false, }, }, }), ) }, [dispatch], ) const sendAction = useCallback( (body) => { if (!body) { return } api.send('action', body) }, [api], ) const sendContext = useCallback( (context) => { api.sendContext(context) }, [api], ) const connect = useCallback(() => { if (api.connected) { return Promise.reject(new Error('The API is already connected')) } return api .connect() .then((initialState) => { if (initialState) { dispatch(setInitialState(initialState)) if (initialState.messages && !!initialState.messages.length) { dispatch(setEvents(initialState)) } if (initialState.userResponded) { dispatch(setHasResponded(initialState.userResponded)) setVisibility({ visibility: visibilityStates.open }) } } }) .catch((error) => { dispatch( setInterrupt({ name: error?.name, message: error?.message, langKey: error?.langKey, action: error?.action, originalEvent: error?.originalEvent, originalError: error?.originalError, }), ) }) }, [api, dispatch, setVisibility]) return { connect, start, sendMessage, sendAction, sendContext, reset, emitEvent, addMessageBubble, addUploadBubble, apiConnected: api.connected, apiConfigReady: api.configReady, } } export default useSeamlyCommands