@burdenoff/microfe-store 2026.912.1 → 2026.912.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.
@@ -9,8 +9,12 @@ import { AlertCircle as s, ArrowLeft as c, Loader2 as l, ShieldCheck as u } from
9
9
  import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
10
10
  import { EmphasisPanel as m, IllustratedEmptyState as h, PagePurpose as g } from "@burdenoff/fe-libs/ui";
11
11
  //#region src/pages/MyLicensesPage.tsx
12
- var _ = (e) => e === "ACTIVE" ? "bg-status-success-bg-subtle text-status-success-text" : e === "SUSPENDED" || e === "PENDING" ? "bg-status-warning-bg-subtle text-status-warning-text" : e === "EXPIRED" || e === "REVOKED" ? "bg-status-error-bg-subtle text-status-error-text" : "bg-bg-sunken text-text-muted", v = () => {
13
- let v = i(), { basePath: y } = e(), { t: b } = o(), x = n(), { entitlements: S, hasMore: C, loading: w, error: T, refetch: E, loadMore: D } = t(), O = r(() => S.slice().sort((e, t) => e.id.localeCompare(t.id)), [S]);
12
+ var _ = (e) => new Date(e).toLocaleDateString("en-US", {
13
+ year: "numeric",
14
+ month: "short",
15
+ day: "numeric"
16
+ }), v = (e) => e === "ACTIVE" ? "bg-status-success-bg-subtle text-status-success-text" : e === "SUSPENDED" || e === "PENDING" ? "bg-status-warning-bg-subtle text-status-warning-text" : e === "EXPIRED" || e === "REVOKED" ? "bg-status-error-bg-subtle text-status-error-text" : "bg-bg-sunken text-text-muted", y = () => {
17
+ let y = i(), { basePath: b } = e(), { t: x } = o(), S = n(), { entitlements: C, hasMore: w, loading: T, error: E, refetch: D, loadMore: O } = t(), k = r(() => C.slice().sort((e, t) => e.id.localeCompare(t.id)), [C]);
14
18
  return /* @__PURE__ */ p("div", {
15
19
  className: "flex h-full flex-col",
16
20
  children: [/* @__PURE__ */ f("header", {
@@ -19,16 +23,16 @@ var _ = (e) => e === "ACTIVE" ? "bg-status-success-bg-subtle text-status-success
19
23
  className: "mx-auto flex max-w-5xl items-center gap-4",
20
24
  children: [/* @__PURE__ */ f("button", {
21
25
  type: "button",
22
- onClick: () => v(-1),
26
+ onClick: () => y(-1),
23
27
  "aria-label": "Go back",
24
28
  className: "cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary",
25
29
  children: /* @__PURE__ */ f(c, { className: "size-5" })
26
30
  }), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("h1", {
27
31
  className: "text-2xl font-bold text-text-primary",
28
- children: b("pages.licenses.title", { defaultValue: "My Licenses" })
32
+ children: x("pages.licenses.title", { defaultValue: "My Licenses" })
29
33
  }), /* @__PURE__ */ f("p", {
30
34
  className: "text-sm text-text-muted",
31
- children: b("pages.licenses.subtitle", { defaultValue: "Review and manage your product entitlements" })
35
+ children: x("pages.licenses.subtitle", { defaultValue: "Review and manage your product entitlements" })
32
36
  })] })]
33
37
  })
34
38
  }), /* @__PURE__ */ f("main", {
@@ -37,55 +41,55 @@ var _ = (e) => e === "ACTIVE" ? "bg-status-success-bg-subtle text-status-success
37
41
  className: "mx-auto max-w-5xl",
38
42
  children: [/* @__PURE__ */ f(g, {
39
43
  className: "mb-6",
40
- children: x("pages.licenses.purpose", "Every paid app you own grants a license (entitlement) that proves your right to use it. Check here to confirm a license is active, find a license key to enter into a product, and see when paid access expires — so you're never caught out by a lapsed or suspended entitlement.")
41
- }), w ? /* @__PURE__ */ f("output", {
42
- "aria-label": x("pages.licenses.loading", "Loading licenses"),
44
+ children: S("pages.licenses.purpose", "Every paid app you own grants a license (entitlement) that proves your right to use it. Check here to confirm a license is active, find a license key to enter into a product, and see when paid access expires — so you're never caught out by a lapsed or suspended entitlement.")
45
+ }), T ? /* @__PURE__ */ f("output", {
46
+ "aria-label": S("pages.licenses.loading", "Loading licenses"),
43
47
  className: "flex items-center justify-center py-16",
44
48
  children: /* @__PURE__ */ f(l, {
45
49
  className: "size-8 animate-spin text-text-muted",
46
50
  "aria-hidden": "true"
47
51
  })
48
- }) : T ? /* @__PURE__ */ p("div", {
52
+ }) : E ? /* @__PURE__ */ p("div", {
49
53
  role: "alert",
50
54
  className: "rounded-xl border border-status-error-border bg-status-error-bg-subtle p-8 text-center",
51
55
  children: [
52
56
  /* @__PURE__ */ f(s, { className: "mx-auto mb-3 size-10 text-status-error-text" }),
53
57
  /* @__PURE__ */ f("h3", {
54
58
  className: "text-lg font-semibold text-status-error-text",
55
- children: b("pages.licenses.failedToLoad", { defaultValue: "Failed to load licenses" })
59
+ children: x("pages.licenses.failedToLoad", { defaultValue: "Failed to load licenses" })
56
60
  }),
57
61
  /* @__PURE__ */ f("p", {
58
62
  className: "mt-2 text-sm text-text-muted",
59
- children: T.message
63
+ children: E.message
60
64
  }),
61
65
  /* @__PURE__ */ f("button", {
62
66
  type: "button",
63
- onClick: () => E(),
67
+ onClick: () => D(),
64
68
  className: "mt-4 cursor-pointer rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text",
65
- children: b("common.tryAgain", { defaultValue: "Try Again" })
69
+ children: x("common.tryAgain", { defaultValue: "Try Again" })
66
70
  })
67
71
  ]
68
- }) : O.length === 0 ? /* @__PURE__ */ f(h, {
72
+ }) : k.length === 0 ? /* @__PURE__ */ f(h, {
69
73
  illustration: "empty-data",
70
- title: b("pages.licenses.emptyTitle", { defaultValue: "No licenses yet" }),
71
- description: b("pages.licenses.emptyDescription", { defaultValue: "Purchase apps from the marketplace to see your licenses here." }),
74
+ title: x("pages.licenses.emptyTitle", { defaultValue: "No licenses yet" }),
75
+ description: x("pages.licenses.emptyDescription", { defaultValue: "Purchase apps from the marketplace to see your licenses here." }),
72
76
  action: /* @__PURE__ */ f("button", {
73
77
  type: "button",
74
- onClick: () => v(`${y}/marketplace`),
78
+ onClick: () => y(`${b}/marketplace`),
75
79
  className: "cursor-pointer rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text",
76
- children: b("pages.licenses.browseMarketplace", { defaultValue: "Browse Marketplace" })
80
+ children: x("pages.licenses.browseMarketplace", { defaultValue: "Browse Marketplace" })
77
81
  })
78
82
  }) : /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(m, {
79
83
  className: "mb-6",
80
84
  children: /* @__PURE__ */ f(a, {
81
- label: b("pages.licenses.activeLicenses", { defaultValue: "Active licenses" }),
82
- used: O.filter((e) => e.status === "ACTIVE").length,
85
+ label: x("pages.licenses.activeLicenses", { defaultValue: "Active licenses" }),
86
+ used: k.filter((e) => e.status === "ACTIVE").length,
83
87
  limit: null,
84
- unit: b("pages.licenses.licensesUnit", { defaultValue: "licenses" })
88
+ unit: x("pages.licenses.licensesUnit", { defaultValue: "licenses" })
85
89
  })
86
90
  }), /* @__PURE__ */ p("ul", {
87
91
  className: "flex flex-col gap-y-4",
88
- children: [O.map((e) => /* @__PURE__ */ f("li", {
92
+ children: [k.map((e) => /* @__PURE__ */ f("li", {
89
93
  className: "rounded-xl border border-border-seam bg-bg-surface p-4 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-[var(--shadow-pop)]",
90
94
  children: /* @__PURE__ */ p("div", {
91
95
  className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
@@ -94,43 +98,43 @@ var _ = (e) => e === "ACTIVE" ? "bg-status-success-bg-subtle text-status-success
94
98
  className: "flex items-center gap-2",
95
99
  children: [/* @__PURE__ */ f(u, { className: "size-4 text-status-success-text" }), /* @__PURE__ */ f("h3", {
96
100
  className: "font-semibold text-text-primary",
97
- children: x("pages.licenses.product", "Product {{id}}", { id: e.productId })
101
+ children: S("pages.licenses.product", "Product {{id}}", { id: e.productId })
98
102
  })]
99
103
  }),
100
104
  /* @__PURE__ */ f("p", {
101
105
  className: "mt-1 text-sm text-text-muted",
102
- children: b("pages.licenses.entitlementId", {
106
+ children: x("pages.licenses.entitlementId", {
103
107
  defaultValue: `Entitlement ID: ${e.id}`,
104
108
  id: e.id
105
109
  })
106
110
  }),
107
111
  e.licenseKey && /* @__PURE__ */ f("p", {
108
- className: "mt-1 text-sm text-text-muted",
109
- children: b("pages.licenses.licenseKey", {
112
+ className: "mt-1 break-all text-sm text-text-muted",
113
+ children: x("pages.licenses.licenseKey", {
110
114
  defaultValue: `License key: ${e.licenseKey}`,
111
115
  key: e.licenseKey
112
116
  })
113
117
  }),
114
118
  e.expiresAt && /* @__PURE__ */ f("p", {
115
119
  className: "mt-1 text-sm text-text-muted",
116
- children: b("pages.licenses.expiresOn", {
117
- defaultValue: `Expires on ${new Date(e.expiresAt).toLocaleDateString()}`,
118
- date: new Date(e.expiresAt).toLocaleDateString()
120
+ children: x("pages.licenses.expiresOn", {
121
+ defaultValue: `Expires on ${_(e.expiresAt)}`,
122
+ date: _(e.expiresAt)
119
123
  })
120
124
  })
121
125
  ] }), /* @__PURE__ */ f("span", {
122
- className: `rounded-full px-3 py-1 text-xs font-semibold ${_(e.status)} ${e.status === "ACTIVE" ? "motion-safe:animate-vc-glow-pulse" : ""}`,
126
+ className: `rounded-full px-3 py-1 text-xs font-semibold ${v(e.status)} ${e.status === "ACTIVE" ? "motion-safe:animate-vc-glow-pulse" : ""}`,
123
127
  children: e.status
124
128
  })]
125
129
  })
126
- }, e.id)), C && /* @__PURE__ */ f("li", {
130
+ }, e.id)), w && /* @__PURE__ */ f("li", {
127
131
  className: "flex justify-center pt-4 list-none",
128
132
  children: /* @__PURE__ */ f("button", {
129
133
  type: "button",
130
- onClick: D,
131
- disabled: w,
134
+ onClick: O,
135
+ disabled: T,
132
136
  className: "rounded-lg border border-border-default px-6 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-subtle disabled:opacity-50",
133
- children: w ? x("common.loading", "Loading…") : x("common.loadMore", "Load more")
137
+ children: T ? S("common.loading", "Loading…") : S("common.loadMore", "Load more")
134
138
  })
135
139
  })]
136
140
  })] })]
@@ -139,6 +143,6 @@ var _ = (e) => e === "ACTIVE" ? "bg-status-success-bg-subtle text-status-success
139
143
  });
