@withpotter/components 0.13.0-next.85 → 0.13.0-next.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,6 +13,7 @@ import {
13
13
  Plus
14
14
  } from "lucide-react";
15
15
  import { formatDate, formatBytes } from "@withpotter/lib/utils";
16
+ import { pickPlanPrice } from "@withpotter/lib/plan-price";
16
17
  const STORAGE_BASELINE_BYTES = 500 * 1024 * 1024;
17
18
  function getStatusBadge(status) {
18
19
  switch (status) {
@@ -69,13 +70,13 @@ function OverviewTab({
69
70
  subscription ? getStatusBadge(subscription.status) : /* @__PURE__ */ jsx(Badge, { variant: "info", children: "Free" })
70
71
  ] }),
71
72
  /* @__PURE__ */ jsx("div", { className: "p-5", children: subscription ? (() => {
72
- const planPriceUsd = subscription.plan.prices?.["USD"] ?? 0;
73
- const isFreePlan = subscription.plan.slug === "free" || planPriceUsd === 0;
73
+ const planPrice = pickPlanPrice(subscription.plan.prices);
74
+ const isFreePlan = subscription.plan.slug === "free" || !planPrice || planPrice.amount === 0;
74
75
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
75
76
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
76
77
  /* @__PURE__ */ jsxs("div", { children: [
77
78
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-[var(--text-primary)]", children: (subscription.plan.name.split("\u2014")[0] || subscription.plan.name).trim() }),
78
- /* @__PURE__ */ jsx("p", { className: "text-[var(--text-tertiary)]", children: isFreePlan ? "Free plan" : `${formatCurrency(planPriceUsd, "USD")}/${subscription.plan.interval}` })
79
+ /* @__PURE__ */ jsx("p", { className: "text-[var(--text-tertiary)]", children: isFreePlan ? "Free plan" : `${formatCurrency(planPrice?.amount ?? 0, planPrice?.currency ?? "NGN")}/${subscription.plan.interval}` })
79
80
  ] }),
80
81
  /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
81
82
  !isFreePlan && subscription.currentPeriod.end && /* @__PURE__ */ jsxs("p", { className: "text-sm text-[var(--text-tertiary)]", children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/billing/overview-tab.tsx"],"sourcesContent":["import { Badge } from '@withpotter/ui-kit/badge';\nimport { Button } from '@withpotter/ui-kit/button';\nimport {\n Wallet,\n AlertTriangle,\n Check,\n X,\n HardDrive,\n Wifi,\n MessageSquare,\n Mail,\n Plus,\n} from 'lucide-react';\nimport { formatDate, formatBytes } from '@withpotter/lib/utils';\nimport type {\n Subscription,\n BillingTab,\n CurrentUsage,\n MessagingCreditsInfo,\n EmailCreditsInfo,\n} from './helpers';\n\nexport const STORAGE_BASELINE_BYTES = 500 * 1024 * 1024; // 500 MB\n\n// Status badge helper (used only in overview)\nfunction getStatusBadge(status: string) {\n switch (status) {\n case 'active':\n case 'trialing':\n return <Badge variant=\"success\">Active</Badge>;\n case 'past_due':\n return <Badge variant=\"error\">Past due</Badge>;\n case 'cancelled':\n return <Badge variant=\"secondary\">Cancelled</Badge>;\n case 'non_renewing':\n return <Badge variant=\"warning\">Cancelling</Badge>;\n default:\n return <Badge variant=\"secondary\">{status}</Badge>;\n }\n}\n\ninterface OverviewTabProps {\n subscription: Subscription | null | undefined;\n currentUsage: CurrentUsage | null | undefined;\n addOnBytes: number;\n creditsInfo: MessagingCreditsInfo | null | undefined;\n emailCreditsInfo: EmailCreditsInfo | null | undefined;\n formatCurrency: (amount: number, currency: string) => string;\n onCancelClick: () => void;\n onUpgradeNow: () => void;\n onNavigateTab: (tab: BillingTab, subView?: string) => void;\n onBuyStorage: () => void;\n buyStoragePending: boolean;\n onTopUpCredits: () => void;\n topUpCreditsPending: boolean;\n onTopUpEmailCredits: () => void;\n topUpEmailCreditsPending: boolean;\n}\n\nexport function OverviewTab({\n subscription,\n currentUsage,\n addOnBytes,\n creditsInfo,\n emailCreditsInfo,\n formatCurrency,\n onCancelClick,\n onUpgradeNow,\n onNavigateTab,\n onBuyStorage,\n buyStoragePending,\n onTopUpCredits,\n topUpCreditsPending,\n onTopUpEmailCredits,\n topUpEmailCreditsPending,\n}: OverviewTabProps) {\n const storageUsedBytes = currentUsage?.storage.usedBytes ?? 0;\n const storageFileCount = currentUsage?.storage.fileCount ?? 0;\n const bandwidthUsedBytes = currentUsage?.bandwidth?.usedBytes ?? 0;\n const storageLimitBytes = STORAGE_BASELINE_BYTES + addOnBytes;\n const storagePct = Math.min(\n 100,\n Math.round((storageUsedBytes / storageLimitBytes) * 100),\n );\n const isOverBaseline = storageUsedBytes >= storageLimitBytes;\n const isApproaching = storagePct >= 80 && !isOverBaseline;\n\n return (\n <div className=\"space-y-6\">\n {/* Current Plan Card */}\n <div className=\"bg-[var(--bg-base)] rounded-md border border-[var(--border-default)] overflow-x-auto\">\n <div className=\"px-5 py-4 border-b border-[var(--border-subtle)] flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 rounded-md bg-[var(--accent-secondary)] text-brand-500\">\n <Wallet className=\"w-5 h-5\" />\n </div>\n <div>\n <h2 className=\"text-base font-medium text-[var(--text-primary)]\">\n Current plan\n </h2>\n <p className=\"text-sm text-[var(--text-tertiary)]\">\n Your subscription details\n </p>\n </div>\n </div>\n {subscription ? getStatusBadge(subscription.status) : <Badge variant=\"info\">Free</Badge>}\n </div>\n\n <div className=\"p-5\">\n {subscription ? (() => {\n const planPriceUsd = subscription.plan.prices?.['USD'] ?? 0;\n const isFreePlan =\n subscription.plan.slug === 'free' || planPriceUsd === 0;\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)]\">\n {(subscription.plan.name.split('—')[0] || subscription.plan.name).trim()}\n </h3>\n <p className=\"text-[var(--text-tertiary)]\">\n {isFreePlan\n ? 'Free plan'\n : `${formatCurrency(planPriceUsd, 'USD')}/${subscription.plan.interval}`}\n </p>\n </div>\n <div className=\"text-right\">\n {!isFreePlan && subscription.currentPeriod.end && (\n <p className=\"text-sm text-[var(--text-tertiary)]\">\n Renews on {formatDate(subscription.currentPeriod.end)}\n </p>\n )}\n {!isFreePlan && subscription.cancellation.cancelAtPeriodEnd && (\n <div className=\"flex items-center gap-1 text-[var(--error)]\">\n <AlertTriangle className=\"h-4 w-4\" />\n <span className=\"text-sm\">\n Cancels on{' '}\n {formatDate(subscription.cancellation.endsAt!)}\n </span>\n </div>\n )}\n </div>\n </div>\n\n <div className=\"h-px bg-[var(--bg-muted)]\" />\n\n {/* Plan-level transaction fees no longer apply — category fees\n are owned by PricingPolicy and surfaced in the Rates tab. */}\n <div className=\"text-sm\">\n <p className=\"text-[var(--text-tertiary)]\">Custom domain</p>\n <p className=\"text-xs text-[var(--text-muted)] mb-1\">\n Link your own domain\n </p>\n <p className=\"font-medium\">\n {subscription.plan.features.customDomain ? (\n <Check className=\"h-4 w-4 text-[var(--success)]\" />\n ) : (\n <X className=\"h-4 w-4 text-[var(--text-muted)]\" />\n )}\n </p>\n </div>\n\n {!isFreePlan && subscription.status !== 'cancelled' && (\n <div className=\"pt-4 flex items-center justify-between border-t border-[var(--border-subtle)]\">\n <Button\n variant=\"secondary\"\n onClick={onCancelClick}\n disabled={subscription.cancellation.cancelAtPeriodEnd}\n >\n {subscription.cancellation.cancelAtPeriodEnd\n ? 'Cancellation Pending'\n : 'Cancel Subscription'}\n </Button>\n </div>\n )}\n\n {isFreePlan && (\n <div className=\"pt-4 flex items-center justify-between border-t border-[var(--border-subtle)]\">\n <Button variant=\"primary\" onClick={onUpgradeNow}>\n Upgrade to Plus\n </Button>\n </div>\n )}\n </div>\n );\n })() : (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)]\">\n Free plan\n </h3>\n <p className=\"text-[var(--text-tertiary)]\">\n $0/month\n </p>\n </div>\n </div>\n\n <div className=\"h-px bg-[var(--bg-muted)]\" />\n\n <div className=\"text-sm text-[var(--text-tertiary)]\">\n Activate a plan to unlock custom domains, lower transaction\n fees, and the full set of growth tools.\n </div>\n\n <div className=\"pt-4 flex items-center justify-between border-t border-[var(--border-subtle)]\">\n <Button\n variant=\"primary\"\n onClick={() => onNavigateTab('plan')}\n >\n Upgrade plan\n </Button>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Usage This Period — always shown so storage is visible from day one */}\n <div className=\"bg-[var(--bg-base)] rounded-md border border-[var(--border-default)]\">\n <div className=\"px-5 py-4 border-b border-[var(--border-subtle)] flex items-center justify-between\">\n <h2 className=\"text-base font-medium text-[var(--text-primary)]\">\n Usage this period\n </h2>\n {currentUsage && (\n <span className=\"text-xs text-[var(--text-tertiary)]\">\n {formatDate(currentUsage.period.start)} –{' '}\n {formatDate(currentUsage.period.end)}\n </span>\n )}\n </div>\n <div className=\"divide-y divide-[var(--border-subtle)]\">\n {/* Storage — always visible */}\n <div className=\"px-5 py-4 text-sm\">\n <div className=\"flex items-center justify-between mb-1.5\">\n <div className=\"flex items-center gap-2 text-[var(--text-secondary)]\">\n <HardDrive className=\"w-3.5 h-3.5\" />\n <span>Image storage</span>\n {addOnBytes > 0 && (\n <span className=\"text-xs text-brand-500 bg-brand-500/10 px-1.5 py-0.5 rounded\">\n +{formatBytes(addOnBytes)} purchased\n </span>\n )}\n </div>\n <span className=\"text-xs text-[var(--text-tertiary)]\">\n {formatBytes(storageUsedBytes)} of{' '}\n {formatBytes(storageLimitBytes)} used\n </span>\n </div>\n {storageFileCount > 0 && (\n <p className=\"text-xs text-[var(--text-muted)] mb-1.5\">\n {storageFileCount} {storageFileCount === 1 ? 'file' : 'files'}{' '}\n uploaded this period\n </p>\n )}\n <div className=\"w-full h-1.5 bg-[var(--bg-muted)] rounded-full overflow-hidden\">\n <div\n className={`h-full rounded-full transition-[width] duration-500 ${\n isOverBaseline\n ? 'bg-[var(--error)]'\n : isApproaching\n ? 'bg-[var(--warning)]'\n : 'bg-brand-500'\n }`}\n style={{\n width:\n storagePct === 0 ? '0%' : `${Math.max(storagePct, 1)}%`,\n }}\n />\n </div>\n {isApproaching && (\n <p className=\"text-xs text-[var(--warning)] mt-1\">\n Approaching your storage limit. Consider adding more storage.\n </p>\n )}\n {isOverBaseline && (\n <p className=\"text-xs text-[var(--error)] mt-1\">\n You&apos;ve used {formatBytes(storageUsedBytes)} (\n {formatBytes(storageLimitBytes)} limit). Overage of{' '}\n {formatBytes(storageUsedBytes - storageLimitBytes)} will be\n charged at end of month.\n </p>\n )}\n <button\n type=\"button\"\n onClick={onBuyStorage}\n disabled={buyStoragePending}\n className=\"mt-2 flex items-center gap-1 text-xs text-brand-500 hover:text-brand-600 hover:underline disabled:opacity-50 cursor-pointer\"\n >\n <Plus className=\"w-3 h-3\" />\n Buy more storage\n </button>\n </div>\n\n {/* Bandwidth */}\n <div className=\"px-5 py-4 text-sm border-t border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2 text-[var(--text-secondary)]\">\n <Wifi className=\"w-3.5 h-3.5\" />\n <span>Bandwidth</span>\n </div>\n <span className=\"text-xs text-[var(--text-tertiary)]\">\n {bandwidthUsedBytes > 0\n ? `${formatBytes(bandwidthUsedBytes)} used this period`\n : '—'}\n </span>\n </div>\n <p className=\"text-xs text-[var(--text-muted)] mt-1\">\n Served via CDN. Detailed tracking coming soon.\n </p>\n </div>\n\n {/* Messaging Credits */}\n <div className=\"px-5 py-4 text-sm border-t border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between mb-1.5\">\n <div className=\"flex items-center gap-2 text-[var(--text-secondary)]\">\n <MessageSquare className=\"w-3.5 h-3.5\" />\n <span>Messaging credits</span>\n </div>\n <span className=\"font-medium text-[var(--text-primary)]\">\n {creditsInfo != null\n ? `${creditsInfo.balance.toLocaleString()} remaining`\n : '—'}\n </span>\n </div>\n\n {creditsInfo && (\n <>\n {/* Usage bar */}\n {creditsInfo.monthlyAllowance > 0 && (\n <>\n <div className=\"flex items-center justify-between text-xs text-[var(--text-muted)] mb-1\">\n <span>\n {creditsInfo.usedThisPeriod.toLocaleString()} of{' '}\n {creditsInfo.monthlyAllowance.toLocaleString()} included\n used\n </span>\n </div>\n <div className=\"w-full h-1.5 bg-[var(--bg-muted)] rounded-full overflow-hidden\">\n <div\n className={`h-full rounded-full transition-[width] duration-500 ${\n creditsInfo.overage > 0\n ? 'bg-[var(--error)]'\n : creditsInfo.usedThisPeriod /\n creditsInfo.monthlyAllowance >=\n 0.8\n ? 'bg-[var(--warning)]'\n : 'bg-brand-500'\n }`}\n style={{\n width: `${Math.min(100, Math.round((creditsInfo.usedThisPeriod / creditsInfo.monthlyAllowance) * 100))}%`,\n }}\n />\n </div>\n </>\n )}\n\n {/* Low balance warning */}\n {creditsInfo.isLowBalance && creditsInfo.overage === 0 && (\n <p className=\"text-xs text-[var(--warning)] mt-1\">\n Low balance — top up to avoid message failures.\n </p>\n )}\n\n {/* Overage */}\n {creditsInfo.overage > 0 && (\n <p className=\"text-xs text-[var(--error)] mt-1\">\n {creditsInfo.overage.toLocaleString()} credits over your\n included allowance. Est. a-la-carte charge:{' '}\n {formatCurrency(creditsInfo.overageCostNgn, 'NGN')}.\n </p>\n )}\n </>\n )}\n\n <button\n type=\"button\"\n onClick={onTopUpCredits}\n disabled={topUpCreditsPending}\n className=\"mt-2 flex items-center gap-1 text-xs text-brand-500 hover:text-brand-600 hover:underline disabled:opacity-50 cursor-pointer\"\n >\n <Plus className=\"w-3 h-3\" />\n Top up credits\n </button>\n </div>\n\n {/* Email Credits */}\n <div className=\"px-5 py-4 text-sm border-t border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between mb-1.5\">\n <div className=\"flex items-center gap-2 text-[var(--text-secondary)]\">\n <Mail className=\"w-3.5 h-3.5\" />\n <span>Email credits</span>\n </div>\n <span className=\"font-medium text-[var(--text-primary)]\">\n {emailCreditsInfo != null\n ? `${emailCreditsInfo.balance.toLocaleString()} remaining`\n : '—'}\n </span>\n </div>\n\n {emailCreditsInfo && (\n <>\n {emailCreditsInfo.monthlyAllowance > 0 && (\n <>\n <div className=\"flex items-center justify-between text-xs text-[var(--text-muted)] mb-1\">\n <span>\n {emailCreditsInfo.usedThisPeriod.toLocaleString()} of{' '}\n {emailCreditsInfo.monthlyAllowance.toLocaleString()}{' '}\n included used\n </span>\n </div>\n <div className=\"w-full h-1.5 bg-[var(--bg-muted)] rounded-full overflow-hidden\">\n <div\n className={`h-full rounded-full transition-[width] duration-500 ${\n emailCreditsInfo.usedThisPeriod /\n emailCreditsInfo.monthlyAllowance >=\n 0.8\n ? 'bg-[var(--warning)]'\n : 'bg-brand-500'\n }`}\n style={{\n width: `${Math.min(100, Math.round((emailCreditsInfo.usedThisPeriod / emailCreditsInfo.monthlyAllowance) * 100))}%`,\n }}\n />\n </div>\n </>\n )}\n\n {emailCreditsInfo.isLowBalance && (\n <p className=\"text-xs text-[var(--warning)] mt-1\">\n Low balance — top up to keep emails sending.\n </p>\n )}\n </>\n )}\n\n <button\n type=\"button\"\n onClick={onTopUpEmailCredits}\n disabled={topUpEmailCreditsPending}\n className=\"mt-2 flex items-center gap-1 text-xs text-brand-500 hover:text-brand-600 hover:underline disabled:opacity-50 cursor-pointer\"\n >\n <Plus className=\"w-3 h-3\" />\n Top up email credits\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/billing/overview-tab.tsx"],"sourcesContent":["import { Badge } from '@withpotter/ui-kit/badge';\nimport { Button } from '@withpotter/ui-kit/button';\nimport {\n Wallet,\n AlertTriangle,\n Check,\n X,\n HardDrive,\n Wifi,\n MessageSquare,\n Mail,\n Plus,\n} from 'lucide-react';\nimport { formatDate, formatBytes } from '@withpotter/lib/utils';\nimport { pickPlanPrice } from '@withpotter/lib/plan-price';\nimport type {\n Subscription,\n BillingTab,\n CurrentUsage,\n MessagingCreditsInfo,\n EmailCreditsInfo,\n} from './helpers';\n\nexport const STORAGE_BASELINE_BYTES = 500 * 1024 * 1024; // 500 MB\n\n// Status badge helper (used only in overview)\nfunction getStatusBadge(status: string) {\n switch (status) {\n case 'active':\n case 'trialing':\n return <Badge variant=\"success\">Active</Badge>;\n case 'past_due':\n return <Badge variant=\"error\">Past due</Badge>;\n case 'cancelled':\n return <Badge variant=\"secondary\">Cancelled</Badge>;\n case 'non_renewing':\n return <Badge variant=\"warning\">Cancelling</Badge>;\n default:\n return <Badge variant=\"secondary\">{status}</Badge>;\n }\n}\n\ninterface OverviewTabProps {\n subscription: Subscription | null | undefined;\n currentUsage: CurrentUsage | null | undefined;\n addOnBytes: number;\n creditsInfo: MessagingCreditsInfo | null | undefined;\n emailCreditsInfo: EmailCreditsInfo | null | undefined;\n formatCurrency: (amount: number, currency: string) => string;\n onCancelClick: () => void;\n onUpgradeNow: () => void;\n onNavigateTab: (tab: BillingTab, subView?: string) => void;\n onBuyStorage: () => void;\n buyStoragePending: boolean;\n onTopUpCredits: () => void;\n topUpCreditsPending: boolean;\n onTopUpEmailCredits: () => void;\n topUpEmailCreditsPending: boolean;\n}\n\nexport function OverviewTab({\n subscription,\n currentUsage,\n addOnBytes,\n creditsInfo,\n emailCreditsInfo,\n formatCurrency,\n onCancelClick,\n onUpgradeNow,\n onNavigateTab,\n onBuyStorage,\n buyStoragePending,\n onTopUpCredits,\n topUpCreditsPending,\n onTopUpEmailCredits,\n topUpEmailCreditsPending,\n}: OverviewTabProps) {\n const storageUsedBytes = currentUsage?.storage.usedBytes ?? 0;\n const storageFileCount = currentUsage?.storage.fileCount ?? 0;\n const bandwidthUsedBytes = currentUsage?.bandwidth?.usedBytes ?? 0;\n const storageLimitBytes = STORAGE_BASELINE_BYTES + addOnBytes;\n const storagePct = Math.min(\n 100,\n Math.round((storageUsedBytes / storageLimitBytes) * 100),\n );\n const isOverBaseline = storageUsedBytes >= storageLimitBytes;\n const isApproaching = storagePct >= 80 && !isOverBaseline;\n\n return (\n <div className=\"space-y-6\">\n {/* Current Plan Card */}\n <div className=\"bg-[var(--bg-base)] rounded-md border border-[var(--border-default)] overflow-x-auto\">\n <div className=\"px-5 py-4 border-b border-[var(--border-subtle)] flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 rounded-md bg-[var(--accent-secondary)] text-brand-500\">\n <Wallet className=\"w-5 h-5\" />\n </div>\n <div>\n <h2 className=\"text-base font-medium text-[var(--text-primary)]\">\n Current plan\n </h2>\n <p className=\"text-sm text-[var(--text-tertiary)]\">\n Your subscription details\n </p>\n </div>\n </div>\n {subscription ? getStatusBadge(subscription.status) : <Badge variant=\"info\">Free</Badge>}\n </div>\n\n <div className=\"p-5\">\n {subscription ? (() => {\n const planPrice = pickPlanPrice(subscription.plan.prices);\n const isFreePlan =\n subscription.plan.slug === 'free' || !planPrice || planPrice.amount === 0;\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)]\">\n {(subscription.plan.name.split('—')[0] || subscription.plan.name).trim()}\n </h3>\n <p className=\"text-[var(--text-tertiary)]\">\n {isFreePlan\n ? 'Free plan'\n : `${formatCurrency(planPrice?.amount ?? 0, planPrice?.currency ?? 'NGN')}/${subscription.plan.interval}`}\n </p>\n </div>\n <div className=\"text-right\">\n {!isFreePlan && subscription.currentPeriod.end && (\n <p className=\"text-sm text-[var(--text-tertiary)]\">\n Renews on {formatDate(subscription.currentPeriod.end)}\n </p>\n )}\n {!isFreePlan && subscription.cancellation.cancelAtPeriodEnd && (\n <div className=\"flex items-center gap-1 text-[var(--error)]\">\n <AlertTriangle className=\"h-4 w-4\" />\n <span className=\"text-sm\">\n Cancels on{' '}\n {formatDate(subscription.cancellation.endsAt!)}\n </span>\n </div>\n )}\n </div>\n </div>\n\n <div className=\"h-px bg-[var(--bg-muted)]\" />\n\n {/* Plan-level transaction fees no longer apply — category fees\n are owned by PricingPolicy and surfaced in the Rates tab. */}\n <div className=\"text-sm\">\n <p className=\"text-[var(--text-tertiary)]\">Custom domain</p>\n <p className=\"text-xs text-[var(--text-muted)] mb-1\">\n Link your own domain\n </p>\n <p className=\"font-medium\">\n {subscription.plan.features.customDomain ? (\n <Check className=\"h-4 w-4 text-[var(--success)]\" />\n ) : (\n <X className=\"h-4 w-4 text-[var(--text-muted)]\" />\n )}\n </p>\n </div>\n\n {!isFreePlan && subscription.status !== 'cancelled' && (\n <div className=\"pt-4 flex items-center justify-between border-t border-[var(--border-subtle)]\">\n <Button\n variant=\"secondary\"\n onClick={onCancelClick}\n disabled={subscription.cancellation.cancelAtPeriodEnd}\n >\n {subscription.cancellation.cancelAtPeriodEnd\n ? 'Cancellation Pending'\n : 'Cancel Subscription'}\n </Button>\n </div>\n )}\n\n {isFreePlan && (\n <div className=\"pt-4 flex items-center justify-between border-t border-[var(--border-subtle)]\">\n <Button variant=\"primary\" onClick={onUpgradeNow}>\n Upgrade to Plus\n </Button>\n </div>\n )}\n </div>\n );\n })() : (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)]\">\n Free plan\n </h3>\n <p className=\"text-[var(--text-tertiary)]\">\n $0/month\n </p>\n </div>\n </div>\n\n <div className=\"h-px bg-[var(--bg-muted)]\" />\n\n <div className=\"text-sm text-[var(--text-tertiary)]\">\n Activate a plan to unlock custom domains, lower transaction\n fees, and the full set of growth tools.\n </div>\n\n <div className=\"pt-4 flex items-center justify-between border-t border-[var(--border-subtle)]\">\n <Button\n variant=\"primary\"\n onClick={() => onNavigateTab('plan')}\n >\n Upgrade plan\n </Button>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Usage This Period — always shown so storage is visible from day one */}\n <div className=\"bg-[var(--bg-base)] rounded-md border border-[var(--border-default)]\">\n <div className=\"px-5 py-4 border-b border-[var(--border-subtle)] flex items-center justify-between\">\n <h2 className=\"text-base font-medium text-[var(--text-primary)]\">\n Usage this period\n </h2>\n {currentUsage && (\n <span className=\"text-xs text-[var(--text-tertiary)]\">\n {formatDate(currentUsage.period.start)} –{' '}\n {formatDate(currentUsage.period.end)}\n </span>\n )}\n </div>\n <div className=\"divide-y divide-[var(--border-subtle)]\">\n {/* Storage — always visible */}\n <div className=\"px-5 py-4 text-sm\">\n <div className=\"flex items-center justify-between mb-1.5\">\n <div className=\"flex items-center gap-2 text-[var(--text-secondary)]\">\n <HardDrive className=\"w-3.5 h-3.5\" />\n <span>Image storage</span>\n {addOnBytes > 0 && (\n <span className=\"text-xs text-brand-500 bg-brand-500/10 px-1.5 py-0.5 rounded\">\n +{formatBytes(addOnBytes)} purchased\n </span>\n )}\n </div>\n <span className=\"text-xs text-[var(--text-tertiary)]\">\n {formatBytes(storageUsedBytes)} of{' '}\n {formatBytes(storageLimitBytes)} used\n </span>\n </div>\n {storageFileCount > 0 && (\n <p className=\"text-xs text-[var(--text-muted)] mb-1.5\">\n {storageFileCount} {storageFileCount === 1 ? 'file' : 'files'}{' '}\n uploaded this period\n </p>\n )}\n <div className=\"w-full h-1.5 bg-[var(--bg-muted)] rounded-full overflow-hidden\">\n <div\n className={`h-full rounded-full transition-[width] duration-500 ${\n isOverBaseline\n ? 'bg-[var(--error)]'\n : isApproaching\n ? 'bg-[var(--warning)]'\n : 'bg-brand-500'\n }`}\n style={{\n width:\n storagePct === 0 ? '0%' : `${Math.max(storagePct, 1)}%`,\n }}\n />\n </div>\n {isApproaching && (\n <p className=\"text-xs text-[var(--warning)] mt-1\">\n Approaching your storage limit. Consider adding more storage.\n </p>\n )}\n {isOverBaseline && (\n <p className=\"text-xs text-[var(--error)] mt-1\">\n You&apos;ve used {formatBytes(storageUsedBytes)} (\n {formatBytes(storageLimitBytes)} limit). Overage of{' '}\n {formatBytes(storageUsedBytes - storageLimitBytes)} will be\n charged at end of month.\n </p>\n )}\n <button\n type=\"button\"\n onClick={onBuyStorage}\n disabled={buyStoragePending}\n className=\"mt-2 flex items-center gap-1 text-xs text-brand-500 hover:text-brand-600 hover:underline disabled:opacity-50 cursor-pointer\"\n >\n <Plus className=\"w-3 h-3\" />\n Buy more storage\n </button>\n </div>\n\n {/* Bandwidth */}\n <div className=\"px-5 py-4 text-sm border-t border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2 text-[var(--text-secondary)]\">\n <Wifi className=\"w-3.5 h-3.5\" />\n <span>Bandwidth</span>\n </div>\n <span className=\"text-xs text-[var(--text-tertiary)]\">\n {bandwidthUsedBytes > 0\n ? `${formatBytes(bandwidthUsedBytes)} used this period`\n : '—'}\n </span>\n </div>\n <p className=\"text-xs text-[var(--text-muted)] mt-1\">\n Served via CDN. Detailed tracking coming soon.\n </p>\n </div>\n\n {/* Messaging Credits */}\n <div className=\"px-5 py-4 text-sm border-t border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between mb-1.5\">\n <div className=\"flex items-center gap-2 text-[var(--text-secondary)]\">\n <MessageSquare className=\"w-3.5 h-3.5\" />\n <span>Messaging credits</span>\n </div>\n <span className=\"font-medium text-[var(--text-primary)]\">\n {creditsInfo != null\n ? `${creditsInfo.balance.toLocaleString()} remaining`\n : '—'}\n </span>\n </div>\n\n {creditsInfo && (\n <>\n {/* Usage bar */}\n {creditsInfo.monthlyAllowance > 0 && (\n <>\n <div className=\"flex items-center justify-between text-xs text-[var(--text-muted)] mb-1\">\n <span>\n {creditsInfo.usedThisPeriod.toLocaleString()} of{' '}\n {creditsInfo.monthlyAllowance.toLocaleString()} included\n used\n </span>\n </div>\n <div className=\"w-full h-1.5 bg-[var(--bg-muted)] rounded-full overflow-hidden\">\n <div\n className={`h-full rounded-full transition-[width] duration-500 ${\n creditsInfo.overage > 0\n ? 'bg-[var(--error)]'\n : creditsInfo.usedThisPeriod /\n creditsInfo.monthlyAllowance >=\n 0.8\n ? 'bg-[var(--warning)]'\n : 'bg-brand-500'\n }`}\n style={{\n width: `${Math.min(100, Math.round((creditsInfo.usedThisPeriod / creditsInfo.monthlyAllowance) * 100))}%`,\n }}\n />\n </div>\n </>\n )}\n\n {/* Low balance warning */}\n {creditsInfo.isLowBalance && creditsInfo.overage === 0 && (\n <p className=\"text-xs text-[var(--warning)] mt-1\">\n Low balance — top up to avoid message failures.\n </p>\n )}\n\n {/* Overage */}\n {creditsInfo.overage > 0 && (\n <p className=\"text-xs text-[var(--error)] mt-1\">\n {creditsInfo.overage.toLocaleString()} credits over your\n included allowance. Est. a-la-carte charge:{' '}\n {formatCurrency(creditsInfo.overageCostNgn, 'NGN')}.\n </p>\n )}\n </>\n )}\n\n <button\n type=\"button\"\n onClick={onTopUpCredits}\n disabled={topUpCreditsPending}\n className=\"mt-2 flex items-center gap-1 text-xs text-brand-500 hover:text-brand-600 hover:underline disabled:opacity-50 cursor-pointer\"\n >\n <Plus className=\"w-3 h-3\" />\n Top up credits\n </button>\n </div>\n\n {/* Email Credits */}\n <div className=\"px-5 py-4 text-sm border-t border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between mb-1.5\">\n <div className=\"flex items-center gap-2 text-[var(--text-secondary)]\">\n <Mail className=\"w-3.5 h-3.5\" />\n <span>Email credits</span>\n </div>\n <span className=\"font-medium text-[var(--text-primary)]\">\n {emailCreditsInfo != null\n ? `${emailCreditsInfo.balance.toLocaleString()} remaining`\n : '—'}\n </span>\n </div>\n\n {emailCreditsInfo && (\n <>\n {emailCreditsInfo.monthlyAllowance > 0 && (\n <>\n <div className=\"flex items-center justify-between text-xs text-[var(--text-muted)] mb-1\">\n <span>\n {emailCreditsInfo.usedThisPeriod.toLocaleString()} of{' '}\n {emailCreditsInfo.monthlyAllowance.toLocaleString()}{' '}\n included used\n </span>\n </div>\n <div className=\"w-full h-1.5 bg-[var(--bg-muted)] rounded-full overflow-hidden\">\n <div\n className={`h-full rounded-full transition-[width] duration-500 ${\n emailCreditsInfo.usedThisPeriod /\n emailCreditsInfo.monthlyAllowance >=\n 0.8\n ? 'bg-[var(--warning)]'\n : 'bg-brand-500'\n }`}\n style={{\n width: `${Math.min(100, Math.round((emailCreditsInfo.usedThisPeriod / emailCreditsInfo.monthlyAllowance) * 100))}%`,\n }}\n />\n </div>\n </>\n )}\n\n {emailCreditsInfo.isLowBalance && (\n <p className=\"text-xs text-[var(--warning)] mt-1\">\n Low balance — top up to keep emails sending.\n </p>\n )}\n </>\n )}\n\n <button\n type=\"button\"\n onClick={onTopUpEmailCredits}\n disabled={topUpEmailCreditsPending}\n className=\"mt-2 flex items-center gap-1 text-xs text-brand-500 hover:text-brand-600 hover:underline disabled:opacity-50 cursor-pointer\"\n >\n <Plus className=\"w-3 h-3\" />\n Top up email credits\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -11,6 +11,7 @@ import {
11
11
  Lock
12
12
  } from "lucide-react";
13
13
  import { useFormatCurrency } from "@withpotter/hooks/use-format-currency";
14
+ import { pickPlanPrice } from "@withpotter/lib/plan-price";
14
15
  const PLUS_FEATURES = [
15
16
  {
16
17
  icon: ShoppingCart,
@@ -52,7 +53,7 @@ function PlansTab({
52
53
  subscribePending
53
54
  }
54
55
  ),
55
- /* @__PURE__ */ jsx(ProPlusCard, { plusPlan }),
56
+ /* @__PURE__ */ jsx(ProPlusCard, {}),
56
57
  /* @__PURE__ */ jsx(SuperProCard, {})
57
58
  ] }),
58
59
  /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-tertiary)] text-center", children: "Prices billed monthly per workspace \xB7 Cancel any time." })
@@ -69,7 +70,7 @@ function PlusCard({
69
70
  const rawName = plan?.name ?? "Plus";
70
71
  const displayName = rawName.split("\u2014")[0]?.trim() || rawName;
71
72
  const displayInterval = plan?.interval ?? "month";
72
- const displayAmount = plan?.prices?.["USD"];
73
+ const displayPrice = pickPlanPrice(plan?.prices);
73
74
  return /* @__PURE__ */ jsxs("div", { className: "bg-[var(--bg-base)] rounded-md border border-[var(--accent-primary)] overflow-hidden flex flex-col", children: [
74
75
  /* @__PURE__ */ jsxs("div", { className: "px-5 pt-5 pb-4 border-b border-[var(--border-subtle)]", children: [
75
76
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
@@ -78,7 +79,7 @@ function PlusCard({
78
79
  ] }),
79
80
  /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-tertiary)] mt-1", children: "Everything you need to run your business on Box." }),
80
81
  /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-baseline gap-1", children: [
81
- /* @__PURE__ */ jsx("span", { className: "text-3xl font-bold text-[var(--text-primary)]", children: displayAmount !== void 0 ? formatCurrency(displayAmount, "USD") : "\u2014" }),
82
+ /* @__PURE__ */ jsx("span", { className: "text-3xl font-bold text-[var(--text-primary)]", children: displayPrice ? formatCurrency(displayPrice.amount, displayPrice.currency) : "\u2014" }),
82
83
  /* @__PURE__ */ jsxs("span", { className: "text-xs text-[var(--text-tertiary)]", children: [
83
84
  "/ ",
84
85
  displayInterval
@@ -110,11 +111,7 @@ function PlusCard({
110
111
  ) })
111
112
  ] });
112
113
  }
113
- function ProPlusCard({ plusPlan }) {
114
- const formatCurrency = useFormatCurrency();
115
- const plusAmount = plusPlan?.prices?.["USD"];
116
- const upgradeUsd = 5;
117
- const proPlusAmount = plusAmount === void 0 ? void 0 : plusAmount + upgradeUsd;
114
+ function ProPlusCard() {
118
115
  return /* @__PURE__ */ jsxs("div", { className: "bg-[var(--bg-base)] rounded-md border border-[var(--border-default)] overflow-hidden flex flex-col", children: [
119
116
  /* @__PURE__ */ jsxs("div", { className: "px-5 pt-5 pb-4 border-b border-[var(--border-subtle)]", children: [
120
117
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
@@ -122,10 +119,7 @@ function ProPlusCard({ plusPlan }) {
122
119
  /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: "Coming soon" })
123
120
  ] }),
124
121
  /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-tertiary)] mt-1", children: "Plus, plus our team helping you grow." }),
125
- /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-baseline gap-1", children: [
126
- /* @__PURE__ */ jsx("span", { className: "text-3xl font-bold text-[var(--text-primary)]", children: proPlusAmount !== void 0 ? formatCurrency(proPlusAmount, "USD") : "+$5" }),
127
- /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--text-tertiary)]", children: proPlusAmount !== void 0 ? "/ month" : "/ month over Plus" })
128
- ] })
122
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex items-baseline gap-1", children: /* @__PURE__ */ jsx("span", { className: "text-lg font-semibold text-[var(--text-primary)]", children: "Priced on top of Plus" }) })
129
123
  ] }),
