"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { AuthGuard } from "@/components/AuthGuard"; import { Button, SectionTitle } from "@/components/ui"; import { api, ApiError, type Subscription } from "@/lib/api"; import { useMe } from "@/hooks/useMe"; import { loadCommercialInvoices, loadCommercialPricing, loadCommercialTransactions, loadCommercialUsage, } from "../adapters"; import { 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"; 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 () => { try { const subscription = await api.subscriptions.get(tenantId).catch(() => null); setSub(subscription); } catch (err) { setError(err instanceof ApiError ? err.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<{ id?: string; status?: string; plan_id?: string; trial_ends_at?: string | null; starts_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) { setMsg(`عملیات ${mode} از commercial API ثبت شد.`); if (commercial.data.status) { setSub({ id: commercial.data.id || "commercial", tenant_id: me.current_tenant_id, plan_id: commercial.data.plan_id || item.pricing_item_code, status: commercial.data.status as Subscription["status"], trial_ends_at: commercial.data.trial_ends_at ?? null, starts_at: commercial.data.starts_at ?? new Date().toISOString(), ends_at: null, created_at: new Date().toISOString(), }); } return; } const planId = typeof item.metadata?.plan_id === "string" ? item.metadata.plan_id : null; if (!planId) { setError( commercial.message || "فعال‌سازی نیازمند commercial subscriptions API یا plan_id در metadata است." ); return; } const ends = new Date(); ends.setDate(ends.getDate() + (item.trial_days || 14)); const created = await api.subscriptions.create(me.current_tenant_id, { plan_id: planId, status: mode === "trial" ? "trialing" : "active", trial_ends_at: mode === "trial" ? ends.toISOString() : null, starts_at: new Date().toISOString(), }); setSub(created); setMsg("اشتراک از طریق bridge ثبت شد."); } catch (err) { setError(err instanceof ApiError ? err.message : "عملیات ناموفق بود"); } finally { setBusy(false); } }; const applyCoupon = async () => { if (!me?.current_tenant_id || !coupon.trim()) return; setBusy(true); setError(""); const res = await commercialPost("/api/v1/commercial/coupons/apply", { tenant_id: me.current_tenant_id, coupon_code: coupon.trim(), }); if (!res.ok) setError(res.message); else setMsg("کوپن ارسال شد (در صورت پشتیبانی بک‌اند)."); setBusy(false); }; if (meLoading) { return (

در حال بارگذاری...

); } return (
{sub ? (
{sub.trial_ends_at ? (

trial_ends_at: {sub.trial_ends_at}

) : null}
) : null} {error ?

{error}

: null} {msg ?

{msg}

: null}
setCoupon(e.target.value)} />
{pricing?.availability === "ready" && pricing.data.length ? (
    {pricing.data.map((item) => (
  • {item.display_name}

    {item.pricing_item_code}

    مدل: {item.pricing_model || "—"} · ارز: {item.currency || "—"} · مبلغ:{" "} {item.amount_minor != null ? item.amount_minor : "از بک‌اند"} {item.tax_class_code ? ` · مالیات: ${item.tax_class_code}` : ""}

  • ))}
) : ( )}
{invoices?.availability === "ready" && invoices.data.length ? (
    {invoices.data.map((inv) => (
  • {inv.display_name || inv.invoice_code} · {inv.status || "—"} ·{" "} {inv.amount_minor != null ? inv.amount_minor : "—"} {inv.currency || ""} {inv.href ? ( رسید ) : null}
  • ))}
) : ( )}
{txns?.availability === "ready" && txns.data.length ? (
    {txns.data.map((t) => (
  • {t.display_name || t.transaction_code} · {t.status || "—"} ·{" "} {t.amount_minor != null ? t.amount_minor : "—"} {t.currency || ""}
  • ))}
) : ( )}
{usage?.availability === "ready" && usage.data.length ? (
    {usage.data.map((q) => (
  • {q.label || q.key}: {q.used ?? "—"} / {q.limit ?? "∞"} {q.unit || ""}
  • ))}
) : ( )}
); } export function CommercialBillingPage() { return ( ); }