"use client"; import { useEffect, useState } from "react"; import { shallowEqual } from "@xstate/react"; import type { LoginStatus } from "@/data/dto/auth"; import { useAppNavigator } from "@/router/use-app-navigator"; import { usePaymentDispatch, usePaymentSelector } from "@/stores/payment"; import { useUserSelector } from "@/stores/user/user-context"; import { getDefaultPayChannelForCountryCode } from "@/lib/payment/default_pay_channel"; import { getFirstRechargeOfferBannerDismissed, recordFirstRechargeOfferBannerDismissed, } from "@/lib/chat/first_recharge_offer_banner"; export interface FirstRechargeOfferBannerEligibility { historyLoaded: boolean; loginStatus: LoginStatus; isFirstRecharge: boolean; dismissed: boolean; } export interface UseFirstRechargeOfferBannerInput { historyLoaded: boolean; loginStatus: LoginStatus; } export interface UseFirstRechargeOfferBannerOutput { visible: boolean; discountPercent: number; close: () => void; claim: () => void; } interface DismissalState { userId: string | null; loaded: boolean; dismissed: boolean; } const FIRST_RECHARGE_DEFAULT_DISCOUNT_PERCENT = 50; export function shouldShowFirstRechargeOfferBanner( input: FirstRechargeOfferBannerEligibility, ): boolean { if (!input.historyLoaded) return false; if (input.loginStatus === "notLoggedIn" || input.loginStatus === "guest") { return false; } if (!input.isFirstRecharge) return false; return !input.dismissed; } export function useFirstRechargeOfferBanner({ historyLoaded, loginStatus, }: UseFirstRechargeOfferBannerInput): UseFirstRechargeOfferBannerOutput { const navigator = useAppNavigator(); const payment = usePaymentSelector( (state) => ({ isFirstRecharge: state.context.isFirstRecharge, status: String(state.value), }), shallowEqual, ); const paymentDispatch = usePaymentDispatch(); const user = useUserSelector( (state) => ({ countryCode: state.context.currentUser?.countryCode, id: state.context.currentUser?.id ?? null, }), shallowEqual, ); const isAuthenticatedUser = loginStatus !== "notLoggedIn" && loginStatus !== "guest"; const userId = user.id; const hasUserIdentity = !isAuthenticatedUser || Boolean(userId); const [dismissalState, setDismissalState] = useState(() => ({ userId, loaded: false, dismissed: false, })); const discountPercent = FIRST_RECHARGE_DEFAULT_DISCOUNT_PERCENT; useEffect(() => { if (!isAuthenticatedUser) return; if (payment.status !== "idle") return; const defaultPayChannel = getDefaultPayChannelForCountryCode( user.countryCode, ); paymentDispatch({ type: "PaymentInit", payChannel: defaultPayChannel }); }, [ payment.status, paymentDispatch, isAuthenticatedUser, user.countryCode, ]); useEffect(() => { let cancelled = false; const loadDismissal = async () => { const dismissed = await getFirstRechargeOfferBannerDismissed(userId); if (cancelled) return; setDismissalState({ userId, loaded: true, dismissed, }); }; void loadDismissal(); return () => { cancelled = true; }; }, [userId]); const dismissalLoaded = dismissalState.userId === userId && dismissalState.loaded; const visible = hasUserIdentity && dismissalLoaded && shouldShowFirstRechargeOfferBanner({ historyLoaded, loginStatus, isFirstRecharge: payment.isFirstRecharge, dismissed: dismissalState.dismissed, }); function close(): void { setDismissalState({ userId, loaded: true, dismissed: true, }); void recordFirstRechargeOfferBannerDismissed(userId); } function claim(): void { navigator.openSubscription({ type: "vip", returnTo: "chat" }); } return { visible, discountPercent, close, claim, }; }