"use client"; import { AuthStorage } from "@/data/storage/auth/auth_storage"; import { UserStorage } from "@/data/storage/user/user_storage"; import type { PendingChatPromotionType } from "@/data/storage/navigation"; import type { LoginStatus } from "@/data/schemas/auth"; import type { CheckoutIntent } from "@/data/schemas/auth"; import { DEFAULT_CHARACTER_SLUG, getCharacterById, getCharacterBySlug, } from "@/data/constants/character"; import { getCharacterRoutes, ROUTES } from "@/router/routes"; export type ExternalEntryTarget = | typeof ROUTES.chat | typeof ROUTES.tip | typeof ROUTES.privateZone | typeof ROUTES.subscription; export interface ExternalEntryPayload { deviceId?: string | null; asid?: string | null; psid?: string | null; avatarUrl?: string | null; } export interface ExternalEntryTargetInput { target?: string | null; character?: string | null; } export interface ExternalEntryPromotionInput { mode?: string | null; promotionType?: string | null; } export interface ExternalFacebookIdentityBindingInput { hasInitialized: boolean; isLoading: boolean; loginStatus: LoginStatus; asid?: string | null; psid?: string | null; } export function shouldBindExternalFacebookIdentity({ hasInitialized, isLoading, loginStatus, asid, psid, }: ExternalFacebookIdentityBindingInput): boolean { const isRealUser = loginStatus === "email" || loginStatus === "google" || loginStatus === "facebook" || loginStatus === "facebookMessenger"; return ( hasInitialized && !isLoading && isRealUser && (hasValue(asid) || hasValue(psid)) ); } export function resolveExternalEntryPromotionType({ mode, promotionType, }: ExternalEntryPromotionInput): PendingChatPromotionType | null { if (mode?.trim().toLowerCase() !== "promotion") return null; const normalizedType = promotionType?.trim().toLowerCase(); if ( normalizedType === "voice" || normalizedType === "image" || normalizedType === "private" ) { return normalizedType; } return null; } export function resolveExternalEntryTarget({ target, }: ExternalEntryTargetInput): ExternalEntryTarget { return resolveTarget(target) ?? ROUTES.chat; } export function resolveExternalEntryDestination({ target, character, }: ExternalEntryTargetInput): string { const characterSlug = getCharacterBySlug(character)?.slug ?? DEFAULT_CHARACTER_SLUG; const routes = getCharacterRoutes(characterSlug); const resolvedTarget = resolveExternalEntryTarget({ target }); if (resolvedTarget === ROUTES.subscription) { return `${ROUTES.subscription}?type=topup`; } if (resolvedTarget === ROUTES.tip) return routes.tip; if (resolvedTarget === ROUTES.privateZone) return routes.privateZone; return routes.chat; } export function resolveCheckoutIntentDestination( intent: CheckoutIntent, ): string { const params = new URLSearchParams({ planId: intent.planId }); if (intent.recipientCharacterId) { const character = getCharacterById(intent.recipientCharacterId); const routes = getCharacterRoutes( character?.slug ?? DEFAULT_CHARACTER_SLUG, ); if (intent.chatActionId) params.set("chatActionId", intent.chatActionId); params.set("payChannel", "stripe"); return `${routes.tip}?${params.toString()}`; } params.set("autoRenew", intent.autoRenew ? "1" : "0"); if (intent.commercialOfferId) { params.set("commercialOfferId", intent.commercialOfferId); } if (intent.chatActionId) params.set("chatActionId", intent.chatActionId); params.set("payChannel", "stripe"); return `${ROUTES.subscription}?${params.toString()}`; } export async function persistExternalEntryPayload({ deviceId, asid, psid, avatarUrl, }: ExternalEntryPayload): Promise { const authStorage = AuthStorage.getInstance(); const userStorage = UserStorage.getInstance(); const tasks: Promise[] = []; if (hasValue(deviceId)) { tasks.push(authStorage.setDeviceId(deviceId)); } if (hasValue(asid)) { tasks.push(authStorage.setAsid(asid)); } if (hasValue(psid)) { tasks.push(authStorage.setPsid(psid)); } if (hasValue(avatarUrl)) { tasks.push(userStorage.setAvatarUrl(avatarUrl)); } await Promise.all(tasks); } function resolveTarget( value: string | null | undefined, ): ExternalEntryTarget | null { if (!value) return null; const target = value.trim().toLowerCase(); if (target === "chat") return ROUTES.chat; if (target === "tip") return ROUTES.tip; if (target === "private-zone" || target === "private-room") { return ROUTES.privateZone; } if (target === "topup") return ROUTES.subscription; if (target === "checkout") return ROUTES.subscription; return null; } function hasValue(value: string | null | undefined): value is string { return typeof value === "string" && value.trim().length > 0; }