import { applyOlderHistoryLoadedOutput, applyHistoryLoadedOutput, applyNetworkHistoryLoadedOutput, canLoadMoreHistory, } from "../helper/history"; import { countLockedHistoryMessages, shouldPromptUnlockHistory, } from "../helper/unlock"; import type { ChatState } from "../chat-state"; import { baseChatMachineSetup } from "./setup"; import { getCharacterErrorCode } from "@/data/services/api"; const applyLocalHistoryLoadedAction = baseChatMachineSetup.assign( ({ event }) => { if (event.type !== "ChatLocalHistoryLoaded") return {}; return applyHistoryLoadedOutput(event.output); }, ); const applyNetworkHistoryLoadedAction = baseChatMachineSetup.assign( ({ context, event }) => { if (event.type !== "ChatNetworkHistoryLoaded") return {}; return applyNetworkHistoryLoadedOutput(context, event.output); }, ); const applyNetworkHistoryLoadedAndClearPaymentAction = baseChatMachineSetup.assign(({ context, event }) => { if (event.type !== "ChatNetworkHistoryLoaded") return {}; return { ...applyNetworkHistoryLoadedOutput(context, event.output), paymentUnlockPending: false, }; }); const showUnlockHistoryPromptFromNetworkAction = baseChatMachineSetup.assign( ({ context, event }) => { if (event.type !== "ChatNetworkHistoryLoaded") return {}; const nextHistory = applyNetworkHistoryLoadedOutput(context, event.output); return { ...nextHistory, paymentUnlockPending: false, unlockHistoryPromptVisible: true, lockedHistoryCount: countLockedHistoryMessages(nextHistory.messages), unlockHistoryError: null, }; }, ); const markHistoryLoadFailedAction = baseChatMachineSetup.assign( ({ context, event }) => { if (event.type !== "ChatHistoryLoadFailed") return {}; const characterErrorCode = getCharacterErrorCode(event.error); return { historyLoaded: true, characterErrorCode, canSendMessage: characterErrorCode === "CHARACTER_DISABLED" || characterErrorCode === "CHARACTER_NOT_FOUND" ? false : context.canSendMessage, }; }, ); const markLoadMoreHistoryStartedAction = baseChatMachineSetup.assign({ isLoadingMoreHistory: true, }); const requestOlderHistoryPageAction = baseChatMachineSetup.sendTo( "loadMoreHistory", ({ context }) => ({ type: "LoadMoreHistoryPageRequested", offset: context.nextHistoryOffset, limit: context.historyLimit, }), ); const applyOlderHistoryLoadedAction = baseChatMachineSetup.assign( ({ context, event }) => { if (event.type !== "ChatOlderHistoryLoaded") return {}; return applyOlderHistoryLoadedOutput(context, event.output); }, ); const markOlderHistoryLoadFailedAction = baseChatMachineSetup.assign({ isLoadingMoreHistory: false, }); export const historyMachineSetup = baseChatMachineSetup.extend({ actions: { applyLocalHistoryLoaded: applyLocalHistoryLoadedAction, applyNetworkHistoryLoaded: applyNetworkHistoryLoadedAction, applyNetworkHistoryLoadedAndClearPayment: applyNetworkHistoryLoadedAndClearPaymentAction, showUnlockHistoryPromptFromNetwork: showUnlockHistoryPromptFromNetworkAction, markHistoryLoadFailed: markHistoryLoadFailedAction, markLoadMoreHistoryStarted: markLoadMoreHistoryStartedAction, requestOlderHistoryPage: requestOlderHistoryPageAction, applyOlderHistoryLoaded: applyOlderHistoryLoadedAction, markOlderHistoryLoadFailed: markOlderHistoryLoadFailedAction, }, }); export const historyPaginationTransitions = { ChatLoadMoreHistoryRequested: { guard: ({ context }: { context: ChatState }) => canLoadMoreHistory(context), actions: ["markLoadMoreHistoryStarted", "requestOlderHistoryPage"], }, ChatOlderHistoryLoaded: { actions: "applyOlderHistoryLoaded", }, ChatOlderHistoryLoadFailed: { actions: "markOlderHistoryLoadFailed", }, } as const; export const guestInitializingState = historyMachineSetup.createStateConfig({ on: { ChatLocalHistoryLoaded: { target: "ready", actions: "applyLocalHistoryLoaded", }, ChatNetworkHistoryLoaded: { target: "ready", actions: "applyNetworkHistoryLoaded", }, ChatHistoryLoadFailed: { target: "ready", actions: "markHistoryLoadFailed", }, }, }); export const userInitializingState = historyMachineSetup.createStateConfig({ on: { ChatLocalHistoryLoaded: { target: "ready", actions: "applyLocalHistoryLoaded", }, ChatNetworkHistoryLoaded: [ { guard: ({ context, event }) => event.type === "ChatNetworkHistoryLoaded" && context.paymentUnlockPending && shouldPromptUnlockHistory(event.output.messages), target: "ready", actions: "showUnlockHistoryPromptFromNetwork", }, { target: "ready", actions: "applyNetworkHistoryLoadedAndClearPayment", }, ], ChatHistoryLoadFailed: { target: "ready", actions: "markHistoryLoadFailed", }, }, });