83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
"use client";
|
|
|
|
import type { Dispatch, ReactNode } from "react";
|
|
import { createActorContext, shallowEqual } from "@xstate/react";
|
|
import type { SnapshotFrom } from "xstate";
|
|
|
|
import { privateZoomMachine } from "./private-zoom-machine";
|
|
import type {
|
|
PrivateZoomEvent,
|
|
PrivateZoomState as MachineContext,
|
|
} from "./private-zoom-machine";
|
|
|
|
/** Route UI reads this projection instead of the Private Zoom snapshot. */
|
|
export interface PrivateZoomContextState {
|
|
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 PrivateZoomSnapshot = SnapshotFrom<typeof privateZoomMachine>;
|
|
type PrivateZoomSelector<T> = (snapshot: PrivateZoomSnapshot) => T;
|
|
|
|
const PrivateZoomActorContext = createActorContext(privateZoomMachine);
|
|
|
|
export interface PrivateZoomProviderProps {
|
|
children: ReactNode;
|
|
characterId: string;
|
|
}
|
|
|
|
export function PrivateZoomProvider({
|
|
children,
|
|
characterId,
|
|
}: PrivateZoomProviderProps) {
|
|
return (
|
|
<PrivateZoomActorContext.Provider options={{ input: { characterId } }}>
|
|
{children}
|
|
</PrivateZoomActorContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function usePrivateZoomState(): PrivateZoomContextState {
|
|
return usePrivateZoomSelector(selectPrivateZoomState, shallowEqual);
|
|
}
|
|
|
|
export function usePrivateZoomDispatch(): Dispatch<PrivateZoomEvent> {
|
|
return PrivateZoomActorContext.useActorRef().send;
|
|
}
|
|
|
|
export function usePrivateZoomSelector<T>(
|
|
selector: PrivateZoomSelector<T>,
|
|
compare?: (previous: T, next: T) => boolean,
|
|
): T {
|
|
return PrivateZoomActorContext.useSelector(selector, compare);
|
|
}
|
|
|
|
function selectPrivateZoomState(
|
|
state: PrivateZoomSnapshot,
|
|
): PrivateZoomContextState {
|
|
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"),
|
|
};
|
|
}
|