179 lines
5.0 KiB
TypeScript
179 lines
5.0 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,
|
|
sourceCharacterSlug?: string | null,
|
|
): 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");
|
|
const characterSlug =
|
|
getCharacterBySlug(sourceCharacterSlug)?.slug ?? DEFAULT_CHARACTER_SLUG;
|
|
params.set("character", characterSlug);
|
|
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;
|
|
}
|