@burdenoff/microfe-store 2026.625.1 → 2026.625.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.
@@ -3,134 +3,125 @@ import { useMyEntitlements as t } from "../hooks/useStoreGraphQL.js";
3
3
  import { useMemo as n } from "react";
4
4
  import { QuotaMeter as r } from "@burdenoff/fe-libs/shared/components";
5
5
  import { useI18n as i } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
6
- import { AlertCircle as a, ArrowLeft as o, KeyRound as s, Loader2 as c, ShieldCheck as l } from "lucide-react";
7
- import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
8
- import { useNavigate as p } from "react-router-dom";
9
- import { EmphasisPanel as m } from "@burdenoff/fe-libs/ui";
6
+ import { AlertCircle as a, ArrowLeft as o, Loader2 as s, ShieldCheck as c } from "lucide-react";
7
+ import { Fragment as l, jsx as u, jsxs as d } from "react/jsx-runtime";
8
+ import { useNavigate as f } from "react-router-dom";
9
+ import { EmphasisPanel as p, IllustratedEmptyState as m } from "@burdenoff/fe-libs/ui";
10
10
  //#region src/pages/MyLicensesPage.tsx
11
11
  var h = (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", g = () => {
12
- let g = p(), { basePath: _ } = e(), { t: v } = i(), { entitlements: y, hasMore: b, loading: x, error: S, refetch: C, loadMore: w } = t(), T = n(() => y.slice().sort((e, t) => e.id.localeCompare(t.id)), [y]);
13
- return /* @__PURE__ */ f("div", {
12
+ let g = f(), { basePath: _ } = e(), { t: v } = i(), { entitlements: y, hasMore: b, loading: x, error: S, refetch: C, loadMore: w } = t(), T = n(() => y.slice().sort((e, t) => e.id.localeCompare(t.id)), [y]);
13
+ return /* @__PURE__ */ d("div", {
14
14
  className: "flex h-full flex-col",
15
- children: [/* @__PURE__ */ d("header", {
15
+ children: [/* @__PURE__ */ u("header", {
16
16
  className: "sticky top-0 z-10 border-b border-border-seam bg-bg-surface px-6 py-4",
17
- children: /* @__PURE__ */ f("div", {
17
+ children: /* @__PURE__ */ d("div", {
18
18
  className: "mx-auto flex max-w-5xl items-center gap-4",
19
- children: [/* @__PURE__ */ d("button", {
19
+ children: [/* @__PURE__ */ u("button", {
20
20
  type: "button",
21
21
  onClick: () => g(-1),
22
22
  "aria-label": "Go back",
23
23
  className: "cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary",
24
- children: /* @__PURE__ */ d(o, { className: "size-5" })
25
- }), /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("h1", {
24
+ children: /* @__PURE__ */ u(o, { className: "size-5" })
25
+ }), /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("h1", {
26
26
  className: "text-2xl font-bold text-text-primary",
27
27
  children: v("pages.licenses.title", { defaultValue: "My Licenses" })
28
- }), /* @__PURE__ */ d("p", {
28
+ }), /* @__PURE__ */ u("p", {
29
29
  className: "text-sm text-text-muted",
30
30
  children: v("pages.licenses.subtitle", { defaultValue: "Review and manage your product entitlements" })
31
31
  })] })]
32
32
  })
33
- }), /* @__PURE__ */ d("main", {
33
+ }), /* @__PURE__ */ u("main", {
34
34
  className: "flex-1 overflow-y-auto p-6",
35
- children: /* @__PURE__ */ d("div", {
35
+ children: /* @__PURE__ */ u("div", {
36
36
  className: "mx-auto max-w-5xl",
37
- children: x ? /* @__PURE__ */ d("output", {
37
+ children: x ? /* @__PURE__ */ u("output", {
38
38
  "aria-label": "Loading licenses",
39
39
  className: "flex items-center justify-center py-16",
40
- children: /* @__PURE__ */ d(c, {
40
+ children: /* @__PURE__ */ u(s, {
41
41
  className: "size-8 animate-spin text-text-muted",
42
42
  "aria-hidden": "true"
43
43
  })
44
- }) : S ? /* @__PURE__ */ f("div", {
44
+ }) : S ? /* @__PURE__ */ d("div", {
45
45
  role: "alert",
46
46
  className: "rounded-xl border border-status-error-border bg-status-error-bg-subtle p-8 text-center",
47
47
  children: [
48
- /* @__PURE__ */ d(a, { className: "mx-auto mb-3 size-10 text-status-error-text" }),
49
- /* @__PURE__ */ d("h3", {
48
+ /* @__PURE__ */ u(a, { className: "mx-auto mb-3 size-10 text-status-error-text" }),
49
+ /* @__PURE__ */ u("h3", {
50
50
  className: "text-lg font-semibold text-status-error-text",
51
51
  children: v("pages.licenses.failedToLoad", { defaultValue: "Failed to load licenses" })
52
52
  }),
53
- /* @__PURE__ */ d("p", {
53
+ /* @__PURE__ */ u("p", {
54
54
  className: "mt-2 text-sm text-text-muted",
55
55
  children: S.message
56
56
  }),
57
- /* @__PURE__ */ d("button", {
57
+ /* @__PURE__ */ u("button", {
58
58
  type: "button",
59
59
  onClick: () => C(),
60
60
  className: "mt-4 cursor-pointer rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text",
61
61
  children: v("common.tryAgain", { defaultValue: "Try Again" })
62
62
  })
63
63
  ]
64
- }) : T.length === 0 ? /* @__PURE__ */ f("div", {
65
- className: "rounded-xl border border-border-default bg-bg-surface p-12 text-center",
66
- children: [
67
- /* @__PURE__ */ d(s, { className: "mx-auto mb-3 size-12 text-text-muted" }),
68
- /* @__PURE__ */ d("h3", {
69
- className: "text-lg font-semibold text-text-primary",
70
- children: v("pages.licenses.emptyTitle", { defaultValue: "No licenses yet" })
71
- }),
72
- /* @__PURE__ */ d("p", {
73
- className: "mt-2 text-sm text-text-muted",
74
- children: v("pages.licenses.emptyDescription", { defaultValue: "Purchase apps from the marketplace to see your licenses here." })
75
- }),
76
- /* @__PURE__ */ d("button", {
77
- type: "button",
78
- onClick: () => g(`${_}/marketplace`),
79
- className: "mt-4 cursor-pointer rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text",
80
- children: v("pages.licenses.browseMarketplace", { defaultValue: "Browse Marketplace" })
81
- })
82
- ]
83
- }) : /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d(m, {
64
+ }) : T.length === 0 ? /* @__PURE__ */ u(m, {
65
+ illustration: "empty-data",
66
+ title: v("pages.licenses.emptyTitle", { defaultValue: "No licenses yet" }),
67
+ description: v("pages.licenses.emptyDescription", { defaultValue: "Purchase apps from the marketplace to see your licenses here." }),
68
+ action: /* @__PURE__ */ u("button", {
69
+ type: "button",
70
+ onClick: () => g(`${_}/marketplace`),
71
+ className: "cursor-pointer rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text",
72
+ children: v("pages.licenses.browseMarketplace", { defaultValue: "Browse Marketplace" })
73
+ })
74
+ }) : /* @__PURE__ */ d(l, { children: [/* @__PURE__ */ u(p, {
84
75
  className: "mb-6",
85
- children: /* @__PURE__ */ d(r, {
76
+ children: /* @__PURE__ */ u(r, {
86
77
  label: v("pages.licenses.activeLicenses", { defaultValue: "Active licenses" }),
87
78
  used: T.filter((e) => e.status === "ACTIVE").length,
88
79
  limit: null,
89
80
  unit: v("pages.licenses.licensesUnit", { defaultValue: "licenses" })
90
81
  })
91
- }), /* @__PURE__ */ f("ul", {
82
+ }), /* @__PURE__ */ d("ul", {
92
83
  className: "flex flex-col gap-y-4",
93
- children: [T.map((e) => /* @__PURE__ */ d("li", {
84
+ children: [T.map((e) => /* @__PURE__ */ u("li", {
94
85
  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)]",
95
- children: /* @__PURE__ */ f("div", {
86
+ children: /* @__PURE__ */ d("div", {
96
87
  className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
97
- children: [/* @__PURE__ */ f("div", { children: [
98
- /* @__PURE__ */ f("div", {
88
+ children: [/* @__PURE__ */ d("div", { children: [
89
+ /* @__PURE__ */ d("div", {
99
90
  className: "flex items-center gap-2",
100
- children: [/* @__PURE__ */ d(l, { className: "size-4 text-status-success-text" }), /* @__PURE__ */ f("h3", {
91
+ children: [/* @__PURE__ */ u(c, { className: "size-4 text-status-success-text" }), /* @__PURE__ */ d("h3", {
101
92
  className: "font-semibold text-text-primary",
102
93
  children: ["Product ", e.productId]
103
94
  })]
104
95
  }),
105
- /* @__PURE__ */ d("p", {
96
+ /* @__PURE__ */ u("p", {
106
97
  className: "mt-1 text-sm text-text-muted",
107
98
  children: v("pages.licenses.entitlementId", {
108
99
  defaultValue: `Entitlement ID: ${e.id}`,
109
100
  id: e.id
110
101
  })
111
102
  }),
112
- e.licenseKey && /* @__PURE__ */ d("p", {
103
+ e.licenseKey && /* @__PURE__ */ u("p", {
113
104
  className: "mt-1 text-sm text-text-muted",
114
105
  children: v("pages.licenses.licenseKey", {
115
106
  defaultValue: `License key: ${e.licenseKey}`,
116
107
  key: e.licenseKey
117
108
  })
118
109
  }),
119
- e.expiresAt && /* @__PURE__ */ d("p", {
110
+ e.expiresAt && /* @__PURE__ */ u("p", {
120
111
  className: "mt-1 text-sm text-text-muted",
121
112
  children: v("pages.licenses.expiresOn", {
122
113
  defaultValue: `Expires on ${new Date(e.expiresAt).toLocaleDateString()}`,
123
114
  date: new Date(e.expiresAt).toLocaleDateString()
124
115
  })
125
116
  })
126
- ] }), /* @__PURE__ */ d("span", {
127
- className: `rounded-full px-3 py-1 text-xs font-semibold ${h(e.status)}`,
117
+ ] }), /* @__PURE__ */ u("span", {
118
+ className: `rounded-full px-3 py-1 text-xs font-semibold ${h(e.status)} ${e.status === "ACTIVE" ? "motion-safe:animate-vc-glow-pulse" : ""}`,
128
119
  children: e.status
129
120
  })]
130
121
  })
131
- }, e.id)), b && /* @__PURE__ */ d("li", {
122
+ }, e.id)), b && /* @__PURE__ */ u("li", {
132
123
  className: "flex justify-center pt-4 list-none",
133
- children: /* @__PURE__ */ d("button", {
124
+ children: /* @__PURE__ */ u("button", {
134
125
  type: "button",
135
126
  onClick: w,
136
127
  disabled: x,
@@ -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-dom';\nimport { KeyRound, ArrowLeft, ShieldCheck, AlertCircle, Loader2 } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { QuotaMeter } from '@burdenoff/fe-libs/shared/components';\nimport { EmphasisPanel } 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 { 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 {loading ? (\n <output\n aria-label=\"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 <div className=\"rounded-xl border border-border-default bg-bg-surface p-12 text-center\">\n <KeyRound className=\"mx-auto mb-3 size-12 text-text-muted\" />\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {t('pages.licenses.emptyTitle', { defaultValue: 'No licenses yet' })}\n </h3>\n <p className=\"mt-2 text-sm text-text-muted\">\n {t('pages.licenses.emptyDescription', {\n defaultValue: 'Purchase apps from the marketplace to see your licenses here.',\n })}\n </p>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/marketplace`)}\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('pages.licenses.browseMarketplace', { defaultValue: 'Browse Marketplace' })}\n </button>\n </div>\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 Product {license.productId}\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 >\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 ? 'Loading…' : 'Load more'}\n </button>\n </li>\n )}\n </ul>\n </>\n )}\n </div>\n </main>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;AAkBA,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,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;cACZ,IACC,kBAAC,UAAD;KACE,cAAW;KACX,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,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD,EAAU,WAAU,wCAAyC,CAAA;MAC7D,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAE,6BAA6B,EAAE,cAAc,mBAAmB,CAAC;OACjE,CAAA;MACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAE,mCAAmC,EACpC,cAAc,iEACf,CAAC;OACA,CAAA;MACJ,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,EAAS,GAAG,EAAS,cAAc;OAClD,WAAU;iBAET,EAAE,oCAAoC,EAAE,cAAc,sBAAsB,CAAC;OACvE,CAAA;MACL;SAEN,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;oBAAd,CAAgD,YACrC,EAAQ,UACd;YACD;;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;kBAErF,EAAQ;QACJ,CAAA,CACH;;MACH,EAxCE,EAAQ,GAwCV,CACL,EACD,KACC,kBAAC,MAAD;MAAI,WAAU;gBACZ,kBAAC,UAAD;OACE,MAAK;OACL,SAAS;OACT,UAAU;OACV,WAAU;iBAET,IAAU,aAAa;OACjB,CAAA;MACN,CAAA,CAEJ;OACJ,EAAA,CAAA;IAED,CAAA;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-dom';\nimport { ArrowLeft, ShieldCheck, AlertCircle, Loader2 } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { QuotaMeter } from '@burdenoff/fe-libs/shared/components';\nimport { EmphasisPanel, IllustratedEmptyState } 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 { 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 {loading ? (\n <output\n aria-label=\"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 Product {license.productId}\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'\n ? 'motion-safe:animate-vc-glow-pulse'\n : ''\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 ? 'Loading…' : '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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"}
@@ -9,9 +9,9 @@ import { useI18n as c } from "@burdenoff/fe-libs/shared/providers/shell/I18nProv
9
9
  import { ArrowLeft as l, CheckCircle as u, Clock as d, Download as f, Loader2 as p, Package as m, RefreshCw as h, ShoppingBag as g, XCircle as _ } from "lucide-react";
10
10
  import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
11
11
  import { useNavigate as x } from "react-router-dom";
12
- import { GlassCard as S } from "@burdenoff/fe-libs/ui";
12
+ import { GlassCard as S, IllustratedEmptyState as C } from "@burdenoff/fe-libs/ui";
13
13
  //#region src/pages/OrdersPage.tsx
14
- var C = (e) => {
14
+ var w = (e) => {
15
15
  switch (e) {
16
16
  case "COMPLETED":
17
17
  case "FULFILLED":
@@ -51,7 +51,7 @@ var C = (e) => {
51
51
  label: e
52
52
  };
53
53
  }
54
- }, w = ({ item: e, orderId: t, orderStatus: r, onOpenInstallModal: i, installing: a }) => {
54
+ }, T = ({ item: e, orderId: t, orderStatus: r, onOpenInstallModal: i, installing: a }) => {
55
55
  let o = r === "COMPLETED" || r === "FULFILLED" || r === "PROCESSED", s = e.productType !== "PHYSICAL" && e.productType !== "MERCHANDISE";
56
56
  return /* @__PURE__ */ b("div", {
57
57
  className: "flex items-center gap-4 rounded-lg border border-border-seam bg-bg-sunken/50 p-4",
@@ -109,8 +109,8 @@ var C = (e) => {
109
109
  })
110
110
  ]
111
111
  });
112
- }, T = ({ order: e, onOpenInstallModal: t, installingItem: r }) => {
113
- let i = C(e.status), a = i.icon;
112
+ }, E = ({ order: e, onOpenInstallModal: t, installingItem: r }) => {
113
+ let i = w(e.status), a = i.icon;
114
114
  return /* @__PURE__ */ b(S, {
115
115
  className: "p-6",
116
116
  children: [
@@ -151,7 +151,7 @@ var C = (e) => {
151
151
  }),
152
152
  /* @__PURE__ */ y("div", {
153
153
  className: "space-y-3",
154
- children: e.items.map((n) => /* @__PURE__ */ y(w, {
154
+ children: e.items.map((n) => /* @__PURE__ */ y(T, {
155
155
  item: n,
156
156
  orderId: e.id,
157
157
  orderStatus: e.status,
@@ -183,8 +183,8 @@ var C = (e) => {
183
183
  })
184
184
  ]
185
185
  });
186
- }, E = () => {
187
- let n = x(), { basePath: u } = e(), { t: d } = c(), { orders: f, loading: h, error: v, refetchOrders: S, hasMore: C, loadMore: w } = i(), { installations: E, refetch: D } = r();
186
+ }, D = () => {
187
+ let n = x(), { basePath: u } = e(), { t: d } = c(), { orders: f, loading: h, error: v, refetchOrders: S, hasMore: w, loadMore: T } = i(), { installations: D, refetch: O } = r();
188
188
  t({
189
189
  onData: () => {
190
190
  S();
@@ -193,7 +193,7 @@ var C = (e) => {
193
193
  console.warn("OrderStatusUpdated subscription error:", e.message);
194
194
  }
195
195
  });
196
- let [O, k] = s(!1), [A, j] = s(null), [M, N] = s(null), [P, F] = s(null), I = o(() => new Set(E.flatMap((e) => e.status === "ACTIVE" ? [e.productId] : [])), [E]), L = f.map((e) => {
196
+ let [k, A] = s(!1), [j, M] = s(null), [N, P] = s(null), [F, I] = s(null), L = o(() => new Set(D.flatMap((e) => e.status === "ACTIVE" ? [e.productId] : [])), [D]), R = f.map((e) => {
197
197
  let t = e.lineItems || [], n = t.reduce((e, t) => e + t.subtotal, 0), r = e.total - n, i = t.map((t, n) => ({
198
198
  id: `${e.id}-${n}`,
199
199
  productId: t.productId,
@@ -204,7 +204,7 @@ var C = (e) => {
204
204
  quantity: t.quantity,
205
205
  unitPrice: t.unitPrice,
206
206
  totalPrice: t.subtotal,
207
- installed: I.has(t.productId)
207
+ installed: L.has(t.productId)
208
208
  }));
209
209
  return {
210
210
  id: e.id,
@@ -216,21 +216,21 @@ var C = (e) => {
216
216
  status: e.status,
217
217
  createdAt: e.createdAt
218
218
  };
219
- }), R = (e, t) => {
220
- j(e), F(t.id), N({
219
+ }), z = (e, t) => {
220
+ M(e), I(t.id), P({
221
221
  id: t.productId,
222
222
  name: t.productName,
223
223
  icon: t.productIcon,
224
224
  type: t.productType,
225
225
  version: t.version
226
- }), k(!0);
227
- }, z = () => {
228
- k(!1), j(null), N(null), F(null);
229
- }, B = (e, t) => {
230
- !A || !P || (console.log(`Successfully installed ${M?.name} to workspace ${t} (${e})`), z(), D());
231
- }, V = (e) => {
226
+ }), A(!0);
227
+ }, B = () => {
228
+ A(!1), M(null), P(null), I(null);
229
+ }, V = (e, t) => {
230
+ !j || !F || (console.log(`Successfully installed ${N?.name} to workspace ${t} (${e})`), B(), O());
231
+ }, H = (e) => {
232
232
  console.error("Installation failed:", e.message);
233
- }, H = () => {
233
+ }, U = () => {
234
234
  n(`${u}/marketplace`);
235
235
  };
236
236
  return /* @__PURE__ */ b("div", {
@@ -256,9 +256,9 @@ var C = (e) => {
256
256
  className: "text-xl font-bold text-text-primary",
257
257
  children: d("pages.orders.title", { defaultValue: "My Orders" })
258
258
  }),
259
- L.length > 0 && /* @__PURE__ */ y("span", {
259
+ R.length > 0 && /* @__PURE__ */ y("span", {
260
260
  className: "rounded-full bg-action-primary-bg px-2.5 py-0.5 text-sm font-medium text-action-primary-text",
261
- children: L.length
261
+ children: R.length
262
262
  })
263
263
  ]
264
264
  })]
@@ -295,44 +295,32 @@ var C = (e) => {
295
295
  }),
296
296
  /* @__PURE__ */ b("button", {
297
297
  type: "button",
298
- onClick: H,
299
- 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",
300
- children: [/* @__PURE__ */ y(g, { className: "size-5" }), "Browse Marketplace"]
301
- })
302
- ]
303
- }) : L.length === 0 ? /* @__PURE__ */ b("div", {
304
- className: "flex flex-col items-center justify-center py-16 text-center",
305
- children: [
306
- /* @__PURE__ */ y("div", {
307
- className: "mb-6 rounded-full bg-bg-sunken p-6",
308
- children: /* @__PURE__ */ y(g, { className: "size-16 text-text-muted" })
309
- }),
310
- /* @__PURE__ */ y("h2", {
311
- className: "mb-2 text-2xl font-bold text-text-primary",
312
- children: d("pages.orders.emptyTitle", { defaultValue: "No orders yet" })
313
- }),
314
- /* @__PURE__ */ y("p", {
315
- className: "mb-6 max-w-md text-text-muted",
316
- children: "You have not placed any orders yet. Browse the marketplace to discover apps and products!"
317
- }),
318
- /* @__PURE__ */ b("button", {
319
- type: "button",
320
- onClick: H,
298
+ onClick: U,
321
299
  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",
322
300
  children: [/* @__PURE__ */ y(g, { className: "size-5" }), "Browse Marketplace"]
323
301
  })
324
302
  ]
303
+ }) : R.length === 0 ? /* @__PURE__ */ y(C, {
304
+ illustration: "empty-data",
305
+ title: d("pages.orders.emptyTitle", { defaultValue: "No orders yet" }),
306
+ description: "You have not placed any orders yet. Browse the marketplace to discover apps and products!",
307
+ action: /* @__PURE__ */ b("button", {
308
+ type: "button",
309
+ onClick: U,
310
+ 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",
311
+ children: [/* @__PURE__ */ y(g, { className: "size-5" }), "Browse Marketplace"]
312
+ })
325
313
  }) : /* @__PURE__ */ b("ul", {
326
314
  className: "space-y-6",
327
- children: [L.map((e) => /* @__PURE__ */ y("li", { children: /* @__PURE__ */ y(T, {
315
+ children: [R.map((e) => /* @__PURE__ */ y("li", { children: /* @__PURE__ */ y(E, {
328
316
  order: e,
329
- onOpenInstallModal: R,
330
- installingItem: O ? P : null
331
- }) }, e.id)), C && /* @__PURE__ */ y("li", {
317
+ onOpenInstallModal: z,
318
+ installingItem: k ? F : null
319
+ }) }, e.id)), w && /* @__PURE__ */ y("li", {
332
320
  className: "flex justify-center pt-4 list-none",
333
321
  children: /* @__PURE__ */ b("button", {
334
322
  type: "button",
335
- onClick: w,
323
+ onClick: T,
336
324
  disabled: h,
337
325
  className: "flex items-center gap-2 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",
338
326
  "aria-label": d("common.loadMore", { defaultValue: "Load more" }),
@@ -344,18 +332,18 @@ var C = (e) => {
344
332
  })]
345
333
  })
346
334
  }),
347
- M && /* @__PURE__ */ y(a, {
348
- isOpen: O,
349
- onClose: z,
350
- app: M,
351
- orderId: A,
352
- onInstallSuccess: B,
353
- onInstallError: V
335
+ N && /* @__PURE__ */ y(a, {
336
+ isOpen: k,
337
+ onClose: B,
338
+ app: N,
339
+ orderId: j,
340
+ onInstallSuccess: V,
341
+ onInstallError: H
354
342
  })
355
343
  ]
356
344
  });
357
345
  };
358
346
  //#endregion
359
- export { E as OrdersPage };
347
+ export { D as OrdersPage };
360
348
 
361
349
  //# sourceMappingURL=OrdersPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OrdersPage.js","names":[],"sources":["../../src/pages/OrdersPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Package,\n ArrowLeft,\n ShoppingBag,\n Download,\n CheckCircle,\n Clock,\n XCircle,\n RefreshCw,\n Loader2,\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 { GlassCard } 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 subtotal: number;\n tax: number;\n total: number;\n status:\n | 'PENDING'\n | 'PROCESSING'\n | 'COMPLETED'\n | 'FAILED'\n | 'CANCELLED'\n | 'FULFILLED'\n | 'PROCESSED'\n | 'REFUNDED';\n createdAt: string;\n}\n\n/**\n * Get status icon and color\n */\nconst getStatusDisplay = (status: UIOrder['status']) => {\n switch (status) {\n case 'COMPLETED':\n case 'FULFILLED':\n case 'PROCESSED':\n return {\n icon: CheckCircle,\n color: 'text-status-success-text bg-status-success-bg-subtle/10',\n label: 'Completed',\n };\n case 'PROCESSING':\n return {\n icon: Clock,\n color: 'text-status-warning-text bg-status-warning-bg-subtle/10',\n label: 'Processing',\n };\n case 'PENDING':\n return {\n icon: Clock,\n color: 'text-status-warning-text bg-status-warning-bg-subtle/10',\n label: 'Pending',\n };\n case 'FAILED':\n return {\n icon: XCircle,\n color: 'text-status-error-text bg-status-error-bg-subtle/10',\n label: 'Failed',\n };\n case 'REFUNDED':\n return {\n icon: RefreshCw,\n color: 'text-status-warning-text bg-status-warning-bg-subtle/10',\n label: 'Refunded',\n };\n case 'CANCELLED':\n return { icon: RefreshCw, color: 'text-text-muted bg-bg-sunken', label: 'Cancelled' };\n default:\n return { icon: Clock, color: 'text-text-muted', label: status };\n }\n};\n\n/**\n * Order item card with Install App button\n */\nconst OrderItemCard: FC<{\n item: OrderItem;\n orderId: string;\n orderStatus: UIOrder['status'];\n onOpenInstallModal: (orderId: string, item: OrderItem) => void;\n installing: boolean;\n}> = ({ item, orderId, orderStatus, onOpenInstallModal, installing }) => {\n const isOrderSuccessful =\n orderStatus === 'COMPLETED' || orderStatus === 'FULFILLED' || orderStatus === 'PROCESSED';\n const isInstallable = item.productType !== 'PHYSICAL' && item.productType !== 'MERCHANDISE';\n return (\n <div className=\"flex items-center gap-4 rounded-lg border border-border-seam bg-bg-sunken/50 p-4\">\n {/* Product Icon */}\n <div className=\"size-14 flex-shrink-0 overflow-hidden rounded-lg bg-bg-sunken\">\n {item.productIcon ? (\n <img src={item.productIcon} alt={item.productName} className=\"size-full object-cover\" />\n ) : (\n <div className=\"flex size-full items-center justify-center text-lg font-bold text-text-muted\">\n {item.productName.charAt(0)}\n </div>\n )}\n </div>\n\n {/* Product Info */}\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"font-medium text-text-primary truncate\">{item.productName}</h4>\n <div className=\"flex items-center gap-2 mt-1\">\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 <span className=\"text-sm text-text-muted\">\n {item.quantity} x {formatPrice(item.unitPrice)}\n </span>\n </div>\n </div>\n\n {/* Price */}\n <div className=\"text-right\">\n <p className=\"font-semibold tabular-nums text-text-primary\">\n {formatPrice(item.totalPrice)}\n </p>\n </div>\n\n {/* Install Button - only show when order is successfully processed */}\n <div className=\"flex-shrink-0\">\n {item.installed ? (\n <span className=\"inline-flex items-center gap-1.5 rounded-lg bg-status-success-bg-subtle/10 px-4 py-2 text-sm font-medium text-status-success-text\">\n <CheckCircle className=\"size-4\" />\n Installed\n </span>\n ) : isOrderSuccessful && isInstallable ? (\n <button\n type=\"button\"\n onClick={() => onOpenInstallModal(orderId, item)}\n disabled={installing}\n className=\"inline-flex cursor-pointer items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-opacity hover:opacity-90 disabled:opacity-50\"\n >\n {installing ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n Installing…\n </>\n ) : (\n <>\n <Download className=\"size-4\" />\n Install App\n </>\n )}\n </button>\n ) : null}\n </div>\n </div>\n );\n};\n\n/**\n * Order card component\n */\nconst OrderCard: FC<{\n order: UIOrder;\n onOpenInstallModal: (orderId: string, item: OrderItem) => void;\n installingItem: string | null;\n}> = ({ order, onOpenInstallModal, installingItem }) => {\n const statusDisplay = getStatusDisplay(order.status);\n const StatusIcon = statusDisplay.icon;\n\n return (\n <GlassCard className=\"p-6\">\n {/* Order Header */}\n <div className=\"flex items-start justify-between mb-4\">\n <div>\n <div className=\"flex items-center gap-3\">\n <h3 className=\"text-lg font-semibold text-text-primary\">{order.orderNumber}</h3>\n <span\n className={`inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-sm font-semibold ${statusDisplay.color}`}\n >\n <StatusIcon className=\"size-4\" />\n {statusDisplay.label}\n </span>\n </div>\n <p className=\"text-sm text-text-muted mt-1\">\n {new Date(order.createdAt).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n })}\n </p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-xl font-bold tabular-nums text-text-primary\">\n {formatPrice(order.total)}\n </p>\n <p className=\"text-xs text-text-muted\">\n {order.items.length} {order.items.length === 1 ? 'item' : 'items'}\n </p>\n </div>\n </div>\n\n {/* Order Items */}\n <div className=\"space-y-3\">\n {order.items.map((item) => (\n <OrderItemCard\n key={item.id}\n item={item}\n orderId={order.id}\n orderStatus={order.status}\n onOpenInstallModal={onOpenInstallModal}\n installing={installingItem === item.id}\n />\n ))}\n </div>\n\n {/* Order Summary */}\n {/* TODO(ux-sweep): no order-details modal exists; tax + shipping live inline. When a modal lands, wrap \"Tax + shipping advanced\" in OptionalFields. */}\n <div className=\"mt-4 pt-4 border-t border-border-seam\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-muted\">Subtotal</span>\n <span className=\"tabular-nums text-text-primary\">{formatPrice(order.subtotal)}</span>\n </div>\n <div className=\"flex justify-between text-sm mt-1\">\n <span className=\"text-text-muted\">Tax</span>\n <span className=\"tabular-nums text-text-primary\">{formatPrice(order.tax)}</span>\n </div>\n </div>\n </GlassCard>\n );\n};\n\n/**\n * OrdersPage component\n *\n * Displays a list of all orders with their items and Install App buttons\n */\nexport const OrdersPage: FC = () => {\n const navigate = useNavigate();\n const { basePath } = useStore();\n const { t } = useI18n();\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 // 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 // Calculate subtotal from line items (with safety check)\n const lineItems = order.lineItems || [];\n const subtotal = lineItems.reduce((sum, item) => sum + item.subtotal, 0);\n // Estimate tax (backend doesn't store separate tax amount)\n const tax = order.total - subtotal;\n\n // Map lineItems to items with unique IDs\n const items: OrderItem[] = lineItems.map((item, index) => ({\n id: `${order.id}-${index}`, // Generate unique ID for each line item\n productId: item.productId,\n productName: item.name, // Backend uses 'name', UI expects 'productName'\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, // Backend uses 'subtotal', UI expects 'totalPrice'\n installed: installedProductIds.has(item.productId),\n }));\n\n return {\n id: order.id,\n orderNumber: `#${order.id.slice(-8).toUpperCase()}`, // Generate order number from ID\n items,\n subtotal,\n tax,\n total: order.total,\n status: order.status as UIOrder['status'], // Cast to union type\n createdAt: order.createdAt,\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 if (!selectedOrderId || !selectedItemId) return;\n\n console.log(\n `Successfully installed ${selectedApp?.name} to workspace ${workspaceName} (${workspaceId})`\n );\n\n // Reset modal state\n handleCloseModal();\n void refetchInstallations();\n };\n\n const handleInstallError = (error: Error) => {\n console.error('Installation failed:', error.message);\n // Error is displayed in modal, no need to close it\n };\n\n const handleBrowseMarketplace = () => {\n navigate(`${basePath}/marketplace`);\n };\n\n return (\n <div className=\"h-full overflow-y-auto\">\n {/* Header */}\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 max-w-4xl\">\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 px-2.5 py-0.5 text-sm font-medium text-action-primary-text\">\n {orders.length}\n </span>\n )}\n </div>\n </div>\n </div>\n </header>\n\n <main className=\"mx-auto max-w-4xl p-6\">\n {loading ? (\n // Loading State\n <output\n aria-label=\"Loading orders\"\n className=\"flex flex-col items-center justify-center py-16\"\n >\n <Loader2 className=\"size-12 animate-spin text-text-muted mb-4\" aria-hidden=\"true\" />\n <p className=\"text-text-muted\">Loading your orders…</p>\n </output>\n ) : error ? (\n // Error State\n <div role=\"alert\" className=\"flex flex-col items-center justify-center py-16 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 || 'An error occurred while loading your orders. Please try again.'}\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 Browse Marketplace\n </button>\n </div>\n ) : orders.length === 0 ? (\n // Empty State\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <div className=\"mb-6 rounded-full bg-bg-sunken p-6\">\n <ShoppingBag className=\"size-16 text-text-muted\" />\n </div>\n <h2 className=\"mb-2 text-2xl font-bold text-text-primary\">\n {t('pages.orders.emptyTitle', { defaultValue: 'No orders yet' })}\n </h2>\n <p className=\"mb-6 max-w-md text-text-muted\">\n You have not placed any orders yet. Browse the marketplace to discover apps and\n products!\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 Browse Marketplace\n </button>\n </div>\n ) : (\n // Orders List\n <ul className=\"space-y-6\">\n {orders.map((order) => (\n <li key={order.id}>\n <OrderCard\n order={order}\n onOpenInstallModal={handleOpenInstallModal}\n installingItem={isModalOpen ? selectedItemId : null}\n />\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=\"flex items-center gap-2 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 aria-label={t('common.loadMore', { defaultValue: 'Load more' })}\n >\n {loading ? <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" /> : null}\n {t('common.loadMore', { defaultValue: 'Load more' })}\n </button>\n </li>\n )}\n </ul>\n )}\n </main>\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 } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Package,\n ArrowLeft,\n ShoppingBag,\n Download,\n CheckCircle,\n Clock,\n XCircle,\n RefreshCw,\n Loader2,\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 { GlassCard, IllustratedEmptyState } 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 subtotal: number;\n tax: number;\n total: number;\n status:\n | 'PENDING'\n | 'PROCESSING'\n | 'COMPLETED'\n | 'FAILED'\n | 'CANCELLED'\n | 'FULFILLED'\n | 'PROCESSED'\n | 'REFUNDED';\n createdAt: string;\n}\n\n/**\n * Get status icon and color\n */\nconst getStatusDisplay = (status: UIOrder['status']) => {\n switch (status) {\n case 'COMPLETED':\n case 'FULFILLED':\n case 'PROCESSED':\n return {\n icon: CheckCircle,\n color: 'text-status-success-text bg-status-success-bg-subtle/10',\n label: 'Completed',\n };\n case 'PROCESSING':\n return {\n icon: Clock,\n color: 'text-status-warning-text bg-status-warning-bg-subtle/10',\n label: 'Processing',\n };\n case 'PENDING':\n return {\n icon: Clock,\n color: 'text-status-warning-text bg-status-warning-bg-subtle/10',\n label: 'Pending',\n };\n case 'FAILED':\n return {\n icon: XCircle,\n color: 'text-status-error-text bg-status-error-bg-subtle/10',\n label: 'Failed',\n };\n case 'REFUNDED':\n return {\n icon: RefreshCw,\n color: 'text-status-warning-text bg-status-warning-bg-subtle/10',\n label: 'Refunded',\n };\n case 'CANCELLED':\n return { icon: RefreshCw, color: 'text-text-muted bg-bg-sunken', label: 'Cancelled' };\n default:\n return { icon: Clock, color: 'text-text-muted', label: status };\n }\n};\n\n/**\n * Order item card with Install App button\n */\nconst OrderItemCard: FC<{\n item: OrderItem;\n orderId: string;\n orderStatus: UIOrder['status'];\n onOpenInstallModal: (orderId: string, item: OrderItem) => void;\n installing: boolean;\n}> = ({ item, orderId, orderStatus, onOpenInstallModal, installing }) => {\n const isOrderSuccessful =\n orderStatus === 'COMPLETED' || orderStatus === 'FULFILLED' || orderStatus === 'PROCESSED';\n const isInstallable = item.productType !== 'PHYSICAL' && item.productType !== 'MERCHANDISE';\n return (\n <div className=\"flex items-center gap-4 rounded-lg border border-border-seam bg-bg-sunken/50 p-4\">\n {/* Product Icon */}\n <div className=\"size-14 flex-shrink-0 overflow-hidden rounded-lg bg-bg-sunken\">\n {item.productIcon ? (\n <img src={item.productIcon} alt={item.productName} className=\"size-full object-cover\" />\n ) : (\n <div className=\"flex size-full items-center justify-center text-lg font-bold text-text-muted\">\n {item.productName.charAt(0)}\n </div>\n )}\n </div>\n\n {/* Product Info */}\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"font-medium text-text-primary truncate\">{item.productName}</h4>\n <div className=\"flex items-center gap-2 mt-1\">\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 <span className=\"text-sm text-text-muted\">\n {item.quantity} x {formatPrice(item.unitPrice)}\n </span>\n </div>\n </div>\n\n {/* Price */}\n <div className=\"text-right\">\n <p className=\"font-semibold tabular-nums text-text-primary\">\n {formatPrice(item.totalPrice)}\n </p>\n </div>\n\n {/* Install Button - only show when order is successfully processed */}\n <div className=\"flex-shrink-0\">\n {item.installed ? (\n <span className=\"inline-flex items-center gap-1.5 rounded-lg bg-status-success-bg-subtle/10 px-4 py-2 text-sm font-medium text-status-success-text\">\n <CheckCircle className=\"size-4\" />\n Installed\n </span>\n ) : isOrderSuccessful && isInstallable ? (\n <button\n type=\"button\"\n onClick={() => onOpenInstallModal(orderId, item)}\n disabled={installing}\n className=\"inline-flex cursor-pointer items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-opacity hover:opacity-90 disabled:opacity-50\"\n >\n {installing ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n Installing…\n </>\n ) : (\n <>\n <Download className=\"size-4\" />\n Install App\n </>\n )}\n </button>\n ) : null}\n </div>\n </div>\n );\n};\n\n/**\n * Order card component\n */\nconst OrderCard: FC<{\n order: UIOrder;\n onOpenInstallModal: (orderId: string, item: OrderItem) => void;\n installingItem: string | null;\n}> = ({ order, onOpenInstallModal, installingItem }) => {\n const statusDisplay = getStatusDisplay(order.status);\n const StatusIcon = statusDisplay.icon;\n\n return (\n <GlassCard className=\"p-6\">\n {/* Order Header */}\n <div className=\"flex items-start justify-between mb-4\">\n <div>\n <div className=\"flex items-center gap-3\">\n <h3 className=\"text-lg font-semibold text-text-primary\">{order.orderNumber}</h3>\n <span\n className={`inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-sm font-semibold ${statusDisplay.color}`}\n >\n <StatusIcon className=\"size-4\" />\n {statusDisplay.label}\n </span>\n </div>\n <p className=\"text-sm text-text-muted mt-1\">\n {new Date(order.createdAt).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n })}\n </p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-xl font-bold tabular-nums text-text-primary\">\n {formatPrice(order.total)}\n </p>\n <p className=\"text-xs text-text-muted\">\n {order.items.length} {order.items.length === 1 ? 'item' : 'items'}\n </p>\n </div>\n </div>\n\n {/* Order Items */}\n <div className=\"space-y-3\">\n {order.items.map((item) => (\n <OrderItemCard\n key={item.id}\n item={item}\n orderId={order.id}\n orderStatus={order.status}\n onOpenInstallModal={onOpenInstallModal}\n installing={installingItem === item.id}\n />\n ))}\n </div>\n\n {/* Order Summary */}\n {/* TODO(ux-sweep): no order-details modal exists; tax + shipping live inline. When a modal lands, wrap \"Tax + shipping advanced\" in OptionalFields. */}\n <div className=\"mt-4 pt-4 border-t border-border-seam\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-muted\">Subtotal</span>\n <span className=\"tabular-nums text-text-primary\">{formatPrice(order.subtotal)}</span>\n </div>\n <div className=\"flex justify-between text-sm mt-1\">\n <span className=\"text-text-muted\">Tax</span>\n <span className=\"tabular-nums text-text-primary\">{formatPrice(order.tax)}</span>\n </div>\n </div>\n </GlassCard>\n );\n};\n\n/**\n * OrdersPage component\n *\n * Displays a list of all orders with their items and Install App buttons\n */\nexport const OrdersPage: FC = () => {\n const navigate = useNavigate();\n const { basePath } = useStore();\n const { t } = useI18n();\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 // 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 // Calculate subtotal from line items (with safety check)\n const lineItems = order.lineItems || [];\n const subtotal = lineItems.reduce((sum, item) => sum + item.subtotal, 0);\n // Estimate tax (backend doesn't store separate tax amount)\n const tax = order.total - subtotal;\n\n // Map lineItems to items with unique IDs\n const items: OrderItem[] = lineItems.map((item, index) => ({\n id: `${order.id}-${index}`, // Generate unique ID for each line item\n productId: item.productId,\n productName: item.name, // Backend uses 'name', UI expects 'productName'\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, // Backend uses 'subtotal', UI expects 'totalPrice'\n installed: installedProductIds.has(item.productId),\n }));\n\n return {\n id: order.id,\n orderNumber: `#${order.id.slice(-8).toUpperCase()}`, // Generate order number from ID\n items,\n subtotal,\n tax,\n total: order.total,\n status: order.status as UIOrder['status'], // Cast to union type\n createdAt: order.createdAt,\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 if (!selectedOrderId || !selectedItemId) return;\n\n console.log(\n `Successfully installed ${selectedApp?.name} to workspace ${workspaceName} (${workspaceId})`\n );\n\n // Reset modal state\n handleCloseModal();\n void refetchInstallations();\n };\n\n const handleInstallError = (error: Error) => {\n console.error('Installation failed:', error.message);\n // Error is displayed in modal, no need to close it\n };\n\n const handleBrowseMarketplace = () => {\n navigate(`${basePath}/marketplace`);\n };\n\n return (\n <div className=\"h-full overflow-y-auto\">\n {/* Header */}\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 max-w-4xl\">\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 px-2.5 py-0.5 text-sm font-medium text-action-primary-text\">\n {orders.length}\n </span>\n )}\n </div>\n </div>\n </div>\n </header>\n\n <main className=\"mx-auto max-w-4xl p-6\">\n {loading ? (\n // Loading State\n <output\n aria-label=\"Loading orders\"\n className=\"flex flex-col items-center justify-center py-16\"\n >\n <Loader2 className=\"size-12 animate-spin text-text-muted mb-4\" aria-hidden=\"true\" />\n <p className=\"text-text-muted\">Loading your orders…</p>\n </output>\n ) : error ? (\n // Error State\n <div role=\"alert\" className=\"flex flex-col items-center justify-center py-16 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 || 'An error occurred while loading your orders. Please try again.'}\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 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=\"You have not placed any orders yet. Browse the marketplace to discover apps and products!\"\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 Browse Marketplace\n </button>\n }\n />\n ) : (\n // Orders List\n <ul className=\"space-y-6\">\n {orders.map((order) => (\n <li key={order.id}>\n <OrderCard\n order={order}\n onOpenInstallModal={handleOpenInstallModal}\n installingItem={isModalOpen ? selectedItemId : null}\n />\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=\"flex items-center gap-2 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 aria-label={t('common.loadMore', { defaultValue: 'Load more' })}\n >\n {loading ? <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" /> : null}\n {t('common.loadMore', { defaultValue: 'Load more' })}\n </button>\n </li>\n )}\n </ul>\n )}\n </main>\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.625.1",
3
+ "version": "2026.625.3",
4
4
  "description": "Store microfrontend for Burdenoff products",
5
5
  "type": "module",
6
6
  "files": [
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@apollo/client": "^4.0.11",
43
- "@burdenoff/fe-libs": "2026.625.2",
43
+ "@burdenoff/fe-libs": "2026.625.3",
44
44
  "@tanstack/react-query": "^5.90.16",
45
45
  "clsx": "^2.1.1",
46
46
  "graphql": "^16.10.0",