import { createChatPromotionState } from "../helper/promotion"; import { appendCommercialMessage } from "../helper/commercial-message"; import { shouldPromptUnlockHistory } from "../helper/unlock"; import { createInitialChatState } from "../chat-state"; import { guestInitializingState, historyPaginationTransitions, userInitializingState, } from "./history-flow"; import { guestReadyState, guestSendingState, userSendingViaHttpState, } from "./send-flow"; import { unlockingHistoryState, unlockingMessageState, unlockMachineSetup, } from "./unlock-flow"; const startGuestSessionAction = unlockMachineSetup.assign( ({ context }) => ({ ...createInitialChatState( context.characterId, context.emptyChatGreeting, ), promotion: context.promotion, }), ); const startUserSessionAction = unlockMachineSetup.assign( ({ context }) => ({ ...createInitialChatState( context.characterId, context.emptyChatGreeting, ), promotion: context.promotion, }), ); const clearChatSessionAction = unlockMachineSetup.assign(({ context }) => ({ ...createInitialChatState(context.characterId, context.emptyChatGreeting), })); const injectPromotionAction = unlockMachineSetup.assign(({ event }) => { if (event.type !== "ChatPromotionInjected") return {}; return { promotion: createChatPromotionState( event.promotion, event.messageId, ), }; }); const clearPromotionAction = unlockMachineSetup.assign({ promotion: null }); const appendCommercialMessageAction = unlockMachineSetup.assign( ({ context, event }) => { if (event.type !== "ChatCommercialMessageReceived") return {}; return { messages: appendCommercialMessage( context.messages, context.characterId, event.message, ), }; }, ); export const chatMachineSetup = unlockMachineSetup.extend({ actions: { startGuestSession: startGuestSessionAction, startUserSession: startUserSessionAction, clearChatSession: clearChatSessionAction, injectPromotion: injectPromotionAction, clearPromotion: clearPromotionAction, appendCommercialMessage: appendCommercialMessageAction, }, }); const idleState = chatMachineSetup.createStateConfig({ on: { ChatGuestLogin: { target: "#chat.guestSession", actions: "startGuestSession", }, ChatUserLogin: { target: "#chat.userSession", actions: "startUserSession", }, }, }); const guestSessionState = chatMachineSetup.createStateConfig({ invoke: [ { id: "messageQueue", src: "httpMessageQueue", input: ({ context }) => ({ characterId: context.characterId }), }, { id: "loadHistory", src: "loadHistory", input: ({ context }) => ({ characterId: context.characterId, emptyChatGreeting: context.emptyChatGreeting, }), }, { id: "loadMoreHistory", src: "loadMoreHistory", input: ({ context }) => ({ characterId: context.characterId, emptyChatGreeting: context.emptyChatGreeting, }), }, ], on: { ...historyPaginationTransitions, ChatUserLogin: { target: "#chat.userSession", actions: "startUserSession", }, ChatNetworkHistoryLoaded: { actions: "applyNetworkHistoryLoaded", }, ChatHistoryLoadFailed: { actions: "markHistoryLoadFailed", }, ChatQueuedSendStarted: { actions: "markQueuedSendStarted", }, ChatQueuedHttpDone: { actions: "applyQueuedHttpOutput", }, ChatQueuedSendError: { actions: "appendQueuedSendErrorMessage", }, }, initial: "initializing", states: { initializing: guestInitializingState, ready: guestReadyState, sending: guestSendingState, }, }); const userReadyState = chatMachineSetup.createStateConfig({ on: { ChatNetworkHistoryLoaded: [ { guard: ({ context, event }) => event.type === "ChatNetworkHistoryLoaded" && context.paymentUnlockPending && shouldPromptUnlockHistory(event.output.messages), actions: "showUnlockHistoryPromptFromNetwork", }, { guard: ({ context }) => context.paymentUnlockPending, actions: "applyNetworkHistoryLoadedAndClearPayment", }, { actions: "applyNetworkHistoryLoaded", }, ], ChatSendMessage: { guard: ({ context, event }) => context.canSendMessage && event.content.trim().length > 0, actions: ["appendUserMessage", "enqueueMessage"], }, ChatSendImage: { actions: "appendUserImage", }, ChatUnlockMessageRequested: { guard: ({ event }) => event.displayMessageId.trim().length > 0, target: "unlockingMessage", actions: "markUnlockMessageStarted", }, }, }); const userSessionState = chatMachineSetup.createStateConfig({ invoke: [ { id: "messageQueue", src: "httpMessageQueue", input: ({ context }) => ({ characterId: context.characterId }), }, { id: "loadHistory", src: "loadHistory", input: ({ context }) => ({ characterId: context.characterId, emptyChatGreeting: context.emptyChatGreeting, }), }, { id: "loadMoreHistory", src: "loadMoreHistory", input: ({ context }) => ({ characterId: context.characterId, emptyChatGreeting: context.emptyChatGreeting, }), }, ], on: { ChatHistoryRefreshRequested: { target: "#chat.userSession", reenter: true, actions: "startUserSession", }, ...historyPaginationTransitions, ChatGuestLogin: { target: "#chat.guestSession", actions: "startGuestSession", }, ChatLogout: { target: "#chat.idle", actions: "clearChatSession", }, ChatHistoryLoadFailed: { actions: "markHistoryLoadFailed", }, ChatQueuedSendStarted: { actions: "markQueuedSendStarted", }, ChatQueuedHttpDone: { actions: "applyQueuedHttpOutput", }, ChatQueuedSendError: { actions: "appendQueuedSendErrorMessage", }, ChatPaymentSucceeded: [ { guard: ({ context }) => context.historyLoaded && shouldPromptUnlockHistory(context.messages), actions: ["clearUpgradePrompt", "showUnlockHistoryPrompt"], }, { guard: ({ context }) => !context.historyLoaded, actions: ["clearUpgradePrompt", "markPaymentUnlockPending"], }, { guard: ({ context }) => context.historyLoaded, actions: ["clearUpgradePrompt", "dismissUnlockHistoryPrompt"], }, ], ChatUnlockHistoryConfirmed: { target: ".unlockingHistory", actions: "markUnlockHistoryStarted", }, ChatUnlockHistoryDismissed: { actions: "dismissUnlockHistoryPrompt", }, ChatUnlockPaywallNavigationConsumed: { actions: "clearUnlockPaywallRequest", }, }, initial: "initializing", states: { initializing: userInitializingState, ready: userReadyState, sendingViaHttp: userSendingViaHttpState, unlockingHistory: unlockingHistoryState, unlockingMessage: unlockingMessageState, }, }); export const chatRootStateConfig = chatMachineSetup.createStateConfig({ initial: "idle", on: { ChatPromotionInjected: { actions: "injectPromotion" }, ChatPromotionCleared: { actions: "clearPromotion" }, ChatCommercialMessageReceived: { actions: "appendCommercialMessage" }, }, states: { idle: idleState, guestSession: guestSessionState, userSession: userSessionState, }, });