140
144
  };
141
145
  //#endregion
142
- export { v as MyLicensesPage };
146
+ export { y as MyLicensesPage };
143
147
 
144
148
  //# sourceMappingURL=MyLicensesPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MyLicensesPage.js","names":[],"sources":["../../src/pages/MyLicensesPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo } from 'react';\nimport { useNavigate } from 'react-router';\nimport { ArrowLeft, ShieldCheck, AlertCircle, Loader2 } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useTr } from '../shared/hooks/useTr';\nimport { QuotaMeter } from '@burdenoff/fe-libs/shared/components';\nimport { EmphasisPanel, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useStore } from '../providers/StoreProvider';\nimport { useMyEntitlements } from '../hooks/useStoreGraphQL';\n\ninterface LicenseItem {\n id: string;\n productId: string;\n status: string;\n licenseKey?: string | null;\n expiresAt?: string | null;\n}\n\nconst statusClass = (status: string): string => {\n if (status === 'ACTIVE') return 'bg-status-success-bg-subtle text-status-success-text';\n if (status === 'SUSPENDED' || status === 'PENDING') {\n return 'bg-status-warning-bg-subtle text-status-warning-text';\n }\n if (status === 'EXPIRED' || status === 'REVOKED') {\n return 'bg-status-error-bg-subtle text-status-error-text';\n }\n return 'bg-bg-sunken text-text-muted';\n};\n\nexport const MyLicensesPage: FC = () => {\n const navigate = useNavigate();\n const { basePath } = useStore();\n const { t } = useI18n();\n const tr = useTr();\n const { entitlements, hasMore, loading, error, refetch, loadMore } = useMyEntitlements();\n\n const licenses = useMemo(\n () => (entitlements as LicenseItem[]).slice().sort((a, b) => a.id.localeCompare(b.id)),\n [entitlements]\n );\n\n return (\n <div className=\"flex h-full flex-col\">\n <header className=\"sticky top-0 z-10 border-b border-border-seam bg-bg-surface px-6 py-4\">\n <div className=\"mx-auto flex max-w-5xl items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate(-1)}\n aria-label=\"Go back\"\n className=\"cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n {t('pages.licenses.title', { defaultValue: 'My Licenses' })}\n </h1>\n <p className=\"text-sm text-text-muted\">\n {t('pages.licenses.subtitle', {\n defaultValue: 'Review and manage your product entitlements',\n })}\n </p>\n </div>\n </div>\n </header>\n\n <main className=\"flex-1 overflow-y-auto p-6\">\n <div className=\"mx-auto max-w-5xl\">\n <PagePurpose className=\"mb-6\">\n {tr(\n 'pages.licenses.purpose',\n \"Every paid app you own grants a license (entitlement) that proves your right to use it. Check here to confirm a license is active, find a license key to enter into a product, and see when paid access expires — so you're never caught out by a lapsed or suspended entitlement.\"\n )}\n </PagePurpose>\n {loading ? (\n <output\n aria-label={tr('pages.licenses.loading', 'Loading licenses')}\n className=\"flex items-center justify-center py-16\"\n >\n <Loader2 className=\"size-8 animate-spin text-text-muted\" aria-hidden=\"true\" />\n </output>\n ) : error ? (\n <div\n role=\"alert\"\n className=\"rounded-xl border border-status-error-border bg-status-error-bg-subtle p-8 text-center\"\n >\n <AlertCircle className=\"mx-auto mb-3 size-10 text-status-error-text\" />\n <h3 className=\"text-lg font-semibold text-status-error-text\">\n {t('pages.licenses.failedToLoad', { defaultValue: 'Failed to load licenses' })}\n </h3>\n <p className=\"mt-2 text-sm text-text-muted\">{error.message}</p>\n <button\n type=\"button\"\n onClick={() => refetch()}\n className=\"mt-4 cursor-pointer rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n {t('common.tryAgain', { defaultValue: 'Try Again' })}\n </button>\n </div>\n ) : licenses.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('pages.licenses.emptyTitle', { defaultValue: 'No licenses yet' })}\n description={t('pages.licenses.emptyDescription', {\n defaultValue: 'Purchase apps from the marketplace to see your licenses here.',\n })}\n action={\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/marketplace`)}\n className=\"cursor-pointer rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n {t('pages.licenses.browseMarketplace', { defaultValue: 'Browse Marketplace' })}\n </button>\n }\n />\n ) : (\n <>\n {/*\n Inline quota meter showing active-license consumption vs the\n workspace plan limit. The limit is sourced from the billing\n summary when available; passing `null` renders an\n \"Unlimited\" indicator instead of misleading 0/0 progress.\n */}\n <EmphasisPanel className=\"mb-6\">\n <QuotaMeter\n label={t('pages.licenses.activeLicenses', {\n defaultValue: 'Active licenses',\n })}\n used={licenses.filter((l) => l.status === 'ACTIVE').length}\n limit={null}\n unit={t('pages.licenses.licensesUnit', {\n defaultValue: 'licenses',\n })}\n />\n </EmphasisPanel>\n <ul className=\"flex flex-col gap-y-4\">\n {licenses.map((license) => (\n <li\n key={license.id}\n className=\"rounded-xl border border-border-seam bg-bg-surface p-4 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-[var(--shadow-pop)]\"\n >\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <ShieldCheck className=\"size-4 text-status-success-text\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('pages.licenses.product', 'Product {{id}}', {\n id: license.productId,\n })}\n </h3>\n </div>\n <p className=\"mt-1 text-sm text-text-muted\">\n {t('pages.licenses.entitlementId', {\n defaultValue: `Entitlement ID: ${license.id}`,\n id: license.id,\n })}\n </p>\n {license.licenseKey && (\n <p className=\"mt-1 text-sm text-text-muted\">\n {t('pages.licenses.licenseKey', {\n defaultValue: `License key: ${license.licenseKey}`,\n key: license.licenseKey,\n })}\n </p>\n )}\n {license.expiresAt && (\n <p className=\"mt-1 text-sm text-text-muted\">\n {t('pages.licenses.expiresOn', {\n defaultValue: `Expires on ${new Date(license.expiresAt).toLocaleDateString()}`,\n date: new Date(license.expiresAt).toLocaleDateString(),\n })}\n </p>\n )}\n </div>\n <span\n className={`rounded-full px-3 py-1 text-xs font-semibold ${statusClass(license.status)} ${\n license.status === 'ACTIVE' ? 'motion-safe:animate-vc-glow-pulse' : ''\n }`}\n >\n {license.status}\n </span>\n </div>\n </li>\n ))}\n {hasMore && (\n <li className=\"flex justify-center pt-4 list-none\">\n <button\n type=\"button\"\n onClick={loadMore}\n disabled={loading}\n className=\"rounded-lg border border-border-default px-6 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-subtle disabled:opacity-50\"\n >\n {loading\n ? tr('common.loading', 'Loading…')\n : tr('common.loadMore', 'Load more')}\n </button>\n </li>\n )}\n </ul>\n </>\n )}\n </div>\n </main>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;AAmBA,IAAM,KAAe,MACf,MAAW,WAAiB,yDAC5B,MAAW,eAAe,MAAW,YAChC,yDAEL,MAAW,aAAa,MAAW,YAC9B,qDAEF,gCAGI,UAA2B;CACtC,IAAM,IAAW,GAAa,EACxB,EAAE,gBAAa,GAAU,EACzB,EAAE,SAAM,GAAS,EACjB,IAAK,GAAO,EACZ,EAAE,iBAAc,YAAS,YAAS,UAAO,YAAS,gBAAa,GAAmB,EAElF,IAAW,QACR,EAA+B,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,CAAC,EACtF,CAAC,EAAa,CACf;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,UAAD;GAAQ,WAAU;aAChB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAS,GAAG;KAC3B,cAAW;KACX,WAAU;eAEV,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA;KACzB,CAAA,EACT,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAE,wBAAwB,EAAE,cAAc,eAAe,CAAC;KACxD,CAAA,EACL,kBAAC,KAAD;KAAG,WAAU;eACV,EAAE,2BAA2B,EAC5B,cAAc,+CACf,CAAC;KACA,CAAA,CACA,EAAA,CAAA,CACF;;GACC,CAAA,EAET,kBAAC,QAAD;GAAM,WAAU;aACd,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAa,WAAU;eACpB,EACC,0BACA,qRACD;KACW,CAAA,EACb,IACC,kBAAC,UAAD;KACE,cAAY,EAAG,0BAA0B,mBAAmB;KAC5D,WAAU;eAEV,kBAAC,GAAD;MAAS,WAAU;MAAsC,eAAY;MAAS,CAAA;KACvE,CAAA,GACP,IACF,kBAAC,OAAD;KACE,MAAK;KACL,WAAU;eAFZ;MAIE,kBAAC,GAAD,EAAa,WAAU,+CAAgD,CAAA;MACvE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAE,+BAA+B,EAAE,cAAc,2BAA2B,CAAC;OAC3E,CAAA;MACL,kBAAC,KAAD;OAAG,WAAU;iBAAgC,EAAM;OAAY,CAAA;MAC/D,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,GAAS;OACxB,WAAU;iBAET,EAAE,mBAAmB,EAAE,cAAc,aAAa,CAAC;OAC7C,CAAA;MACL;SACJ,EAAS,WAAW,IACtB,kBAAC,GAAD;KACE,cAAa;KACb,OAAO,EAAE,6BAA6B,EAAE,cAAc,mBAAmB,CAAC;KAC1E,aAAa,EAAE,mCAAmC,EAChD,cAAc,iEACf,CAAC;KACF,QACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAS,GAAG,EAAS,cAAc;MAClD,WAAU;gBAET,EAAE,oCAAoC,EAAE,cAAc,sBAAsB,CAAC;MACvE,CAAA;KAEX,CAAA,GAEF,kBAAA,GAAA,EAAA,UAAA,CAOE,kBAAC,GAAD;KAAe,WAAU;eACvB,kBAAC,GAAD;MACE,OAAO,EAAE,iCAAiC,EACxC,cAAc,mBACf,CAAC;MACF,MAAM,EAAS,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC;MACpD,OAAO;MACP,MAAM,EAAE,+BAA+B,EACrC,cAAc,YACf,CAAC;MACF,CAAA;KACY,CAAA,EAChB,kBAAC,MAAD;KAAI,WAAU;eAAd,CACG,EAAS,KAAK,MACb,kBAAC,MAAD;MAEE,WAAU;gBAEV,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAa,WAAU,mCAAoC,CAAA,EAC3D,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAG,0BAA0B,kBAAkB,EAC9C,IAAI,EAAQ,WACb,CAAC;UACC,CAAA,CACD;;QACN,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAE,gCAAgC;UACjC,cAAc,mBAAmB,EAAQ;UACzC,IAAI,EAAQ;UACb,CAAC;SACA,CAAA;QACH,EAAQ,cACP,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAE,6BAA6B;UAC9B,cAAc,gBAAgB,EAAQ;UACtC,KAAK,EAAQ;UACd,CAAC;SACA,CAAA;QAEL,EAAQ,aACP,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAE,4BAA4B;UAC7B,cAAc,cAAc,IAAI,KAAK,EAAQ,UAAU,CAAC,oBAAoB;UAC5E,MAAM,IAAI,KAAK,EAAQ,UAAU,CAAC,oBAAoB;UACvD,CAAC;SACA,CAAA;QAEF,EAAA,CAAA,EACN,kBAAC,QAAD;QACE,WAAW,gDAAgD,EAAY,EAAQ,OAAO,CAAC,GACrF,EAAQ,WAAW,WAAW,sCAAsC;kBAGrE,EAAQ;QACJ,CAAA,CACH;;MACH,EA5CE,EAAQ,GA4CV,CACL,EACD,KACC,kBAAC,MAAD;MAAI,WAAU;gBACZ,kBAAC,UAAD;OACE,MAAK;OACL,SAAS;OACT,UAAU;OACV,WAAU;iBAET,IACG,EAAG,kBAAkB,WAAW,GAChC,EAAG,mBAAmB,YAAY;OAC/B,CAAA;MACN,CAAA,CAEJ;OACJ,EAAA,CAAA,CAED;;GACD,CAAA,CACH"}
