"use client"; import type { Dispatch, ReactNode } from "react"; import { createActorContext, shallowEqual } from "@xstate/react"; import type { SnapshotFrom } from "xstate"; import { privateRoomMachine } from "./private-room-machine"; import type { PrivateRoomEvent, PrivateRoomState as MachineContext, } from "./private-room-machine"; /** Route UI reads this projection instead of the Private Room snapshot. */ export interface PrivateRoomContextState { characterId: string; status: string; items: MachineContext["items"]; creditBalance: number; errorMessage: string | null; unlockingAlbumId: string | null; unlockErrorMessage: string | null; pendingConfirmAlbumId: string | null; unlockPaywallRequest: MachineContext["unlockPaywallRequest"]; unlockSuccessNonce: number; isLoading: boolean; isUnlocking: boolean; } type PrivateRoomSnapshot = SnapshotFrom; type PrivateRoomSelector = (snapshot: PrivateRoomSnapshot) => T; const PrivateRoomActorContext = createActorContext(privateRoomMachine); export interface PrivateRoomProviderProps { children: ReactNode; characterId: string; } export function PrivateRoomProvider({ children, characterId, }: PrivateRoomProviderProps) { return ( {children} ); } export function usePrivateRoomState(): PrivateRoomContextState { return usePrivateRoomSelector(selectPrivateRoomState, shallowEqual); } export function usePrivateRoomDispatch(): Dispatch { return PrivateRoomActorContext.useActorRef().send; } export function usePrivateRoomSelector( selector: PrivateRoomSelector, compare?: (previous: T, next: T) => boolean, ): T { return PrivateRoomActorContext.useSelector(selector, compare); } function selectPrivateRoomState( state: PrivateRoomSnapshot, ): PrivateRoomContextState { return { characterId: state.context.characterId, status: String(state.value), items: state.context.items, creditBalance: state.context.creditBalance, errorMessage: state.context.errorMessage, unlockingAlbumId: state.context.unlockingAlbumId, unlockErrorMessage: state.context.unlockErrorMessage, pendingConfirmAlbumId: state.context.pendingConfirmAlbumId, unlockPaywallRequest: state.context.unlockPaywallRequest, unlockSuccessNonce: state.context.unlockSuccessNonce, isLoading: state.matches("loading"), isUnlocking: state.matches("unlocking"), }; }