130
124
  /* @__PURE__ */ jsx("div", { className: "px-5 py-4 flex-1", children: /* @__PURE__ */ jsx("ul", { className: "space-y-2.5", children: PRO_PLUS_FEATURES.map((text) => /* @__PURE__ */ jsxs(
131
125
  "li",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/billing/plans-tab.tsx"],"sourcesContent":["import { Button } from '@withpotter/ui-kit/button';\nimport { Badge } from '@withpotter/ui-kit/badge';\nimport {\n Check,\n Globe,\n MessageSquare,\n ShoppingCart,\n BarChart3,\n Loader2,\n Lock,\n} from 'lucide-react';\nimport { useFormatCurrency } from '@withpotter/hooks/use-format-currency';\nimport type { BillingPlan, Subscription } from './helpers';\n\n// ── Plus tier — included features ──────────────────────────────────────\nconst PLUS_FEATURES = [\n {\n icon: ShoppingCart,\n text: 'All modules — orders, bookings, inventory, subscriptions',\n },\n { icon: Globe, text: 'Custom domain support' },\n { icon: MessageSquare, text: '200 transactional emails / month included' },\n { icon: BarChart3, text: 'Full analytics and reporting' },\n];\n\n// ── Pro Plus tier — value-added services preview ───────────────────────\nconst PRO_PLUS_FEATURES = [\n 'User-generated content (UGC) campaigns produced for you',\n 'Distribution support across owned and paid channels',\n 'Branding & business-strategy office hours',\n];\n\n// ── Super Pro tier — premium / agency-grade services ───────────────────\nconst SUPER_PRO_FEATURES = [\n 'Full brand system — identity, kit, guidelines',\n 'In-person terminals & POS integration',\n 'Priority human support and account management',\n];\n\ninterface PlansTabProps {\n /** Region-resolved Plus plan returned by /billing/plans/active. */\n plusPlan: BillingPlan | undefined;\n subscription: Subscription | null | undefined;\n onSubscribe: () => void;\n subscribePending: boolean;\n}\n\nexport function PlansTab({\n plusPlan,\n subscription,\n onSubscribe,\n subscribePending,\n}: PlansTabProps) {\n return (\n <div className=\"space-y-6\">\n {/* Promise banner */}\n <div className=\"rounded-md border border-[var(--border-default)] bg-[var(--bg-subtle)] px-4 py-3 text-sm text-[var(--text-secondary)]\">\n <span className=\"font-medium text-[var(--text-primary)]\">\n Cheaper than IG ads that might not convert.\n </span>{' '}\n Pay for the platform, keep what you make.\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <PlusCard\n plan={plusPlan}\n subscription={subscription}\n onSubscribe={onSubscribe}\n subscribePending={subscribePending}\n />\n <ProPlusCard plusPlan={plusPlan} />\n <SuperProCard />\n </div>\n\n <p className=\"text-xs text-[var(--text-tertiary)] text-center\">\n Prices billed monthly per workspace · Cancel any time.\n </p>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Plus — today's live tier\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction PlusCard({\n plan,\n subscription,\n onSubscribe,\n subscribePending,\n}: {\n plan: BillingPlan | undefined;\n subscription: Subscription | null | undefined;\n onSubscribe: () => void;\n subscribePending: boolean;\n}) {\n const formatCurrency = useFormatCurrency();\n\n const isActive = subscription && !['cancelled'].includes(subscription.status);\n const rawName = plan?.name ?? 'Plus';\n // Plan names sometimes encode region (e.g. \"Plus — Nigeria\"). We always\n // bill in USD list price and convert at checkout, so strip the region\n // suffix to avoid showing \"Plus — Nigeria\" next to a $ amount.\n const displayName = rawName.split('—')[0]?.trim() || rawName;\n const displayInterval = plan?.interval ?? 'month';\n const displayAmount = plan?.prices?.['USD'];\n\n return (\n <div className=\"bg-[var(--bg-base)] rounded-md border border-[var(--accent-primary)] overflow-hidden flex flex-col\">\n <div className=\"px-5 pt-5 pb-4 border-b border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-base font-semibold text-[var(--text-primary)]\">\n {displayName}\n </h2>\n {isActive ? (\n <Badge variant=\"success\">Active</Badge>\n ) : (\n <Badge variant=\"info\">Available now</Badge>\n )}\n </div>\n <p className=\"text-xs text-[var(--text-tertiary)] mt-1\">\n Everything you need to run your business on Box.\n </p>\n\n <div className=\"mt-4 flex items-baseline gap-1\">\n <span className=\"text-3xl font-bold text-[var(--text-primary)]\">\n {displayAmount !== undefined ? formatCurrency(displayAmount, 'USD') : '—'}\n </span>\n <span className=\"text-xs text-[var(--text-tertiary)]\">\n / {displayInterval}\n </span>\n </div>\n </div>\n\n <div className=\"px-5 py-4 flex-1\">\n <ul className=\"space-y-2.5\">\n {PLUS_FEATURES.map(({ text }) => (\n <li\n key={text}\n className=\"flex items-start gap-2 text-sm text-[var(--text-secondary)]\"\n >\n <Check className=\"w-4 h-4 flex-shrink-0 text-[var(--success)] mt-0.5\" />\n <span>{text}</span>\n </li>\n ))}\n </ul>\n </div>\n\n <div className=\"px-5 pb-5\">\n {isActive ? (\n <div className=\"w-full py-2.5 rounded-md bg-[var(--bg-subtle)] border border-[var(--border-default)] text-center text-sm font-medium text-[var(--text-tertiary)]\">\n Workspace is active\n </div>\n ) : (\n <Button\n className=\"w-full\"\n onClick={onSubscribe}\n disabled={subscribePending || !plan}\n >\n {subscribePending ? (\n <Loader2 className=\"w-4 h-4 animate-spin mr-2\" />\n ) : null}\n Activate workspace\n </Button>\n )}\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Pro Plus — Plus + value-added services (coming soon)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction ProPlusCard({ plusPlan }: { plusPlan: BillingPlan | undefined }) {\n const formatCurrency = useFormatCurrency();\n const plusAmount = plusPlan?.prices?.['USD'];\n\n // Pro Plus is roughly +$5 / month on top of Plus (USD list price; currency\n // conversion happens at checkout).\n const upgradeUsd = 5;\n const proPlusAmount =\n plusAmount === undefined ? undefined : plusAmount + upgradeUsd;\n\n return (\n <div className=\"bg-[var(--bg-base)] rounded-md border border-[var(--border-default)] overflow-hidden flex flex-col\">\n <div className=\"px-5 pt-5 pb-4 border-b border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-base font-semibold text-[var(--text-primary)]\">\n Pro Plus\n </h2>\n <Badge variant=\"secondary\">Coming soon</Badge>\n </div>\n <p className=\"text-xs text-[var(--text-tertiary)] mt-1\">\n Plus, plus our team helping you grow.\n </p>\n\n <div className=\"mt-4 flex items-baseline gap-1\">\n <span className=\"text-3xl font-bold text-[var(--text-primary)]\">\n {proPlusAmount !== undefined ? formatCurrency(proPlusAmount, 'USD') : '+$5'}\n </span>\n <span className=\"text-xs text-[var(--text-tertiary)]\">\n {proPlusAmount !== undefined ? '/ month' : '/ month over Plus'}\n </span>\n </div>\n </div>\n\n <div className=\"px-5 py-4 flex-1\">\n <ul className=\"space-y-2.5\">\n {PRO_PLUS_FEATURES.map((text) => (\n <li\n key={text}\n className=\"flex items-start gap-2 text-sm text-[var(--text-secondary)]\"\n >\n <Check className=\"w-4 h-4 flex-shrink-0 text-[var(--text-muted)] mt-0.5\" />\n <span>{text}</span>\n </li>\n ))}\n </ul>\n </div>\n\n <div className=\"px-5 pb-5\">\n <div className=\"w-full py-2.5 rounded-md bg-[var(--bg-subtle)] border border-[var(--border-default)] text-center text-sm font-medium text-[var(--text-tertiary)] flex items-center justify-center gap-2\">\n <Lock className=\"w-3.5 h-3.5\" />\n Coming soon\n </div>\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Super Pro — branding, terminals, advanced (coming soon)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction SuperProCard() {\n return (\n <div className=\"bg-[var(--bg-base)] rounded-md border border-[var(--border-default)] overflow-hidden flex flex-col\">\n <div className=\"px-5 pt-5 pb-4 border-b border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-base font-semibold text-[var(--text-primary)]\">\n Super Pro\n </h2>\n <Badge variant=\"secondary\">Coming soon</Badge>\n </div>\n <p className=\"text-xs text-[var(--text-tertiary)] mt-1\">\n For brands operating at scale.\n </p>\n\n <div className=\"mt-4 flex items-baseline gap-1\">\n <span className=\"text-3xl font-bold text-[var(--text-primary)]\">\n Custom\n </span>\n </div>\n </div>\n\n <div className=\"px-5 py-4 flex-1\">\n <ul className=\"space-y-2.5\">\n {SUPER_PRO_FEATURES.map((text) => (\n <li\n key={text}\n className=\"flex items-start gap-2 text-sm text-[var(--text-secondary)]\"\n >\n <Check className=\"w-4 h-4 flex-shrink-0 text-[var(--text-muted)] mt-0.5\" />\n <span>{text}</span>\n </li>\n ))}\n </ul>\n </div>\n\n <div className=\"px-5 pb-5\">\n <div className=\"w-full py-2.5 rounded-md bg-[var(--bg-subtle)] border border-[var(--border-default)] text-center text-sm font-medium text-[var(--text-tertiary)] flex items-center justify-center gap-2\">\n <Lock className=\"w-3.5 h-3.5\" />\n Coming soon\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"AAwDM,SACE,KADF;AAxDN,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,yBAAyB;AAIlC,MAAM,gBAAgB;AAAA,EACpB;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,EAAE,MAAM,OAAO,MAAM,wBAAwB;AAAA,EAC7C,EAAE,MAAM,eAAe,MAAM,4CAA4C;AAAA,EACzE,EAAE,MAAM,WAAW,MAAM,+BAA+B;AAC1D;AAGA,MAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AACF;AAGA,MAAM,qBAAqB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF;AAUO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkB;AAChB,SACE,qBAAC,SAAI,WAAU,aAEb;AAAA,yBAAC,SAAI,WAAU,yHACb;AAAA,0BAAC,UAAK,WAAU,0CAAyC,yDAEzD;AAAA,MAAQ;AAAA,MAAI;AAAA,OAEd;AAAA,IAEA,qBAAC,SAAI,WAAU,6BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,MACA,oBAAC,eAAY,UAAoB;AAAA,MACjC,oBAAC,gBAAa;AAAA,OAChB;AAAA,IAEA,oBAAC,OAAE,WAAU,mDAAkD,uEAE/D;AAAA,KACF;AAEJ;AAMA,SAAS,SAAS;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,iBAAiB,kBAAkB;AAEzC,QAAM,WAAW,gBAAgB,CAAC,CAAC,WAAW,EAAE,SAAS,aAAa,MAAM;AAC5E,QAAM,UAAU,MAAM,QAAQ;AAI9B,QAAM,cAAc,QAAQ,MAAM,QAAG,EAAE,CAAC,GAAG,KAAK,KAAK;AACrD,QAAM,kBAAkB,MAAM,YAAY;AAC1C,QAAM,gBAAgB,MAAM,SAAS,KAAK;AAE1C,SACE,qBAAC,SAAI,WAAU,sGACb;AAAA,yBAAC,SAAI,WAAU,yDACb;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,QAAG,WAAU,sDACX,uBACH;AAAA,QACC,WACC,oBAAC,SAAM,SAAQ,WAAU,oBAAM,IAE/B,oBAAC,SAAM,SAAQ,QAAO,2BAAa;AAAA,SAEvC;AAAA,MACA,oBAAC,OAAE,WAAU,4CAA2C,8DAExD;AAAA,MAEA,qBAAC,SAAI,WAAU,kCACb;AAAA,4BAAC,UAAK,WAAU,iDACb,4BAAkB,SAAY,eAAe,eAAe,KAAK,IAAI,UACxE;AAAA,QACA,qBAAC,UAAK,WAAU,uCAAsC;AAAA;AAAA,UACjD;AAAA,WACL;AAAA,SACF;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,oBACb,8BAAC,QAAG,WAAU,eACX,wBAAc,IAAI,CAAC,EAAE,KAAK,MACzB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAM,WAAU,sDAAqD;AAAA,UACtE,oBAAC,UAAM,gBAAK;AAAA;AAAA;AAAA,MAJP;AAAA,IAKP,CACD,GACH,GACF;AAAA,IAEA,oBAAC,SAAI,WAAU,aACZ,qBACC,oBAAC,SAAI,WAAU,oJAAmJ,iCAElK,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU,oBAAoB,CAAC;AAAA,QAE9B;AAAA,6BACC,oBAAC,WAAQ,WAAU,6BAA4B,IAC7C;AAAA,UAAK;AAAA;AAAA;AAAA,IAEX,GAEJ;AAAA,KACF;AAEJ;AAMA,SAAS,YAAY,EAAE,SAAS,GAA0C;AACxE,QAAM,iBAAiB,kBAAkB;AACzC,QAAM,aAAa,UAAU,SAAS,KAAK;AAI3C,QAAM,aAAa;AACnB,QAAM,gBACJ,eAAe,SAAY,SAAY,aAAa;AAEtD,SACE,qBAAC,SAAI,WAAU,sGACb;AAAA,yBAAC,SAAI,WAAU,yDACb;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,QAAG,WAAU,sDAAqD,sBAEnE;AAAA,QACA,oBAAC,SAAM,SAAQ,aAAY,yBAAW;AAAA,SACxC;AAAA,MACA,oBAAC,OAAE,WAAU,4CAA2C,mDAExD;AAAA,MAEA,qBAAC,SAAI,WAAU,kCACb;AAAA,4BAAC,UAAK,WAAU,iDACb,4BAAkB,SAAY,eAAe,eAAe,KAAK,IAAI,OACxE;AAAA,QACA,oBAAC,UAAK,WAAU,uCACb,4BAAkB,SAAY,YAAY,qBAC7C;AAAA,SACF;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,oBACb,8BAAC,QAAG,WAAU,eACX,4BAAkB,IAAI,CAAC,SACtB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAM,WAAU,yDAAwD;AAAA,UACzE,oBAAC,UAAM,gBAAK;AAAA;AAAA;AAAA,MAJP;AAAA,IAKP,CACD,GACH,GACF;AAAA,IAEA,oBAAC,SAAI,WAAU,aACb,+BAAC,SAAI,WAAU,2LACb;AAAA,0BAAC,QAAK,WAAU,eAAc;AAAA,MAAE;AAAA,OAElC,GACF;AAAA,KACF;AAEJ;AAMA,SAAS,eAAe;AACtB,SACE,qBAAC,SAAI,WAAU,sGACb;AAAA,yBAAC,SAAI,WAAU,yDACb;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,QAAG,WAAU,sDAAqD,uBAEnE;AAAA,QACA,oBAAC,SAAM,SAAQ,aAAY,yBAAW;AAAA,SACxC;AAAA,MACA,oBAAC,OAAE,WAAU,4CAA2C,4CAExD;AAAA,MAEA,oBAAC,SAAI,WAAU,kCACb,8BAAC,UAAK,WAAU,iDAAgD,oBAEhE,GACF;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,oBACb,8BAAC,QAAG,WAAU,eACX,6BAAmB,IAAI,CAAC,SACvB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAM,WAAU,yDAAwD;AAAA,UACzE,oBAAC,UAAM,gBAAK;AAAA;AAAA;AAAA,MAJP;AAAA,IAKP,CACD,GACH,GACF;AAAA,IAEA,oBAAC,SAAI,WAAU,aACb,+BAAC,SAAI,WAAU,2LACb;AAAA,0BAAC,QAAK,WAAU,eAAc;AAAA,MAAE;AAAA,OAElC,GACF;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/billing/plans-tab.tsx"],"sourcesContent":["import { Button } from '@withpotter/ui-kit/button';\nimport { Badge } from '@withpotter/ui-kit/badge';\nimport {\n Check,\n Globe,\n MessageSquare,\n ShoppingCart,\n BarChart3,\n Loader2,\n Lock,\n} from 'lucide-react';\nimport { useFormatCurrency } from '@withpotter/hooks/use-format-currency';\nimport { pickPlanPrice } from '@withpotter/lib/plan-price';\nimport type { BillingPlan, Subscription } from './helpers';\n\n// ── Plus tier — included features ──────────────────────────────────────\nconst PLUS_FEATURES = [\n {\n icon: ShoppingCart,\n text: 'All modules — orders, bookings, inventory, subscriptions',\n },\n { icon: Globe, text: 'Custom domain support' },\n { icon: MessageSquare, text: '200 transactional emails / month included' },\n { icon: BarChart3, text: 'Full analytics and reporting' },\n];\n\n// ── Pro Plus tier — value-added services preview ───────────────────────\nconst PRO_PLUS_FEATURES = [\n 'User-generated content (UGC) campaigns produced for you',\n 'Distribution support across owned and paid channels',\n 'Branding & business-strategy office hours',\n];\n\n// ── Super Pro tier — premium / agency-grade services ───────────────────\nconst SUPER_PRO_FEATURES = [\n 'Full brand system — identity, kit, guidelines',\n 'In-person terminals & POS integration',\n 'Priority human support and account management',\n];\n\ninterface PlansTabProps {\n /** Region-resolved Plus plan returned by /billing/plans/active. */\n plusPlan: BillingPlan | undefined;\n subscription: Subscription | null | undefined;\n onSubscribe: () => void;\n subscribePending: boolean;\n}\n\nexport function PlansTab({\n plusPlan,\n subscription,\n onSubscribe,\n subscribePending,\n}: PlansTabProps) {\n return (\n <div className=\"space-y-6\">\n {/* Promise banner */}\n <div className=\"rounded-md border border-[var(--border-default)] bg-[var(--bg-subtle)] px-4 py-3 text-sm text-[var(--text-secondary)]\">\n <span className=\"font-medium text-[var(--text-primary)]\">\n Cheaper than IG ads that might not convert.\n </span>{' '}\n Pay for the platform, keep what you make.\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <PlusCard\n plan={plusPlan}\n subscription={subscription}\n onSubscribe={onSubscribe}\n subscribePending={subscribePending}\n />\n <ProPlusCard />\n <SuperProCard />\n </div>\n\n <p className=\"text-xs text-[var(--text-tertiary)] text-center\">\n Prices billed monthly per workspace · Cancel any time.\n </p>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Plus — today's live tier\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction PlusCard({\n plan,\n subscription,\n onSubscribe,\n subscribePending,\n}: {\n plan: BillingPlan | undefined;\n subscription: Subscription | null | undefined;\n onSubscribe: () => void;\n subscribePending: boolean;\n}) {\n const formatCurrency = useFormatCurrency();\n\n const isActive = subscription && !['cancelled'].includes(subscription.status);\n const rawName = plan?.name ?? 'Plus';\n // Plan names sometimes encode region (e.g. \"Plus — Nigeria\"). The card\n // shows the naira price when the plan has one, so strip the region suffix\n // to avoid showing \"Plus — Nigeria\" next to the amount.\n const displayName = rawName.split('—')[0]?.trim() || rawName;\n const displayInterval = plan?.interval ?? 'month';\n const displayPrice = pickPlanPrice(plan?.prices);\n\n return (\n <div className=\"bg-[var(--bg-base)] rounded-md border border-[var(--accent-primary)] overflow-hidden flex flex-col\">\n <div className=\"px-5 pt-5 pb-4 border-b border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-base font-semibold text-[var(--text-primary)]\">\n {displayName}\n </h2>\n {isActive ? (\n <Badge variant=\"success\">Active</Badge>\n ) : (\n <Badge variant=\"info\">Available now</Badge>\n )}\n </div>\n <p className=\"text-xs text-[var(--text-tertiary)] mt-1\">\n Everything you need to run your business on Box.\n </p>\n\n <div className=\"mt-4 flex items-baseline gap-1\">\n <span className=\"text-3xl font-bold text-[var(--text-primary)]\">\n {displayPrice ? formatCurrency(displayPrice.amount, displayPrice.currency) : '—'}\n </span>\n <span className=\"text-xs text-[var(--text-tertiary)]\">\n / {displayInterval}\n </span>\n </div>\n </div>\n\n <div className=\"px-5 py-4 flex-1\">\n <ul className=\"space-y-2.5\">\n {PLUS_FEATURES.map(({ text }) => (\n <li\n key={text}\n className=\"flex items-start gap-2 text-sm text-[var(--text-secondary)]\"\n >\n <Check className=\"w-4 h-4 flex-shrink-0 text-[var(--success)] mt-0.5\" />\n <span>{text}</span>\n </li>\n ))}\n </ul>\n </div>\n\n <div className=\"px-5 pb-5\">\n {isActive ? (\n <div className=\"w-full py-2.5 rounded-md bg-[var(--bg-subtle)] border border-[var(--border-default)] text-center text-sm font-medium text-[var(--text-tertiary)]\">\n Workspace is active\n </div>\n ) : (\n <Button\n className=\"w-full\"\n onClick={onSubscribe}\n disabled={subscribePending || !plan}\n >\n {subscribePending ? (\n <Loader2 className=\"w-4 h-4 animate-spin mr-2\" />\n ) : null}\n Activate workspace\n </Button>\n )}\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Pro Plus — Plus + value-added services (coming soon)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction ProPlusCard() {\n return (\n <div className=\"bg-[var(--bg-base)] rounded-md border border-[var(--border-default)] overflow-hidden flex flex-col\">\n <div className=\"px-5 pt-5 pb-4 border-b border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-base font-semibold text-[var(--text-primary)]\">\n Pro Plus\n </h2>\n <Badge variant=\"secondary\">Coming soon</Badge>\n </div>\n <p className=\"text-xs text-[var(--text-tertiary)] mt-1\">\n Plus, plus our team helping you grow.\n </p>\n\n <div className=\"mt-4 flex items-baseline gap-1\">\n <span className=\"text-lg font-semibold text-[var(--text-primary)]\">\n Priced on top of Plus\n </span>\n </div>\n </div>\n\n <div className=\"px-5 py-4 flex-1\">\n <ul className=\"space-y-2.5\">\n {PRO_PLUS_FEATURES.map((text) => (\n <li\n key={text}\n className=\"flex items-start gap-2 text-sm text-[var(--text-secondary)]\"\n >\n <Check className=\"w-4 h-4 flex-shrink-0 text-[var(--text-muted)] mt-0.5\" />\n <span>{text}</span>\n </li>\n ))}\n </ul>\n </div>\n\n <div className=\"px-5 pb-5\">\n <div className=\"w-full py-2.5 rounded-md bg-[var(--bg-subtle)] border border-[var(--border-default)] text-center text-sm font-medium text-[var(--text-tertiary)] flex items-center justify-center gap-2\">\n <Lock className=\"w-3.5 h-3.5\" />\n Coming soon\n </div>\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Super Pro — branding, terminals, advanced (coming soon)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction SuperProCard() {\n return (\n <div className=\"bg-[var(--bg-base)] rounded-md border border-[var(--border-default)] overflow-hidden flex flex-col\">\n <div className=\"px-5 pt-5 pb-4 border-b border-[var(--border-subtle)]\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-base font-semibold text-[var(--text-primary)]\">\n Super Pro\n </h2>\n <Badge variant=\"secondary\">Coming soon</Badge>\n </div>\n <p className=\"text-xs text-[var(--text-tertiary)] mt-1\">\n For brands operating at scale.\n </p>\n\n <div className=\"mt-4 flex items-baseline gap-1\">\n <span className=\"text-3xl font-bold text-[var(--text-primary)]\">\n Custom\n </span>\n </div>\n </div>\n\n <div className=\"px-5 py-4 flex-1\">\n <ul className=\"space-y-2.5\">\n {SUPER_PRO_FEATURES.map((text) => (\n <li\n key={text}\n className=\"flex items-start gap-2 text-sm text-[var(--text-secondary)]\"\n >\n <Check className=\"w-4 h-4 flex-shrink-0 text-[var(--text-muted)] mt-0.5\" />\n <span>{text}</span>\n </li>\n ))}\n </ul>\n </div>\n\n <div className=\"px-5 pb-5\">\n <div className=\"w-full py-2.5 rounded-md bg-[var(--bg-subtle)] border border-[var(--border-default)] text-center text-sm font-medium text-[var(--text-tertiary)] flex items-center justify-center gap-2\">\n <Lock className=\"w-3.5 h-3.5\" />\n Coming soon\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"AAyDM,SACE,KADF;AAzDN,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,yBAAyB;AAClC,SAAS,qBAAqB;AAI9B,MAAM,gBAAgB;AAAA,EACpB;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,EAAE,MAAM,OAAO,MAAM,wBAAwB;AAAA,EAC7C,EAAE,MAAM,eAAe,MAAM,4CAA4C;AAAA,EACzE,EAAE,MAAM,WAAW,MAAM,+BAA+B;AAC1D;AAGA,MAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AACF;AAGA,MAAM,qBAAqB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF;AAUO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkB;AAChB,SACE,qBAAC,SAAI,WAAU,aAEb;AAAA,yBAAC,SAAI,WAAU,yHACb;AAAA,0BAAC,UAAK,WAAU,0CAAyC,yDAEzD;AAAA,MAAQ;AAAA,MAAI;AAAA,OAEd;AAAA,IAEA,qBAAC,SAAI,WAAU,6BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,MACA,oBAAC,eAAY;AAAA,MACb,oBAAC,gBAAa;AAAA,OAChB;AAAA,IAEA,oBAAC,OAAE,WAAU,mDAAkD,uEAE/D;AAAA,KACF;AAEJ;AAMA,SAAS,SAAS;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,iBAAiB,kBAAkB;AAEzC,QAAM,WAAW,gBAAgB,CAAC,CAAC,WAAW,EAAE,SAAS,aAAa,MAAM;AAC5E,QAAM,UAAU,MAAM,QAAQ;AAI9B,QAAM,cAAc,QAAQ,MAAM,QAAG,EAAE,CAAC,GAAG,KAAK,KAAK;AACrD,QAAM,kBAAkB,MAAM,YAAY;AAC1C,QAAM,eAAe,cAAc,MAAM,MAAM;AAE/C,SACE,qBAAC,SAAI,WAAU,sGACb;AAAA,yBAAC,SAAI,WAAU,yDACb;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,QAAG,WAAU,sDACX,uBACH;AAAA,QACC,WACC,oBAAC,SAAM,SAAQ,WAAU,oBAAM,IAE/B,oBAAC,SAAM,SAAQ,QAAO,2BAAa;AAAA,SAEvC;AAAA,MACA,oBAAC,OAAE,WAAU,4CAA2C,8DAExD;AAAA,MAEA,qBAAC,SAAI,WAAU,kCACb;AAAA,4BAAC,UAAK,WAAU,iDACb,yBAAe,eAAe,aAAa,QAAQ,aAAa,QAAQ,IAAI,UAC/E;AAAA,QACA,qBAAC,UAAK,WAAU,uCAAsC;AAAA;AAAA,UACjD;AAAA,WACL;AAAA,SACF;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,oBACb,8BAAC,QAAG,WAAU,eACX,wBAAc,IAAI,CAAC,EAAE,KAAK,MACzB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAM,WAAU,sDAAqD;AAAA,UACtE,oBAAC,UAAM,gBAAK;AAAA;AAAA;AAAA,MAJP;AAAA,IAKP,CACD,GACH,GACF;AAAA,IAEA,oBAAC,SAAI,WAAU,aACZ,qBACC,oBAAC,SAAI,WAAU,oJAAmJ,iCAElK,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU,oBAAoB,CAAC;AAAA,QAE9B;AAAA,6BACC,oBAAC,WAAQ,WAAU,6BAA4B,IAC7C;AAAA,UAAK;AAAA;AAAA;AAAA,IAEX,GAEJ;AAAA,KACF;AAEJ;AAMA,SAAS,cAAc;AACrB,SACE,qBAAC,SAAI,WAAU,sGACb;AAAA,yBAAC,SAAI,WAAU,yDACb;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,QAAG,WAAU,sDAAqD,sBAEnE;AAAA,QACA,oBAAC,SAAM,SAAQ,aAAY,yBAAW;AAAA,SACxC;AAAA,MACA,oBAAC,OAAE,WAAU,4CAA2C,mDAExD;AAAA,MAEA,oBAAC,SAAI,WAAU,kCACb,8BAAC,UAAK,WAAU,oDAAmD,mCAEnE,GACF;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,oBACb,8BAAC,QAAG,WAAU,eACX,4BAAkB,IAAI,CAAC,SACtB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAM,WAAU,yDAAwD;AAAA,UACzE,oBAAC,UAAM,gBAAK;AAAA;AAAA;AAAA,MAJP;AAAA,IAKP,CACD,GACH,GACF;AAAA,IAEA,oBAAC,SAAI,WAAU,aACb,+BAAC,SAAI,WAAU,2LACb;AAAA,0BAAC,QAAK,WAAU,eAAc;AAAA,MAAE;AAAA,OAElC,GACF;AAAA,KACF;AAEJ;AAMA,SAAS,eAAe;AACtB,SACE,qBAAC,SAAI,WAAU,sGACb;AAAA,yBAAC,SAAI,WAAU,yDACb;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,QAAG,WAAU,sDAAqD,uBAEnE;AAAA,QACA,oBAAC,SAAM,SAAQ,aAAY,yBAAW;AAAA,SACxC;AAAA,MACA,oBAAC,OAAE,WAAU,4CAA2C,4CAExD;AAAA,MAEA,oBAAC,SAAI,WAAU,kCACb,8BAAC,UAAK,WAAU,iDAAgD,oBAEhE,GACF;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,oBACb,8BAAC,QAAG,WAAU,eACX,6BAAmB,IAAI,CAAC,SACvB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAM,WAAU,yDAAwD;AAAA,UACzE,oBAAC,UAAM,gBAAK;AAAA;AAAA;AAAA,MAJP;AAAA,IAKP,CACD,GACH,GACF;AAAA,IAEA,oBAAC,SAAI,WAAU,aACb,+BAAC,SAAI,WAAU,2LACb;AAAA,0BAAC,QAAK,WAAU,eAAc;AAAA,MAAE;AAAA,OAElC,GACF;AAAA,KACF;AAEJ;","names":[]}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import React, { useMemo, useState } from "react";
4
+ import { pickPlanPrice } from "@withpotter/lib/plan-price";
4
5
  import {
5
6
  AlertTriangle,
6
7
  ArrowRight,
@@ -52,17 +53,17 @@ function MobileBillingPlanScreen({
52
53
  }) {
53
54
  const sortedPlans = useMemo(() => {
54
55
  return [...plans ?? []].sort((a, b) => {
55
- const ap = Object.values(a.prices)[0] ?? 0;
56
- const bp = Object.values(b.prices)[0] ?? 0;
56
+ const ap = pickPlanPrice(a.prices)?.amount ?? 0;
57
+ const bp = pickPlanPrice(b.prices)?.amount ?? 0;
57
58
  return ap - bp;
58
59
  });
59
60
  }, [plans]);
60
61
  const currentPlanId = subscription?.plan?.id;
61
62
  const [selectedId, setSelectedId] = useState(
62
- currentPlanId ?? sortedPlans.find((p) => Object.values(p.prices)[0] > 0)?.id ?? null
63
+ currentPlanId ?? sortedPlans.find((p) => (pickPlanPrice(p.prices)?.amount ?? 0) > 0)?.id ?? null
63
64
  );
64
65
  const selected = sortedPlans.find((p) => p.id === selectedId);
65
- const selectedPrice = selected ? Object.values(selected.prices)[0] ?? 0 : 0;
66
+ const selectedPrice = selected ? pickPlanPrice(selected.prices)?.amount ?? 0 : 0;
66
67
  const isCurrent = selectedId === currentPlanId;
67
68
  const cancelling = subscription?.cancellation?.cancelAtPeriodEnd;
68
69
  return /* @__PURE__ */ jsxs(
@@ -131,7 +132,7 @@ function MobileBillingPlanScreen({
131
132
  }
132
133
  ),
133
134
  /* @__PURE__ */ jsx("section", { className: "mt-6 grid grid-cols-2 gap-2", children: sortedPlans.map((p) => {
134
- const price = Object.values(p.prices)[0] ?? 0;
135
+ const price = pickPlanPrice(p.prices)?.amount ?? 0;
135
136
  const isActive = p.id === selectedId;
136
137
  return /* @__PURE__ */ jsxs(
137
138
  Button,
@@ -830,7 +831,7 @@ function MobileBillingInvoicesScreen({
830
831
  formatCurrency
831
832
  }) {
832
833
  const plan = subscription?.plan;
833
- const planPrice = plan ? Object.values(plan.prices)[0] ?? 0 : 0;
834
+ const planPrice = plan ? pickPlanPrice(plan.prices)?.amount ?? 0 : 0;
834
835
  const renewsAt = subscription?.currentPeriod?.end;
835
836
  return /* @__PURE__ */ jsxs(
836
837
  "div",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/mobile/screens/billing-flows.tsx"],"sourcesContent":["'use client';\n\n/**\n * Mobile Billing — sub-screens\n *\n * Mockup contract: BillingPlanUpgrade, BillingCredits, BillingTopUpSheet,\n * BillingInvoices, BillingUsage in mobile-redesign-mockups.tsx.\n *\n * Rendered from /dashboard/settings/billing on mobile when the user\n * drills past the Billing hub. The hub itself lives in `./billing.tsx`.\n */\n\nimport React, { useMemo, useState } from 'react';\nimport {\n AlertTriangle,\n ArrowRight,\n Calculator,\n Check,\n CheckCircle2,\n CreditCard,\n Download,\n Landmark,\n Loader2,\n Mail,\n MessageCircle,\n MessageSquare,\n Percent,\n Plus,\n Receipt,\n Smartphone,\n Star,\n Trash2,\n TrendingUp,\n} from 'lucide-react';\nimport {\n BackBar,\n BottomSheet,\n MOBILE_BOTTOM_OFFSET_MIN,\n StickyCtaBar,\n stickyCtaScrollPadding,\n TextField,\n} from '@withpotter/components/mobile/primitives';\nimport type {\n BillingPlan,\n Subscription,\n PaymentMethod,\n Invoice,\n MessagingCreditsInfo,\n EmailCreditsInfo,\n CreditPack,\n EmailCreditPack,\n CurrentPricingPolicyResponse,\n BillingLedgerSummaryResponse,\n FeePreviewRequest,\n FeePreviewResponse,\n BusinessCategory,\n} from '@withpotter/pages-core/dashboard/settings/billing/_components';\nimport {\n useMessagingData,\n type CreditTransaction,\n type UsageStats,\n} from '@withpotter/hooks/use-messaging-data';\nimport { Select } from '@withpotter/ui-kit/select';\nimport {\n BOX_HIDE_SMS,\n BOX_HIDE_WHATSAPP,\n phoneChannelsLabel,\n} from '@withpotter/lib/box-channels';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { Input } from '@withpotter/ui-kit';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Plan & upgrade\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileBillingPlanScreenProps {\n plans: BillingPlan[] | undefined;\n subscription: Subscription | null | undefined;\n isPending: boolean;\n onSubscribe: (planId: string) => void;\n onCancel: () => void;\n onBack: () => void;\n formatCurrency: (n: number) => string;\n}\n\nexport function MobileBillingPlanScreen({\n plans,\n subscription,\n isPending,\n onSubscribe,\n onCancel,\n onBack,\n formatCurrency,\n}: MobileBillingPlanScreenProps) {\n const sortedPlans = useMemo(() => {\n return [...(plans ?? [])].sort((a, b) => {\n const ap = Object.values(a.prices)[0] ?? 0;\n const bp = Object.values(b.prices)[0] ?? 0;\n return ap - bp;\n });\n }, [plans]);\n\n const currentPlanId = subscription?.plan?.id;\n const [selectedId, setSelectedId] = useState<string | null>(\n currentPlanId ??\n sortedPlans.find((p) => Object.values(p.prices)[0] > 0)?.id ??\n null,\n );\n const selected = sortedPlans.find((p) => p.id === selectedId);\n const selectedPrice = selected ? (Object.values(selected.prices)[0] ?? 0) : 0;\n const isCurrent = selectedId === currentPlanId;\n const cancelling = subscription?.cancellation?.cancelAtPeriodEnd;\n\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Plan\" onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: stickyCtaScrollPadding(false) }}\n >\n {/* Hero */}\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor:\n 'color-mix(in srgb, var(--mb-accent) 28%, transparent)',\n background: 'color-mix(in srgb, var(--mb-accent) 8%, transparent)',\n }}\n >\n <p\n className=\"text-2xs font-medium\"\n style={{ color: 'var(--mb-accent)' }}\n >\n {selected?.name ?? 'Choose a plan'}\n </p>\n <p\n className=\"mt-1 text-4xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {selected ? formatCurrency(selectedPrice) : '—'}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {selected?.description || 'Per business · billed monthly'}\n </p>\n {cancelling && subscription?.cancellation?.endsAt && (\n <div\n className=\"mt-3 rounded-2xl border p-4 text-2xs\"\n style={{\n borderColor:\n 'color-mix(in srgb, var(--mb-warn) 36%, transparent)',\n background:\n 'color-mix(in srgb, var(--mb-warn) 10%, transparent)',\n color: 'var(--mb-warn)',\n }}\n >\n Cancellation scheduled for{' '}\n {new Date(subscription.cancellation.endsAt).toLocaleDateString()}\n </div>\n )}\n </section>\n\n {/* Plan grid */}\n <section className=\"mt-6 grid grid-cols-2 gap-2\">\n {sortedPlans.map((p) => {\n const price = Object.values(p.prices)[0] ?? 0;\n const isActive = p.id === selectedId;\n return (\n <Button\n variant=\"secondary\"\n size=\"icon\"\n className=\"text-left\"\n key={p.id}\n onClick={() => setSelectedId(p.id)}\n style={{\n borderColor: isActive\n ? 'var(--mb-accent)'\n : 'var(--mb-border)',\n background: isActive\n ? 'color-mix(in srgb, var(--mb-accent) 8%, transparent)'\n : 'var(--mb-card)',\n }}\n >\n <p\n className=\"text-2xs font-medium\"\n style={{\n color: isActive\n ? 'var(--mb-accent)'\n : 'var(--mb-text-tertiary)',\n }}\n >\n {p.name}\n </p>\n <p\n className=\"mt-1 text-2xl font-bold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {price === 0 ? 'Free' : formatCurrency(price)}\n </p>\n <p\n className=\"mt-1 line-clamp-2 text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {p.description ?? `${p.interval} plan`}\n </p>\n {p.id === currentPlanId && (\n <p\n className=\"mt-2 inline-flex items-center gap-1 text-3xs font-semibold\"\n style={{ color: 'var(--mb-good)' }}\n >\n <CheckCircle2 />\n Current\n </p>\n )}\n </Button>\n );\n })}\n </section>\n\n {/* Features */}\n {selected && (\n <section className=\"mt-6 space-y-2\">\n <Caption>Included in {selected.name}</Caption>\n <FeatureRows features={selected.features} />\n </section>\n )}\n\n {/* Cancel current plan */}\n {currentPlanId && !cancelling && (\n <section className=\"mt-6\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"flex h-11 w-full items-center justify-center rounded-2xl border text-sm font-medium\"\n style={{\n borderColor:\n 'color-mix(in srgb, var(--mb-bad) 32%, transparent)',\n background: 'transparent',\n color: 'var(--mb-bad)',\n }}\n >\n Cancel subscription\n </button>\n </section>\n )}\n </div>\n\n {/* Sticky CTA */}\n {selected && !isCurrent && (\n <StickyCtaBar respectTabBar={false}>\n <button\n type=\"button\"\n disabled={isPending}\n onClick={() => onSubscribe(selected.id)}\n className=\"flex h-12 w-full items-center justify-center gap-2 rounded-2xl text-md font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {isPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <>\n {currentPlanId ? 'Switch to' : 'Subscribe to'} {selected.name}\n <ArrowRight className=\"size-4\" />\n </>\n )}\n </button>\n </StickyCtaBar>\n )}\n </div>\n );\n}\n\nfunction FeatureRows({\n features,\n}: {\n features: Record<string, boolean | string | number>;\n}) {\n const rows = Object.entries(features).filter(\n ([, v]) => v !== false && v != null,\n );\n if (rows.length === 0) {\n return (\n <p className=\"text-xs\" style={{ color: 'var(--mb-text-tertiary)' }}>\n Standard features included.\n </p>\n );\n }\n return (\n <div\n className=\"rounded-2xl border\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n {rows.map(([key, value], i) => (\n <div\n key={key}\n className=\"flex items-center gap-3 px-4 py-3\"\n style={{\n borderTop: i === 0 ? 'none' : '1px solid var(--mb-border)',\n }}\n >\n <Check\n className=\"size-4 shrink-0\"\n style={{ color: 'var(--mb-good)' }}\n />\n <p className=\"flex-1 text-sm\" style={{ color: 'var(--mb-text)' }}>\n {humanizeKey(key)}\n {typeof value !== 'boolean' && value !== '' && (\n <span style={{ color: 'var(--mb-text-tertiary)' }}>\n {' '}\n · {String(value)}\n </span>\n )}\n </p>\n </div>\n ))}\n </div>\n );\n}\n\nfunction humanizeKey(k: string) {\n return k\n .replace(/[_-]+/g, ' ')\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n .replace(/^./, (c) => c.toUpperCase());\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Credits hub (replaces messaging + email tabs on mobile)\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileBillingCreditsScreenProps {\n channel: 'messaging' | 'email';\n messagingCredits: MessagingCreditsInfo | null | undefined;\n emailCredits: EmailCreditsInfo | null | undefined;\n onTopUpMessaging: () => void;\n onTopUpEmail: () => void;\n onBack: () => void;\n}\n\nexport function MobileBillingCreditsScreen({\n channel,\n messagingCredits,\n emailCredits,\n onTopUpMessaging,\n onTopUpEmail,\n onBack,\n}: MobileBillingCreditsScreenProps) {\n const isMessaging = channel === 'messaging';\n const info = isMessaging ? messagingCredits : emailCredits;\n const onTopUp = isMessaging ? onTopUpMessaging : onTopUpEmail;\n const title = isMessaging ? 'Messaging credits' : 'Email credits';\n\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title={title} onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: stickyCtaScrollPadding(false) }}\n >\n {/* Balance hero */}\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <p\n className=\"text-2xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Available balance\n </p>\n <p\n className=\"mt-1 text-5xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {(info?.balance ?? 0).toLocaleString()}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {isMessaging\n ? `1 credit ≈ 1 ${(phoneChannelsLabel() ?? 'SMS / WhatsApp').replace(' / ', ' or 1 ')} message`\n : '1 credit = 1 email send'}\n </p>\n {info?.isLowBalance && (\n <div\n className=\"mt-3 flex items-center gap-2 rounded-2xl border p-4 text-2xs\"\n style={{\n borderColor:\n 'color-mix(in srgb, var(--mb-warn) 36%, transparent)',\n background:\n 'color-mix(in srgb, var(--mb-warn) 10%, transparent)',\n color: 'var(--mb-warn)',\n }}\n >\n <AlertTriangle />\n Low balance — top up to keep sending\n </div>\n )}\n </section>\n\n {/* Channel meters */}\n <section className=\"mt-6 space-y-3\">\n {isMessaging ? (\n <>\n {!BOX_HIDE_SMS && (\n <ChannelRow\n icon={Smartphone}\n label=\"SMS\"\n balance={info?.balance ?? 0}\n allowance={info?.monthlyAllowance ?? 0}\n used={info?.usedThisPeriod ?? 0}\n color=\"var(--mb-warn)\"\n />\n )}\n {!BOX_HIDE_WHATSAPP && (\n <ChannelRow\n icon={MessageSquare}\n label=\"WhatsApp\"\n balance={info?.balance ?? 0}\n allowance={info?.monthlyAllowance ?? 0}\n used={info?.usedThisPeriod ?? 0}\n color=\"var(--mb-good)\"\n />\n )}\n </>\n ) : (\n <ChannelRow\n icon={Mail}\n label=\"Email\"\n balance={info?.balance ?? 0}\n allowance={info?.monthlyAllowance ?? 0}\n used={info?.usedThisPeriod ?? 0}\n color=\"var(--mb-accent)\"\n />\n )}\n </section>\n\n {/* Period summary */}\n <section className=\"mt-6 grid grid-cols-2 gap-2\">\n <StatTile\n label=\"Used this period\"\n value={(info?.usedThisPeriod ?? 0).toLocaleString()}\n />\n <StatTile\n label=\"Monthly allowance\"\n value={(info?.monthlyAllowance ?? 0).toLocaleString()}\n />\n <StatTile\n label=\"Total purchased\"\n value={(info?.totalPurchased ?? 0).toLocaleString()}\n />\n <StatTile\n label=\"Resets\"\n value={\n info?.nextResetDate\n ? new Date(info.nextResetDate).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n })\n : '—'\n }\n />\n </section>\n </div>\n\n {/* Sticky CTA */}\n <StickyCtaBar respectTabBar={false}>\n <button\n type=\"button\"\n onClick={onTopUp}\n className=\"flex h-12 w-full items-center justify-center gap-2 rounded-2xl text-md font-semibold\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n <Plus className=\"size-4\" />\n Top up {isMessaging ? 'messaging' : 'email'} credits\n </button>\n </StickyCtaBar>\n </div>\n );\n}\n\nfunction ChannelRow({\n icon: Icon,\n label,\n balance,\n allowance,\n used,\n color,\n}: {\n icon: React.ComponentType<{\n className?: string;\n style?: React.CSSProperties;\n }>;\n label: string;\n balance: number;\n allowance: number;\n used: number;\n color: string;\n}) {\n const denom = Math.max(allowance, balance + used, 1);\n const pct = Math.max(0, Math.min(100, Math.round((balance / denom) * 100)));\n return (\n <div\n className=\"rounded-2xl border p-4\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n <div className=\"flex items-center gap-3\">\n <div\n className=\"flex h-9 w-9 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Icon className=\"h-4 w-4\" style={{ color }} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p\n className=\"text-sm font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n {label}\n </p>\n <p\n className=\"mt-0.5 text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {used.toLocaleString()} used this month\n </p>\n </div>\n <p\n className=\"text-base font-bold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {balance.toLocaleString()}\n </p>\n </div>\n <div\n className=\"mt-3 h-1.5 w-full overflow-hidden rounded-full\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <div\n style={{\n width: `${pct}%`,\n background: color,\n height: '100%',\n }}\n />\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Top-up — full screen (mockup: BillingTopUpSheet)\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype TopUpChannel = 'email' | 'sms' | 'whatsapp';\n\ninterface MobileBillingTopUpScreenProps {\n open: boolean;\n onClose: () => void;\n initialChannel: TopUpChannel;\n messagingPacks: CreditPack[];\n emailPacks: EmailCreditPack[];\n isPendingMessaging: boolean;\n isPendingEmail: boolean;\n onPurchaseMessaging: (credits: number) => void;\n onPurchaseEmail: (credits: number) => void;\n formatCurrency: (n: number) => string;\n}\n\nexport function MobileBillingTopUpScreen({\n open,\n onClose,\n initialChannel,\n messagingPacks,\n emailPacks,\n isPendingMessaging,\n isPendingEmail,\n onPurchaseMessaging,\n onPurchaseEmail,\n formatCurrency,\n}: MobileBillingTopUpScreenProps) {\n // A channel the box has taken away is never the one the screen opens on.\n const [channel, setChannel] = useState<TopUpChannel>(\n (initialChannel === 'sms' && BOX_HIDE_SMS) ||\n (initialChannel === 'whatsapp' && BOX_HIDE_WHATSAPP)\n ? 'email'\n : initialChannel,\n );\n const isEmail = channel === 'email';\n const packs = isEmail ? emailPacks : messagingPacks;\n\n const [selectedCredits, setSelectedCredits] = useState<number | null>(null);\n\n // Sync channel when the screen is (re)opened from a different entry point.\n React.useEffect(() => {\n if (open) setChannel(initialChannel);\n }, [open, initialChannel]);\n\n // Default-select the second pack (Best value) whenever the channel changes\n // or the pack list refreshes.\n React.useEffect(() => {\n if (packs.length === 0) {\n setSelectedCredits(null);\n return;\n }\n setSelectedCredits(packs[1]?.credits ?? packs[0].credits);\n }, [channel, packs]);\n\n const selected = packs.find((p) => p.credits === selectedCredits);\n const subtotal = selected?.priceNgn ?? 0;\n const vat = Math.round(subtotal * 0.075 * 100) / 100;\n const total = subtotal + vat;\n const isPending = isEmail ? isPendingEmail : isPendingMessaging;\n\n if (!open) return null;\n\n return (\n <div\n className=\"fixed inset-0 z-[90] flex flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Top up\" onBack={onClose} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: stickyCtaScrollPadding(false) }}\n >\n {/* Channel */}\n <section className=\"mt-6\">\n <Caption>Channel</Caption>\n <div\n className={`mt-2 grid gap-2 ${\n ['', 'grid-cols-1', 'grid-cols-2', 'grid-cols-3'][\n 1 + (BOX_HIDE_SMS ? 0 : 1) + (BOX_HIDE_WHATSAPP ? 0 : 1)\n ]\n }`}\n >\n <ChannelPill\n icon={Mail}\n label=\"Email\"\n active={channel === 'email'}\n onClick={() => setChannel('email')}\n />\n {!BOX_HIDE_SMS && (\n <ChannelPill\n icon={MessageCircle}\n label=\"SMS\"\n active={channel === 'sms'}\n onClick={() => setChannel('sms')}\n />\n )}\n {!BOX_HIDE_WHATSAPP && (\n <ChannelPill\n icon={MessageSquare}\n label=\"WhatsApp\"\n active={channel === 'whatsapp'}\n onClick={() => setChannel('whatsapp')}\n />\n )}\n </div>\n </section>\n\n {/* Packs */}\n <section className=\"mt-6 space-y-2\">\n <Caption>Choose pack</Caption>\n {packs.length === 0 ? (\n <p\n className=\"rounded-2xl border p-4 text-center text-xs\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n color: 'var(--mb-text-tertiary)',\n }}\n >\n No packs available right now.\n </p>\n ) : (\n packs.map((p, i) => {\n const isActive = p.credits === selectedCredits;\n const badge = i === 1 ? 'Best value' : null;\n return (\n <button\n key={`${p.label}-${p.credits}`}\n type=\"button\"\n onClick={() => setSelectedCredits(p.credits)}\n className=\"flex w-full items-center justify-between gap-3 rounded-2xl border p-4 text-left\"\n style={{\n borderColor: isActive\n ? 'var(--mb-accent)'\n : 'var(--mb-border)',\n background: isActive\n ? 'color-mix(in srgb, var(--mb-accent) 8%, transparent)'\n : 'var(--mb-card)',\n }}\n >\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <p\n className=\"text-md font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n {p.label}\n </p>\n {badge && (\n <span\n className=\"rounded-full px-2 py-0.5 text-3xs font-semibold\"\n style={{\n background:\n 'color-mix(in srgb, var(--mb-good) 16%, transparent)',\n color: 'var(--mb-good)',\n }}\n >\n {badge}\n </span>\n )}\n </div>\n <p\n className=\"mt-0.5 text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {p.credits.toLocaleString()} credits\n </p>\n </div>\n <p\n className=\"text-lg font-bold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {formatCurrency(p.priceNgn)}\n </p>\n </button>\n );\n })\n )}\n </section>\n\n {/* Summary */}\n {selected && (\n <section\n className=\"mt-6 rounded-2xl border\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <SummaryRow\n label={`${selected.label} pack`}\n value={formatCurrency(subtotal)}\n />\n <RowDivider />\n <SummaryRow label=\"VAT (7.5%)\" value={formatCurrency(vat)} />\n <RowDivider />\n <SummaryRow label=\"Total\" value={formatCurrency(total)} emphasis />\n </section>\n )}\n </div>\n\n {/* Sticky Pay CTA — floating card variant */}\n <StickyCtaBar\n respectTabBar={false}\n className=\"px-3\"\n style={{ background: 'transparent' }}\n >\n <div\n className=\"rounded-[26px] border p-2\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'color-mix(in srgb, var(--mb-card) 95%, transparent)',\n backdropFilter: 'blur(12px)',\n WebkitBackdropFilter: 'blur(12px)',\n }}\n >\n <button\n type=\"button\"\n disabled={isPending || !selected}\n onClick={() => {\n if (!selected) return;\n if (isEmail) onPurchaseEmail(selected.credits);\n else onPurchaseMessaging(selected.credits);\n }}\n className=\"flex h-12 w-full items-center justify-center gap-2 rounded-2xl text-md font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {isPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <>\n Pay {selected ? formatCurrency(total) : ''}\n <ArrowRight className=\"size-4\" />\n </>\n )}\n </button>\n </div>\n </StickyCtaBar>\n </div>\n );\n}\n\nfunction ChannelPill({\n icon: Icon,\n label,\n active,\n onClick,\n}: {\n icon: React.ComponentType<{ className?: string }>;\n label: string;\n active?: boolean;\n onClick?: () => void;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"flex h-16 flex-col items-center justify-center gap-1 rounded-2xl border text-2xs font-semibold\"\n style={{\n borderColor: active ? 'var(--mb-accent)' : 'var(--mb-border)',\n background: active\n ? 'color-mix(in srgb, var(--mb-accent) 10%, transparent)'\n : 'var(--mb-card)',\n color: active ? 'var(--mb-accent)' : 'var(--mb-text-secondary)',\n }}\n >\n <Icon className=\"h-4 w-4\" />\n {label}\n </button>\n );\n}\n\nfunction SummaryRow({\n label,\n value,\n emphasis,\n}: {\n label: string;\n value: string;\n emphasis?: boolean;\n}) {\n return (\n <div className=\"flex items-center justify-between px-4 py-3\">\n <span\n className=\"text-xs\"\n style={{\n color: emphasis ? 'var(--mb-text)' : 'var(--mb-text-tertiary)',\n fontWeight: emphasis ? 600 : 400,\n }}\n >\n {label}\n </span>\n <span\n className=\"tabular-nums\"\n style={{\n color: 'var(--mb-text)',\n fontSize: emphasis ? 15 : 13,\n fontWeight: emphasis ? 700 : 500,\n }}\n >\n {value}\n </span>\n </div>\n );\n}\n\nfunction RowDivider() {\n return <div style={{ height: 1, background: 'var(--mb-border)' }} />;\n}\n\nfunction formatMobileMinorCurrency(\n valueCents: number,\n currency: string,\n formatCurrency: (n: number, c?: string) => string,\n) {\n return formatCurrency(Math.round(valueCents / 100), currency);\n}\n\nfunction formatMobileBps(bps: number) {\n return `${(bps / 100).toFixed(bps % 100 === 0 ? 0 : 2)}%`;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Invoices\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileBillingInvoicesScreenProps {\n invoices: Invoice[];\n loading: boolean;\n subscription: Subscription | null | undefined;\n onDownload: (id: string, num: string) => void;\n onBack: () => void;\n formatCurrency: (n: number, c?: string) => string;\n}\n\nexport function MobileBillingInvoicesScreen({\n invoices,\n loading,\n subscription,\n onDownload,\n onBack,\n formatCurrency,\n}: MobileBillingInvoicesScreenProps) {\n const plan = subscription?.plan;\n const planPrice = plan ? (Object.values(plan.prices)[0] ?? 0) : 0;\n const renewsAt = subscription?.currentPeriod?.end;\n\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Invoices\" onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: MOBILE_BOTTOM_OFFSET_MIN }}\n >\n {/* Current cycle */}\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <p\n className=\"text-2xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Current cycle\n </p>\n <p\n className=\"mt-1 text-4xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {plan ? formatCurrency(planPrice) : '—'}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {renewsAt\n ? `Next invoice · ${new Date(renewsAt).toLocaleDateString(undefined, { month: 'short', day: 'numeric' })}`\n : 'No upcoming invoice'}\n </p>\n </section>\n\n {/* List */}\n <section className=\"mt-6 space-y-2\">\n <Caption>Documents</Caption>\n {loading ? (\n <p\n className=\"py-6 text-center text-xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Loading…\n </p>\n ) : invoices.length === 0 ? (\n <EmptyCard\n icon={Receipt}\n title=\"No invoices yet\"\n hint=\"Once you're billed, your receipts will appear here\"\n />\n ) : (\n invoices.map((inv) => (\n <button\n key={inv.id}\n type=\"button\"\n onClick={() => onDownload(inv.id, inv.invoiceNumber)}\n className=\"flex w-full items-center gap-3 rounded-2xl border p-4 text-left\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <div\n className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Receipt\n className=\"size-4\"\n style={{ color: 'var(--mb-text-secondary)' }}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p\n className=\"truncate text-sm font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n {inv.invoiceNumber}\n </p>\n <p\n className=\"mt-0.5 truncate text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {new Date(inv.createdAt).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}\n {' · '}\n <span style={{ textTransform: 'capitalize' }}>\n {inv.status}\n </span>\n </p>\n </div>\n <div className=\"flex shrink-0 flex-col items-end gap-1\">\n <p\n className=\"text-md font-semibold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {formatCurrency(inv.amounts.total, inv.amounts.currency)}\n </p>\n <Download style={{ color: 'var(--mb-text-muted)' }} />\n </div>\n </button>\n ))\n )}\n </section>\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Usage / history\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileBillingUsageScreenProps {\n onBack: () => void;\n}\n\nexport function MobileBillingUsageScreen({\n onBack,\n}: MobileBillingUsageScreenProps) {\n const {\n loading,\n transactions,\n transactionTotal,\n usageStats,\n formatDate,\n getTransactionTypeLabel,\n getTransactionIcon,\n } = useMessagingData();\n\n const [period, setPeriod] = useState<'7d' | '30d' | '90d'>('30d');\n\n const totalSends =\n (usageStats?.smsCount ?? 0) + (usageStats?.whatsappCount ?? 0);\n const totalSpend =\n (usageStats?.smsCredits ?? 0) + (usageStats?.whatsappCredits ?? 0);\n\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Usage\" onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: MOBILE_BOTTOM_OFFSET_MIN }}\n >\n {/* Period chips */}\n <div\n className=\"mt-3 flex gap-1 rounded-full p-1\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n {(['7d', '30d', '90d'] as const).map((k) => (\n <button\n key={k}\n type=\"button\"\n onClick={() => setPeriod(k)}\n className=\"flex-1 rounded-full px-2 py-1.5 text-xs font-medium\"\n style={{\n background: period === k ? 'var(--mb-card)' : 'transparent',\n color:\n period === k ? 'var(--mb-text)' : 'var(--mb-text-tertiary)',\n }}\n >\n {k === '7d'\n ? 'Last 7 days'\n : k === '30d'\n ? 'Last 30 days'\n : 'Last 90 days'}\n </button>\n ))}\n </div>\n\n {/* Spend hero */}\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <p\n className=\"text-2xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Credits used\n </p>\n <p\n className=\"mt-1 text-4xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {totalSpend.toLocaleString()}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {totalSends.toLocaleString()} sends · {transactionTotal} ledger\n entries\n </p>\n </section>\n\n {/* By channel */}\n <section className=\"mt-6 space-y-3\">\n <Caption>By channel</Caption>\n {!BOX_HIDE_SMS && (\n <BreakdownBar\n label=\"SMS\"\n sends={usageStats?.smsCount ?? 0}\n credits={usageStats?.smsCredits ?? 0}\n total={totalSpend}\n color=\"var(--mb-warn)\"\n />\n )}\n {!BOX_HIDE_WHATSAPP && (\n <BreakdownBar\n label=\"WhatsApp\"\n sends={usageStats?.whatsappCount ?? 0}\n credits={usageStats?.whatsappCredits ?? 0}\n total={totalSpend}\n color=\"var(--mb-good)\"\n />\n )}\n </section>\n\n {/* Recent activity */}\n <section className=\"mt-6 space-y-2\">\n <Caption>Recent activity</Caption>\n {loading ? (\n <p\n className=\"py-6 text-center text-xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Loading…\n </p>\n ) : transactions.length === 0 ? (\n <EmptyCard\n icon={TrendingUp}\n title=\"No activity yet\"\n hint=\"Send a campaign or top up to see ledger entries here\"\n />\n ) : (\n transactions\n .slice(0, 12)\n .map((tx) => (\n <ActivityRow\n key={tx.id}\n tx={tx}\n formatDate={formatDate}\n getLabel={getTransactionTypeLabel}\n getIcon={getTransactionIcon}\n />\n ))\n )}\n </section>\n </div>\n </div>\n );\n}\n\nfunction BreakdownBar({\n label,\n sends,\n credits,\n total,\n color,\n}: {\n label: string;\n sends: number;\n credits: number;\n total: number;\n color: string;\n}) {\n const pct =\n total > 0\n ? Math.max(0, Math.min(100, Math.round((credits / total) * 100)))\n : 0;\n return (\n <div\n className=\"rounded-2xl border p-4\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n <div className=\"flex items-center justify-between text-xs\">\n <span style={{ color: 'var(--mb-text)' }}>{label}</span>\n <span\n className=\"tabular-nums\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {sends.toLocaleString()} sends · {credits.toLocaleString()} credits\n </span>\n </div>\n <div\n className=\"mt-2 h-1.5 w-full overflow-hidden rounded-full\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <div style={{ width: `${pct}%`, background: color, height: '100%' }} />\n </div>\n </div>\n );\n}\n\nfunction ActivityRow({\n tx,\n formatDate,\n getLabel,\n getIcon,\n}: {\n tx: CreditTransaction;\n formatDate: (s: string) => string;\n getLabel: (t: string) => string;\n getIcon: (t: string) => React.ComponentType<{ className?: string }>;\n}) {\n const Icon = getIcon(tx.type);\n const isAdd = tx.amount > 0;\n return (\n <div\n className=\"flex items-center gap-3 rounded-2xl border p-4\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n <div\n className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Icon className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p\n className=\"truncate text-sm font-medium\"\n style={{ color: 'var(--mb-text)' }}\n >\n {getLabel(tx.type)}\n </p>\n <p\n className=\"mt-0.5 truncate text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {tx.description || formatDate(tx.createdAt)}\n </p>\n </div>\n <p\n className=\"text-sm font-semibold tabular-nums\"\n style={{\n color: isAdd ? 'var(--mb-good)' : 'var(--mb-text)',\n }}\n >\n {isAdd ? '+' : ''}\n {tx.amount.toLocaleString()}\n </p>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Rates and fee ledger\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst MOBILE_FEE_CATEGORIES: Array<{ value: BusinessCategory; label: string }> =\n [\n { value: 'selling', label: 'Selling' },\n { value: 'bookings', label: 'Bookings' },\n { value: 'digital', label: 'Digital' },\n { value: 'consultations', label: 'Consultations' },\n { value: 'events', label: 'Events' },\n ];\n\ninterface MobileBillingRatesScreenProps {\n policy: CurrentPricingPolicyResponse | undefined;\n ledgerSummary: BillingLedgerSummaryResponse | undefined;\n policyLoading: boolean;\n ledgerLoading: boolean;\n previewResult: FeePreviewResponse | undefined;\n previewPending: boolean;\n onPreview: (payload: FeePreviewRequest) => void;\n onBack: () => void;\n formatCurrency: (n: number, c?: string) => string;\n}\n\nexport function MobileBillingRatesScreen({\n policy,\n ledgerSummary,\n policyLoading,\n ledgerLoading,\n previewResult,\n previewPending,\n onPreview,\n onBack,\n formatCurrency,\n}: MobileBillingRatesScreenProps) {\n const [category, setCategory] = useState<BusinessCategory>('selling');\n const [amount, setAmount] = useState('10000');\n const currency =\n policy?.policy.currency ?? ledgerSummary?.context.currency ?? 'NGN';\n const selectedRule = policy?.policy.rules.platform_fee[category];\n const totals = previewResult?.calculation.totals;\n\n const runPreview = () => {\n const amountValue = Number(amount.replace(/,/g, ''));\n if (!Number.isFinite(amountValue) || amountValue < 0) return;\n onPreview({\n lineItems: [\n {\n id: 'mobile-preview',\n category,\n grossCents: Math.round(amountValue * 100),\n },\n ],\n });\n };\n\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Rates\" onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: MOBILE_BOTTOM_OFFSET_MIN }}\n >\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor:\n 'color-mix(in srgb, var(--mb-accent) 28%, transparent)',\n background: 'color-mix(in srgb, var(--mb-accent) 8%, transparent)',\n }}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p\n className=\"text-2xs font-medium\"\n style={{ color: 'var(--mb-accent)' }}\n >\n {policyLoading\n ? 'Loading policy'\n : `Policy v${policy?.policy.version ?? '—'}`}\n </p>\n <p\n className=\"mt-1 text-4xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {selectedRule ? formatMobileBps(selectedRule.rate_bps) : '—'}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {policy\n ? `${policy.policy.region} · ${policy.policy.tier} · ${currency}`\n : 'Current business rate'}\n </p>\n </div>\n <div\n className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Percent\n className=\"size-5\"\n style={{ color: 'var(--mb-accent)' }}\n />\n </div>\n </div>\n </section>\n\n <section className=\"mt-6 space-y-3\">\n <Caption>Preview</Caption>\n <div\n className=\"rounded-2xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <div className=\"grid grid-cols-2 gap-2\">\n <div\n className=\"text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Category\n <Select\n value={category}\n onChange={(next) => setCategory(next as BusinessCategory)}\n options={MOBILE_FEE_CATEGORIES}\n ariaLabel=\"Category\"\n searchable={MOBILE_FEE_CATEGORIES.length > 15}\n className=\"mt-1.5\"\n />\n </div>\n <label\n className=\"text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Amount\n <Input\n value={amount}\n onChange={(event) => setAmount(event.target.value)}\n inputMode=\"decimal\"\n className=\"h-11 w-full\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-elevated)',\n color: 'var(--mb-text)',\n }}\n />\n </label>\n </div>\n <button\n type=\"button\"\n disabled={!policy || previewPending}\n onClick={runPreview}\n className=\"mt-3 flex h-11 w-full items-center justify-center gap-2 rounded-2xl text-sm font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {previewPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Calculator className=\"size-4\" />\n )}\n Calculate fees\n </button>\n </div>\n </section>\n\n {totals && (\n <section className=\"mt-6 grid grid-cols-2 gap-2\">\n <StatTile\n label=\"Platform fee\"\n value={formatMobileMinorCurrency(\n totals.platformFeeCents,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"Settlement\"\n value={formatMobileMinorCurrency(\n totals.settlementFeeCents,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"VAT\"\n value={formatMobileMinorCurrency(\n totals.vatCents,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"Total fees\"\n value={formatMobileMinorCurrency(\n totals.platformFeeCents +\n totals.settlementFeeCents +\n totals.vatCents,\n currency,\n formatCurrency,\n )}\n />\n </section>\n )}\n\n <section className=\"mt-6 grid grid-cols-2 gap-2\">\n <StatTile\n label=\"Gross tracked\"\n value={formatMobileMinorCurrency(\n ledgerSummary?.totals.grossCents ?? 0,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"Platform fees\"\n value={formatMobileMinorCurrency(\n ledgerSummary?.totals.platformFeeCents ?? 0,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"Rev share\"\n value={formatMobileMinorCurrency(\n ledgerSummary?.totals.revShareCents ?? 0,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"Entries\"\n value={\n ledgerLoading\n ? '…'\n : (ledgerSummary?.totals.feeLedgerEntries ?? 0).toLocaleString()\n }\n />\n </section>\n\n <section className=\"mt-6 space-y-2\">\n <Caption>Recent fees</Caption>\n {(ledgerSummary?.recentFees ?? []).slice(0, 8).map((fee) => (\n <div\n key={fee.id}\n className=\"flex items-center gap-3 rounded-2xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <div\n className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Landmark\n className=\"size-4\"\n style={{ color: 'var(--mb-text-secondary)' }}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p\n className=\"truncate text-sm font-medium capitalize\"\n style={{ color: 'var(--mb-text)' }}\n >\n {fee.category}\n </p>\n <p\n className=\"mt-0.5 truncate text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {new Date(fee.createdAt).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n })}\n </p>\n </div>\n <p\n className=\"text-sm font-semibold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {formatMobileMinorCurrency(\n fee.platformFeeCents + fee.vatCents,\n currency,\n formatCurrency,\n )}\n </p>\n </div>\n ))}\n {!ledgerLoading && (ledgerSummary?.recentFees.length ?? 0) === 0 && (\n <EmptyCard\n icon={Receipt}\n title=\"No fees yet\"\n hint=\"Paid orders and bookings will appear here\"\n />\n )}\n </section>\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Payment methods\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileBillingPaymentMethodsScreenProps {\n paymentMethods: PaymentMethod[] | undefined;\n loading: boolean;\n onAdd: () => void;\n addPending: boolean;\n onRemove: (id: string) => void;\n removePending: boolean;\n deletingId: string | null;\n onSetDeletingId: (id: string | null) => void;\n onSetDefault: (id: string) => void;\n onBack: () => void;\n}\n\nexport function MobileBillingPaymentMethodsScreen({\n paymentMethods,\n loading,\n onAdd,\n addPending,\n onRemove,\n removePending,\n deletingId,\n onSetDeletingId,\n onSetDefault,\n onBack,\n}: MobileBillingPaymentMethodsScreenProps) {\n const list = paymentMethods ?? [];\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Payment method\" onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: stickyCtaScrollPadding(false) }}\n >\n <section className=\"mt-6 space-y-2\">\n {loading ? (\n <p\n className=\"py-6 text-center text-xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Loading…\n </p>\n ) : list.length === 0 ? (\n <EmptyCard\n icon={CreditCard}\n title=\"No payment methods\"\n hint=\"Add a card to keep your plan active\"\n />\n ) : (\n list.map((pm) => (\n <div\n key={pm.id}\n className=\"flex items-center gap-3 rounded-2xl border p-4\"\n style={{\n borderColor: pm.isDefault\n ? 'var(--mb-accent)'\n : 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <div\n className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <CreditCard\n className=\"size-4\"\n style={{ color: 'var(--mb-text-secondary)' }}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <p\n className=\"truncate text-sm font-semibold capitalize\"\n style={{ color: 'var(--mb-text)' }}\n >\n {pm.card?.brand ?? pm.type} ····{pm.card?.last4 ?? '••••'}\n </p>\n {pm.isDefault && (\n <span\n className=\"rounded-full px-2 py-0.5 text-3xs font-semibold\"\n style={{\n background:\n 'color-mix(in srgb, var(--mb-good) 16%, transparent)',\n color: 'var(--mb-good)',\n }}\n >\n Default\n </span>\n )}\n {pm.isExpired && (\n <span\n className=\"rounded-full px-2 py-0.5 text-3xs font-semibold\"\n style={{\n background:\n 'color-mix(in srgb, var(--mb-bad) 14%, transparent)',\n color: 'var(--mb-bad)',\n }}\n >\n Expired\n </span>\n )}\n </div>\n {pm.card && (\n <p\n className=\"mt-0.5 truncate text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Expires {String(pm.card.expMonth).padStart(2, '0')}/\n {String(pm.card.expYear).slice(-2)}\n </p>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-1\">\n {!pm.isDefault && (\n <button\n type=\"button\"\n onClick={() => onSetDefault(pm.id)}\n aria-label=\"Set default\"\n className=\"flex h-8 w-8 items-center justify-center rounded-full\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Star style={{ color: 'var(--mb-text-secondary)' }} />\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => onSetDeletingId(pm.id)}\n aria-label=\"Remove\"\n className=\"flex h-8 w-8 items-center justify-center rounded-full\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Trash2 style={{ color: 'var(--mb-bad)' }} />\n </button>\n </div>\n </div>\n ))\n )}\n </section>\n </div>\n\n {/* Sticky add CTA */}\n <StickyCtaBar respectTabBar={false}>\n <button\n type=\"button\"\n disabled={addPending}\n onClick={onAdd}\n className=\"flex h-12 w-full items-center justify-center gap-2 rounded-2xl text-md font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {addPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <>\n <Plus className=\"size-4\" />\n Add payment method\n </>\n )}\n </button>\n </StickyCtaBar>\n\n {/* Confirm remove sheet */}\n <BottomSheet open={!!deletingId} onClose={() => onSetDeletingId(null)}>\n <div className=\"px-1 pb-1\">\n <p\n className=\"text-base font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n Remove this payment method?\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n You can add a new card any time. If this is your default, your\n subscription may fail to renew.\n </p>\n <div className=\"mt-4 flex gap-2\">\n <button\n type=\"button\"\n onClick={() => onSetDeletingId(null)}\n className=\"flex h-11 flex-1 items-center justify-center rounded-2xl text-sm font-medium\"\n style={{\n background: 'var(--mb-elevated)',\n color: 'var(--mb-text)',\n }}\n >\n Keep\n </button>\n <button\n type=\"button\"\n disabled={removePending}\n onClick={() => deletingId && onRemove(deletingId)}\n className=\"flex h-11 flex-1 items-center justify-center gap-2 rounded-2xl text-sm font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-bad)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {removePending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n 'Remove'\n )}\n </button>\n </div>\n </div>\n </BottomSheet>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Cancel subscription bottom sheet\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileCancelSubscriptionSheetProps {\n open: boolean;\n onClose: () => void;\n onConfirm: (reason?: string) => void;\n isPending: boolean;\n endsAt?: string | null;\n}\n\nexport function MobileCancelSubscriptionSheet({\n open,\n onClose,\n onConfirm,\n isPending,\n endsAt,\n}: MobileCancelSubscriptionSheetProps) {\n const [reason, setReason] = useState('');\n return (\n <BottomSheet open={open} onClose={onClose}>\n <div className=\"px-1 pb-1\">\n <p\n className=\"text-base font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n Cancel subscription?\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n You&apos;ll keep access until\n {endsAt\n ? ` ${new Date(endsAt).toLocaleDateString()}`\n : ' the end of the current period'}\n . You can reactivate any time before then.\n </p>\n\n <label\n className=\"mt-4 block text-2xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Reason (optional)\n </label>\n <TextField\n className=\"mt-1\"\n multiline\n value={reason}\n onChange={setReason}\n placeholder=\"Help us improve…\"\n />\n\n <div className=\"mt-4 flex gap-2\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"flex h-11 flex-1 items-center justify-center rounded-2xl text-sm font-medium\"\n style={{\n background: 'var(--mb-elevated)',\n color: 'var(--mb-text)',\n }}\n >\n Keep plan\n </button>\n <button\n type=\"button\"\n disabled={isPending}\n onClick={() => onConfirm(reason.trim() || undefined)}\n className=\"flex h-11 flex-1 items-center justify-center gap-2 rounded-2xl text-sm font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-bad)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {isPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n 'Confirm cancel'\n )}\n </button>\n </div>\n </div>\n </BottomSheet>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Shared bits\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction Caption({ children }: { children: React.ReactNode }) {\n return (\n <p\n className=\"text-3xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {children}\n </p>\n );\n}\n\nfunction StatTile({ label, value }: { label: string; value: string }) {\n return (\n <div\n className=\"rounded-2xl border p-4\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n <p className=\"text-2xs\" style={{ color: 'var(--mb-text-tertiary)' }}>\n {label}\n </p>\n <p\n className=\"mt-1 text-base font-bold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {value}\n </p>\n </div>\n );\n}\n\nfunction EmptyCard({\n icon: Icon,\n title,\n hint,\n}: {\n icon: React.ComponentType<{\n className?: string;\n style?: React.CSSProperties;\n }>;\n title: string;\n hint?: string;\n}) {\n return (\n <div\n className=\"rounded-2xl border p-8 text-center\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n <Icon\n className=\"mx-auto h-8 w-8\"\n style={{ color: 'var(--mb-text-muted)' }}\n />\n <p\n className=\"mt-2 text-sm font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n {title}\n </p>\n {hint && (\n <p\n className=\"mt-1 text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {hint}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/mobile/screens/billing-flows.tsx"],"sourcesContent":["'use client';\n\n/**\n * Mobile Billing — sub-screens\n *\n * Mockup contract: BillingPlanUpgrade, BillingCredits, BillingTopUpSheet,\n * BillingInvoices, BillingUsage in mobile-redesign-mockups.tsx.\n *\n * Rendered from /dashboard/settings/billing on mobile when the user\n * drills past the Billing hub. The hub itself lives in `./billing.tsx`.\n */\n\nimport React, { useMemo, useState } from 'react';\nimport { pickPlanPrice } from '@withpotter/lib/plan-price';\nimport {\n AlertTriangle,\n ArrowRight,\n Calculator,\n Check,\n CheckCircle2,\n CreditCard,\n Download,\n Landmark,\n Loader2,\n Mail,\n MessageCircle,\n MessageSquare,\n Percent,\n Plus,\n Receipt,\n Smartphone,\n Star,\n Trash2,\n TrendingUp,\n} from 'lucide-react';\nimport {\n BackBar,\n BottomSheet,\n MOBILE_BOTTOM_OFFSET_MIN,\n StickyCtaBar,\n stickyCtaScrollPadding,\n TextField,\n} from '@withpotter/components/mobile/primitives';\nimport type {\n BillingPlan,\n Subscription,\n PaymentMethod,\n Invoice,\n MessagingCreditsInfo,\n EmailCreditsInfo,\n CreditPack,\n EmailCreditPack,\n CurrentPricingPolicyResponse,\n BillingLedgerSummaryResponse,\n FeePreviewRequest,\n FeePreviewResponse,\n BusinessCategory,\n} from '@withpotter/pages-core/dashboard/settings/billing/_components';\nimport {\n useMessagingData,\n type CreditTransaction,\n type UsageStats,\n} from '@withpotter/hooks/use-messaging-data';\nimport { Select } from '@withpotter/ui-kit/select';\nimport {\n BOX_HIDE_SMS,\n BOX_HIDE_WHATSAPP,\n phoneChannelsLabel,\n} from '@withpotter/lib/box-channels';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { Input } from '@withpotter/ui-kit';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Plan & upgrade\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileBillingPlanScreenProps {\n plans: BillingPlan[] | undefined;\n subscription: Subscription | null | undefined;\n isPending: boolean;\n onSubscribe: (planId: string) => void;\n onCancel: () => void;\n onBack: () => void;\n formatCurrency: (n: number) => string;\n}\n\nexport function MobileBillingPlanScreen({\n plans,\n subscription,\n isPending,\n onSubscribe,\n onCancel,\n onBack,\n formatCurrency,\n}: MobileBillingPlanScreenProps) {\n const sortedPlans = useMemo(() => {\n return [...(plans ?? [])].sort((a, b) => {\n const ap = pickPlanPrice(a.prices)?.amount ?? 0;\n const bp = pickPlanPrice(b.prices)?.amount ?? 0;\n return ap - bp;\n });\n }, [plans]);\n\n const currentPlanId = subscription?.plan?.id;\n const [selectedId, setSelectedId] = useState<string | null>(\n currentPlanId ??\n sortedPlans.find((p) => (pickPlanPrice(p.prices)?.amount ?? 0) > 0)?.id ??\n null,\n );\n const selected = sortedPlans.find((p) => p.id === selectedId);\n const selectedPrice = selected ? (pickPlanPrice(selected.prices)?.amount ?? 0) : 0;\n const isCurrent = selectedId === currentPlanId;\n const cancelling = subscription?.cancellation?.cancelAtPeriodEnd;\n\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Plan\" onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: stickyCtaScrollPadding(false) }}\n >\n {/* Hero */}\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor:\n 'color-mix(in srgb, var(--mb-accent) 28%, transparent)',\n background: 'color-mix(in srgb, var(--mb-accent) 8%, transparent)',\n }}\n >\n <p\n className=\"text-2xs font-medium\"\n style={{ color: 'var(--mb-accent)' }}\n >\n {selected?.name ?? 'Choose a plan'}\n </p>\n <p\n className=\"mt-1 text-4xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {selected ? formatCurrency(selectedPrice) : '—'}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {selected?.description || 'Per business · billed monthly'}\n </p>\n {cancelling && subscription?.cancellation?.endsAt && (\n <div\n className=\"mt-3 rounded-2xl border p-4 text-2xs\"\n style={{\n borderColor:\n 'color-mix(in srgb, var(--mb-warn) 36%, transparent)',\n background:\n 'color-mix(in srgb, var(--mb-warn) 10%, transparent)',\n color: 'var(--mb-warn)',\n }}\n >\n Cancellation scheduled for{' '}\n {new Date(subscription.cancellation.endsAt).toLocaleDateString()}\n </div>\n )}\n </section>\n\n {/* Plan grid */}\n <section className=\"mt-6 grid grid-cols-2 gap-2\">\n {sortedPlans.map((p) => {\n const price = pickPlanPrice(p.prices)?.amount ?? 0;\n const isActive = p.id === selectedId;\n return (\n <Button\n variant=\"secondary\"\n size=\"icon\"\n className=\"text-left\"\n key={p.id}\n onClick={() => setSelectedId(p.id)}\n style={{\n borderColor: isActive\n ? 'var(--mb-accent)'\n : 'var(--mb-border)',\n background: isActive\n ? 'color-mix(in srgb, var(--mb-accent) 8%, transparent)'\n : 'var(--mb-card)',\n }}\n >\n <p\n className=\"text-2xs font-medium\"\n style={{\n color: isActive\n ? 'var(--mb-accent)'\n : 'var(--mb-text-tertiary)',\n }}\n >\n {p.name}\n </p>\n <p\n className=\"mt-1 text-2xl font-bold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {price === 0 ? 'Free' : formatCurrency(price)}\n </p>\n <p\n className=\"mt-1 line-clamp-2 text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {p.description ?? `${p.interval} plan`}\n </p>\n {p.id === currentPlanId && (\n <p\n className=\"mt-2 inline-flex items-center gap-1 text-3xs font-semibold\"\n style={{ color: 'var(--mb-good)' }}\n >\n <CheckCircle2 />\n Current\n </p>\n )}\n </Button>\n );\n })}\n </section>\n\n {/* Features */}\n {selected && (\n <section className=\"mt-6 space-y-2\">\n <Caption>Included in {selected.name}</Caption>\n <FeatureRows features={selected.features} />\n </section>\n )}\n\n {/* Cancel current plan */}\n {currentPlanId && !cancelling && (\n <section className=\"mt-6\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"flex h-11 w-full items-center justify-center rounded-2xl border text-sm font-medium\"\n style={{\n borderColor:\n 'color-mix(in srgb, var(--mb-bad) 32%, transparent)',\n background: 'transparent',\n color: 'var(--mb-bad)',\n }}\n >\n Cancel subscription\n </button>\n </section>\n )}\n </div>\n\n {/* Sticky CTA */}\n {selected && !isCurrent && (\n <StickyCtaBar respectTabBar={false}>\n <button\n type=\"button\"\n disabled={isPending}\n onClick={() => onSubscribe(selected.id)}\n className=\"flex h-12 w-full items-center justify-center gap-2 rounded-2xl text-md font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {isPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <>\n {currentPlanId ? 'Switch to' : 'Subscribe to'} {selected.name}\n <ArrowRight className=\"size-4\" />\n </>\n )}\n </button>\n </StickyCtaBar>\n )}\n </div>\n );\n}\n\nfunction FeatureRows({\n features,\n}: {\n features: Record<string, boolean | string | number>;\n}) {\n const rows = Object.entries(features).filter(\n ([, v]) => v !== false && v != null,\n );\n if (rows.length === 0) {\n return (\n <p className=\"text-xs\" style={{ color: 'var(--mb-text-tertiary)' }}>\n Standard features included.\n </p>\n );\n }\n return (\n <div\n className=\"rounded-2xl border\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n {rows.map(([key, value], i) => (\n <div\n key={key}\n className=\"flex items-center gap-3 px-4 py-3\"\n style={{\n borderTop: i === 0 ? 'none' : '1px solid var(--mb-border)',\n }}\n >\n <Check\n className=\"size-4 shrink-0\"\n style={{ color: 'var(--mb-good)' }}\n />\n <p className=\"flex-1 text-sm\" style={{ color: 'var(--mb-text)' }}>\n {humanizeKey(key)}\n {typeof value !== 'boolean' && value !== '' && (\n <span style={{ color: 'var(--mb-text-tertiary)' }}>\n {' '}\n · {String(value)}\n </span>\n )}\n </p>\n </div>\n ))}\n </div>\n );\n}\n\nfunction humanizeKey(k: string) {\n return k\n .replace(/[_-]+/g, ' ')\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n .replace(/^./, (c) => c.toUpperCase());\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Credits hub (replaces messaging + email tabs on mobile)\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileBillingCreditsScreenProps {\n channel: 'messaging' | 'email';\n messagingCredits: MessagingCreditsInfo | null | undefined;\n emailCredits: EmailCreditsInfo | null | undefined;\n onTopUpMessaging: () => void;\n onTopUpEmail: () => void;\n onBack: () => void;\n}\n\nexport function MobileBillingCreditsScreen({\n channel,\n messagingCredits,\n emailCredits,\n onTopUpMessaging,\n onTopUpEmail,\n onBack,\n}: MobileBillingCreditsScreenProps) {\n const isMessaging = channel === 'messaging';\n const info = isMessaging ? messagingCredits : emailCredits;\n const onTopUp = isMessaging ? onTopUpMessaging : onTopUpEmail;\n const title = isMessaging ? 'Messaging credits' : 'Email credits';\n\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title={title} onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: stickyCtaScrollPadding(false) }}\n >\n {/* Balance hero */}\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <p\n className=\"text-2xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Available balance\n </p>\n <p\n className=\"mt-1 text-5xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {(info?.balance ?? 0).toLocaleString()}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {isMessaging\n ? `1 credit ≈ 1 ${(phoneChannelsLabel() ?? 'SMS / WhatsApp').replace(' / ', ' or 1 ')} message`\n : '1 credit = 1 email send'}\n </p>\n {info?.isLowBalance && (\n <div\n className=\"mt-3 flex items-center gap-2 rounded-2xl border p-4 text-2xs\"\n style={{\n borderColor:\n 'color-mix(in srgb, var(--mb-warn) 36%, transparent)',\n background:\n 'color-mix(in srgb, var(--mb-warn) 10%, transparent)',\n color: 'var(--mb-warn)',\n }}\n >\n <AlertTriangle />\n Low balance — top up to keep sending\n </div>\n )}\n </section>\n\n {/* Channel meters */}\n <section className=\"mt-6 space-y-3\">\n {isMessaging ? (\n <>\n {!BOX_HIDE_SMS && (\n <ChannelRow\n icon={Smartphone}\n label=\"SMS\"\n balance={info?.balance ?? 0}\n allowance={info?.monthlyAllowance ?? 0}\n used={info?.usedThisPeriod ?? 0}\n color=\"var(--mb-warn)\"\n />\n )}\n {!BOX_HIDE_WHATSAPP && (\n <ChannelRow\n icon={MessageSquare}\n label=\"WhatsApp\"\n balance={info?.balance ?? 0}\n allowance={info?.monthlyAllowance ?? 0}\n used={info?.usedThisPeriod ?? 0}\n color=\"var(--mb-good)\"\n />\n )}\n </>\n ) : (\n <ChannelRow\n icon={Mail}\n label=\"Email\"\n balance={info?.balance ?? 0}\n allowance={info?.monthlyAllowance ?? 0}\n used={info?.usedThisPeriod ?? 0}\n color=\"var(--mb-accent)\"\n />\n )}\n </section>\n\n {/* Period summary */}\n <section className=\"mt-6 grid grid-cols-2 gap-2\">\n <StatTile\n label=\"Used this period\"\n value={(info?.usedThisPeriod ?? 0).toLocaleString()}\n />\n <StatTile\n label=\"Monthly allowance\"\n value={(info?.monthlyAllowance ?? 0).toLocaleString()}\n />\n <StatTile\n label=\"Total purchased\"\n value={(info?.totalPurchased ?? 0).toLocaleString()}\n />\n <StatTile\n label=\"Resets\"\n value={\n info?.nextResetDate\n ? new Date(info.nextResetDate).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n })\n : '—'\n }\n />\n </section>\n </div>\n\n {/* Sticky CTA */}\n <StickyCtaBar respectTabBar={false}>\n <button\n type=\"button\"\n onClick={onTopUp}\n className=\"flex h-12 w-full items-center justify-center gap-2 rounded-2xl text-md font-semibold\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n <Plus className=\"size-4\" />\n Top up {isMessaging ? 'messaging' : 'email'} credits\n </button>\n </StickyCtaBar>\n </div>\n );\n}\n\nfunction ChannelRow({\n icon: Icon,\n label,\n balance,\n allowance,\n used,\n color,\n}: {\n icon: React.ComponentType<{\n className?: string;\n style?: React.CSSProperties;\n }>;\n label: string;\n balance: number;\n allowance: number;\n used: number;\n color: string;\n}) {\n const denom = Math.max(allowance, balance + used, 1);\n const pct = Math.max(0, Math.min(100, Math.round((balance / denom) * 100)));\n return (\n <div\n className=\"rounded-2xl border p-4\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n <div className=\"flex items-center gap-3\">\n <div\n className=\"flex h-9 w-9 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Icon className=\"h-4 w-4\" style={{ color }} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p\n className=\"text-sm font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n {label}\n </p>\n <p\n className=\"mt-0.5 text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {used.toLocaleString()} used this month\n </p>\n </div>\n <p\n className=\"text-base font-bold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {balance.toLocaleString()}\n </p>\n </div>\n <div\n className=\"mt-3 h-1.5 w-full overflow-hidden rounded-full\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <div\n style={{\n width: `${pct}%`,\n background: color,\n height: '100%',\n }}\n />\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Top-up — full screen (mockup: BillingTopUpSheet)\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype TopUpChannel = 'email' | 'sms' | 'whatsapp';\n\ninterface MobileBillingTopUpScreenProps {\n open: boolean;\n onClose: () => void;\n initialChannel: TopUpChannel;\n messagingPacks: CreditPack[];\n emailPacks: EmailCreditPack[];\n isPendingMessaging: boolean;\n isPendingEmail: boolean;\n onPurchaseMessaging: (credits: number) => void;\n onPurchaseEmail: (credits: number) => void;\n formatCurrency: (n: number) => string;\n}\n\nexport function MobileBillingTopUpScreen({\n open,\n onClose,\n initialChannel,\n messagingPacks,\n emailPacks,\n isPendingMessaging,\n isPendingEmail,\n onPurchaseMessaging,\n onPurchaseEmail,\n formatCurrency,\n}: MobileBillingTopUpScreenProps) {\n // A channel the box has taken away is never the one the screen opens on.\n const [channel, setChannel] = useState<TopUpChannel>(\n (initialChannel === 'sms' && BOX_HIDE_SMS) ||\n (initialChannel === 'whatsapp' && BOX_HIDE_WHATSAPP)\n ? 'email'\n : initialChannel,\n );\n const isEmail = channel === 'email';\n const packs = isEmail ? emailPacks : messagingPacks;\n\n const [selectedCredits, setSelectedCredits] = useState<number | null>(null);\n\n // Sync channel when the screen is (re)opened from a different entry point.\n React.useEffect(() => {\n if (open) setChannel(initialChannel);\n }, [open, initialChannel]);\n\n // Default-select the second pack (Best value) whenever the channel changes\n // or the pack list refreshes.\n React.useEffect(() => {\n if (packs.length === 0) {\n setSelectedCredits(null);\n return;\n }\n setSelectedCredits(packs[1]?.credits ?? packs[0].credits);\n }, [channel, packs]);\n\n const selected = packs.find((p) => p.credits === selectedCredits);\n const subtotal = selected?.priceNgn ?? 0;\n const vat = Math.round(subtotal * 0.075 * 100) / 100;\n const total = subtotal + vat;\n const isPending = isEmail ? isPendingEmail : isPendingMessaging;\n\n if (!open) return null;\n\n return (\n <div\n className=\"fixed inset-0 z-[90] flex flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Top up\" onBack={onClose} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: stickyCtaScrollPadding(false) }}\n >\n {/* Channel */}\n <section className=\"mt-6\">\n <Caption>Channel</Caption>\n <div\n className={`mt-2 grid gap-2 ${\n ['', 'grid-cols-1', 'grid-cols-2', 'grid-cols-3'][\n 1 + (BOX_HIDE_SMS ? 0 : 1) + (BOX_HIDE_WHATSAPP ? 0 : 1)\n ]\n }`}\n >\n <ChannelPill\n icon={Mail}\n label=\"Email\"\n active={channel === 'email'}\n onClick={() => setChannel('email')}\n />\n {!BOX_HIDE_SMS && (\n <ChannelPill\n icon={MessageCircle}\n label=\"SMS\"\n active={channel === 'sms'}\n onClick={() => setChannel('sms')}\n />\n )}\n {!BOX_HIDE_WHATSAPP && (\n <ChannelPill\n icon={MessageSquare}\n label=\"WhatsApp\"\n active={channel === 'whatsapp'}\n onClick={() => setChannel('whatsapp')}\n />\n )}\n </div>\n </section>\n\n {/* Packs */}\n <section className=\"mt-6 space-y-2\">\n <Caption>Choose pack</Caption>\n {packs.length === 0 ? (\n <p\n className=\"rounded-2xl border p-4 text-center text-xs\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n color: 'var(--mb-text-tertiary)',\n }}\n >\n No packs available right now.\n </p>\n ) : (\n packs.map((p, i) => {\n const isActive = p.credits === selectedCredits;\n const badge = i === 1 ? 'Best value' : null;\n return (\n <button\n key={`${p.label}-${p.credits}`}\n type=\"button\"\n onClick={() => setSelectedCredits(p.credits)}\n className=\"flex w-full items-center justify-between gap-3 rounded-2xl border p-4 text-left\"\n style={{\n borderColor: isActive\n ? 'var(--mb-accent)'\n : 'var(--mb-border)',\n background: isActive\n ? 'color-mix(in srgb, var(--mb-accent) 8%, transparent)'\n : 'var(--mb-card)',\n }}\n >\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <p\n className=\"text-md font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n {p.label}\n </p>\n {badge && (\n <span\n className=\"rounded-full px-2 py-0.5 text-3xs font-semibold\"\n style={{\n background:\n 'color-mix(in srgb, var(--mb-good) 16%, transparent)',\n color: 'var(--mb-good)',\n }}\n >\n {badge}\n </span>\n )}\n </div>\n <p\n className=\"mt-0.5 text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {p.credits.toLocaleString()} credits\n </p>\n </div>\n <p\n className=\"text-lg font-bold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {formatCurrency(p.priceNgn)}\n </p>\n </button>\n );\n })\n )}\n </section>\n\n {/* Summary */}\n {selected && (\n <section\n className=\"mt-6 rounded-2xl border\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <SummaryRow\n label={`${selected.label} pack`}\n value={formatCurrency(subtotal)}\n />\n <RowDivider />\n <SummaryRow label=\"VAT (7.5%)\" value={formatCurrency(vat)} />\n <RowDivider />\n <SummaryRow label=\"Total\" value={formatCurrency(total)} emphasis />\n </section>\n )}\n </div>\n\n {/* Sticky Pay CTA — floating card variant */}\n <StickyCtaBar\n respectTabBar={false}\n className=\"px-3\"\n style={{ background: 'transparent' }}\n >\n <div\n className=\"rounded-[26px] border p-2\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'color-mix(in srgb, var(--mb-card) 95%, transparent)',\n backdropFilter: 'blur(12px)',\n WebkitBackdropFilter: 'blur(12px)',\n }}\n >\n <button\n type=\"button\"\n disabled={isPending || !selected}\n onClick={() => {\n if (!selected) return;\n if (isEmail) onPurchaseEmail(selected.credits);\n else onPurchaseMessaging(selected.credits);\n }}\n className=\"flex h-12 w-full items-center justify-center gap-2 rounded-2xl text-md font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {isPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <>\n Pay {selected ? formatCurrency(total) : ''}\n <ArrowRight className=\"size-4\" />\n </>\n )}\n </button>\n </div>\n </StickyCtaBar>\n </div>\n );\n}\n\nfunction ChannelPill({\n icon: Icon,\n label,\n active,\n onClick,\n}: {\n icon: React.ComponentType<{ className?: string }>;\n label: string;\n active?: boolean;\n onClick?: () => void;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"flex h-16 flex-col items-center justify-center gap-1 rounded-2xl border text-2xs font-semibold\"\n style={{\n borderColor: active ? 'var(--mb-accent)' : 'var(--mb-border)',\n background: active\n ? 'color-mix(in srgb, var(--mb-accent) 10%, transparent)'\n : 'var(--mb-card)',\n color: active ? 'var(--mb-accent)' : 'var(--mb-text-secondary)',\n }}\n >\n <Icon className=\"h-4 w-4\" />\n {label}\n </button>\n );\n}\n\nfunction SummaryRow({\n label,\n value,\n emphasis,\n}: {\n label: string;\n value: string;\n emphasis?: boolean;\n}) {\n return (\n <div className=\"flex items-center justify-between px-4 py-3\">\n <span\n className=\"text-xs\"\n style={{\n color: emphasis ? 'var(--mb-text)' : 'var(--mb-text-tertiary)',\n fontWeight: emphasis ? 600 : 400,\n }}\n >\n {label}\n </span>\n <span\n className=\"tabular-nums\"\n style={{\n color: 'var(--mb-text)',\n fontSize: emphasis ? 15 : 13,\n fontWeight: emphasis ? 700 : 500,\n }}\n >\n {value}\n </span>\n </div>\n );\n}\n\nfunction RowDivider() {\n return <div style={{ height: 1, background: 'var(--mb-border)' }} />;\n}\n\nfunction formatMobileMinorCurrency(\n valueCents: number,\n currency: string,\n formatCurrency: (n: number, c?: string) => string,\n) {\n return formatCurrency(Math.round(valueCents / 100), currency);\n}\n\nfunction formatMobileBps(bps: number) {\n return `${(bps / 100).toFixed(bps % 100 === 0 ? 0 : 2)}%`;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Invoices\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileBillingInvoicesScreenProps {\n invoices: Invoice[];\n loading: boolean;\n subscription: Subscription | null | undefined;\n onDownload: (id: string, num: string) => void;\n onBack: () => void;\n formatCurrency: (n: number, c?: string) => string;\n}\n\nexport function MobileBillingInvoicesScreen({\n invoices,\n loading,\n subscription,\n onDownload,\n onBack,\n formatCurrency,\n}: MobileBillingInvoicesScreenProps) {\n const plan = subscription?.plan;\n const planPrice = plan ? (pickPlanPrice(plan.prices)?.amount ?? 0) : 0;\n const renewsAt = subscription?.currentPeriod?.end;\n\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Invoices\" onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: MOBILE_BOTTOM_OFFSET_MIN }}\n >\n {/* Current cycle */}\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <p\n className=\"text-2xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Current cycle\n </p>\n <p\n className=\"mt-1 text-4xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {plan ? formatCurrency(planPrice) : '—'}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {renewsAt\n ? `Next invoice · ${new Date(renewsAt).toLocaleDateString(undefined, { month: 'short', day: 'numeric' })}`\n : 'No upcoming invoice'}\n </p>\n </section>\n\n {/* List */}\n <section className=\"mt-6 space-y-2\">\n <Caption>Documents</Caption>\n {loading ? (\n <p\n className=\"py-6 text-center text-xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Loading…\n </p>\n ) : invoices.length === 0 ? (\n <EmptyCard\n icon={Receipt}\n title=\"No invoices yet\"\n hint=\"Once you're billed, your receipts will appear here\"\n />\n ) : (\n invoices.map((inv) => (\n <button\n key={inv.id}\n type=\"button\"\n onClick={() => onDownload(inv.id, inv.invoiceNumber)}\n className=\"flex w-full items-center gap-3 rounded-2xl border p-4 text-left\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <div\n className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Receipt\n className=\"size-4\"\n style={{ color: 'var(--mb-text-secondary)' }}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p\n className=\"truncate text-sm font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n {inv.invoiceNumber}\n </p>\n <p\n className=\"mt-0.5 truncate text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {new Date(inv.createdAt).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}\n {' · '}\n <span style={{ textTransform: 'capitalize' }}>\n {inv.status}\n </span>\n </p>\n </div>\n <div className=\"flex shrink-0 flex-col items-end gap-1\">\n <p\n className=\"text-md font-semibold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {formatCurrency(inv.amounts.total, inv.amounts.currency)}\n </p>\n <Download style={{ color: 'var(--mb-text-muted)' }} />\n </div>\n </button>\n ))\n )}\n </section>\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Usage / history\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileBillingUsageScreenProps {\n onBack: () => void;\n}\n\nexport function MobileBillingUsageScreen({\n onBack,\n}: MobileBillingUsageScreenProps) {\n const {\n loading,\n transactions,\n transactionTotal,\n usageStats,\n formatDate,\n getTransactionTypeLabel,\n getTransactionIcon,\n } = useMessagingData();\n\n const [period, setPeriod] = useState<'7d' | '30d' | '90d'>('30d');\n\n const totalSends =\n (usageStats?.smsCount ?? 0) + (usageStats?.whatsappCount ?? 0);\n const totalSpend =\n (usageStats?.smsCredits ?? 0) + (usageStats?.whatsappCredits ?? 0);\n\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Usage\" onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: MOBILE_BOTTOM_OFFSET_MIN }}\n >\n {/* Period chips */}\n <div\n className=\"mt-3 flex gap-1 rounded-full p-1\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n {(['7d', '30d', '90d'] as const).map((k) => (\n <button\n key={k}\n type=\"button\"\n onClick={() => setPeriod(k)}\n className=\"flex-1 rounded-full px-2 py-1.5 text-xs font-medium\"\n style={{\n background: period === k ? 'var(--mb-card)' : 'transparent',\n color:\n period === k ? 'var(--mb-text)' : 'var(--mb-text-tertiary)',\n }}\n >\n {k === '7d'\n ? 'Last 7 days'\n : k === '30d'\n ? 'Last 30 days'\n : 'Last 90 days'}\n </button>\n ))}\n </div>\n\n {/* Spend hero */}\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <p\n className=\"text-2xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Credits used\n </p>\n <p\n className=\"mt-1 text-4xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {totalSpend.toLocaleString()}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {totalSends.toLocaleString()} sends · {transactionTotal} ledger\n entries\n </p>\n </section>\n\n {/* By channel */}\n <section className=\"mt-6 space-y-3\">\n <Caption>By channel</Caption>\n {!BOX_HIDE_SMS && (\n <BreakdownBar\n label=\"SMS\"\n sends={usageStats?.smsCount ?? 0}\n credits={usageStats?.smsCredits ?? 0}\n total={totalSpend}\n color=\"var(--mb-warn)\"\n />\n )}\n {!BOX_HIDE_WHATSAPP && (\n <BreakdownBar\n label=\"WhatsApp\"\n sends={usageStats?.whatsappCount ?? 0}\n credits={usageStats?.whatsappCredits ?? 0}\n total={totalSpend}\n color=\"var(--mb-good)\"\n />\n )}\n </section>\n\n {/* Recent activity */}\n <section className=\"mt-6 space-y-2\">\n <Caption>Recent activity</Caption>\n {loading ? (\n <p\n className=\"py-6 text-center text-xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Loading…\n </p>\n ) : transactions.length === 0 ? (\n <EmptyCard\n icon={TrendingUp}\n title=\"No activity yet\"\n hint=\"Send a campaign or top up to see ledger entries here\"\n />\n ) : (\n transactions\n .slice(0, 12)\n .map((tx) => (\n <ActivityRow\n key={tx.id}\n tx={tx}\n formatDate={formatDate}\n getLabel={getTransactionTypeLabel}\n getIcon={getTransactionIcon}\n />\n ))\n )}\n </section>\n </div>\n </div>\n );\n}\n\nfunction BreakdownBar({\n label,\n sends,\n credits,\n total,\n color,\n}: {\n label: string;\n sends: number;\n credits: number;\n total: number;\n color: string;\n}) {\n const pct =\n total > 0\n ? Math.max(0, Math.min(100, Math.round((credits / total) * 100)))\n : 0;\n return (\n <div\n className=\"rounded-2xl border p-4\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n <div className=\"flex items-center justify-between text-xs\">\n <span style={{ color: 'var(--mb-text)' }}>{label}</span>\n <span\n className=\"tabular-nums\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {sends.toLocaleString()} sends · {credits.toLocaleString()} credits\n </span>\n </div>\n <div\n className=\"mt-2 h-1.5 w-full overflow-hidden rounded-full\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <div style={{ width: `${pct}%`, background: color, height: '100%' }} />\n </div>\n </div>\n );\n}\n\nfunction ActivityRow({\n tx,\n formatDate,\n getLabel,\n getIcon,\n}: {\n tx: CreditTransaction;\n formatDate: (s: string) => string;\n getLabel: (t: string) => string;\n getIcon: (t: string) => React.ComponentType<{ className?: string }>;\n}) {\n const Icon = getIcon(tx.type);\n const isAdd = tx.amount > 0;\n return (\n <div\n className=\"flex items-center gap-3 rounded-2xl border p-4\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n <div\n className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Icon className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p\n className=\"truncate text-sm font-medium\"\n style={{ color: 'var(--mb-text)' }}\n >\n {getLabel(tx.type)}\n </p>\n <p\n className=\"mt-0.5 truncate text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {tx.description || formatDate(tx.createdAt)}\n </p>\n </div>\n <p\n className=\"text-sm font-semibold tabular-nums\"\n style={{\n color: isAdd ? 'var(--mb-good)' : 'var(--mb-text)',\n }}\n >\n {isAdd ? '+' : ''}\n {tx.amount.toLocaleString()}\n </p>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Rates and fee ledger\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst MOBILE_FEE_CATEGORIES: Array<{ value: BusinessCategory; label: string }> =\n [\n { value: 'selling', label: 'Selling' },\n { value: 'bookings', label: 'Bookings' },\n { value: 'digital', label: 'Digital' },\n { value: 'consultations', label: 'Consultations' },\n { value: 'events', label: 'Events' },\n ];\n\ninterface MobileBillingRatesScreenProps {\n policy: CurrentPricingPolicyResponse | undefined;\n ledgerSummary: BillingLedgerSummaryResponse | undefined;\n policyLoading: boolean;\n ledgerLoading: boolean;\n previewResult: FeePreviewResponse | undefined;\n previewPending: boolean;\n onPreview: (payload: FeePreviewRequest) => void;\n onBack: () => void;\n formatCurrency: (n: number, c?: string) => string;\n}\n\nexport function MobileBillingRatesScreen({\n policy,\n ledgerSummary,\n policyLoading,\n ledgerLoading,\n previewResult,\n previewPending,\n onPreview,\n onBack,\n formatCurrency,\n}: MobileBillingRatesScreenProps) {\n const [category, setCategory] = useState<BusinessCategory>('selling');\n const [amount, setAmount] = useState('10000');\n const currency =\n policy?.policy.currency ?? ledgerSummary?.context.currency ?? 'NGN';\n const selectedRule = policy?.policy.rules.platform_fee[category];\n const totals = previewResult?.calculation.totals;\n\n const runPreview = () => {\n const amountValue = Number(amount.replace(/,/g, ''));\n if (!Number.isFinite(amountValue) || amountValue < 0) return;\n onPreview({\n lineItems: [\n {\n id: 'mobile-preview',\n category,\n grossCents: Math.round(amountValue * 100),\n },\n ],\n });\n };\n\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Rates\" onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: MOBILE_BOTTOM_OFFSET_MIN }}\n >\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor:\n 'color-mix(in srgb, var(--mb-accent) 28%, transparent)',\n background: 'color-mix(in srgb, var(--mb-accent) 8%, transparent)',\n }}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p\n className=\"text-2xs font-medium\"\n style={{ color: 'var(--mb-accent)' }}\n >\n {policyLoading\n ? 'Loading policy'\n : `Policy v${policy?.policy.version ?? '—'}`}\n </p>\n <p\n className=\"mt-1 text-4xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {selectedRule ? formatMobileBps(selectedRule.rate_bps) : '—'}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {policy\n ? `${policy.policy.region} · ${policy.policy.tier} · ${currency}`\n : 'Current business rate'}\n </p>\n </div>\n <div\n className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Percent\n className=\"size-5\"\n style={{ color: 'var(--mb-accent)' }}\n />\n </div>\n </div>\n </section>\n\n <section className=\"mt-6 space-y-3\">\n <Caption>Preview</Caption>\n <div\n className=\"rounded-2xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <div className=\"grid grid-cols-2 gap-2\">\n <div\n className=\"text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Category\n <Select\n value={category}\n onChange={(next) => setCategory(next as BusinessCategory)}\n options={MOBILE_FEE_CATEGORIES}\n ariaLabel=\"Category\"\n searchable={MOBILE_FEE_CATEGORIES.length > 15}\n className=\"mt-1.5\"\n />\n </div>\n <label\n className=\"text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Amount\n <Input\n value={amount}\n onChange={(event) => setAmount(event.target.value)}\n inputMode=\"decimal\"\n className=\"h-11 w-full\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-elevated)',\n color: 'var(--mb-text)',\n }}\n />\n </label>\n </div>\n <button\n type=\"button\"\n disabled={!policy || previewPending}\n onClick={runPreview}\n className=\"mt-3 flex h-11 w-full items-center justify-center gap-2 rounded-2xl text-sm font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {previewPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Calculator className=\"size-4\" />\n )}\n Calculate fees\n </button>\n </div>\n </section>\n\n {totals && (\n <section className=\"mt-6 grid grid-cols-2 gap-2\">\n <StatTile\n label=\"Platform fee\"\n value={formatMobileMinorCurrency(\n totals.platformFeeCents,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"Settlement\"\n value={formatMobileMinorCurrency(\n totals.settlementFeeCents,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"VAT\"\n value={formatMobileMinorCurrency(\n totals.vatCents,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"Total fees\"\n value={formatMobileMinorCurrency(\n totals.platformFeeCents +\n totals.settlementFeeCents +\n totals.vatCents,\n currency,\n formatCurrency,\n )}\n />\n </section>\n )}\n\n <section className=\"mt-6 grid grid-cols-2 gap-2\">\n <StatTile\n label=\"Gross tracked\"\n value={formatMobileMinorCurrency(\n ledgerSummary?.totals.grossCents ?? 0,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"Platform fees\"\n value={formatMobileMinorCurrency(\n ledgerSummary?.totals.platformFeeCents ?? 0,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"Rev share\"\n value={formatMobileMinorCurrency(\n ledgerSummary?.totals.revShareCents ?? 0,\n currency,\n formatCurrency,\n )}\n />\n <StatTile\n label=\"Entries\"\n value={\n ledgerLoading\n ? '…'\n : (ledgerSummary?.totals.feeLedgerEntries ?? 0).toLocaleString()\n }\n />\n </section>\n\n <section className=\"mt-6 space-y-2\">\n <Caption>Recent fees</Caption>\n {(ledgerSummary?.recentFees ?? []).slice(0, 8).map((fee) => (\n <div\n key={fee.id}\n className=\"flex items-center gap-3 rounded-2xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <div\n className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Landmark\n className=\"size-4\"\n style={{ color: 'var(--mb-text-secondary)' }}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p\n className=\"truncate text-sm font-medium capitalize\"\n style={{ color: 'var(--mb-text)' }}\n >\n {fee.category}\n </p>\n <p\n className=\"mt-0.5 truncate text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {new Date(fee.createdAt).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n })}\n </p>\n </div>\n <p\n className=\"text-sm font-semibold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {formatMobileMinorCurrency(\n fee.platformFeeCents + fee.vatCents,\n currency,\n formatCurrency,\n )}\n </p>\n </div>\n ))}\n {!ledgerLoading && (ledgerSummary?.recentFees.length ?? 0) === 0 && (\n <EmptyCard\n icon={Receipt}\n title=\"No fees yet\"\n hint=\"Paid orders and bookings will appear here\"\n />\n )}\n </section>\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Payment methods\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileBillingPaymentMethodsScreenProps {\n paymentMethods: PaymentMethod[] | undefined;\n loading: boolean;\n onAdd: () => void;\n addPending: boolean;\n onRemove: (id: string) => void;\n removePending: boolean;\n deletingId: string | null;\n onSetDeletingId: (id: string | null) => void;\n onSetDefault: (id: string) => void;\n onBack: () => void;\n}\n\nexport function MobileBillingPaymentMethodsScreen({\n paymentMethods,\n loading,\n onAdd,\n addPending,\n onRemove,\n removePending,\n deletingId,\n onSetDeletingId,\n onSetDefault,\n onBack,\n}: MobileBillingPaymentMethodsScreenProps) {\n const list = paymentMethods ?? [];\n return (\n <div\n className=\"flex min-h-dvh flex-col\"\n style={{ background: 'var(--mb-canvas)' }}\n >\n <BackBar title=\"Payment method\" onBack={onBack} />\n\n <div\n className=\"flex-1 overflow-y-auto px-4\"\n style={{ paddingBottom: stickyCtaScrollPadding(false) }}\n >\n <section className=\"mt-6 space-y-2\">\n {loading ? (\n <p\n className=\"py-6 text-center text-xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Loading…\n </p>\n ) : list.length === 0 ? (\n <EmptyCard\n icon={CreditCard}\n title=\"No payment methods\"\n hint=\"Add a card to keep your plan active\"\n />\n ) : (\n list.map((pm) => (\n <div\n key={pm.id}\n className=\"flex items-center gap-3 rounded-2xl border p-4\"\n style={{\n borderColor: pm.isDefault\n ? 'var(--mb-accent)'\n : 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <div\n className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <CreditCard\n className=\"size-4\"\n style={{ color: 'var(--mb-text-secondary)' }}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <p\n className=\"truncate text-sm font-semibold capitalize\"\n style={{ color: 'var(--mb-text)' }}\n >\n {pm.card?.brand ?? pm.type} ····{pm.card?.last4 ?? '••••'}\n </p>\n {pm.isDefault && (\n <span\n className=\"rounded-full px-2 py-0.5 text-3xs font-semibold\"\n style={{\n background:\n 'color-mix(in srgb, var(--mb-good) 16%, transparent)',\n color: 'var(--mb-good)',\n }}\n >\n Default\n </span>\n )}\n {pm.isExpired && (\n <span\n className=\"rounded-full px-2 py-0.5 text-3xs font-semibold\"\n style={{\n background:\n 'color-mix(in srgb, var(--mb-bad) 14%, transparent)',\n color: 'var(--mb-bad)',\n }}\n >\n Expired\n </span>\n )}\n </div>\n {pm.card && (\n <p\n className=\"mt-0.5 truncate text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Expires {String(pm.card.expMonth).padStart(2, '0')}/\n {String(pm.card.expYear).slice(-2)}\n </p>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-1\">\n {!pm.isDefault && (\n <button\n type=\"button\"\n onClick={() => onSetDefault(pm.id)}\n aria-label=\"Set default\"\n className=\"flex h-8 w-8 items-center justify-center rounded-full\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Star style={{ color: 'var(--mb-text-secondary)' }} />\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => onSetDeletingId(pm.id)}\n aria-label=\"Remove\"\n className=\"flex h-8 w-8 items-center justify-center rounded-full\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Trash2 style={{ color: 'var(--mb-bad)' }} />\n </button>\n </div>\n </div>\n ))\n )}\n </section>\n </div>\n\n {/* Sticky add CTA */}\n <StickyCtaBar respectTabBar={false}>\n <button\n type=\"button\"\n disabled={addPending}\n onClick={onAdd}\n className=\"flex h-12 w-full items-center justify-center gap-2 rounded-2xl text-md font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {addPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <>\n <Plus className=\"size-4\" />\n Add payment method\n </>\n )}\n </button>\n </StickyCtaBar>\n\n {/* Confirm remove sheet */}\n <BottomSheet open={!!deletingId} onClose={() => onSetDeletingId(null)}>\n <div className=\"px-1 pb-1\">\n <p\n className=\"text-base font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n Remove this payment method?\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n You can add a new card any time. If this is your default, your\n subscription may fail to renew.\n </p>\n <div className=\"mt-4 flex gap-2\">\n <button\n type=\"button\"\n onClick={() => onSetDeletingId(null)}\n className=\"flex h-11 flex-1 items-center justify-center rounded-2xl text-sm font-medium\"\n style={{\n background: 'var(--mb-elevated)',\n color: 'var(--mb-text)',\n }}\n >\n Keep\n </button>\n <button\n type=\"button\"\n disabled={removePending}\n onClick={() => deletingId && onRemove(deletingId)}\n className=\"flex h-11 flex-1 items-center justify-center gap-2 rounded-2xl text-sm font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-bad)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {removePending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n 'Remove'\n )}\n </button>\n </div>\n </div>\n </BottomSheet>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Cancel subscription bottom sheet\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface MobileCancelSubscriptionSheetProps {\n open: boolean;\n onClose: () => void;\n onConfirm: (reason?: string) => void;\n isPending: boolean;\n endsAt?: string | null;\n}\n\nexport function MobileCancelSubscriptionSheet({\n open,\n onClose,\n onConfirm,\n isPending,\n endsAt,\n}: MobileCancelSubscriptionSheetProps) {\n const [reason, setReason] = useState('');\n return (\n <BottomSheet open={open} onClose={onClose}>\n <div className=\"px-1 pb-1\">\n <p\n className=\"text-base font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n Cancel subscription?\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n You&apos;ll keep access until\n {endsAt\n ? ` ${new Date(endsAt).toLocaleDateString()}`\n : ' the end of the current period'}\n . You can reactivate any time before then.\n </p>\n\n <label\n className=\"mt-4 block text-2xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Reason (optional)\n </label>\n <TextField\n className=\"mt-1\"\n multiline\n value={reason}\n onChange={setReason}\n placeholder=\"Help us improve…\"\n />\n\n <div className=\"mt-4 flex gap-2\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"flex h-11 flex-1 items-center justify-center rounded-2xl text-sm font-medium\"\n style={{\n background: 'var(--mb-elevated)',\n color: 'var(--mb-text)',\n }}\n >\n Keep plan\n </button>\n <button\n type=\"button\"\n disabled={isPending}\n onClick={() => onConfirm(reason.trim() || undefined)}\n className=\"flex h-11 flex-1 items-center justify-center gap-2 rounded-2xl text-sm font-semibold disabled:opacity-60\"\n style={{\n background: 'var(--mb-bad)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n {isPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n 'Confirm cancel'\n )}\n </button>\n </div>\n </div>\n </BottomSheet>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Shared bits\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction Caption({ children }: { children: React.ReactNode }) {\n return (\n <p\n className=\"text-3xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {children}\n </p>\n );\n}\n\nfunction StatTile({ label, value }: { label: string; value: string }) {\n return (\n <div\n className=\"rounded-2xl border p-4\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n <p className=\"text-2xs\" style={{ color: 'var(--mb-text-tertiary)' }}>\n {label}\n </p>\n <p\n className=\"mt-1 text-base font-bold tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {value}\n </p>\n </div>\n );\n}\n\nfunction EmptyCard({\n icon: Icon,\n title,\n hint,\n}: {\n icon: React.ComponentType<{\n className?: string;\n style?: React.CSSProperties;\n }>;\n title: string;\n hint?: string;\n}) {\n return (\n <div\n className=\"rounded-2xl border p-8 text-center\"\n style={{ borderColor: 'var(--mb-border)', background: 'var(--mb-card)' }}\n >\n <Icon\n className=\"mx-auto h-8 w-8\"\n style={{ color: 'var(--mb-text-muted)' }}\n />\n <p\n className=\"mt-2 text-sm font-semibold\"\n style={{ color: 'var(--mb-text)' }}\n >\n {title}\n </p>\n {hint && (\n <p\n className=\"mt-1 text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {hint}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -2,6 +2,7 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useRouter } from "next/navigation";
4
4
  import { MobileScreenFrame } from "@withpotter/components/mobile/screen-frame-host";
5
+ import { pickPlanPrice } from "@withpotter/lib/plan-price";
5
6
  import {
6
7
  BOX_EMAIL_ONLY,
7
8
  phoneChannelsLabel
@@ -29,8 +30,7 @@ function MobileBillingScreen({
29
30
  }) {
30
31
  const router = useRouter();
31
32
  const plan = subscription?.plan;
32
- const planPriceCurrency = plan ? Object.keys(plan.prices)[0] : null;
33
- const planPrice = plan && planPriceCurrency ? plan.prices[planPriceCurrency] : 0;
33
+ const planPrice = plan ? pickPlanPrice(plan.prices)?.amount ?? 0 : 0;
34
34
  const status = subscription?.status ?? "inactive";
35
35
  const renewsAt = subscription?.currentPeriod?.end ?? null;
36
36
  const defaultPM = paymentMethods?.find((m) => m.isDefault) ?? paymentMethods?.[0];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/mobile/screens/billing.tsx"],"sourcesContent":["'use client';\n\nimport { useRouter } from 'next/navigation';\nimport { MobileScreenFrame } from '@withpotter/components/mobile/screen-frame-host';\n\n/**\n * Mobile screen — Billing hub\n *\n * Visual contract: `BillingHub` in mobile-redesign-mockups.tsx\n * Route: /dashboard/settings/billing (mobile)\n */\n\nimport React from 'react';\nimport {\n BOX_EMAIL_ONLY,\n phoneChannelsLabel,\n} from '@withpotter/lib/box-channels';\nimport {\n ChevronRight,\n CreditCard,\n Mail,\n MessageCircle,\n Percent,\n Receipt,\n Star,\n Wallet,\n} from 'lucide-react';\nimport type {\n BillingPlan,\n Subscription,\n PaymentMethod,\n MessagingCreditsInfo,\n EmailCreditsInfo,\n} from '@withpotter/pages-core/dashboard/settings/billing/_components';\n\n/**\n * The screens this drawer can send you to, named as the billing page's mobile\n * router names them.\n *\n * It used to keep its own list, and the two drifted: this file emitted\n * `subscription` and `history` where the page renders `plan` and `usage`, so two\n * of the seven rows led nowhere. Exported, and consumed by the page's own state,\n * so a name can only be wrong in one place.\n */\nexport type MobileBillingScreenKey =\n | 'overview'\n | 'plan'\n | 'messaging'\n | 'email'\n | 'invoices'\n | 'usage'\n | 'payment';\n\ninterface MobileBillingScreenProps {\n subscription: Subscription | null | undefined;\n plans?: BillingPlan[];\n paymentMethods?: PaymentMethod[];\n invoiceCount?: number;\n messagingCredits: MessagingCreditsInfo | null | undefined;\n emailCredits: EmailCreditsInfo | null | undefined;\n formatCurrency: (n: number) => string;\n onSelectTab: (tab: MobileBillingScreenKey) => void;\n onTopUpMessaging?: () => void;\n onManagePlan?: () => void;\n}\n\nexport function MobileBillingScreen({\n subscription,\n paymentMethods,\n invoiceCount,\n messagingCredits,\n emailCredits,\n formatCurrency,\n onSelectTab,\n onTopUpMessaging,\n onManagePlan,\n}: MobileBillingScreenProps) {\n const router = useRouter();\n const plan = subscription?.plan;\n const planPriceCurrency = plan ? Object.keys(plan.prices)[0] : null;\n const planPrice =\n plan && planPriceCurrency ? plan.prices[planPriceCurrency] : 0;\n const status = subscription?.status ?? 'inactive';\n const renewsAt = subscription?.currentPeriod?.end ?? null;\n const defaultPM =\n paymentMethods?.find((m) => m.isDefault) ?? paymentMethods?.[0];\n\n // Messaging credits pay for SMS and WhatsApp; an email-only box has neither.\n const totalCredits =\n (BOX_EMAIL_ONLY ? 0 : (messagingCredits?.balance ?? 0)) +\n (emailCredits?.balance ?? 0);\n\n return (\n /* The frame owns the app row, the sheet, the title and the tab bar. Every\n native screen used to draw all four itself — the same root div, the same\n `env(safe-area-inset-top)`, the same title, the same `<BottomTabBar/>`,\n thirteen times and already disagreeing on padding and title size. */\n <MobileScreenFrame title={'Billing'}>\n {/* Plan card */}\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor: 'color-mix(in srgb, var(--mb-accent) 28%, transparent)',\n background: 'color-mix(in srgb, var(--mb-accent) 8%, transparent)',\n }}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p\n className=\"text-3xs font-medium\"\n style={{ color: 'var(--mb-accent)' }}\n >\n {plan?.name ?? 'No active plan'}\n </p>\n <p\n className=\"mt-1 text-4xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {plan ? formatCurrency(planPrice) : '—'}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {renewsAt\n ? `Renews ${new Date(renewsAt).toLocaleDateString()}`\n : 'No renewal date'}\n {defaultPM?.card\n ? ` · ${defaultPM.card.brand} ending ${defaultPM.card.last4}`\n : ''}\n </p>\n </div>\n <StatusPill status={status} />\n </div>\n <button\n type=\"button\"\n onClick={onManagePlan ?? (() => onSelectTab('plan'))}\n className=\"mt-4 flex h-11 w-full items-center justify-center gap-2 rounded-2xl text-sm font-semibold\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n Manage plan\n </button>\n </section>\n\n {/* Credits card */}\n <section\n className=\"mt-4 rounded-2xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <div className=\"flex items-center justify-between\">\n <div>\n <p\n className=\"text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Credits available\n </p>\n <p\n className=\"mt-1 text-3xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {totalCredits.toLocaleString()}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={\n BOX_EMAIL_ONLY\n ? () => onSelectTab('email')\n : (onTopUpMessaging ?? (() => onSelectTab('messaging')))\n }\n className=\"rounded-full px-3 py-1.5 text-2xs font-semibold\"\n style={{\n background:\n 'color-mix(in srgb, var(--mb-accent) 15%, transparent)',\n color: 'var(--mb-accent)',\n }}\n >\n Top up\n </button>\n </div>\n <div className=\"mt-4 space-y-3\">\n <CreditMeter\n label=\"Email\"\n info={emailCredits}\n color=\"var(--mb-accent)\"\n />\n {/* Named for the phone channels the box still has; none, no meter. */}\n {phoneChannelsLabel() && (\n <CreditMeter\n label={phoneChannelsLabel()!}\n info={messagingCredits}\n color=\"var(--mb-warn)\"\n />\n )}\n </div>\n </section>\n\n {/* Tools */}\n <section className=\"mt-6\">\n <Caption>Billing tools</Caption>\n <div className=\"mt-2 space-y-2\">\n <ToolRow\n icon={Star}\n label=\"Plan\"\n hint={plan?.name ?? 'Choose a plan'}\n onClick={() => onSelectTab('plan')}\n />\n {!BOX_EMAIL_ONLY && (\n <ToolRow\n icon={MessageCircle}\n label=\"Messaging credits\"\n hint={`${(messagingCredits?.balance ?? 0).toLocaleString()} available`}\n onClick={() => onSelectTab('messaging')}\n />\n )}\n <ToolRow\n icon={Mail}\n label=\"Email credits\"\n hint={`${(emailCredits?.balance ?? 0).toLocaleString()} available`}\n onClick={() => onSelectTab('email')}\n />\n <ToolRow\n icon={Receipt}\n label=\"Statements\"\n hint={`${invoiceCount ?? 0} document${invoiceCount === 1 ? '' : 's'}`}\n onClick={() => onSelectTab('invoices')}\n />\n <ToolRow\n icon={CreditCard}\n label=\"Payment method\"\n hint={\n defaultPM?.card\n ? `${defaultPM.card.brand} ending ${defaultPM.card.last4}`\n : 'Add a card'\n }\n onClick={() => onSelectTab('payment')}\n />\n <ToolRow\n icon={Percent}\n label=\"Rates & fees\"\n hint=\"Policy, preview, ledger\"\n // Rates live on the Payments hub now — what Box charges per\n // transaction belongs beside the money it comes out of, not in\n // the billing drawer.\n onClick={() => router.push('/dashboard/payments')}\n />\n <ToolRow\n icon={Wallet}\n label=\"Usage history\"\n hint=\"Past activity\"\n onClick={() => onSelectTab('usage')}\n />\n </div>\n </section>\n </MobileScreenFrame>\n );\n}\n\n// ─────────────────────────────────────────────────────────────\n\nfunction Caption({ children }: { children: React.ReactNode }) {\n return (\n <p\n className=\"text-3xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {children}\n </p>\n );\n}\n\nfunction StatusPill({ status }: { status: string }) {\n const isActive = /active|trial/i.test(status);\n const isCancelled = /cancel/i.test(status);\n const color = isActive\n ? 'var(--mb-good)'\n : isCancelled\n ? 'var(--mb-warn)'\n : 'var(--mb-text-tertiary)';\n const bg = isActive\n ? 'color-mix(in srgb, var(--mb-good) 12%, transparent)'\n : isCancelled\n ? 'color-mix(in srgb, var(--mb-warn) 12%, transparent)'\n : 'var(--mb-elevated)';\n const border = isActive\n ? 'color-mix(in srgb, var(--mb-good) 36%, transparent)'\n : isCancelled\n ? 'color-mix(in srgb, var(--mb-warn) 36%, transparent)'\n : 'var(--mb-border)';\n return (\n <span\n className=\"rounded-full border px-2.5 py-1 text-3xs font-semibold capitalize\"\n style={{ borderColor: border, background: bg, color }}\n >\n {status || 'inactive'}\n </span>\n );\n}\n\nfunction CreditMeter({\n label,\n info,\n color,\n}: {\n label: string;\n info: MessagingCreditsInfo | EmailCreditsInfo | null | undefined;\n color: string;\n}) {\n const balance = info?.balance ?? 0;\n const allowance = info?.monthlyAllowance ?? 0;\n const denom = Math.max(allowance, balance, 1);\n const pct = Math.max(0, Math.min(100, Math.round((balance / denom) * 100)));\n return (\n <div>\n <div className=\"flex items-center justify-between text-2xs\">\n <span style={{ color: 'var(--mb-text-secondary)' }}>{label}</span>\n <span\n className=\"tabular-nums\"\n style={{ color: 'var(--mb-text)', fontWeight: 600 }}\n >\n {balance.toLocaleString()}\n </span>\n </div>\n <div\n className=\"mt-1.5 h-1.5 w-full overflow-hidden rounded-full\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <div style={{ width: `${pct}%`, background: color, height: '100%' }} />\n </div>\n </div>\n );\n}\n\nfunction ToolRow({\n icon: Icon,\n label,\n hint,\n onClick,\n}: {\n icon: React.ComponentType<{\n className?: string;\n style?: React.CSSProperties;\n }>;\n label: string;\n hint?: string;\n onClick?: () => void;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"flex w-full items-center gap-3 rounded-2xl border p-4 text-left\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n minHeight: 60,\n }}\n >\n <div\n className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Icon\n className=\"h-4 w-4\"\n style={{ color: 'var(--mb-text-secondary)' }}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p\n className=\"truncate text-sm font-medium\"\n style={{ color: 'var(--mb-text)' }}\n >\n {label}\n </p>\n {hint ? (\n <p\n className=\"mt-0.5 truncate text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {hint}\n </p>\n ) : null}\n </div>\n <ChevronRight\n className=\"size-4\"\n style={{ color: 'var(--mb-text-muted)' }}\n />\n </button>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/mobile/screens/billing.tsx"],"sourcesContent":["'use client';\n\nimport { useRouter } from 'next/navigation';\nimport { MobileScreenFrame } from '@withpotter/components/mobile/screen-frame-host';\n\n/**\n * Mobile screen — Billing hub\n *\n * Visual contract: `BillingHub` in mobile-redesign-mockups.tsx\n * Route: /dashboard/settings/billing (mobile)\n */\n\nimport React from 'react';\nimport { pickPlanPrice } from '@withpotter/lib/plan-price';\nimport {\n BOX_EMAIL_ONLY,\n phoneChannelsLabel,\n} from '@withpotter/lib/box-channels';\nimport {\n ChevronRight,\n CreditCard,\n Mail,\n MessageCircle,\n Percent,\n Receipt,\n Star,\n Wallet,\n} from 'lucide-react';\nimport type {\n BillingPlan,\n Subscription,\n PaymentMethod,\n MessagingCreditsInfo,\n EmailCreditsInfo,\n} from '@withpotter/pages-core/dashboard/settings/billing/_components';\n\n/**\n * The screens this drawer can send you to, named as the billing page's mobile\n * router names them.\n *\n * It used to keep its own list, and the two drifted: this file emitted\n * `subscription` and `history` where the page renders `plan` and `usage`, so two\n * of the seven rows led nowhere. Exported, and consumed by the page's own state,\n * so a name can only be wrong in one place.\n */\nexport type MobileBillingScreenKey =\n | 'overview'\n | 'plan'\n | 'messaging'\n | 'email'\n | 'invoices'\n | 'usage'\n | 'payment';\n\ninterface MobileBillingScreenProps {\n subscription: Subscription | null | undefined;\n plans?: BillingPlan[];\n paymentMethods?: PaymentMethod[];\n invoiceCount?: number;\n messagingCredits: MessagingCreditsInfo | null | undefined;\n emailCredits: EmailCreditsInfo | null | undefined;\n formatCurrency: (n: number) => string;\n onSelectTab: (tab: MobileBillingScreenKey) => void;\n onTopUpMessaging?: () => void;\n onManagePlan?: () => void;\n}\n\nexport function MobileBillingScreen({\n subscription,\n paymentMethods,\n invoiceCount,\n messagingCredits,\n emailCredits,\n formatCurrency,\n onSelectTab,\n onTopUpMessaging,\n onManagePlan,\n}: MobileBillingScreenProps) {\n const router = useRouter();\n const plan = subscription?.plan;\n const planPrice = plan ? (pickPlanPrice(plan.prices)?.amount ?? 0) : 0;\n const status = subscription?.status ?? 'inactive';\n const renewsAt = subscription?.currentPeriod?.end ?? null;\n const defaultPM =\n paymentMethods?.find((m) => m.isDefault) ?? paymentMethods?.[0];\n\n // Messaging credits pay for SMS and WhatsApp; an email-only box has neither.\n const totalCredits =\n (BOX_EMAIL_ONLY ? 0 : (messagingCredits?.balance ?? 0)) +\n (emailCredits?.balance ?? 0);\n\n return (\n /* The frame owns the app row, the sheet, the title and the tab bar. Every\n native screen used to draw all four itself — the same root div, the same\n `env(safe-area-inset-top)`, the same title, the same `<BottomTabBar/>`,\n thirteen times and already disagreeing on padding and title size. */\n <MobileScreenFrame title={'Billing'}>\n {/* Plan card */}\n <section\n className=\"mt-6 rounded-3xl border p-4\"\n style={{\n borderColor: 'color-mix(in srgb, var(--mb-accent) 28%, transparent)',\n background: 'color-mix(in srgb, var(--mb-accent) 8%, transparent)',\n }}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p\n className=\"text-3xs font-medium\"\n style={{ color: 'var(--mb-accent)' }}\n >\n {plan?.name ?? 'No active plan'}\n </p>\n <p\n className=\"mt-1 text-4xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {plan ? formatCurrency(planPrice) : '—'}\n </p>\n <p\n className=\"mt-1 text-xs\"\n style={{ color: 'var(--mb-text-secondary)' }}\n >\n {renewsAt\n ? `Renews ${new Date(renewsAt).toLocaleDateString()}`\n : 'No renewal date'}\n {defaultPM?.card\n ? ` · ${defaultPM.card.brand} ending ${defaultPM.card.last4}`\n : ''}\n </p>\n </div>\n <StatusPill status={status} />\n </div>\n <button\n type=\"button\"\n onClick={onManagePlan ?? (() => onSelectTab('plan'))}\n className=\"mt-4 flex h-11 w-full items-center justify-center gap-2 rounded-2xl text-sm font-semibold\"\n style={{\n background: 'var(--mb-accent)',\n color: 'var(--mb-accent-fg)',\n }}\n >\n Manage plan\n </button>\n </section>\n\n {/* Credits card */}\n <section\n className=\"mt-4 rounded-2xl border p-4\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n }}\n >\n <div className=\"flex items-center justify-between\">\n <div>\n <p\n className=\"text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n Credits available\n </p>\n <p\n className=\"mt-1 text-3xl font-bold leading-tight tabular-nums\"\n style={{ color: 'var(--mb-text)' }}\n >\n {totalCredits.toLocaleString()}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={\n BOX_EMAIL_ONLY\n ? () => onSelectTab('email')\n : (onTopUpMessaging ?? (() => onSelectTab('messaging')))\n }\n className=\"rounded-full px-3 py-1.5 text-2xs font-semibold\"\n style={{\n background:\n 'color-mix(in srgb, var(--mb-accent) 15%, transparent)',\n color: 'var(--mb-accent)',\n }}\n >\n Top up\n </button>\n </div>\n <div className=\"mt-4 space-y-3\">\n <CreditMeter\n label=\"Email\"\n info={emailCredits}\n color=\"var(--mb-accent)\"\n />\n {/* Named for the phone channels the box still has; none, no meter. */}\n {phoneChannelsLabel() && (\n <CreditMeter\n label={phoneChannelsLabel()!}\n info={messagingCredits}\n color=\"var(--mb-warn)\"\n />\n )}\n </div>\n </section>\n\n {/* Tools */}\n <section className=\"mt-6\">\n <Caption>Billing tools</Caption>\n <div className=\"mt-2 space-y-2\">\n <ToolRow\n icon={Star}\n label=\"Plan\"\n hint={plan?.name ?? 'Choose a plan'}\n onClick={() => onSelectTab('plan')}\n />\n {!BOX_EMAIL_ONLY && (\n <ToolRow\n icon={MessageCircle}\n label=\"Messaging credits\"\n hint={`${(messagingCredits?.balance ?? 0).toLocaleString()} available`}\n onClick={() => onSelectTab('messaging')}\n />\n )}\n <ToolRow\n icon={Mail}\n label=\"Email credits\"\n hint={`${(emailCredits?.balance ?? 0).toLocaleString()} available`}\n onClick={() => onSelectTab('email')}\n />\n <ToolRow\n icon={Receipt}\n label=\"Statements\"\n hint={`${invoiceCount ?? 0} document${invoiceCount === 1 ? '' : 's'}`}\n onClick={() => onSelectTab('invoices')}\n />\n <ToolRow\n icon={CreditCard}\n label=\"Payment method\"\n hint={\n defaultPM?.card\n ? `${defaultPM.card.brand} ending ${defaultPM.card.last4}`\n : 'Add a card'\n }\n onClick={() => onSelectTab('payment')}\n />\n <ToolRow\n icon={Percent}\n label=\"Rates & fees\"\n hint=\"Policy, preview, ledger\"\n // Rates live on the Payments hub now — what Box charges per\n // transaction belongs beside the money it comes out of, not in\n // the billing drawer.\n onClick={() => router.push('/dashboard/payments')}\n />\n <ToolRow\n icon={Wallet}\n label=\"Usage history\"\n hint=\"Past activity\"\n onClick={() => onSelectTab('usage')}\n />\n </div>\n </section>\n </MobileScreenFrame>\n );\n}\n\n// ─────────────────────────────────────────────────────────────\n\nfunction Caption({ children }: { children: React.ReactNode }) {\n return (\n <p\n className=\"text-3xs font-medium\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {children}\n </p>\n );\n}\n\nfunction StatusPill({ status }: { status: string }) {\n const isActive = /active|trial/i.test(status);\n const isCancelled = /cancel/i.test(status);\n const color = isActive\n ? 'var(--mb-good)'\n : isCancelled\n ? 'var(--mb-warn)'\n : 'var(--mb-text-tertiary)';\n const bg = isActive\n ? 'color-mix(in srgb, var(--mb-good) 12%, transparent)'\n : isCancelled\n ? 'color-mix(in srgb, var(--mb-warn) 12%, transparent)'\n : 'var(--mb-elevated)';\n const border = isActive\n ? 'color-mix(in srgb, var(--mb-good) 36%, transparent)'\n : isCancelled\n ? 'color-mix(in srgb, var(--mb-warn) 36%, transparent)'\n : 'var(--mb-border)';\n return (\n <span\n className=\"rounded-full border px-2.5 py-1 text-3xs font-semibold capitalize\"\n style={{ borderColor: border, background: bg, color }}\n >\n {status || 'inactive'}\n </span>\n );\n}\n\nfunction CreditMeter({\n label,\n info,\n color,\n}: {\n label: string;\n info: MessagingCreditsInfo | EmailCreditsInfo | null | undefined;\n color: string;\n}) {\n const balance = info?.balance ?? 0;\n const allowance = info?.monthlyAllowance ?? 0;\n const denom = Math.max(allowance, balance, 1);\n const pct = Math.max(0, Math.min(100, Math.round((balance / denom) * 100)));\n return (\n <div>\n <div className=\"flex items-center justify-between text-2xs\">\n <span style={{ color: 'var(--mb-text-secondary)' }}>{label}</span>\n <span\n className=\"tabular-nums\"\n style={{ color: 'var(--mb-text)', fontWeight: 600 }}\n >\n {balance.toLocaleString()}\n </span>\n </div>\n <div\n className=\"mt-1.5 h-1.5 w-full overflow-hidden rounded-full\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <div style={{ width: `${pct}%`, background: color, height: '100%' }} />\n </div>\n </div>\n );\n}\n\nfunction ToolRow({\n icon: Icon,\n label,\n hint,\n onClick,\n}: {\n icon: React.ComponentType<{\n className?: string;\n style?: React.CSSProperties;\n }>;\n label: string;\n hint?: string;\n onClick?: () => void;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"flex w-full items-center gap-3 rounded-2xl border p-4 text-left\"\n style={{\n borderColor: 'var(--mb-border)',\n background: 'var(--mb-card)',\n minHeight: 60,\n }}\n >\n <div\n className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-xl\"\n style={{ background: 'var(--mb-elevated)' }}\n >\n <Icon\n className=\"h-4 w-4\"\n style={{ color: 'var(--mb-text-secondary)' }}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p\n className=\"truncate text-sm font-medium\"\n style={{ color: 'var(--mb-text)' }}\n >\n {label}\n </p>\n {hint ? (\n <p\n className=\"mt-0.5 truncate text-2xs\"\n style={{ color: 'var(--mb-text-tertiary)' }}\n >\n {hint}\n </p>\n ) : null}\n </div>\n <ChevronRight\n className=\"size-4\"\n style={{ color: 'var(--mb-text-muted)' }}\n />\n </button>\n );\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withpotter/components",
3
- "version": "0.13.0-next.85",
3
+ "version": "0.13.0-next.86",
4
4
  "description": "Box dashboard feature components: editors, mobile screens, pickers, and composite UI built on @withpotter/ui-kit.",
5
5
  "license": "UNLICENSED",
6
6
  "sideEffects": [
@@ -50,9 +50,9 @@
50
50
  "@tiptap/react": "^3.22.5",
51
51
  "@tiptap/starter-kit": "^3.22.5",
52
52
  "@tiptap/suggestion": "^3.22.5",
53
- "@withpotter/hooks": "^0.13.0-next.85",
54
- "@withpotter/lib": "^0.13.0-next.85",
55
- "@withpotter/ui-kit": "^0.13.0-next.85",
53
+ "@withpotter/hooks": "^0.13.0-next.86",
54
+ "@withpotter/lib": "^0.13.0-next.86",
55
+ "@withpotter/ui-kit": "^0.13.0-next.86",
56
56
  "@xyflow/react": "^12.11.2",
57
57
  "dompurify": "^3.3.1",
58
58
  "jsqr": "1.4.0",