"use client"; import { useEffect } from "react"; import { Gift, ImageIcon, MessageCircle, Mic2, Sparkles, } from "lucide-react"; import { FaCoins } from "react-icons/fa6"; import { BackButton } from "@/app/_components"; import { MobileShell } from "@/app/_components/core"; import { resolveGlobalRouteContext, type GlobalReturnToValue, } from "@/router/global-route-context"; import { useAuthState } from "@/stores/auth/auth-context"; import { useUserDispatch, useUserState } from "@/stores/user/user-context"; import styles from "./coins-rules-screen.module.css"; interface CoinRuleItem { title: string; cost: string; free?: string; icon: typeof MessageCircle; } const formatDailyFreeMessages = (count: number, label: string): string => `${Math.max(0, Math.trunc(count))} free ${label} daily`; const formatCoinCost = (cost: number | null, unit: string): string => cost === null ? "Current rate shown at unlock" : `${Math.max(0, Math.trunc(cost))} coins / ${unit}`; const createCoinRules = ( dailyFreeChatLimit: number | null, dailyFreePrivateLimit: number | null, costs: { normalMessage: number | null; privateMessage: number | null; voiceMessage: number | null; photo: number | null; privateAlbum10: number | null; privateAlbum20: number | null; }, ): readonly CoinRuleItem[] => [ { title: "Standard Chat", cost: formatCoinCost(costs.normalMessage, "message"), free: dailyFreeChatLimit === null ? "Current daily allowance loads from your account" : formatDailyFreeMessages(dailyFreeChatLimit, "messages"), icon: MessageCircle, }, { title: "Private Chat", cost: formatCoinCost(costs.privateMessage, "message"), free: dailyFreePrivateLimit === null ? "Current daily allowance loads from your account" : formatDailyFreeMessages(dailyFreePrivateLimit, "private messages"), icon: Sparkles, }, { title: "Voice Message", cost: formatCoinCost(costs.voiceMessage, "message"), icon: Mic2, }, // { // title: "Voice Call", // cost: "50 coins / call", // icon: Phone, // }, { title: "Photo", cost: formatCoinCost(costs.photo, "photo"), icon: ImageIcon, }, { title: "Private Album", cost: costs.privateAlbum10 === null ? "Current price shown in Private Zone" : `10 photos / ${Math.max(0, Math.trunc(costs.privateAlbum10))} coins`, icon: ImageIcon, }, { title: "Private Album", cost: costs.privateAlbum20 === null ? "Current price shown in Private Zone" : `20 photos / ${Math.max(0, Math.trunc(costs.privateAlbum20))} coins`, icon: ImageIcon, }, ] as const; export interface CoinsRulesScreenProps { returnTo?: GlobalReturnToValue; } export function CoinsRulesScreen({ returnTo }: CoinsRulesScreenProps) { const navigation = resolveGlobalRouteContext(returnTo); const authState = useAuthState(); const userState = useUserState(); const userDispatch = useUserDispatch(); const entitlements = userState.entitlements; const dailyFreeChatLimit = entitlements?.quotas.normalChatFreeDaily ?? userState.currentUser?.dailyFreeChatLimit ?? null; const dailyFreePrivateLimit = entitlements?.quotas.privateUnlockFreeDaily ?? userState.currentUser?.dailyFreePrivateLimit ?? null; const standardChatLabel = dailyFreeChatLimit === null ? "the current daily allowance shown for your account" : formatDailyFreeMessages(dailyFreeChatLimit, "messages"); const privateChatLabel = dailyFreePrivateLimit === null ? "the current private allowance shown for your account" : formatDailyFreeMessages(dailyFreePrivateLimit, "private messages"); const coinRules = createCoinRules( dailyFreeChatLimit, dailyFreePrivateLimit, { normalMessage: entitlements?.costs.normal_message ?? null, privateMessage: entitlements?.costs.private_message ?? null, voiceMessage: entitlements?.costs.voice_message ?? null, photo: entitlements?.costs.photo ?? null, privateAlbum10: entitlements?.costs.private_album_10 ?? null, privateAlbum20: entitlements?.costs.private_album_20 ?? null, }, ); useEffect(() => { if (!authState.hasInitialized || authState.isLoading) return; if (authState.loginStatus === "notLoggedIn") return; userDispatch({ type: "UserFetch" }); }, [ authState.hasInitialized, authState.isLoading, authState.loginStatus, userDispatch, ]); return (

Coins Guide

Coin Usage Rules

See how many coins each interaction costs before you top up.

Free Allowance

Standard chat includes {standardChatLabel}. Private chat includes{" "} {privateChatLabel}.

{coinRules.map((rule, index) => { const Icon = rule.icon; return (

{rule.title}

{rule.free ? (

{rule.free}

) : null}

{rule.cost}

); })}
); }