Files
cozsweet-frontend-nextjs/src/app/private-room/use-private-room-flow.ts
T

124 lines
3.6 KiB
TypeScript

"use client";
import { type Dispatch, useEffect, useRef } from "react";
import type { LoginStatus } from "@/data/schemas/auth";
import { useGuestLoginBootstrap } from "@/hooks/use-guest-login-bootstrap";
import { behaviorAnalytics } from "@/lib/analytics";
import { useActiveCharacterRoutes } from "@/providers/character-provider";
import { useAppNavigator } from "@/router/use-app-navigator";
import type { AuthEvent } from "@/stores/auth/auth-events";
import type { PrivateRoomEvent } from "@/stores/private-room";
import type { PrivateRoomUnlockPaywallRequest } from "@/stores/private-room/private-room-state";
import { useUserDispatch } from "@/stores/user/user-context";
export interface UsePrivateRoomBootstrapFlowInput {
authDispatch: Dispatch<AuthEvent>;
hasInitialized: boolean;
isAuthLoading: boolean;
loginStatus: LoginStatus;
roomDispatch: Dispatch<PrivateRoomEvent>;
roomStatus: string;
}
export interface UsePrivateRoomUnlockPaywallNavigationInput {
loginStatus: LoginStatus;
roomDispatch: Dispatch<PrivateRoomEvent>;
unlockPaywallRequest: PrivateRoomUnlockPaywallRequest | null;
}
export function isPrivateRoomAuthRequired(loginStatus: LoginStatus): boolean {
return loginStatus === "guest" || loginStatus === "notLoggedIn";
}
export function usePrivateRoomBootstrapFlow({
authDispatch,
hasInitialized,
isAuthLoading,
loginStatus,
roomDispatch,
roomStatus,
}: UsePrivateRoomBootstrapFlowInput): void {
const previousLoginStatusRef = useRef(loginStatus);
useGuestLoginBootstrap({
dispatch: authDispatch,
hasInitialized,
isLoading: isAuthLoading,
loginStatus,
});
useEffect(() => {
if (!hasInitialized || isAuthLoading) return;
if (loginStatus === "notLoggedIn") return;
const previousLoginStatus = previousLoginStatusRef.current;
previousLoginStatusRef.current = loginStatus;
if (roomStatus === "idle") {
roomDispatch({ type: "PrivateRoomInit" });
return;
}
if (previousLoginStatus !== loginStatus && roomStatus !== "loading") {
roomDispatch({ type: "PrivateRoomRefresh" });
}
}, [
hasInitialized,
isAuthLoading,
loginStatus,
roomDispatch,
roomStatus,
]);
}
export function usePrivateRoomUnlockPaywallNavigation({
loginStatus,
roomDispatch,
unlockPaywallRequest,
}: UsePrivateRoomUnlockPaywallNavigationInput): void {
const navigator = useAppNavigator();
const characterRoutes = useActiveCharacterRoutes();
useEffect(() => {
if (!unlockPaywallRequest) return;
if (isPrivateRoomAuthRequired(loginStatus)) {
navigator.openAuth(characterRoutes.privateRoom);
} else {
behaviorAnalytics.paywallShown({
entryPoint: "private_album_unlock",
triggerReason: "insufficient_credits",
});
navigator.openSubscription({
type: "topup",
returnTo: "private-room",
analytics: {
entryPoint: "private_album_unlock",
triggerReason: "insufficient_credits",
},
});
}
roomDispatch({ type: "PrivateRoomUnlockPaywallConsumed" });
}, [
characterRoutes.privateRoom,
loginStatus,
navigator,
roomDispatch,
unlockPaywallRequest,
]);
}
export function usePrivateRoomUnlockSuccessRefresh(
unlockSuccessNonce: number,
): void {
const userDispatch = useUserDispatch();
const lastUnlockSuccessNonceRef = useRef(0);
useEffect(() => {
if (unlockSuccessNonce <= lastUnlockSuccessNonceRef.current) return;
lastUnlockSuccessNonceRef.current = unlockSuccessNonce;
userDispatch({ type: "UserFetch" });
}, [unlockSuccessNonce, userDispatch]);
}