1
+ {"version":3,"file":"MyLicensesPage.js","names":[],"sources":["../../src/pages/MyLicensesPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo } from 'react';\nimport { useNavigate } from 'react-router';\nimport { ArrowLeft, ShieldCheck, AlertCircle, Loader2 } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useTr } from '../shared/hooks/useTr';\nimport { QuotaMeter } from '@burdenoff/fe-libs/shared/components';\nimport { EmphasisPanel, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useStore } from '../providers/StoreProvider';\nimport { useMyEntitlements } from '../hooks/useStoreGraphQL';\n\ninterface LicenseItem {\n id: string;\n productId: string;\n status: string;\n licenseKey?: string | null;\n expiresAt?: string | null;\n}\n\n/** en-US, spelled-out month — avoids the DD/MM vs MM/DD ambiguity of a bare\n * toLocaleDateString() (which follows the browser's locale, not a fixed one). */\nconst formatDate = (value: string): string =>\n new Date(value).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });\n\nconst statusClass = (status: string): string => {\n if (status === 'ACTIVE') return 'bg-status-success-bg-subtle text-status-success-text';\n if (status === 'SUSPENDED' || status === 'PENDING') {\n return 'bg-status-warning-bg-subtle text-status-warning-text';\n }\n if (status === 'EXPIRED' || status === 'REVOKED') {\n return 'bg-status-error-bg-subtle text-status-error-text';\n }\n return 'bg-bg-sunken text-text-muted';\n};\n\nexport const MyLicensesPage: FC = () => {\n const navigate = useNavigate();\n const { basePath } = useStore();\n const { t } = useI18n();\n const tr = useTr();\n const { entitlements, hasMore, loading, error, refetch, loadMore } = useMyEntitlements();\n\n const licenses = useMemo(\n () => (entitlements as LicenseItem[]).slice().sort((a, b) => a.id.localeCompare(b.id)),\n [entitlements]\n );\n\n return (\n <div className=\"flex h-full flex-col\">\n <header className=\"sticky top-0 z-10 border-b border-border-seam bg-bg-surface px-6 py-4\">\n <div className=\"mx-auto flex max-w-5xl items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate(-1)}\n aria-label=\"Go back\"\n className=\"cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n {t('pages.licenses.title', { defaultValue: 'My Licenses' })}\n </h1>\n <p className=\"text-sm text-text-muted\">\n {t('pages.licenses.subtitle', {\n defaultValue: 'Review and manage your product entitlements',\n })}\n </p>\n </div>\n </div>\n </header>\n\n <main className=\"flex-1 overflow-y-auto p-6\">\n <div className=\"mx-auto max-w-5xl\">\n <PagePurpose className=\"mb-6\">\n {tr(\n 'pages.licenses.purpose',\n \"Every paid app you own grants a license (entitlement) that proves your right to use it. Check here to confirm a license is active, find a license key to enter into a product, and see when paid access expires — so you're never caught out by a lapsed or suspended entitlement.\"\n )}\n </PagePurpose>\n {loading ? (\n <output\n aria-label={tr('pages.licenses.loading', 'Loading licenses')}\n className=\"flex items-center justify-center py-16\"\n >\n <Loader2 className=\"size-8 animate-spin text-text-muted\" aria-hidden=\"true\" />\n </output>\n ) : error ? (\n <div\n role=\"alert\"\n className=\"rounded-xl border border-status-error-border bg-status-error-bg-subtle p-8 text-center\"\n >\n <AlertCircle className=\"mx-auto mb-3 size-10 text-status-error-text\" />\n <h3 className=\"text-lg font-semibold text-status-error-text\">\n {t('pages.licenses.failedToLoad', { defaultValue: 'Failed to load licenses' })}\n </h3>\n <p className=\"mt-2 text-sm text-text-muted\">{error.message}</p>\n <button\n type=\"button\"\n onClick={() => refetch()}\n className=\"mt-4 cursor-pointer rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n {t('common.tryAgain', { defaultValue: 'Try Again' })}\n </button>\n </div>\n ) : licenses.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('pages.licenses.emptyTitle', { defaultValue: 'No licenses yet' })}\n description={t('pages.licenses.emptyDescription', {\n defaultValue: 'Purchase apps from the marketplace to see your licenses here.',\n })}\n action={\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/marketplace`)}\n className=\"cursor-pointer rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n {t('pages.licenses.browseMarketplace', { defaultValue: 'Browse Marketplace' })}\n </button>\n }\n />\n ) : (\n <>\n {/*\n Inline quota meter showing active-license consumption vs the\n workspace plan limit. The limit is sourced from the billing\n summary when available; passing `null` renders an\n \"Unlimited\" indicator instead of misleading 0/0 progress.\n */}\n <EmphasisPanel className=\"mb-6\">\n <QuotaMeter\n label={t('pages.licenses.activeLicenses', {\n defaultValue: 'Active licenses',\n })}\n used={licenses.filter((l) => l.status === 'ACTIVE').length}\n limit={null}\n unit={t('pages.licenses.licensesUnit', {\n defaultValue: 'licenses',\n })}\n />\n </EmphasisPanel>\n <ul className=\"flex flex-col gap-y-4\">\n {licenses.map((license) => (\n <li\n key={license.id}\n className=\"rounded-xl border border-border-seam bg-bg-surface p-4 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-[var(--shadow-pop)]\"\n >\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <ShieldCheck className=\"size-4 text-status-success-text\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('pages.licenses.product', 'Product {{id}}', {\n id: license.productId,\n })}\n </h3>\n </div>\n <p className=\"mt-1 text-sm text-text-muted\">\n {t('pages.licenses.entitlementId', {\n defaultValue: `Entitlement ID: ${license.id}`,\n id: license.id,\n })}\n </p>\n {license.licenseKey && (\n <p className=\"mt-1 break-all text-sm text-text-muted\">\n {t('pages.licenses.licenseKey', {\n defaultValue: `License key: ${license.licenseKey}`,\n key: license.licenseKey,\n })}\n </p>\n )}\n {license.expiresAt && (\n <p className=\"mt-1 text-sm text-text-muted\">\n {t('pages.licenses.expiresOn', {\n defaultValue: `Expires on ${formatDate(license.expiresAt)}`,\n date: formatDate(license.expiresAt),\n })}\n </p>\n )}\n </div>\n <span\n className={`rounded-full px-3 py-1 text-xs font-semibold ${statusClass(license.status)} ${\n license.status === 'ACTIVE' ? 'motion-safe:animate-vc-glow-pulse' : ''\n }`}\n >\n {license.status}\n </span>\n </div>\n </li>\n ))}\n {hasMore && (\n <li className=\"flex justify-center pt-4 list-none\">\n <button\n type=\"button\"\n onClick={loadMore}\n disabled={loading}\n className=\"rounded-lg border border-border-default px-6 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-subtle disabled:opacity-50\"\n >\n {loading\n ? tr('common.loading', 'Loading…')\n : tr('common.loadMore', 'Load more')}\n </button>\n </li>\n )}\n </ul>\n </>\n )}\n </div>\n </main>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -246,7 +246,7 @@ var D = [
246
246
  className: "overflow-hidden rounded-xl border border-border-seam bg-bg-surface",
247
247
  children: [
248
248
  /* @__PURE__ */ C("div", {
249
- className: "hidden border-b border-border-seam bg-bg-sunken/50 md:grid md:grid-cols-[40px_1fr_180px_140px_120px_160px]",
249
+ className: "hidden border-b border-border-seam bg-bg-sunken/50 md:grid md:grid-cols-[40px_130px_140px_1fr_120px_140px]",
250
250
  children: [
251
251
  /* @__PURE__ */ S("div", { className: $ }),
252
252
  /* @__PURE__ */ S("div", {
@@ -278,7 +278,7 @@ var D = [
278
278
  children: [/* @__PURE__ */ C("button", {
279
279
  type: "button",
280
280
  onClick: () => se(e.id),
281
- className: "grid w-full cursor-pointer grid-cols-[40px_1fr_180px_140px_120px_160px] items-center transition-colors hover:bg-bg-sunken/50 md:grid",
281
+ className: "grid w-full cursor-pointer grid-cols-[40px_130px_140px_1fr_120px_140px] items-center transition-colors hover:bg-bg-sunken/50 md:grid",
282
282
  children: [
283
283
  /* @__PURE__ */ S("div", {
284
284
  className: `${Q} flex justify-center`,
@@ -1 +1 @@
1
- {"version":3,"file":"OrdersPage.js","names":[],"sources":["../../src/pages/OrdersPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState, useCallback } from 'react';\nimport { useNavigate } from 'react-router';\nimport {\n Package,\n ArrowLeft,\n ShoppingBag,\n Download,\n CheckCircle,\n Clock,\n XCircle,\n RefreshCw,\n Loader2,\n ChevronRight,\n} from 'lucide-react';\nimport { useStore } from '../providers/StoreProvider';\nimport { useInstallations } from '../hooks/useInstallations';\nimport { useOrders } from '../hooks/useOrders';\nimport { formatPrice } from '../utils';\nimport { InstallAppModal, type AppInfo } from '../components/InstallAppModal';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useTr } from '../shared/hooks/useTr';\nimport { GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useOrderStatusUpdatedSubscription } from '../generated/global-operations';\n\n// Local types for UI\ninterface OrderItem {\n id: string;\n productId: string;\n productName: string;\n productIcon?: string;\n productType: string;\n version?: string;\n quantity: number;\n unitPrice: number;\n totalPrice: number;\n installed?: boolean;\n}\n\ninterface UIOrder {\n id: string;\n orderNumber: string;\n items: OrderItem[];\n /** The order's own catalog-native currency — what item unitPrice/totalPrice\n * below are denominated in (the listed price), regardless of what was\n * actually charged. */\n catalogCurrency: string;\n /** Currency of subtotal/tax/total below — the actually-charged currency\n * when a payment transaction exists, otherwise catalogCurrency (e.g. an\n * unpaid order, or one paid entirely with credits). */\n currency: string;\n subtotal: number;\n tax: number;\n total: number;\n /** True when subtotal/tax/total reflect the real gateway charge\n * (transaction.metadata) rather than the order's catalog-native amounts. */\n isActualCharge: boolean;\n status:\n | 'PENDING'\n | 'PROCESSING'\n | 'COMPLETED'\n | 'FAILED'\n | 'CANCELLED'\n | 'FULFILLED'\n | 'PROCESSED'\n | 'REFUNDED';\n createdAt: string;\n fulfillment?: {\n status?: string | null;\n trackingNumber?: string | null;\n trackingUrl?: string | null;\n carrier?: string | null;\n estimatedDeliveryDate?: string | null;\n } | null;\n}\n\ntype OrdersTab = 'completed' | 'pending';\n\n/** Safely reads a finite number out of an untyped JSON metadata field. */\nfunction toFiniteNumber(value: unknown): number | null {\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n}\n\nconst SUCCESSFUL_ORDER_STATUSES: UIOrder['status'][] = ['COMPLETED', 'FULFILLED', 'PROCESSED'];\n\n/**\n * Get status badge config\n */\nconst getStatusDisplay = (\n status: UIOrder['status'],\n tr: (key: string, fallback: string) => string\n) => {\n switch (status) {\n case 'COMPLETED':\n case 'FULFILLED':\n case 'PROCESSED':\n return {\n icon: CheckCircle,\n classes:\n 'bg-status-success-bg-subtle/15 text-status-success-text border-status-success-text/20',\n label: tr('pages.orders.statusCompleted', 'Completed'),\n };\n case 'PROCESSING':\n return {\n icon: Clock,\n classes:\n 'bg-status-warning-bg-subtle/15 text-status-warning-text border-status-warning-text/20',\n label: tr('pages.orders.statusProcessing', 'Processing'),\n };\n case 'PENDING':\n return {\n icon: Clock,\n classes:\n 'bg-status-warning-bg-subtle/15 text-status-warning-text border-status-warning-text/20',\n label: tr('pages.orders.statusPending', 'Pending'),\n };\n case 'FAILED':\n return {\n icon: XCircle,\n classes: 'bg-status-error-bg-subtle/15 text-status-error-text border-status-error-text/20',\n label: tr('pages.orders.statusFailed', 'Failed'),\n };\n case 'REFUNDED':\n return {\n icon: RefreshCw,\n classes:\n 'bg-status-warning-bg-subtle/15 text-status-warning-text border-status-warning-text/20',\n label: tr('pages.orders.statusRefunded', 'Refunded'),\n };\n case 'CANCELLED':\n return {\n icon: RefreshCw,\n classes: 'bg-bg-sunken text-text-muted border-border-default',\n label: tr('pages.orders.statusCancelled', 'Cancelled'),\n };\n default:\n return {\n icon: Clock,\n classes: 'bg-bg-sunken text-text-muted border-border-default',\n label: status,\n };\n }\n};\n\n/**\n * Status badge component\n */\nconst StatusBadge: FC<{\n status: UIOrder['status'];\n tr: (key: string, fallback: string) => string;\n}> = ({ status, tr }) => {\n const display = getStatusDisplay(status, tr);\n const Icon = display.icon;\n return (\n <span\n className={`inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-semibold ${display.classes}`}\n >\n <Icon className=\"size-3.5\" />\n {display.label}\n </span>\n );\n};\n\n/**\n * OrdersPage component\n *\n * Displays a table of all orders with expandable rows showing line items\n * and Install App buttons for digital products.\n */\nexport const OrdersPage: FC = () => {\n const navigate = useNavigate();\n const { basePath } = useStore();\n const { t } = useI18n();\n const tr = useTr();\n const { orders: backendOrders, loading, error, refetchOrders, hasMore, loadMore } = useOrders();\n const { installations, refetch: refetchInstallations } = useInstallations();\n\n useOrderStatusUpdatedSubscription({\n onData: () => {\n void refetchOrders();\n },\n onError: (err) => {\n console.warn('OrderStatusUpdated subscription error:', err.message);\n },\n });\n\n // Expanded rows tracking\n const [expandedOrders, setExpandedOrders] = useState<Set<string>>(new Set());\n const [activeTab, setActiveTab] = useState<OrdersTab>('completed');\n\n // Modal state\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [selectedOrderId, setSelectedOrderId] = useState<string | null>(null);\n const [selectedApp, setSelectedApp] = useState<AppInfo | null>(null);\n const [selectedItemId, setSelectedItemId] = useState<string | null>(null);\n\n const installedProductIds = useMemo(\n () =>\n new Set(\n installations.flatMap((installation) =>\n installation.status === 'ACTIVE' ? [installation.productId] : []\n )\n ),\n [installations]\n );\n\n // Map backend orders to UI format\n const orders: UIOrder[] = backendOrders.map((order) => {\n const lineItems = order.lineItems || [];\n const catalogSubtotal = lineItems.reduce((sum, item) => sum + item.subtotal, 0);\n\n // Prefer the real gateway charge (BOFF-7192): order.total/currency are\n // the order's own catalog-native bookkeeping, which can differ from\n // what was actually charged — e.g. a USD-listed item charged in INR via\n // Razorpay, with GST added. The actual subtotal/tax/total live in the\n // paired transaction's metadata (see webhook handlers for how it's\n // written); transaction.amount/currency alone is only the pre-tax\n // gateway amount, not the full charge.\n const gatewayMeta = order.transaction?.metadata;\n const gatewaySubtotal = toFiniteNumber(gatewayMeta?.subtotal);\n const gatewayTax = toFiniteNumber(gatewayMeta?.taxAmount);\n const gatewayTotal = toFiniteNumber(gatewayMeta?.total);\n const hasActualCharge =\n gatewaySubtotal != null && gatewayTotal != null && order.transaction?.currency != null;\n\n const currency = hasActualCharge ? order.transaction!.currency : order.currency;\n const subtotal = hasActualCharge ? gatewaySubtotal! : catalogSubtotal;\n const tax = hasActualCharge ? (gatewayTax ?? 0) : 0;\n const total = hasActualCharge ? gatewayTotal! : order.total;\n\n const items: OrderItem[] = lineItems.map((item, index) => ({\n id: `${order.id}-${index}`,\n productId: item.productId,\n productName: item.name,\n productIcon: item.productIcon,\n productType:\n item.productType ||\n (typeof item.itemType === 'string' ? item.itemType.toUpperCase() : 'APP'),\n version: item.version,\n quantity: item.quantity,\n unitPrice: item.unitPrice,\n totalPrice: item.subtotal,\n installed: installedProductIds.has(item.productId),\n }));\n\n return {\n id: order.id,\n orderNumber: `#${order.id.slice(-8).toUpperCase()}`,\n items,\n catalogCurrency: order.currency,\n currency,\n subtotal,\n tax,\n total,\n isActualCharge: hasActualCharge,\n status: order.status as UIOrder['status'],\n createdAt: order.createdAt,\n fulfillment: order.fulfillment ?? null,\n };\n });\n\n const completedOrders = useMemo(\n () => orders.filter((order) => SUCCESSFUL_ORDER_STATUSES.includes(order.status)),\n [orders]\n );\n\n const pendingOrders = useMemo(\n () => orders.filter((order) => !SUCCESSFUL_ORDER_STATUSES.includes(order.status)),\n [orders]\n );\n\n const visibleOrders = activeTab === 'completed' ? completedOrders : pendingOrders;\n\n const toggleExpand = useCallback((orderId: string) => {\n setExpandedOrders((prev) => {\n const next = new Set(prev);\n if (next.has(orderId)) {\n next.delete(orderId);\n } else {\n next.add(orderId);\n }\n return next;\n });\n }, []);\n\n const handleOpenInstallModal = (orderId: string, item: OrderItem) => {\n setSelectedOrderId(orderId);\n setSelectedItemId(item.id);\n setSelectedApp({\n id: item.productId,\n name: item.productName,\n icon: item.productIcon,\n type: item.productType,\n version: item.version,\n });\n setIsModalOpen(true);\n };\n\n const handleCloseModal = () => {\n setIsModalOpen(false);\n setSelectedOrderId(null);\n setSelectedApp(null);\n setSelectedItemId(null);\n };\n\n const handleInstallSuccess = (_workspaceId: string, _workspaceName: string) => {\n handleCloseModal();\n void refetchInstallations();\n };\n\n const handleInstallError = (_error: Error) => {\n // Error is displayed in modal\n };\n\n const handleBrowseMarketplace = () => {\n navigate(`${basePath}/marketplace`);\n };\n\n // ──── Shared table cell classes ────\n const cellCls = 'px-4 py-3 text-sm';\n const headerCls =\n 'px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-text-muted';\n\n return (\n <div className=\"flex h-full flex-col\">\n {/* Header */}\n <header className=\"flex-shrink-0 border-b border-border-seam bg-bg-surface px-6 py-4\">\n <div className=\"mx-auto max-w-6xl\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate(-1)}\n aria-label=\"Go back\"\n className=\"cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <div className=\"flex items-center gap-3\">\n <Package className=\"size-6 text-text-primary\" />\n <h1 className=\"text-xl font-bold text-text-primary\">\n {t('pages.orders.title', { defaultValue: 'My Orders' })}\n </h1>\n {orders.length > 0 && (\n <span className=\"rounded-full bg-action-primary-bg/10 px-2.5 py-0.5 text-sm font-medium text-action-primary-bg\">\n {orders.length}\n </span>\n )}\n </div>\n </div>\n </div>\n </div>\n </header>\n\n {/* Scrollable content area */}\n <div className=\"flex-1 overflow-y-auto\">\n <div className=\"mx-auto max-w-6xl p-6\">\n <PagePurpose className=\"mb-6\">\n {tr(\n 'pages.orders.purpose',\n \"A record of everything you've purchased from the marketplace. Track each order's status, review what you paid, and — once an order is complete — install the apps you bought into a workspace right from here. Come back to re-install on a new workspace or check a past receipt.\"\n )}\n </PagePurpose>\n\n {loading && orders.length === 0 ? (\n // ── Loading state ──\n <div className=\"flex flex-col items-center justify-center py-24\">\n <Loader2 className=\"size-12 animate-spin text-text-muted mb-4\" aria-hidden=\"true\" />\n <p className=\"text-text-muted\">\n {tr('pages.orders.loading', 'Loading your orders…')}\n </p>\n </div>\n ) : error ? (\n // ── Error state ──\n <div className=\"flex flex-col items-center justify-center py-24 text-center\">\n <div className=\"mb-6 rounded-full bg-status-error-bg-subtle/10 p-6\">\n <XCircle className=\"size-16 text-status-error-text\" />\n </div>\n <h2 className=\"mb-2 text-2xl font-bold text-text-primary\">\n {t('pages.orders.failedToLoad', { defaultValue: 'Failed to load orders' })}\n </h2>\n <p className=\"mb-6 max-w-md text-text-muted\">\n {error.message ||\n tr(\n 'pages.orders.errorDescription',\n 'An error occurred while loading your orders. Please try again.'\n )}\n </p>\n <button\n type=\"button\"\n onClick={handleBrowseMarketplace}\n className=\"cursor-pointer flex items-center gap-2 rounded-lg bg-action-primary-bg px-6 py-3 font-semibold text-action-primary-text transition-opacity hover:opacity-90\"\n >\n <ShoppingBag className=\"size-5\" />\n {tr('pages.orders.browseMarketplace', 'Browse Marketplace')}\n </button>\n </div>\n ) : orders.length === 0 ? (\n // ── Empty state ──\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('pages.orders.emptyTitle', { defaultValue: 'No orders yet' })}\n description={tr(\n 'pages.orders.emptyDescription',\n 'You have not placed any orders yet. Browse the marketplace to discover apps and products!'\n )}\n action={\n <button\n type=\"button\"\n onClick={handleBrowseMarketplace}\n className=\"cursor-pointer flex items-center gap-2 rounded-lg bg-action-primary-bg px-6 py-3 font-semibold text-action-primary-text transition-opacity hover:opacity-90\"\n >\n <ShoppingBag className=\"size-5\" />\n {tr('pages.orders.browseMarketplace', 'Browse Marketplace')}\n </button>\n }\n />\n ) : (\n // ── Table ──\n <div className=\"space-y-4\">\n <div className=\"inline-flex rounded-xl border border-border-seam bg-bg-surface p-1\">\n <button\n type=\"button\"\n onClick={() => setActiveTab('completed')}\n className={`rounded-lg px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === 'completed'\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-muted hover:bg-bg-sunken hover:text-text-primary'\n }`}\n >\n {tr('pages.orders.tabCompleted', 'Completed')}\n <span className=\"ml-2 rounded-full bg-black/10 px-2 py-0.5 text-xs\">\n {completedOrders.length}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={() => setActiveTab('pending')}\n className={`rounded-lg px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === 'pending'\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-muted hover:bg-bg-sunken hover:text-text-primary'\n }`}\n >\n {tr('pages.orders.tabPending', 'Pending')}\n <span className=\"ml-2 rounded-full bg-black/10 px-2 py-0.5 text-xs\">\n {pendingOrders.length}\n </span>\n </button>\n </div>\n\n {visibleOrders.length === 0 ? (\n <GlassCard className=\"p-10 text-center\">\n <div className=\"mx-auto mb-4 flex size-14 items-center justify-center rounded-full bg-bg-sunken text-text-muted\">\n <Package className=\"size-6\" />\n </div>\n <h2 className=\"mb-2 text-lg font-semibold text-text-primary\">\n {activeTab === 'completed'\n ? tr('pages.orders.noCompletedTitle', 'No completed orders yet')\n : tr('pages.orders.noPendingTitle', 'No pending orders')}\n </h2>\n <p className=\"text-sm text-text-muted\">\n {activeTab === 'completed'\n ? tr(\n 'pages.orders.noCompletedDescription',\n 'Completed purchases will appear here once payment is successful.'\n )\n : tr(\n 'pages.orders.noPendingDescription',\n 'Orders that are pending, processing, failed, refunded, or cancelled will appear here.'\n )}\n </p>\n </GlassCard>\n ) : (\n <div className=\"overflow-hidden rounded-xl border border-border-seam bg-bg-surface\">\n {/* Table Header */}\n <div className=\"hidden border-b border-border-seam bg-bg-sunken/50 md:grid md:grid-cols-[40px_1fr_180px_140px_120px_160px]\">\n <div className={headerCls} />\n <div className={headerCls}>{tr('pages.orders.colOrder', 'Order')}</div>\n <div className={headerCls}>{tr('pages.orders.colDate', 'Date')}</div>\n <div className={headerCls}>{tr('pages.orders.colItems', 'Items')}</div>\n <div className={`${headerCls} text-right`}>\n {tr('pages.orders.colTotal', 'Total')}\n </div>\n <div className={`${headerCls} text-center`}>\n {tr('pages.orders.colStatus', 'Status')}\n </div>\n </div>\n\n {/* Table Body */}\n {visibleOrders.map((order) => {\n const isExpanded = expandedOrders.has(order.id);\n const isSuccessful =\n order.status === 'COMPLETED' ||\n order.status === 'FULFILLED' ||\n order.status === 'PROCESSED';\n\n return (\n <div key={order.id} className=\"border-b border-border-seam last:border-b-0\">\n {/* Order Row */}\n <button\n type=\"button\"\n onClick={() => toggleExpand(order.id)}\n className=\"grid w-full cursor-pointer grid-cols-[40px_1fr_180px_140px_120px_160px] items-center transition-colors hover:bg-bg-sunken/50 md:grid\"\n >\n {/* Expand/collapse chevron */}\n <div className={`${cellCls} flex justify-center`}>\n <ChevronRight\n className={`size-4 text-text-muted transition-transform duration-200 ${\n isExpanded ? 'rotate-90' : ''\n }`}\n />\n </div>\n\n {/* Order number */}\n <div className={`${cellCls} font-medium text-text-primary`}>\n {order.orderNumber}\n </div>\n\n {/* Date */}\n <div className={`${cellCls} text-text-muted`}>\n {new Date(order.createdAt).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })}\n </div>\n\n {/* Items summary */}\n <div className={`${cellCls} text-text-muted`}>\n {order.items.length}{' '}\n {order.items.length === 1\n ? tr('pages.orders.item', 'item')\n : tr('pages.orders.items', 'items')}\n <span className=\"block text-xs text-text-muted/70\">\n {order.items.map((i) => i.productName).join(', ')}\n </span>\n </div>\n\n {/* Total */}\n <div\n className={`${cellCls} text-right font-semibold tabular-nums text-text-primary`}\n >\n {formatPrice(order.total, order.currency)}\n </div>\n\n {/* Status */}\n <div className={`${cellCls} flex justify-center`}>\n <StatusBadge status={order.status} tr={tr} />\n </div>\n </button>\n\n {/* Expanded: Line items */}\n {isExpanded && (\n <div className=\"border-t border-border-seam bg-bg-sunken/30\">\n {order.fulfillment && (\n <div className=\"mx-4 mt-4 rounded-xl border border-border-seam bg-bg-surface px-4 py-4 md:mx-12\">\n <div className=\"flex flex-col gap-3 md:flex-row md:items-center md:justify-between\">\n <div>\n <div className=\"text-sm font-semibold text-text-primary\">\n {tr('pages.orders.orderTracking', 'Order tracking')}\n </div>\n <div className=\"mt-1 text-xs text-text-muted\">\n {order.fulfillment.status ||\n tr('pages.orders.statusPending', 'Pending')}\n {order.fulfillment.carrier\n ? ` · ${order.fulfillment.carrier}`\n : ''}\n {order.fulfillment.estimatedDeliveryDate\n ? ` · ${tr('pages.orders.estimatedDelivery', 'Est. delivery {{date}}', { date: new Date(order.fulfillment.estimatedDeliveryDate).toLocaleDateString() })}`\n : ''}\n </div>\n </div>\n\n <div className=\"flex flex-col items-start gap-2 md:items-end\">\n {order.fulfillment.trackingNumber && (\n <div className=\"text-xs text-text-muted\">\n {tr(\n 'pages.orders.trackingNumber',\n 'Tracking #: {{number}}',\n { number: order.fulfillment.trackingNumber }\n )}\n </div>\n )}\n {order.fulfillment.trackingUrl && (\n <a\n href={order.fulfillment.trackingUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 rounded-md border border-border-default px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken\"\n >\n {tr('pages.orders.trackPackage', 'Track package')}\n <ChevronRight className=\"size-3.5\" />\n </a>\n )}\n </div>\n </div>\n\n <div className=\"mt-4 grid gap-2 sm:grid-cols-4\">\n {[\n {\n key: 'PROCESSING',\n label: tr('pages.orders.stepProcessing', 'Processing'),\n },\n {\n key: 'SHIPPED',\n label: tr('pages.orders.stepShipped', 'Shipped'),\n },\n {\n key: 'OUT_FOR_DELIVERY',\n label: tr(\n 'pages.orders.stepOutForDelivery',\n 'Out for delivery'\n ),\n },\n {\n key: 'DELIVERED',\n label: tr('pages.orders.stepDelivered', 'Delivered'),\n },\n ].map((step) => {\n const current = order.fulfillment?.status || 'PENDING';\n const reached =\n [\n 'PROCESSING',\n 'READY_TO_SHIP',\n 'SHIPPED',\n 'IN_TRANSIT',\n 'OUT_FOR_DELIVERY',\n 'DELIVERED',\n ].indexOf(current) >=\n [\n 'PROCESSING',\n 'SHIPPED',\n 'OUT_FOR_DELIVERY',\n 'DELIVERED',\n ].indexOf(step.key);\n return (\n <div\n key={step.key}\n className={`rounded-lg border px-3 py-2 text-xs font-medium ${\n reached\n ? 'border-status-success-border bg-status-success-bg-subtle text-status-success-text'\n : 'border-border-seam bg-bg-sunken/40 text-text-muted'\n }`}\n >\n {step.label}\n </div>\n );\n })}\n </div>\n </div>\n )}\n\n {/* Column headers for items */}\n <div className=\"hidden grid-cols-[1fr_100px_120px_160px] gap-4 px-12 py-2 md:grid\">\n <span className=\"text-xs font-medium text-text-muted\">\n {tr('pages.orders.colProduct', 'Product')}\n </span>\n <span className=\"text-xs font-medium text-text-muted text-right\">\n {tr('pages.orders.colQty', 'Qty')}\n </span>\n <span className=\"text-xs font-medium text-text-muted text-right\">\n {tr('pages.orders.colPrice', 'Price')}\n </span>\n <span className=\"text-xs font-medium text-text-muted text-center\">\n {tr('pages.orders.colAction', 'Action')}\n </span>\n </div>\n\n {order.items.map((item) => {\n const isInstallable =\n item.productType !== 'PHYSICAL' &&\n item.productType !== 'MERCHANDISE';\n\n return (\n <div\n key={item.id}\n className=\"grid grid-cols-[auto_1fr_auto] items-center gap-3 px-4 py-3 md:px-12 md:grid-cols-[1fr_100px_120px_160px]\"\n >\n {/* Product info */}\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"size-10 flex-shrink-0 overflow-hidden rounded-lg bg-bg-sunken\">\n {item.productIcon ? (\n <img\n src={item.productIcon}\n alt={item.productName}\n className=\"size-full object-cover\"\n />\n ) : (\n <div className=\"flex size-full items-center justify-center text-sm font-bold text-text-muted\">\n {item.productName.charAt(0)}\n </div>\n )}\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {item.productName}\n </p>\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-muted\">\n {item.productType}\n </span>\n </div>\n </div>\n\n {/* Quantity */}\n <div className=\"hidden text-right text-sm text-text-muted md:block\">\n {item.quantity}\n </div>\n\n {/* Price */}\n <div className=\"hidden text-right text-sm font-semibold tabular-nums text-text-primary md:block\">\n {formatPrice(item.totalPrice, order.catalogCurrency)}\n </div>\n\n {/* Mobile price + qty */}\n <div className=\"text-right text-sm text-text-muted md:hidden\">\n <span className=\"tabular-nums\">\n {tr('pages.orders.qtyTimesPrice', '{{qty}} × {{price}}', {\n qty: item.quantity,\n price: formatPrice(item.unitPrice, order.catalogCurrency),\n })}\n </span>\n </div>\n\n {/* Install button */}\n <div className=\"flex justify-end md:justify-center\">\n {item.installed ? (\n <span className=\"inline-flex items-center gap-1 rounded-lg px-3 py-1.5 text-xs font-medium text-status-success-text\">\n <CheckCircle className=\"size-3.5\" />\n {tr('pages.orders.installed', 'Installed')}\n </span>\n ) : isSuccessful && isInstallable ? (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleOpenInstallModal(order.id, item);\n }}\n className=\"inline-flex cursor-pointer items-center gap-1.5 rounded-lg bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-text transition-all hover:opacity-90 active:scale-95\"\n >\n <Download className=\"size-3.5\" />\n {tr('pages.orders.installApp', 'Install App')}\n </button>\n ) : null}\n </div>\n </div>\n );\n })}\n\n {/* Order summary footer */}\n <div className=\"border-t border-border-seam/50 px-4 py-2 md:px-12\">\n {order.isActualCharge && order.currency !== order.catalogCurrency && (\n <p className=\"mb-1 text-right text-xs text-text-muted\">\n {tr(\n 'pages.orders.paidInCurrency',\n 'Listed in {{catalogCurrency}}, actually charged in {{currency}}',\n { catalogCurrency: order.catalogCurrency, currency: order.currency }\n )}\n </p>\n )}\n <div className=\"flex justify-end gap-6 text-xs text-text-muted\">\n <span>\n {tr('pages.orders.subtotal', 'Subtotal:')}{' '}\n <span className=\"tabular-nums text-text-primary\">\n {formatPrice(order.subtotal, order.currency)}\n </span>\n </span>\n <span>\n {tr('pages.orders.tax', 'Tax:')}{' '}\n <span className=\"tabular-nums text-text-primary\">\n {formatPrice(order.tax, order.currency)}\n </span>\n </span>\n <span className=\"font-semibold\">\n {tr('pages.orders.total', 'Total:')}{' '}\n <span className=\"tabular-nums text-text-primary\">\n {formatPrice(order.total, order.currency)}\n </span>\n </span>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n })}\n\n {/* Load More */}\n {hasMore && (\n <div className=\"flex justify-center px-4 py-5\">\n <button\n type=\"button\"\n onClick={loadMore}\n disabled={loading}\n className=\"flex items-center gap-2 rounded-lg border border-border-default px-6 py-2.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-subtle disabled:opacity-50\"\n aria-label={t('common.loadMore', { defaultValue: 'Load more' })}\n >\n {loading ? (\n <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" />\n ) : null}\n {t('common.loadMore', { defaultValue: 'Load more' })}\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n\n {/* Install App Modal */}\n {selectedApp && (\n <InstallAppModal\n isOpen={isModalOpen}\n onClose={handleCloseModal}\n app={selectedApp}\n orderId={selectedOrderId}\n onInstallSuccess={handleInstallSuccess}\n onInstallError={handleInstallError}\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"OrdersPage.js","names":[],"sources":["../../src/pages/OrdersPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState, useCallback } from 'react';\nimport { useNavigate } from 'react-router';\nimport {\n Package,\n ArrowLeft,\n ShoppingBag,\n Download,\n CheckCircle,\n Clock,\n XCircle,\n RefreshCw,\n Loader2,\n ChevronRight,\n} from 'lucide-react';\nimport { useStore } from '../providers/StoreProvider';\nimport { useInstallations } from '../hooks/useInstallations';\nimport { useOrders } from '../hooks/useOrders';\nimport { formatPrice } from '../utils';\nimport { InstallAppModal, type AppInfo } from '../components/InstallAppModal';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useTr } from '../shared/hooks/useTr';\nimport { GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useOrderStatusUpdatedSubscription } from '../generated/global-operations';\n\n// Local types for UI\ninterface OrderItem {\n id: string;\n productId: string;\n productName: string;\n productIcon?: string;\n productType: string;\n version?: string;\n quantity: number;\n unitPrice: number;\n totalPrice: number;\n installed?: boolean;\n}\n\ninterface UIOrder {\n id: string;\n orderNumber: string;\n items: OrderItem[];\n /** The order's own catalog-native currency — what item unitPrice/totalPrice\n * below are denominated in (the listed price), regardless of what was\n * actually charged. */\n catalogCurrency: string;\n /** Currency of subtotal/tax/total below — the actually-charged currency\n * when a payment transaction exists, otherwise catalogCurrency (e.g. an\n * unpaid order, or one paid entirely with credits). */\n currency: string;\n subtotal: number;\n tax: number;\n total: number;\n /** True when subtotal/tax/total reflect the real gateway charge\n * (transaction.metadata) rather than the order's catalog-native amounts. */\n isActualCharge: boolean;\n status:\n | 'PENDING'\n | 'PROCESSING'\n | 'COMPLETED'\n | 'FAILED'\n | 'CANCELLED'\n | 'FULFILLED'\n | 'PROCESSED'\n | 'REFUNDED';\n createdAt: string;\n fulfillment?: {\n status?: string | null;\n trackingNumber?: string | null;\n trackingUrl?: string | null;\n carrier?: string | null;\n estimatedDeliveryDate?: string | null;\n } | null;\n}\n\ntype OrdersTab = 'completed' | 'pending';\n\n/** Safely reads a finite number out of an untyped JSON metadata field. */\nfunction toFiniteNumber(value: unknown): number | null {\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n}\n\nconst SUCCESSFUL_ORDER_STATUSES: UIOrder['status'][] = ['COMPLETED', 'FULFILLED', 'PROCESSED'];\n\n/**\n * Get status badge config\n */\nconst getStatusDisplay = (\n status: UIOrder['status'],\n tr: (key: string, fallback: string) => string\n) => {\n switch (status) {\n case 'COMPLETED':\n case 'FULFILLED':\n case 'PROCESSED':\n return {\n icon: CheckCircle,\n classes:\n 'bg-status-success-bg-subtle/15 text-status-success-text border-status-success-text/20',\n label: tr('pages.orders.statusCompleted', 'Completed'),\n };\n case 'PROCESSING':\n return {\n icon: Clock,\n classes:\n 'bg-status-warning-bg-subtle/15 text-status-warning-text border-status-warning-text/20',\n label: tr('pages.orders.statusProcessing', 'Processing'),\n };\n case 'PENDING':\n return {\n icon: Clock,\n classes:\n 'bg-status-warning-bg-subtle/15 text-status-warning-text border-status-warning-text/20',\n label: tr('pages.orders.statusPending', 'Pending'),\n };\n case 'FAILED':\n return {\n icon: XCircle,\n classes: 'bg-status-error-bg-subtle/15 text-status-error-text border-status-error-text/20',\n label: tr('pages.orders.statusFailed', 'Failed'),\n };\n case 'REFUNDED':\n return {\n icon: RefreshCw,\n classes:\n 'bg-status-warning-bg-subtle/15 text-status-warning-text border-status-warning-text/20',\n label: tr('pages.orders.statusRefunded', 'Refunded'),\n };\n case 'CANCELLED':\n return {\n icon: RefreshCw,\n classes: 'bg-bg-sunken text-text-muted border-border-default',\n label: tr('pages.orders.statusCancelled', 'Cancelled'),\n };\n default:\n return {\n icon: Clock,\n classes: 'bg-bg-sunken text-text-muted border-border-default',\n label: status,\n };\n }\n};\n\n/**\n * Status badge component\n */\nconst StatusBadge: FC<{\n status: UIOrder['status'];\n tr: (key: string, fallback: string) => string;\n}> = ({ status, tr }) => {\n const display = getStatusDisplay(status, tr);\n const Icon = display.icon;\n return (\n <span\n className={`inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-semibold ${display.classes}`}\n >\n <Icon className=\"size-3.5\" />\n {display.label}\n </span>\n );\n};\n\n/**\n * OrdersPage component\n *\n * Displays a table of all orders with expandable rows showing line items\n * and Install App buttons for digital products.\n */\nexport const OrdersPage: FC = () => {\n const navigate = useNavigate();\n const { basePath } = useStore();\n const { t } = useI18n();\n const tr = useTr();\n const { orders: backendOrders, loading, error, refetchOrders, hasMore, loadMore } = useOrders();\n const { installations, refetch: refetchInstallations } = useInstallations();\n\n useOrderStatusUpdatedSubscription({\n onData: () => {\n void refetchOrders();\n },\n onError: (err) => {\n console.warn('OrderStatusUpdated subscription error:', err.message);\n },\n });\n\n // Expanded rows tracking\n const [expandedOrders, setExpandedOrders] = useState<Set<string>>(new Set());\n const [activeTab, setActiveTab] = useState<OrdersTab>('completed');\n\n // Modal state\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [selectedOrderId, setSelectedOrderId] = useState<string | null>(null);\n const [selectedApp, setSelectedApp] = useState<AppInfo | null>(null);\n const [selectedItemId, setSelectedItemId] = useState<string | null>(null);\n\n const installedProductIds = useMemo(\n () =>\n new Set(\n installations.flatMap((installation) =>\n installation.status === 'ACTIVE' ? [installation.productId] : []\n )\n ),\n [installations]\n );\n\n // Map backend orders to UI format\n const orders: UIOrder[] = backendOrders.map((order) => {\n const lineItems = order.lineItems || [];\n const catalogSubtotal = lineItems.reduce((sum, item) => sum + item.subtotal, 0);\n\n // Prefer the real gateway charge (BOFF-7192): order.total/currency are\n // the order's own catalog-native bookkeeping, which can differ from\n // what was actually charged — e.g. a USD-listed item charged in INR via\n // Razorpay, with GST added. The actual subtotal/tax/total live in the\n // paired transaction's metadata (see webhook handlers for how it's\n // written); transaction.amount/currency alone is only the pre-tax\n // gateway amount, not the full charge.\n const gatewayMeta = order.transaction?.metadata;\n const gatewaySubtotal = toFiniteNumber(gatewayMeta?.subtotal);\n const gatewayTax = toFiniteNumber(gatewayMeta?.taxAmount);\n const gatewayTotal = toFiniteNumber(gatewayMeta?.total);\n const hasActualCharge =\n gatewaySubtotal != null && gatewayTotal != null && order.transaction?.currency != null;\n\n const currency = hasActualCharge ? order.transaction!.currency : order.currency;\n const subtotal = hasActualCharge ? gatewaySubtotal! : catalogSubtotal;\n const tax = hasActualCharge ? (gatewayTax ?? 0) : 0;\n const total = hasActualCharge ? gatewayTotal! : order.total;\n\n const items: OrderItem[] = lineItems.map((item, index) => ({\n id: `${order.id}-${index}`,\n productId: item.productId,\n productName: item.name,\n productIcon: item.productIcon,\n productType:\n item.productType ||\n (typeof item.itemType === 'string' ? item.itemType.toUpperCase() : 'APP'),\n version: item.version,\n quantity: item.quantity,\n unitPrice: item.unitPrice,\n totalPrice: item.subtotal,\n installed: installedProductIds.has(item.productId),\n }));\n\n return {\n id: order.id,\n orderNumber: `#${order.id.slice(-8).toUpperCase()}`,\n items,\n catalogCurrency: order.currency,\n currency,\n subtotal,\n tax,\n total,\n isActualCharge: hasActualCharge,\n status: order.status as UIOrder['status'],\n createdAt: order.createdAt,\n fulfillment: order.fulfillment ?? null,\n };\n });\n\n const completedOrders = useMemo(\n () => orders.filter((order) => SUCCESSFUL_ORDER_STATUSES.includes(order.status)),\n [orders]\n );\n\n const pendingOrders = useMemo(\n () => orders.filter((order) => !SUCCESSFUL_ORDER_STATUSES.includes(order.status)),\n [orders]\n );\n\n const visibleOrders = activeTab === 'completed' ? completedOrders : pendingOrders;\n\n const toggleExpand = useCallback((orderId: string) => {\n setExpandedOrders((prev) => {\n const next = new Set(prev);\n if (next.has(orderId)) {\n next.delete(orderId);\n } else {\n next.add(orderId);\n }\n return next;\n });\n }, []);\n\n const handleOpenInstallModal = (orderId: string, item: OrderItem) => {\n setSelectedOrderId(orderId);\n setSelectedItemId(item.id);\n setSelectedApp({\n id: item.productId,\n name: item.productName,\n icon: item.productIcon,\n type: item.productType,\n version: item.version,\n });\n setIsModalOpen(true);\n };\n\n const handleCloseModal = () => {\n setIsModalOpen(false);\n setSelectedOrderId(null);\n setSelectedApp(null);\n setSelectedItemId(null);\n };\n\n const handleInstallSuccess = (_workspaceId: string, _workspaceName: string) => {\n handleCloseModal();\n void refetchInstallations();\n };\n\n const handleInstallError = (_error: Error) => {\n // Error is displayed in modal\n };\n\n const handleBrowseMarketplace = () => {\n navigate(`${basePath}/marketplace`);\n };\n\n // ──── Shared table cell classes ────\n const cellCls = 'px-4 py-3 text-sm';\n const headerCls =\n 'px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-text-muted';\n\n return (\n <div className=\"flex h-full flex-col\">\n {/* Header */}\n <header className=\"flex-shrink-0 border-b border-border-seam bg-bg-surface px-6 py-4\">\n <div className=\"mx-auto max-w-6xl\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate(-1)}\n aria-label=\"Go back\"\n className=\"cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <div className=\"flex items-center gap-3\">\n <Package className=\"size-6 text-text-primary\" />\n <h1 className=\"text-xl font-bold text-text-primary\">\n {t('pages.orders.title', { defaultValue: 'My Orders' })}\n </h1>\n {orders.length > 0 && (\n <span className=\"rounded-full bg-action-primary-bg/10 px-2.5 py-0.5 text-sm font-medium text-action-primary-bg\">\n {orders.length}\n </span>\n )}\n </div>\n </div>\n </div>\n </div>\n </header>\n\n {/* Scrollable content area */}\n <div className=\"flex-1 overflow-y-auto\">\n <div className=\"mx-auto max-w-6xl p-6\">\n <PagePurpose className=\"mb-6\">\n {tr(\n 'pages.orders.purpose',\n \"A record of everything you've purchased from the marketplace. Track each order's status, review what you paid, and — once an order is complete — install the apps you bought into a workspace right from here. Come back to re-install on a new workspace or check a past receipt.\"\n )}\n </PagePurpose>\n\n {loading && orders.length === 0 ? (\n // ── Loading state ──\n <div className=\"flex flex-col items-center justify-center py-24\">\n <Loader2 className=\"size-12 animate-spin text-text-muted mb-4\" aria-hidden=\"true\" />\n <p className=\"text-text-muted\">\n {tr('pages.orders.loading', 'Loading your orders…')}\n </p>\n </div>\n ) : error ? (\n // ── Error state ──\n <div className=\"flex flex-col items-center justify-center py-24 text-center\">\n <div className=\"mb-6 rounded-full bg-status-error-bg-subtle/10 p-6\">\n <XCircle className=\"size-16 text-status-error-text\" />\n </div>\n <h2 className=\"mb-2 text-2xl font-bold text-text-primary\">\n {t('pages.orders.failedToLoad', { defaultValue: 'Failed to load orders' })}\n </h2>\n <p className=\"mb-6 max-w-md text-text-muted\">\n {error.message ||\n tr(\n 'pages.orders.errorDescription',\n 'An error occurred while loading your orders. Please try again.'\n )}\n </p>\n <button\n type=\"button\"\n onClick={handleBrowseMarketplace}\n className=\"cursor-pointer flex items-center gap-2 rounded-lg bg-action-primary-bg px-6 py-3 font-semibold text-action-primary-text transition-opacity hover:opacity-90\"\n >\n <ShoppingBag className=\"size-5\" />\n {tr('pages.orders.browseMarketplace', 'Browse Marketplace')}\n </button>\n </div>\n ) : orders.length === 0 ? (\n // ── Empty state ──\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('pages.orders.emptyTitle', { defaultValue: 'No orders yet' })}\n description={tr(\n 'pages.orders.emptyDescription',\n 'You have not placed any orders yet. Browse the marketplace to discover apps and products!'\n )}\n action={\n <button\n type=\"button\"\n onClick={handleBrowseMarketplace}\n className=\"cursor-pointer flex items-center gap-2 rounded-lg bg-action-primary-bg px-6 py-3 font-semibold text-action-primary-text transition-opacity hover:opacity-90\"\n >\n <ShoppingBag className=\"size-5\" />\n {tr('pages.orders.browseMarketplace', 'Browse Marketplace')}\n </button>\n }\n />\n ) : (\n // ── Table ──\n <div className=\"space-y-4\">\n <div className=\"inline-flex rounded-xl border border-border-seam bg-bg-surface p-1\">\n <button\n type=\"button\"\n onClick={() => setActiveTab('completed')}\n className={`rounded-lg px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === 'completed'\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-muted hover:bg-bg-sunken hover:text-text-primary'\n }`}\n >\n {tr('pages.orders.tabCompleted', 'Completed')}\n <span className=\"ml-2 rounded-full bg-black/10 px-2 py-0.5 text-xs\">\n {completedOrders.length}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={() => setActiveTab('pending')}\n className={`rounded-lg px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === 'pending'\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-muted hover:bg-bg-sunken hover:text-text-primary'\n }`}\n >\n {tr('pages.orders.tabPending', 'Pending')}\n <span className=\"ml-2 rounded-full bg-black/10 px-2 py-0.5 text-xs\">\n {pendingOrders.length}\n </span>\n </button>\n </div>\n\n {visibleOrders.length === 0 ? (\n <GlassCard className=\"p-10 text-center\">\n <div className=\"mx-auto mb-4 flex size-14 items-center justify-center rounded-full bg-bg-sunken text-text-muted\">\n <Package className=\"size-6\" />\n </div>\n <h2 className=\"mb-2 text-lg font-semibold text-text-primary\">\n {activeTab === 'completed'\n ? tr('pages.orders.noCompletedTitle', 'No completed orders yet')\n : tr('pages.orders.noPendingTitle', 'No pending orders')}\n </h2>\n <p className=\"text-sm text-text-muted\">\n {activeTab === 'completed'\n ? tr(\n 'pages.orders.noCompletedDescription',\n 'Completed purchases will appear here once payment is successful.'\n )\n : tr(\n 'pages.orders.noPendingDescription',\n 'Orders that are pending, processing, failed, refunded, or cancelled will appear here.'\n )}\n </p>\n </GlassCard>\n ) : (\n <div className=\"overflow-hidden rounded-xl border border-border-seam bg-bg-surface\">\n {/* Table Header */}\n <div className=\"hidden border-b border-border-seam bg-bg-sunken/50 md:grid md:grid-cols-[40px_130px_140px_1fr_120px_140px]\">\n <div className={headerCls} />\n <div className={headerCls}>{tr('pages.orders.colOrder', 'Order')}</div>\n <div className={headerCls}>{tr('pages.orders.colDate', 'Date')}</div>\n <div className={headerCls}>{tr('pages.orders.colItems', 'Items')}</div>\n <div className={`${headerCls} text-right`}>\n {tr('pages.orders.colTotal', 'Total')}\n </div>\n <div className={`${headerCls} text-center`}>\n {tr('pages.orders.colStatus', 'Status')}\n </div>\n </div>\n\n {/* Table Body */}\n {visibleOrders.map((order) => {\n const isExpanded = expandedOrders.has(order.id);\n const isSuccessful =\n order.status === 'COMPLETED' ||\n order.status === 'FULFILLED' ||\n order.status === 'PROCESSED';\n\n return (\n <div key={order.id} className=\"border-b border-border-seam last:border-b-0\">\n {/* Order Row */}\n <button\n type=\"button\"\n onClick={() => toggleExpand(order.id)}\n className=\"grid w-full cursor-pointer grid-cols-[40px_130px_140px_1fr_120px_140px] items-center transition-colors hover:bg-bg-sunken/50 md:grid\"\n >\n {/* Expand/collapse chevron */}\n <div className={`${cellCls} flex justify-center`}>\n <ChevronRight\n className={`size-4 text-text-muted transition-transform duration-200 ${\n isExpanded ? 'rotate-90' : ''\n }`}\n />\n </div>\n\n {/* Order number */}\n <div className={`${cellCls} font-medium text-text-primary`}>\n {order.orderNumber}\n </div>\n\n {/* Date */}\n <div className={`${cellCls} text-text-muted`}>\n {new Date(order.createdAt).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })}\n </div>\n\n {/* Items summary */}\n <div className={`${cellCls} text-text-muted`}>\n {order.items.length}{' '}\n {order.items.length === 1\n ? tr('pages.orders.item', 'item')\n : tr('pages.orders.items', 'items')}\n <span className=\"block text-xs text-text-muted/70\">\n {order.items.map((i) => i.productName).join(', ')}\n </span>\n </div>\n\n {/* Total */}\n <div\n className={`${cellCls} text-right font-semibold tabular-nums text-text-primary`}\n >\n {formatPrice(order.total, order.currency)}\n </div>\n\n {/* Status */}\n <div className={`${cellCls} flex justify-center`}>\n <StatusBadge status={order.status} tr={tr} />\n </div>\n </button>\n\n {/* Expanded: Line items */}\n {isExpanded && (\n <div className=\"border-t border-border-seam bg-bg-sunken/30\">\n {order.fulfillment && (\n <div className=\"mx-4 mt-4 rounded-xl border border-border-seam bg-bg-surface px-4 py-4 md:mx-12\">\n <div className=\"flex flex-col gap-3 md:flex-row md:items-center md:justify-between\">\n <div>\n <div className=\"text-sm font-semibold text-text-primary\">\n {tr('pages.orders.orderTracking', 'Order tracking')}\n </div>\n <div className=\"mt-1 text-xs text-text-muted\">\n {order.fulfillment.status ||\n tr('pages.orders.statusPending', 'Pending')}\n {order.fulfillment.carrier\n ? ` · ${order.fulfillment.carrier}`\n : ''}\n {order.fulfillment.estimatedDeliveryDate\n ? ` · ${tr('pages.orders.estimatedDelivery', 'Est. delivery {{date}}', { date: new Date(order.fulfillment.estimatedDeliveryDate).toLocaleDateString() })}`\n : ''}\n </div>\n </div>\n\n <div className=\"flex flex-col items-start gap-2 md:items-end\">\n {order.fulfillment.trackingNumber && (\n <div className=\"text-xs text-text-muted\">\n {tr(\n 'pages.orders.trackingNumber',\n 'Tracking #: {{number}}',\n { number: order.fulfillment.trackingNumber }\n )}\n </div>\n )}\n {order.fulfillment.trackingUrl && (\n <a\n href={order.fulfillment.trackingUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 rounded-md border border-border-default px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken\"\n >\n {tr('pages.orders.trackPackage', 'Track package')}\n <ChevronRight className=\"size-3.5\" />\n </a>\n )}\n </div>\n </div>\n\n <div className=\"mt-4 grid gap-2 sm:grid-cols-4\">\n {[\n {\n key: 'PROCESSING',\n label: tr('pages.orders.stepProcessing', 'Processing'),\n },\n {\n key: 'SHIPPED',\n label: tr('pages.orders.stepShipped', 'Shipped'),\n },\n {\n key: 'OUT_FOR_DELIVERY',\n label: tr(\n 'pages.orders.stepOutForDelivery',\n 'Out for delivery'\n ),\n },\n {\n key: 'DELIVERED',\n label: tr('pages.orders.stepDelivered', 'Delivered'),\n },\n ].map((step) => {\n const current = order.fulfillment?.status || 'PENDING';\n const reached =\n [\n 'PROCESSING',\n 'READY_TO_SHIP',\n 'SHIPPED',\n 'IN_TRANSIT',\n 'OUT_FOR_DELIVERY',\n 'DELIVERED',\n ].indexOf(current) >=\n [\n 'PROCESSING',\n 'SHIPPED',\n 'OUT_FOR_DELIVERY',\n 'DELIVERED',\n ].indexOf(step.key);\n return (\n <div\n key={step.key}\n className={`rounded-lg border px-3 py-2 text-xs font-medium ${\n reached\n ? 'border-status-success-border bg-status-success-bg-subtle text-status-success-text'\n : 'border-border-seam bg-bg-sunken/40 text-text-muted'\n }`}\n >\n {step.label}\n </div>\n );\n })}\n </div>\n </div>\n )}\n\n {/* Column headers for items */}\n <div className=\"hidden grid-cols-[1fr_100px_120px_160px] gap-4 px-12 py-2 md:grid\">\n <span className=\"text-xs font-medium text-text-muted\">\n {tr('pages.orders.colProduct', 'Product')}\n </span>\n <span className=\"text-xs font-medium text-text-muted text-right\">\n {tr('pages.orders.colQty', 'Qty')}\n </span>\n <span className=\"text-xs font-medium text-text-muted text-right\">\n {tr('pages.orders.colPrice', 'Price')}\n </span>\n <span className=\"text-xs font-medium text-text-muted text-center\">\n {tr('pages.orders.colAction', 'Action')}\n </span>\n </div>\n\n {order.items.map((item) => {\n const isInstallable =\n item.productType !== 'PHYSICAL' &&\n item.productType !== 'MERCHANDISE';\n\n return (\n <div\n key={item.id}\n className=\"grid grid-cols-[auto_1fr_auto] items-center gap-3 px-4 py-3 md:px-12 md:grid-cols-[1fr_100px_120px_160px]\"\n >\n {/* Product info */}\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"size-10 flex-shrink-0 overflow-hidden rounded-lg bg-bg-sunken\">\n {item.productIcon ? (\n <img\n src={item.productIcon}\n alt={item.productName}\n className=\"size-full object-cover\"\n />\n ) : (\n <div className=\"flex size-full items-center justify-center text-sm font-bold text-text-muted\">\n {item.productName.charAt(0)}\n </div>\n )}\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {item.productName}\n </p>\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-muted\">\n {item.productType}\n </span>\n </div>\n </div>\n\n {/* Quantity */}\n <div className=\"hidden text-right text-sm text-text-muted md:block\">\n {item.quantity}\n </div>\n\n {/* Price */}\n <div className=\"hidden text-right text-sm font-semibold tabular-nums text-text-primary md:block\">\n {formatPrice(item.totalPrice, order.catalogCurrency)}\n </div>\n\n {/* Mobile price + qty */}\n <div className=\"text-right text-sm text-text-muted md:hidden\">\n <span className=\"tabular-nums\">\n {tr('pages.orders.qtyTimesPrice', '{{qty}} × {{price}}', {\n qty: item.quantity,\n price: formatPrice(item.unitPrice, order.catalogCurrency),\n })}\n </span>\n </div>\n\n {/* Install button */}\n <div className=\"flex justify-end md:justify-center\">\n {item.installed ? (\n <span className=\"inline-flex items-center gap-1 rounded-lg px-3 py-1.5 text-xs font-medium text-status-success-text\">\n <CheckCircle className=\"size-3.5\" />\n {tr('pages.orders.installed', 'Installed')}\n </span>\n ) : isSuccessful && isInstallable ? (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleOpenInstallModal(order.id, item);\n }}\n className=\"inline-flex cursor-pointer items-center gap-1.5 rounded-lg bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-text transition-all hover:opacity-90 active:scale-95\"\n >\n <Download className=\"size-3.5\" />\n {tr('pages.orders.installApp', 'Install App')}\n </button>\n ) : null}\n </div>\n </div>\n );\n })}\n\n {/* Order summary footer */}\n <div className=\"border-t border-border-seam/50 px-4 py-2 md:px-12\">\n {order.isActualCharge && order.currency !== order.catalogCurrency && (\n <p className=\"mb-1 text-right text-xs text-text-muted\">\n {tr(\n 'pages.orders.paidInCurrency',\n 'Listed in {{catalogCurrency}}, actually charged in {{currency}}',\n {\n catalogCurrency: order.catalogCurrency,\n currency: order.currency,\n }\n )}\n </p>\n )}\n <div className=\"flex justify-end gap-6 text-xs text-text-muted\">\n <span>\n {tr('pages.orders.subtotal', 'Subtotal:')}{' '}\n <span className=\"tabular-nums text-text-primary\">\n {formatPrice(order.subtotal, order.currency)}\n </span>\n </span>\n <span>\n {tr('pages.orders.tax', 'Tax:')}{' '}\n <span className=\"tabular-nums text-text-primary\">\n {formatPrice(order.tax, order.currency)}\n </span>\n </span>\n <span className=\"font-semibold\">\n {tr('pages.orders.total', 'Total:')}{' '}\n <span className=\"tabular-nums text-text-primary\">\n {formatPrice(order.total, order.currency)}\n </span>\n </span>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n })}\n\n {/* Load More */}\n {hasMore && (\n <div className=\"flex justify-center px-4 py-5\">\n <button\n type=\"button\"\n onClick={loadMore}\n disabled={loading}\n className=\"flex items-center gap-2 rounded-lg border border-border-default px-6 py-2.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-subtle disabled:opacity-50\"\n aria-label={t('common.loadMore', { defaultValue: 'Load more' })}\n >\n {loading ? (\n <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" />\n ) : null}\n {t('common.loadMore', { defaultValue: 'Load more' })}\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n\n {/* Install App Modal */}\n {selectedApp && (\n <InstallAppModal\n isOpen={isModalOpen}\n onClose={handleCloseModal}\n app={selectedApp}\n orderId={selectedOrderId}\n onInstallSuccess={handleInstallSuccess}\n onInstallError={handleInstallError}\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-store",
3
- "version": "2026.912.1",
3
+ "version": "2026.912.3",
4
4
  "description": "Store microfrontend for Burdenoff products",
5
5
  "type": "module",
6
6
  "files": [