@burdenoff/microfe-billing 2026.917.2 → 2026.917.3
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CouponDetailPage.js","names":[],"sources":["../../../../../src/billing/modules/coupons/pages/CouponDetailPage.tsx"],"sourcesContent":["import { type FC, useEffect, useState } from 'react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport {\n ArrowLeft,\n Edit,\n Tag,\n Calendar,\n Users,\n Package,\n BarChart2,\n History,\n ChevronLeft,\n ChevronRight,\n} from 'lucide-react';\nimport { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport {\n useGetCouponLazyQuery,\n useGetCouponUsageHistoryQuery,\n} from '../../../../generated/global-operations';\nimport { Coupon, CouponStatus, CouponUsage } from '../../../../generated/global-types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n ResponsiveTable,\n type ResponsiveTableColumn,\n PagePurpose,\n NextSteps,\n type NextStep,\n} from '@burdenoff/fe-libs/ui';\n\nconst couponUsageColumns: ResponsiveTableColumn<CouponUsage>[] = [\n {\n key: 'userId',\n header: 'User ID',\n priority: 'primary',\n cell: (u) => <span className=\"font-mono\">{u.userId.slice(0, 12)}…</span>,\n },\n {\n key: 'transaction',\n header: 'Transaction',\n cell: (u) =>\n u.transactionId ? (\n <span className=\"font-mono text-xs text-text-link\">{u.transactionId.slice(0, 12)}…</span>\n ) : u.orderId ? (\n <span className=\"text-xs text-text-muted\">Order: {u.orderId.slice(0, 12)}…</span>\n ) : (\n <span className=\"text-text-muted\">, </span>\n ),\n },\n {\n key: 'original',\n header: 'Original',\n cell: (u) => (\n <span className=\"tabular-nums\">\n {u.originalAmount.toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'discount',\n header: 'Discount',\n cell: (u) => (\n <span className=\"tabular-nums text-status-success-text font-medium\">\n -{u.discountValue.toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'final',\n header: 'Final',\n cell: (u) => (\n <span className=\"tabular-nums font-medium\">\n {u.finalAmount.toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'usedAt',\n header: 'Used At',\n cell: (u) => new Date(u.usedAt).toLocaleString(),\n },\n];\n\nfunction StatusBadge({ status }: { status: CouponStatus }) {\n const map: Record<CouponStatus, { label: string; className: string }> = {\n [CouponStatus.Active]: {\n label: 'Active',\n className:\n 'bg-status-success-bg-subtle text-status-success-text border-status-success-bg-subtle',\n },\n [CouponStatus.Inactive]: {\n label: 'Inactive',\n className: 'bg-bg-sunken text-text-muted border-border-subtle',\n },\n [CouponStatus.Expired]: {\n label: 'Expired',\n className:\n 'bg-status-warning-bg-subtle text-status-warning-text border-status-warning-bg-subtle',\n },\n [CouponStatus.Depleted]: {\n label: 'Depleted',\n className: 'bg-status-error-bg-subtle text-status-error-text border-status-error-border',\n },\n };\n const { label, className } = map[status] ?? {\n label: status,\n className: 'bg-bg-sunken text-text-muted',\n };\n return (\n <span\n className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium border ${className}`}\n >\n {label}\n </span>\n );\n}\n\nfunction DetailRow({ label, value }: { label: string; value: React.ReactNode }) {\n return (\n <div className=\"flex items-start gap-2 py-3 border-b border-border-subtle last:border-0\">\n <span className=\"text-sm text-text-muted w-44 shrink-0\">{label}</span>\n <span className=\"text-sm text-text-primary font-medium flex-1\">{value ?? '—'}</span>\n </div>\n );\n}\n\nexport const CouponDetailPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const navigateTo = useBillingNavigate();\n const permissions = useBillingPermissions();\n\n const couponId = window.location.pathname.split('/').filter(Boolean).slice(-1)[0];\n const [activeTab, setActiveTab] = useState<'details' | 'usage'>('details');\n const [usagePage, setUsagePage] = useState(0);\n const USAGE_PAGE_SIZE = 20;\n\n const [getCoupon, { data, loading, error }] = useGetCouponLazyQuery();\n\n const { data: usageData, loading: usageLoading } = useGetCouponUsageHistoryQuery({\n variables: { couponId, limit: USAGE_PAGE_SIZE, offset: usagePage * USAGE_PAGE_SIZE },\n skip: !couponId || activeTab !== 'usage',\n });\n\n useEffect(() => {\n if (couponId) {\n getCoupon({ variables: { id: couponId } });\n }\n }, [couponId, getCoupon]);\n\n if (!permissions.canManageDiscounts) {\n return <AccessDenied message=\"You don't have permission to view coupon details.\" />;\n }\n\n if (loading) {\n return (\n <div className=\"p-8\">\n <PageHeader\n title={tr('billing.coupons.detailTitle', 'Coupon Details')}\n description=\"Loading...\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/coupons')}\n className=\"px-4 py-2 rounded-lg border border-border-subtle text-text-primary hover:bg-bg-sunken flex items-center gap-2\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n }\n />\n <div className=\"flex items-center justify-center h-64\">\n <div className=\"size-8 animate-spin rounded-full border-4 border-action-primary-bg border-t-transparent\" />\n </div>\n </div>\n );\n }\n\n if (error || !data?.getCoupon) {\n return (\n <div className=\"p-8\">\n <PageHeader\n title=\"Coupon Details\"\n description=\"Coupon not found\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/coupons')}\n className=\"px-4 py-2 rounded-lg border border-border-subtle text-text-primary hover:bg-bg-sunken flex items-center gap-2\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n }\n />\n <div className=\"flex items-center justify-center h-64 text-status-error-text text-sm\">\n {error ? `Error: ${error.message}` : 'Coupon not found'}\n </div>\n </div>\n );\n }\n\n const coupon = data.getCoupon as Coupon;\n const usagePercent =\n coupon.maxTotalUses && coupon.maxTotalUses > 0\n ? Math.round((coupon.currentUses / coupon.maxTotalUses) * 100)\n : null;\n\n const nextSteps: NextStep[] = [\n {\n id: 'edit',\n label: 'Edit this coupon',\n description: 'Adjust the discount, limits, expiry or applicable products.',\n onClick: () => navigateTo(`/coupons/${coupon.id}/edit`),\n },\n {\n id: 'usage',\n label: 'Review who has redeemed it',\n description: 'Open the Usage History tab to see every redemption.',\n onClick: () => setActiveTab('usage'),\n },\n {\n id: 'back',\n label: 'Manage all coupons',\n description: 'Return to the full list of discount codes.',\n onClick: () => navigateTo('/coupons'),\n },\n ];\n\n const formatDate = (d: string | null | undefined) =>\n d\n ? new Date(d).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n : null;\n\n const formatValue = () =>\n coupon.type === 'PERCENTAGE'\n ? `${coupon.value}%`\n : `${coupon.value}${coupon.currency ? ` ${coupon.currency}` : ''}`;\n\n return (\n <div className=\"p-8\">\n <PageHeader\n title={coupon.name || coupon.code}\n description={coupon.description || `Coupon code: ${coupon.code}`}\n actions={\n <CTAOverflowMenu\n primary={{\n label: 'Edit',\n onSelect: () => navigateTo(`/coupons/${coupon.id}/edit`),\n icon: <Edit className=\"size-4\" />,\n }}\n actions={[\n {\n label: 'Back to coupons',\n onSelect: () => navigateTo('/coupons'),\n icon: <ArrowLeft className=\"size-4\" />,\n },\n ]}\n />\n }\n />\n\n <PagePurpose className=\"mt-2\">\n Everything about this coupon — its discount, validity window, usage limits and the full\n redemption history. Use it to check how it is performing, edit its terms, or stop it being\n redeemed.\n </PagePurpose>\n\n <NextSteps storageKey=\"billing-coupon-detail\" steps={nextSteps} className=\"mt-4\" />\n\n {/* Tabs */}\n <div className=\"mt-6 border-b border-border-subtle flex gap-1\">\n {(['details', 'usage'] as const).map((tab) => (\n <button\n type=\"button\"\n key={tab}\n onClick={() => setActiveTab(tab)}\n className={`flex items-center gap-2 px-4 py-2.5 text-sm font-medium border-b-2 -mb-px transition-colors ${\n activeTab === tab\n ? 'border-action-primary-bg text-text-primary'\n : 'border-transparent text-text-muted hover:text-text-primary'\n }`}\n >\n {tab === 'details' ? <Tag className=\"size-4\" /> : <History className=\"size-4\" />}\n {tab === 'details'\n ? 'Details'\n : `Usage History${usageData ? ` (${usageData.getCouponUsageHistory.total})` : ''}`}\n </button>\n ))}\n </div>\n\n {activeTab === 'usage' && (\n <div className=\"mt-6 bg-bg-surface border border-border-subtle rounded-lg overflow-hidden\">\n {usageLoading ? (\n <div className=\"flex items-center justify-center h-40\">\n <div className=\"size-6 animate-spin rounded-full border-4 border-action-primary-bg border-t-transparent\" />\n </div>\n ) : !usageData?.getCouponUsageHistory.usages.length ? (\n <div className=\"p-8 text-center text-sm text-text-muted\">\n No usage recorded for this coupon yet.\n </div>\n ) : (\n <>\n <ResponsiveTable\n data={usageData.getCouponUsageHistory.usages}\n rowKey={(u) => u.id}\n columns={couponUsageColumns}\n />\n {(usageData.getCouponUsageHistory.total ?? 0) > USAGE_PAGE_SIZE && (\n <div className=\"flex items-center justify-between p-4 border-t border-border-subtle\">\n <p className=\"text-sm text-text-muted\">\n {usagePage * USAGE_PAGE_SIZE + 1}–\n {Math.min(\n (usagePage + 1) * USAGE_PAGE_SIZE,\n usageData.getCouponUsageHistory.total\n )}{' '}\n of {usageData.getCouponUsageHistory.total}\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setUsagePage((p) => Math.max(0, p - 1))}\n disabled={usagePage === 0}\n className=\"p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40\"\n >\n <ChevronLeft className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setUsagePage((p) => p + 1)}\n disabled={!usageData.getCouponUsageHistory.hasMore}\n className=\"p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40\"\n >\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n )}\n\n {activeTab === 'details' && (\n <div className=\"mt-8 grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Summary cards */}\n <div className=\"lg:col-span-3 grid grid-cols-2 sm:grid-cols-4 gap-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Tag className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Code</span>\n </div>\n <p className=\"text-lg font-mono font-bold text-text-primary\">{coupon.code}</p>\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <BarChart2 className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Discount</span>\n </div>\n <p className=\"text-lg font-bold text-text-primary\">{formatValue()}</p>\n <p className=\"text-xs text-text-muted capitalize\">\n {coupon.type.replace('_', ' ').toLowerCase()}\n </p>\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Users className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Usage</span>\n </div>\n <p className=\"text-lg font-bold text-text-primary\">\n {coupon.currentUses}\n {coupon.maxTotalUses ? ` / ${coupon.maxTotalUses}` : ''}\n </p>\n {usagePercent !== null && (\n <div className=\"mt-1.5 h-1.5 w-full bg-bg-sunken rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-action-primary-bg rounded-full\"\n style={{ width: `${Math.min(usagePercent, 100)}%` }}\n />\n </div>\n )}\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Calendar className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Status</span>\n </div>\n <div className=\"mt-1\">\n <StatusBadge status={coupon.status} />\n </div>\n {coupon.validUntil && (\n <p className=\"text-xs text-text-muted mt-1\">\n Expires {formatDate(coupon.validUntil)}\n </p>\n )}\n </div>\n </div>\n\n {/* Main details */}\n <div className=\"lg:col-span-2 space-y-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Coupon Details\n </h3>\n <DetailRow label=\"Code\" value={<span className=\"font-mono\">{coupon.code}</span>} />\n <DetailRow label=\"Name\" value={coupon.name} />\n <DetailRow label=\"Description\" value={coupon.description} />\n <DetailRow label=\"Type\" value={coupon.type.replace('_', ' ').toLowerCase()} />\n <DetailRow label=\"Value\" value={formatValue()} />\n <DetailRow label=\"Scope\" value={coupon.scope} />\n <DetailRow label=\"Status\" value={<StatusBadge status={coupon.status} />} />\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Restrictions\n </h3>\n <DetailRow\n label=\"Min Purchase Amount\"\n value={\n coupon.minPurchaseAmount != null\n ? `${coupon.minPurchaseAmount}${coupon.currency ? ` ${coupon.currency}` : ''}`\n : null\n }\n />\n <DetailRow\n label=\"Max Discount Amount\"\n value={\n coupon.maxDiscountAmount != null\n ? `${coupon.maxDiscountAmount}${coupon.currency ? ` ${coupon.currency}` : ''}`\n : null\n }\n />\n <DetailRow label=\"Max Uses Per User\" value={coupon.maxUsesPerUser} />\n <DetailRow\n label=\"Restricted Users\"\n value={\n coupon.restrictedToUserIds?.length ? (\n <span className=\"font-mono text-xs break-all\">\n {(coupon.restrictedToUserIds as string[]).join(', ')}\n </span>\n ) : (\n 'No restrictions'\n )\n }\n />\n <DetailRow\n label=\"Applicable Products\"\n value={\n coupon.applicableProducts?.length\n ? (coupon.applicableProducts as string[]).join(', ')\n : 'All products'\n }\n />\n <DetailRow\n label=\"Applicable Product Slugs\"\n value={\n coupon.applicableProductIds?.length\n ? (coupon.applicableProductIds as string[]).join(', ')\n : 'All products'\n }\n />\n <DetailRow\n label=\"Applicable Purchase Types\"\n value={\n coupon.applicableEntityTypes?.length\n ? (coupon.applicableEntityTypes as string[]).join(', ')\n : 'Plan, add-on, and store purchases'\n }\n />\n <DetailRow\n label=\"Excluded Products\"\n value={\n coupon.excludedProducts?.length\n ? (coupon.excludedProducts as string[]).join(', ')\n : 'None'\n }\n />\n </div>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Validity\n </h3>\n <DetailRow label=\"Valid From\" value={formatDate(coupon.validFrom)} />\n <DetailRow label=\"Valid Until\" value={formatDate(coupon.validUntil) ?? 'No expiry'} />\n </div>\n\n {coupon.campaignId && (\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Campaign\n </h3>\n <DetailRow\n label=\"Campaign ID\"\n value={<span className=\"font-mono text-xs\">{coupon.campaignId}</span>}\n />\n <DetailRow label=\"Campaign Name\" value={coupon.campaignName} />\n </div>\n )}\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n <Package className=\"size-4 inline mr-1\" />\n Audit\n </h3>\n <DetailRow label=\"Created\" value={formatDate(coupon.createdAt)} />\n <DetailRow label=\"Last Updated\" value={formatDate(coupon.updatedAt)} />\n <DetailRow label=\"Created By\" value={coupon.createdBy ?? null} />\n </div>\n </div>\n </div>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AA+BA,IAAM,IAA2D;CAC/D;EACE,KAAK;EACL,QAAQ;EACR,UAAU;EACV,OAAO,MAAM,kBAAC,QAAD;GAAM,WAAU;aAAhB,CAA6B,EAAE,OAAO,MAAM,GAAG,EAAE,GAAE,GAAO;;CACzE;CACA;EACE,KAAK;EACL,QAAQ;EACR,OAAO,MACL,EAAE,gBACA,kBAAC,QAAD;GAAM,WAAU;aAAhB,CAAoD,EAAE,cAAc,MAAM,GAAG,EAAE,GAAE,GAAO;OACtF,EAAE,UACJ,kBAAC,QAAD;GAAM,WAAU;aAAhB;IAA0C;IAAQ,EAAE,QAAQ,MAAM,GAAG,EAAE;IAAE;GAAO;OAEhF,kBAAC,QAAD;GAAM,WAAU;aAAkB;EAAQ,CAAA;CAEhD;CACA;EACE,KAAK;EACL,QAAQ;EACR,OAAO,MACL,kBAAC,QAAD;GAAM,WAAU;aAAhB;IACG,EAAE,eAAe,QAAQ,CAAC;IAAE;IAAE,EAAE;GAC7B;;CAEV;CACA;EACE,KAAK;EACL,QAAQ;EACR,OAAO,MACL,kBAAC,QAAD;GAAM,WAAU;aAAhB;IAAoE;IAChE,EAAE,cAAc,QAAQ,CAAC;IAAE;IAAE,EAAE;GAC7B;;CAEV;CACA;EACE,KAAK;EACL,QAAQ;EACR,OAAO,MACL,kBAAC,QAAD;GAAM,WAAU;aAAhB;IACG,EAAE,YAAY,QAAQ,CAAC;IAAE;IAAE,EAAE;GAC1B;;CAEV;CACA;EACE,KAAK;EACL,QAAQ;EACR,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,EAAE,eAAe;CACjD;AACF;AAEA,SAAS,EAAY,EAAE,aAAoC;CAqBzD,IAAM,EAAE,UAAO,iBAAc;GAnB1B,EAAa,SAAS;GACrB,OAAO;GACP,WACE;EACJ;GACC,EAAa,WAAW;GACvB,OAAO;GACP,WAAW;EACb;GACC,EAAa,UAAU;GACtB,OAAO;GACP,WACE;EACJ;GACC,EAAa,WAAW;GACvB,OAAO;GACP,WAAW;EACb;CAE2B,EAAI,MAAW;EAC1C,OAAO;EACP,WAAW;CACb;CACA,OACE,kBAAC,QAAD;EACE,WAAW,kFAAkF;YAE5F;CACG,CAAA;AAEV;AAEA,SAAS,EAAU,EAAE,UAAO,YAAoD;CAC9E,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,QAAD;GAAM,WAAU;aAAyC;EAAY,CAAA,GACrE,kBAAC,QAAD;GAAM,WAAU;aAAgD,KAAS;EAAU,CAAA,CAChF;;AAET;AAEA,IAAa,UAA6B;CACxC,IAAM,EAAE,SAAM,EAAQ,GAChB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAa,EAAE,CAAG;EACxB,OAAO,MAAe,IAAM,IAAW;CACzC,GACM,IAAa,EAAmB,GAChC,IAAc,EAAsB,GAEpC,IAAW,OAAO,SAAS,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,MAAM,EAAE,EAAE,IACzE,CAAC,GAAW,KAAgB,EAA8B,SAAS,GACnE,CAAC,GAAW,KAAgB,EAAS,CAAC,GAGtC,CAAC,GAAW,EAAE,SAAM,YAAS,cAAW,EAAsB,GAE9D,EAAE,MAAM,GAAW,SAAS,MAAiB,EAA8B;EAC/E,WAAW;GAAE;GAAU,OAAO;GAAiB,QAAQ,IAAY;EAAgB;EACnF,MAAM,CAAC,KAAY,MAAc;CACnC,CAAC;CAQD,IANA,QAAgB;EACd,AAAI,KACF,EAAU,EAAE,WAAW,EAAE,IAAI,EAAS,EAAE,CAAC;CAE7C,GAAG,CAAC,GAAU,CAAS,CAAC,GAEpB,CAAC,EAAY,oBACf,OAAO,kBAAC,GAAD,EAAc,SAAQ,oDAAqD,CAAA;CAGpF,IAAI,GACF,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GACE,OAAO,EAAG,+BAA+B,gBAAgB;GACzD,aAAY;GACZ,SACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,UAAU;IACpC,WAAU;cAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,SAAU,CAAA,GAAC,MAE1B;;EAEX,CAAA,GACD,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD,EAAK,WAAU,0FAA2F,CAAA;EACvG,CAAA,CACF;;CAIT,IAAI,KAAS,CAAC,GAAM,WAClB,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GACE,OAAM;GACN,aAAY;GACZ,SACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,UAAU;IACpC,WAAU;cAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,SAAU,CAAA,GAAC,MAE1B;;EAEX,CAAA,GACD,kBAAC,OAAD;GAAK,WAAU;aACZ,IAAQ,UAAU,EAAM,YAAY;EAClC,CAAA,CACF;;CAIT,IAAM,IAAS,EAAK,WACd,IACJ,EAAO,gBAAgB,EAAO,eAAe,IACzC,KAAK,MAAO,EAAO,cAAc,EAAO,eAAgB,GAAG,IAC3D,MAEA,IAAwB;EAC5B;GACE,IAAI;GACJ,OAAO;GACP,aAAa;GACb,eAAe,EAAW,YAAY,EAAO,GAAG,MAAM;EACxD;EACA;GACE,IAAI;GACJ,OAAO;GACP,aAAa;GACb,eAAe,EAAa,OAAO;EACrC;EACA;GACE,IAAI;GACJ,OAAO;GACP,aAAa;GACb,eAAe,EAAW,UAAU;EACtC;CACF,GAEM,KAAc,MAClB,IACI,IAAI,KAAK,CAAC,EAAE,mBAAmB,KAAA,GAAW;EACxC,MAAM;EACN,OAAO;EACP,KAAK;CACP,CAAC,IACD,MAEA,UACJ,EAAO,SAAS,eACZ,GAAG,EAAO,MAAM,KAChB,GAAG,EAAO,QAAQ,EAAO,WAAW,IAAI,EAAO,aAAa;CAElE,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IACE,OAAO,EAAO,QAAQ,EAAO;IAC7B,aAAa,EAAO,eAAe,gBAAgB,EAAO;IAC1D,SACE,kBAAC,GAAD;KACE,SAAS;MACP,OAAO;MACP,gBAAgB,EAAW,YAAY,EAAO,GAAG,MAAM;MACvD,MAAM,kBAAC,GAAD,EAAM,WAAU,SAAU,CAAA;KAClC;KACA,SAAS,CACP;MACE,OAAO;MACP,gBAAgB,EAAW,UAAU;MACrC,MAAM,kBAAC,GAAD,EAAW,WAAU,SAAU,CAAA;KACvC,CACF;IACD,CAAA;GAEJ,CAAA;GAED,kBAAC,GAAD;IAAa,WAAU;cAAO;GAIjB,CAAA;GAEb,kBAAC,GAAD;IAAW,YAAW;IAAwB,OAAO;IAAW,WAAU;GAAQ,CAAA;GAGlF,kBAAC,OAAD;IAAK,WAAU;cACX,CAAC,WAAW,OAAO,EAAY,KAAK,MACpC,kBAAC,UAAD;KACE,MAAK;KAEL,eAAe,EAAa,CAAG;KAC/B,WAAW,+FACT,MAAc,IACV,+CACA;eAPR,CAUuB,EAApB,MAAQ,YAAa,IAA6B,GAA9B,EAAK,WAAU,SAAU,CAAiC,GAC9E,MAAQ,YACL,YACA,gBAAgB,IAAY,KAAK,EAAU,sBAAsB,MAAM,KAAK,IAC1E;OAZD,CAYC,CACT;GACE,CAAA;GAEJ,MAAc,WACb,kBAAC,OAAD;IAAK,WAAU;cACZ,IACC,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD,EAAK,WAAU,0FAA2F,CAAA;IACvG,CAAA,IACF,GAAW,sBAAsB,OAAO,SAK3C,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;KACE,MAAM,EAAU,sBAAsB;KACtC,SAAS,MAAM,EAAE;KACjB,SAAS;IACV,CAAA,IACC,EAAU,sBAAsB,SAAS,KAAK,MAC9C,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,IAAY,KAAkB;OAAE;OAChC,KAAK,KACH,IAAY,KAAK,IAClB,EAAU,sBAAsB,KAClC;OAAG;OAAI;OACH,EAAU,sBAAsB;MACnC;SACH,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,GAAc,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;OACrD,UAAU,MAAc;OACxB,WAAU;iBAEV,kBAAC,GAAD,EAAa,WAAU,SAAU,CAAA;MAC3B,CAAA,GACR,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,GAAc,MAAM,IAAI,CAAC;OACxC,UAAU,CAAC,EAAU,sBAAsB;OAC3C,WAAU;iBAEV,kBAAC,GAAD,EAAc,WAAU,SAAU,CAAA;MAC5B,CAAA,CACL;OACF;MAEP,EAAA,CAAA,IAxCF,kBAAC,OAAD;KAAK,WAAU;eAA0C;IAEpD,CAAA;GAwCJ,CAAA;GAGN,MAAc,aACb,kBAAC,OAAD;IAAK,WAAU;cAAf;KAEE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAK,WAAU,SAAU,CAAA,GACzB,kBAAC,QAAD;UAAM,WAAU;oBAA8C;SAAU,CAAA,CACrE;YACL,kBAAC,KAAD;SAAG,WAAU;mBAAiD,EAAO;QAAQ,CAAA,CAC1E;;OAEL,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD,EAAW,WAAU,SAAU,CAAA,GAC/B,kBAAC,QAAD;WAAM,WAAU;qBAA8C;UAAc,CAAA,CACzE;;SACL,kBAAC,KAAD;UAAG,WAAU;oBAAuC,EAAY;SAAK,CAAA;SACrE,kBAAC,KAAD;UAAG,WAAU;oBACV,EAAO,KAAK,QAAQ,KAAK,GAAG,EAAE,YAAY;SAC1C,CAAA;QACA;;OAEL,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD,EAAO,WAAU,SAAU,CAAA,GAC3B,kBAAC,QAAD;WAAM,WAAU;qBAA8C;UAAW,CAAA,CACtE;;SACL,kBAAC,KAAD;UAAG,WAAU;oBAAb,CACG,EAAO,aACP,EAAO,eAAe,MAAM,EAAO,iBAAiB,EACpD;;SACF,MAAiB,QAChB,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,OAAD;WACE,WAAU;WACV,OAAO,EAAE,OAAO,GAAG,KAAK,IAAI,GAAc,GAAG,EAAE,GAAG;UACnD,CAAA;SACE,CAAA;QAEJ;;OAEL,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,SAAU,CAAA,GAC9B,kBAAC,QAAD;WAAM,WAAU;qBAA8C;UAAY,CAAA,CACvE;;SACL,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,GAAD,EAAa,QAAQ,EAAO,OAAS,CAAA;SAClC,CAAA;SACJ,EAAO,cACN,kBAAC,KAAD;UAAG,WAAU;oBAAb,CAA4C,YACjC,EAAW,EAAO,UAAU,CACpC;;QAEF;;MACF;;KAGL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,MAAD;SAAI,WAAU;mBAAuE;QAEjF,CAAA;QACJ,kBAAC,GAAD;SAAW,OAAM;SAAO,OAAO,kBAAC,QAAD;UAAM,WAAU;oBAAa,EAAO;SAAW,CAAA;QAAI,CAAA;QAClF,kBAAC,GAAD;SAAW,OAAM;SAAO,OAAO,EAAO;QAAO,CAAA;QAC7C,kBAAC,GAAD;SAAW,OAAM;SAAc,OAAO,EAAO;QAAc,CAAA;QAC3D,kBAAC,GAAD;SAAW,OAAM;SAAO,OAAO,EAAO,KAAK,QAAQ,KAAK,GAAG,EAAE,YAAY;QAAI,CAAA;QAC7E,kBAAC,GAAD;SAAW,OAAM;SAAQ,OAAO,EAAY;QAAI,CAAA;QAChD,kBAAC,GAAD;SAAW,OAAM;SAAQ,OAAO,EAAO;QAAQ,CAAA;QAC/C,kBAAC,GAAD;SAAW,OAAM;SAAS,OAAO,kBAAC,GAAD,EAAa,QAAQ,EAAO,OAAS,CAAA;QAAI,CAAA;OACvE;UAEL,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,MAAD;SAAI,WAAU;mBAAuE;QAEjF,CAAA;QACJ,kBAAC,GAAD;SACE,OAAM;SACN,OACE,EAAO,qBAAqB,OAExB,OADA,GAAG,EAAO,oBAAoB,EAAO,WAAW,IAAI,EAAO,aAAa;QAG/E,CAAA;QACD,kBAAC,GAAD;SACE,OAAM;SACN,OACE,EAAO,qBAAqB,OAExB,OADA,GAAG,EAAO,oBAAoB,EAAO,WAAW,IAAI,EAAO,aAAa;QAG/E,CAAA;QACD,kBAAC,GAAD;SAAW,OAAM;SAAoB,OAAO,EAAO;QAAiB,CAAA;QACpE,kBAAC,GAAD;SACE,OAAM;SACN,OACE,EAAO,qBAAqB,SAC1B,kBAAC,QAAD;UAAM,WAAU;oBACZ,EAAO,oBAAiC,KAAK,IAAI;SAC/C,CAAA,IAEN;QAGL,CAAA;QACD,kBAAC,GAAD;SACE,OAAM;SACN,OACE,EAAO,oBAAoB,SACtB,EAAO,mBAAgC,KAAK,IAAI,IACjD;QAEP,CAAA;QACD,kBAAC,GAAD;SACE,OAAM;SACN,OACE,EAAO,sBAAsB,SACxB,EAAO,qBAAkC,KAAK,IAAI,IACnD;QAEP,CAAA;QACD,kBAAC,GAAD;SACE,OAAM;SACN,OACE,EAAO,uBAAuB,SACzB,EAAO,sBAAmC,KAAK,IAAI,IACpD;QAEP,CAAA;QACD,kBAAC,GAAD;SACE,OAAM;SACN,OACE,EAAO,kBAAkB,SACpB,EAAO,iBAA8B,KAAK,IAAI,IAC/C;QAEP,CAAA;OACE;QACF;;KAGL,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,MAAD;UAAI,WAAU;oBAAuE;SAEjF,CAAA;SACJ,kBAAC,GAAD;UAAW,OAAM;UAAa,OAAO,EAAW,EAAO,SAAS;SAAI,CAAA;SACpE,kBAAC,GAAD;UAAW,OAAM;UAAc,OAAO,EAAW,EAAO,UAAU,KAAK;SAAc,CAAA;QAClF;;OAEJ,EAAO,cACN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,MAAD;UAAI,WAAU;oBAAuE;SAEjF,CAAA;SACJ,kBAAC,GAAD;UACE,OAAM;UACN,OAAO,kBAAC,QAAD;WAAM,WAAU;qBAAqB,EAAO;UAAiB,CAAA;SACrE,CAAA;SACD,kBAAC,GAAD;UAAW,OAAM;UAAgB,OAAO,EAAO;SAAe,CAAA;QAC3D;;OAGP,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,MAAD;UAAI,WAAU;oBAAd,CACE,kBAAC,GAAD,EAAS,WAAU,qBAAsB,CAAA,GAAC,OAExC;;SACJ,kBAAC,GAAD;UAAW,OAAM;UAAU,OAAO,EAAW,EAAO,SAAS;SAAI,CAAA;SACjE,kBAAC,GAAD;UAAW,OAAM;UAAe,OAAO,EAAW,EAAO,SAAS;SAAI,CAAA;SACtE,kBAAC,GAAD;UAAW,OAAM;UAAa,OAAO,EAAO,aAAa;SAAO,CAAA;QAC7D;;MACF;;IACF;;EAEJ;;AAET"}
|
|
1
|
+
{"version":3,"file":"CouponDetailPage.js","names":[],"sources":["../../../../../src/billing/modules/coupons/pages/CouponDetailPage.tsx"],"sourcesContent":["import { type FC, useEffect, useState } from 'react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport {\n ArrowLeft,\n Edit,\n Tag,\n Calendar,\n Users,\n Package,\n BarChart2,\n History,\n ChevronLeft,\n ChevronRight,\n} from 'lucide-react';\nimport { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport {\n useGetCouponLazyQuery,\n useGetCouponUsageHistoryQuery,\n} from '../../../../generated/global-operations';\nimport { Coupon, CouponStatus, CouponUsage } from '../../../../generated/global-types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n ResponsiveTable,\n type ResponsiveTableColumn,\n PagePurpose,\n NextSteps,\n type NextStep,\n} from '@burdenoff/fe-libs/ui';\n\nconst couponUsageColumns: ResponsiveTableColumn<CouponUsage>[] = [\n {\n key: 'userId',\n header: 'User ID',\n priority: 'primary',\n cell: (u) => <span className=\"font-mono\">{u.userId.slice(0, 12)}…</span>,\n },\n {\n key: 'transaction',\n header: 'Transaction',\n cell: (u) =>\n u.transactionId ? (\n <span className=\"font-mono text-xs text-text-link\">{u.transactionId.slice(0, 12)}…</span>\n ) : u.orderId ? (\n <span className=\"text-xs text-text-muted\">Order: {u.orderId.slice(0, 12)}…</span>\n ) : (\n <span className=\"text-text-muted\">, </span>\n ),\n },\n {\n key: 'original',\n header: 'Original',\n cell: (u) => (\n <span className=\"tabular-nums\">\n {u.originalAmount.toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'discount',\n header: 'Discount',\n cell: (u) => (\n <span className=\"tabular-nums text-status-success-text font-medium\">\n -{(u.originalAmount - u.finalAmount).toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'final',\n header: 'Final',\n cell: (u) => (\n <span className=\"tabular-nums font-medium\">\n {u.finalAmount.toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'usedAt',\n header: 'Used At',\n cell: (u) => new Date(u.usedAt).toLocaleString(),\n },\n];\n\nfunction StatusBadge({ status }: { status: CouponStatus }) {\n const map: Record<CouponStatus, { label: string; className: string }> = {\n [CouponStatus.Active]: {\n label: 'Active',\n className:\n 'bg-status-success-bg-subtle text-status-success-text border-status-success-bg-subtle',\n },\n [CouponStatus.Inactive]: {\n label: 'Inactive',\n className: 'bg-bg-sunken text-text-muted border-border-subtle',\n },\n [CouponStatus.Expired]: {\n label: 'Expired',\n className:\n 'bg-status-warning-bg-subtle text-status-warning-text border-status-warning-bg-subtle',\n },\n [CouponStatus.Depleted]: {\n label: 'Depleted',\n className: 'bg-status-error-bg-subtle text-status-error-text border-status-error-border',\n },\n };\n const { label, className } = map[status] ?? {\n label: status,\n className: 'bg-bg-sunken text-text-muted',\n };\n return (\n <span\n className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium border ${className}`}\n >\n {label}\n </span>\n );\n}\n\nfunction DetailRow({ label, value }: { label: string; value: React.ReactNode }) {\n return (\n <div className=\"flex items-start gap-2 py-3 border-b border-border-subtle last:border-0\">\n <span className=\"text-sm text-text-muted w-44 shrink-0\">{label}</span>\n <span className=\"text-sm text-text-primary font-medium flex-1\">{value ?? '—'}</span>\n </div>\n );\n}\n\nexport const CouponDetailPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const navigateTo = useBillingNavigate();\n const permissions = useBillingPermissions();\n\n const couponId = window.location.pathname.split('/').filter(Boolean).slice(-1)[0];\n const [activeTab, setActiveTab] = useState<'details' | 'usage'>('details');\n const [usagePage, setUsagePage] = useState(0);\n const USAGE_PAGE_SIZE = 20;\n\n const [getCoupon, { data, loading, error }] = useGetCouponLazyQuery();\n\n const { data: usageData, loading: usageLoading } = useGetCouponUsageHistoryQuery({\n variables: { couponId, limit: USAGE_PAGE_SIZE, offset: usagePage * USAGE_PAGE_SIZE },\n skip: !couponId || activeTab !== 'usage',\n });\n\n useEffect(() => {\n if (couponId) {\n getCoupon({ variables: { id: couponId } });\n }\n }, [couponId, getCoupon]);\n\n if (!permissions.canManageDiscounts) {\n return <AccessDenied message=\"You don't have permission to view coupon details.\" />;\n }\n\n if (loading) {\n return (\n <div className=\"p-8\">\n <PageHeader\n title={tr('billing.coupons.detailTitle', 'Coupon Details')}\n description=\"Loading...\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/coupons')}\n className=\"px-4 py-2 rounded-lg border border-border-subtle text-text-primary hover:bg-bg-sunken flex items-center gap-2\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n }\n />\n <div className=\"flex items-center justify-center h-64\">\n <div className=\"size-8 animate-spin rounded-full border-4 border-action-primary-bg border-t-transparent\" />\n </div>\n </div>\n );\n }\n\n if (error || !data?.getCoupon) {\n return (\n <div className=\"p-8\">\n <PageHeader\n title=\"Coupon Details\"\n description=\"Coupon not found\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/coupons')}\n className=\"px-4 py-2 rounded-lg border border-border-subtle text-text-primary hover:bg-bg-sunken flex items-center gap-2\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n }\n />\n <div className=\"flex items-center justify-center h-64 text-status-error-text text-sm\">\n {error ? `Error: ${error.message}` : 'Coupon not found'}\n </div>\n </div>\n );\n }\n\n const coupon = data.getCoupon as Coupon;\n const usagePercent =\n coupon.maxTotalUses && coupon.maxTotalUses > 0\n ? Math.round((coupon.currentUses / coupon.maxTotalUses) * 100)\n : null;\n\n const nextSteps: NextStep[] = [\n {\n id: 'edit',\n label: 'Edit this coupon',\n description: 'Adjust the discount, limits, expiry or applicable products.',\n onClick: () => navigateTo(`/coupons/${coupon.id}/edit`),\n },\n {\n id: 'usage',\n label: 'Review who has redeemed it',\n description: 'Open the Usage History tab to see every redemption.',\n onClick: () => setActiveTab('usage'),\n },\n {\n id: 'back',\n label: 'Manage all coupons',\n description: 'Return to the full list of discount codes.',\n onClick: () => navigateTo('/coupons'),\n },\n ];\n\n const formatDate = (d: string | null | undefined) =>\n d\n ? new Date(d).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n : null;\n\n const formatValue = () =>\n coupon.type === 'PERCENTAGE'\n ? `${coupon.value}%`\n : `${coupon.value}${coupon.currency ? ` ${coupon.currency}` : ''}`;\n\n return (\n <div className=\"p-8\">\n <PageHeader\n title={coupon.name || coupon.code}\n description={coupon.description || `Coupon code: ${coupon.code}`}\n actions={\n <CTAOverflowMenu\n primary={{\n label: 'Edit',\n onSelect: () => navigateTo(`/coupons/${coupon.id}/edit`),\n icon: <Edit className=\"size-4\" />,\n }}\n actions={[\n {\n label: 'Back to coupons',\n onSelect: () => navigateTo('/coupons'),\n icon: <ArrowLeft className=\"size-4\" />,\n },\n ]}\n />\n }\n />\n\n <PagePurpose className=\"mt-2\">\n Everything about this coupon — its discount, validity window, usage limits and the full\n redemption history. Use it to check how it is performing, edit its terms, or stop it being\n redeemed.\n </PagePurpose>\n\n <NextSteps storageKey=\"billing-coupon-detail\" steps={nextSteps} className=\"mt-4\" />\n\n {/* Tabs */}\n <div className=\"mt-6 border-b border-border-subtle flex gap-1\">\n {(['details', 'usage'] as const).map((tab) => (\n <button\n type=\"button\"\n key={tab}\n onClick={() => setActiveTab(tab)}\n className={`flex items-center gap-2 px-4 py-2.5 text-sm font-medium border-b-2 -mb-px transition-colors ${\n activeTab === tab\n ? 'border-action-primary-bg text-text-primary'\n : 'border-transparent text-text-muted hover:text-text-primary'\n }`}\n >\n {tab === 'details' ? <Tag className=\"size-4\" /> : <History className=\"size-4\" />}\n {tab === 'details'\n ? 'Details'\n : `Usage History${usageData ? ` (${usageData.getCouponUsageHistory.total})` : ''}`}\n </button>\n ))}\n </div>\n\n {activeTab === 'usage' && (\n <div className=\"mt-6 bg-bg-surface border border-border-subtle rounded-lg overflow-hidden\">\n {usageLoading ? (\n <div className=\"flex items-center justify-center h-40\">\n <div className=\"size-6 animate-spin rounded-full border-4 border-action-primary-bg border-t-transparent\" />\n </div>\n ) : !usageData?.getCouponUsageHistory.usages.length ? (\n <div className=\"p-8 text-center text-sm text-text-muted\">\n No usage recorded for this coupon yet.\n </div>\n ) : (\n <>\n <ResponsiveTable\n data={usageData.getCouponUsageHistory.usages}\n rowKey={(u) => u.id}\n columns={couponUsageColumns}\n />\n {(usageData.getCouponUsageHistory.total ?? 0) > USAGE_PAGE_SIZE && (\n <div className=\"flex items-center justify-between p-4 border-t border-border-subtle\">\n <p className=\"text-sm text-text-muted\">\n {usagePage * USAGE_PAGE_SIZE + 1}–\n {Math.min(\n (usagePage + 1) * USAGE_PAGE_SIZE,\n usageData.getCouponUsageHistory.total\n )}{' '}\n of {usageData.getCouponUsageHistory.total}\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setUsagePage((p) => Math.max(0, p - 1))}\n disabled={usagePage === 0}\n className=\"p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40\"\n >\n <ChevronLeft className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setUsagePage((p) => p + 1)}\n disabled={!usageData.getCouponUsageHistory.hasMore}\n className=\"p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40\"\n >\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n )}\n\n {activeTab === 'details' && (\n <div className=\"mt-8 grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Summary cards */}\n <div className=\"lg:col-span-3 grid grid-cols-2 sm:grid-cols-4 gap-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Tag className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Code</span>\n </div>\n <p className=\"text-lg font-mono font-bold text-text-primary\">{coupon.code}</p>\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <BarChart2 className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Discount</span>\n </div>\n <p className=\"text-lg font-bold text-text-primary\">{formatValue()}</p>\n <p className=\"text-xs text-text-muted capitalize\">\n {coupon.type.replace('_', ' ').toLowerCase()}\n </p>\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Users className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Usage</span>\n </div>\n <p className=\"text-lg font-bold text-text-primary\">\n {coupon.currentUses}\n {coupon.maxTotalUses ? ` / ${coupon.maxTotalUses}` : ''}\n </p>\n {usagePercent !== null && (\n <div className=\"mt-1.5 h-1.5 w-full bg-bg-sunken rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-action-primary-bg rounded-full\"\n style={{ width: `${Math.min(usagePercent, 100)}%` }}\n />\n </div>\n )}\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Calendar className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Status</span>\n </div>\n <div className=\"mt-1\">\n <StatusBadge status={coupon.status} />\n </div>\n {coupon.validUntil && (\n <p className=\"text-xs text-text-muted mt-1\">\n Expires {formatDate(coupon.validUntil)}\n </p>\n )}\n </div>\n </div>\n\n {/* Main details */}\n <div className=\"lg:col-span-2 space-y-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Coupon Details\n </h3>\n <DetailRow label=\"Code\" value={<span className=\"font-mono\">{coupon.code}</span>} />\n <DetailRow label=\"Name\" value={coupon.name} />\n <DetailRow label=\"Description\" value={coupon.description} />\n <DetailRow label=\"Type\" value={coupon.type.replace('_', ' ').toLowerCase()} />\n <DetailRow label=\"Value\" value={formatValue()} />\n <DetailRow label=\"Scope\" value={coupon.scope} />\n <DetailRow label=\"Status\" value={<StatusBadge status={coupon.status} />} />\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Restrictions\n </h3>\n <DetailRow\n label=\"Min Purchase Amount\"\n value={\n coupon.minPurchaseAmount != null\n ? `${coupon.minPurchaseAmount}${coupon.currency ? ` ${coupon.currency}` : ''}`\n : null\n }\n />\n <DetailRow\n label=\"Max Discount Amount\"\n value={\n coupon.maxDiscountAmount != null\n ? `${coupon.maxDiscountAmount}${coupon.currency ? ` ${coupon.currency}` : ''}`\n : null\n }\n />\n <DetailRow label=\"Max Uses Per User\" value={coupon.maxUsesPerUser} />\n <DetailRow\n label=\"Restricted Users\"\n value={\n coupon.restrictedToUserIds?.length ? (\n <span className=\"font-mono text-xs break-all\">\n {(coupon.restrictedToUserIds as string[]).join(', ')}\n </span>\n ) : (\n 'No restrictions'\n )\n }\n />\n <DetailRow\n label=\"Applicable Products\"\n value={\n coupon.applicableProducts?.length\n ? (coupon.applicableProducts as string[]).join(', ')\n : 'All products'\n }\n />\n <DetailRow\n label=\"Applicable Product Slugs\"\n value={\n coupon.applicableProductIds?.length\n ? (coupon.applicableProductIds as string[]).join(', ')\n : 'All products'\n }\n />\n <DetailRow\n label=\"Applicable Purchase Types\"\n value={\n coupon.applicableEntityTypes?.length\n ? (coupon.applicableEntityTypes as string[]).join(', ')\n : 'Plan, add-on, and store purchases'\n }\n />\n <DetailRow\n label=\"Excluded Products\"\n value={\n coupon.excludedProducts?.length\n ? (coupon.excludedProducts as string[]).join(', ')\n : 'None'\n }\n />\n </div>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Validity\n </h3>\n <DetailRow label=\"Valid From\" value={formatDate(coupon.validFrom)} />\n <DetailRow label=\"Valid Until\" value={formatDate(coupon.validUntil) ?? 'No expiry'} />\n </div>\n\n {coupon.campaignId && (\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Campaign\n </h3>\n <DetailRow\n label=\"Campaign ID\"\n value={<span className=\"font-mono text-xs\">{coupon.campaignId}</span>}\n />\n <DetailRow label=\"Campaign Name\" value={coupon.campaignName} />\n </div>\n )}\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n <Package className=\"size-4 inline mr-1\" />\n Audit\n </h3>\n <DetailRow label=\"Created\" value={formatDate(coupon.createdAt)} />\n <DetailRow label=\"Last Updated\" value={formatDate(coupon.updatedAt)} />\n <DetailRow label=\"Created By\" value={coupon.createdBy ?? null} />\n </div>\n </div>\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|