"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { AuthGuard } from "@/components/AuthGuard"; import { Button, SectionTitle } from "@/components/ui"; import { useMe } from "@/hooks/useMe"; import { loadCommercialInvoices, loadCommercialPricing, loadCommercialTransactions, loadCommercialUsage, } from "../adapters"; import { commercialGet, commercialPost } from "../adapters/http"; import type { CommercialInvoice, CommercialTransaction, } from "../adapters/billing-ledger"; import type { AdapterResult, CommercialPricingItem, CommercialUsageCounter } from "../types"; import { CommercialEmptyState, PlanBadge, PlatformShell, SubscriptionBanner } from "../components"; import { CommercialSkeleton } from "../components/CommercialSkeleton"; import { commercialEntityName, enumLabel, formatDate, formatMoney, friendlyMessage, humanizeCommercialCode, } from "../presentation"; type CommercialSubscription = { id?: string; status?: string | null; plan_code?: string | null; bundle_code?: string | null; pricing_item_code?: string | null; trial_ends_at?: string | null; current_period_end?: string | null; }; function BillingInner() { const { me, loading: meLoading } = useMe(); const [pricing, setPricing] = useState | null>(null); const [usage, setUsage] = useState | null>(null); const [invoices, setInvoices] = useState | null>(null); const [txns, setTxns] = useState | null>(null); const [sub, setSub] = useState(null); const [coupon, setCoupon] = useState(""); const [error, setError] = useState(""); const [busy, setBusy] = useState(false); const [msg, setMsg] = useState(""); useEffect(() => { void loadCommercialPricing().then(setPricing); }, []); useEffect(() => { if (!me?.current_tenant_id) return; const tenantId = me.current_tenant_id; void (async () => { const dash = await commercialGet<{ subscription?: CommercialSubscription | null; }>(`/api/v1/commercial/dashboard?tenant_id=${encodeURIComponent(tenantId)}`); if (dash.ok) setSub(dash.data.subscription ?? null); else setError(friendlyMessage(dash.message, "اطلاعات اشتراک بارگذاری نشد. لطفاً دوباره تلاش کنید.")); void Promise.all([ loadCommercialUsage(tenantId).then(setUsage), loadCommercialInvoices(tenantId).then(setInvoices), loadCommercialTransactions(tenantId).then(setTxns), ]); })(); }, [me?.current_tenant_id]); const activatePricing = async ( item: CommercialPricingItem, mode: "trial" | "active" | "upgrade" | "downgrade" ) => { if (!me?.current_tenant_id) return; setBusy(true); setError(""); setMsg(""); try { const commercial = await commercialPost<{ subscription?: CommercialSubscription; id?: string; status?: string; plan_code?: string | null; trial_ends_at?: string | null; }>("/api/v1/commercial/subscriptions", { tenant_id: me.current_tenant_id, pricing_item_code: item.pricing_item_code, mode, status: mode === "trial" ? "trialing" : "active", coupon_code: coupon.trim() || undefined, }); if (!commercial.ok) { setError(friendlyMessage(commercial.message, "فعال‌سازی پلن انجام نشد. لطفاً دوباره تلاش کنید.")); return; } const next = commercial.data.subscription ?? { id: commercial.data.id, status: commercial.data.status, plan_code: commercial.data.plan_code ?? item.pricing_item_code, pricing_item_code: item.pricing_item_code, trial_ends_at: commercial.data.trial_ends_at ?? null, }; setSub(next); setMsg(mode === "trial" ? "دوره آزمایشی شما با موفقیت فعال شد." : "پلن شما با موفقیت به‌روزرسانی شد."); } catch (err) { setError(friendlyMessage(err instanceof Error ? err.message : null, "انجام این عملیات ممکن نشد. لطفاً دوباره تلاش کنید.")); } finally { setBusy(false); } }; const applyCoupon = async () => { if (!me?.current_tenant_id || !coupon.trim()) return; setBusy(true); setError(""); setMsg(""); setMsg(`کد تخفیف «${coupon.trim()}» ذخیره شد و هنگام انتخاب پلن اعمال می‌شود.`); setBusy(false); }; if (meLoading) { return ( ); } const planLabel = sub?.plan_code || sub?.pricing_item_code || sub?.bundle_code || undefined; return (

پلن فعلی

وضعیت اشتراک

{enumLabel(sub?.status)}

پایان دوره آزمایشی

{formatDate(sub?.trial_ends_at)}

پرداخت بعدی

{formatDate(sub?.current_period_end)}

{error ?

{error}

: null} {msg ?

{msg}

: null}
setCoupon(e.target.value)} />
{!pricing || pricing.availability === "loading" ? ( ) : pricing.availability !== "ready" || !pricing.data.length ? ( ) : (
    {pricing.data.map((item) => (
  • {commercialEntityName("pricing", item.pricing_item_code, item.display_name)}

    {enumLabel(item.pricing_model)} · {formatMoney(item.amount_minor, item.currency)}

    {item.trial_days ?

    {item.trial_days.toLocaleString("fa-IR")} روز آزمایش رایگان

    : null}
  • ))}
)}
{usage?.availability === "ready" && usage.data.length ? (
    {usage.data.map((u) => (
  • {humanizeCommercialCode(u.key, u.label)}{(u.used ?? 0).toLocaleString("fa-IR")} از {u.limit == null ? "نامحدود" : u.limit.toLocaleString("fa-IR")}
    {u.limit ?
    : null}
  • ))}
) : ( )}
{invoices?.availability === "ready" && invoices.data.length ? (
    {invoices.data.map((inv) => (
  • {commercialEntityName("invoices", inv.invoice_code, inv.display_name)}

    {formatDate(inv.issued_at)}

    {formatMoney(inv.amount_minor, inv.currency)}

    {enumLabel(inv.status)}

  • ))}
) : (

هنوز فاکتوری صادر نشده است.

)} {txns?.availability === "ready" && txns.data.length ? (
    {txns.data.map((t) => (
  • {commercialEntityName("transactions", t.transaction_code, t.display_name)}

    {formatDate(t.occurred_at)}

    {formatMoney(t.amount_minor, t.currency)}

    {enumLabel(t.status)}

  • ))}
) : (

هنوز پرداختی انجام نشده است.

)}
); } export function CommercialBillingPage() { return ( ); }