Files
cozsweet-frontend-nextjs/src/lib/navigation/external_entry.ts
T

175 lines
4.8 KiB
TypeScript

"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<void> {
const authStorage = AuthStorage.getInstance();
const userStorage = UserStorage.getInstance();
const tasks: Promise<unknown>[] = [];
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;
}