@withpotter/components 0.13.0-next.124 → 0.13.0-next.58

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.
Files changed (132) hide show
  1. package/dist/billing/overview-tab.js +3 -4
  2. package/dist/billing/overview-tab.js.map +1 -1
  3. package/dist/billing/plans-tab.js +12 -6
  4. package/dist/billing/plans-tab.js.map +1 -1
  5. package/dist/charts/index.d.ts +1 -1
  6. package/dist/charts/index.js +1 -3
  7. package/dist/charts/index.js.map +1 -1
  8. package/dist/dashboard/activity-feed.d.ts +0 -2
  9. package/dist/dashboard/activity-feed.js +1 -4
  10. package/dist/dashboard/activity-feed.js.map +1 -1
  11. package/dist/dashboard/home/ask-controls.js +0 -1
  12. package/dist/dashboard/home/ask-controls.js.map +1 -1
  13. package/dist/dashboard/home/ask-mode-chip.js +4 -4
  14. package/dist/dashboard/home/ask-mode-chip.js.map +1 -1
  15. package/dist/dashboard/home/home-ask.js +3 -3
  16. package/dist/dashboard/home/home-ask.js.map +1 -1
  17. package/dist/dashboard/home/home-quick-actions.js +1 -9
  18. package/dist/dashboard/home/home-quick-actions.js.map +1 -1
  19. package/dist/dashboard/home/widgets/activity-widget.js +43 -56
  20. package/dist/dashboard/home/widgets/activity-widget.js.map +1 -1
  21. package/dist/dashboard/home/widgets/home-widgets.js +2 -3
  22. package/dist/dashboard/home/widgets/home-widgets.js.map +1 -1
  23. package/dist/dashboard/home/widgets/money-widgets.js +4 -9
  24. package/dist/dashboard/home/widgets/money-widgets.js.map +1 -1
  25. package/dist/dashboard/home/widgets/registry.d.ts +3 -6
  26. package/dist/dashboard/home/widgets/registry.js +2 -12
  27. package/dist/dashboard/home/widgets/registry.js.map +1 -1
  28. package/dist/dashboard/home/widgets/team-widget.js +3 -15
  29. package/dist/dashboard/home/widgets/team-widget.js.map +1 -1
  30. package/dist/dashboard/home/widgets/types.d.ts +1 -13
  31. package/dist/dashboard/home/widgets/types.js.map +1 -1
  32. package/dist/dashboard/home/widgets/use-home-layout.js +4 -9
  33. package/dist/dashboard/home/widgets/use-home-layout.js.map +1 -1
  34. package/dist/dashboard/home/widgets/website-widget.js +1 -9
  35. package/dist/dashboard/home/widgets/website-widget.js.map +1 -1
  36. package/dist/dashboard/page-transition.d.ts +0 -11
  37. package/dist/dashboard/page-transition.js +2 -9
  38. package/dist/dashboard/page-transition.js.map +1 -1
  39. package/dist/features/gift-card-artwork.js +1 -1
  40. package/dist/features/gift-card-artwork.js.map +1 -1
  41. package/dist/features/gift-cards/gift-cards-feature.js +518 -656
  42. package/dist/features/gift-cards/gift-cards-feature.js.map +1 -1
  43. package/dist/features/product-form.js +1 -1
  44. package/dist/features/product-form.js.map +1 -1
  45. package/dist/mobile/screens/billing-flows.js +6 -7
  46. package/dist/mobile/screens/billing-flows.js.map +1 -1
  47. package/dist/mobile/screens/billing.js +2 -2
  48. package/dist/mobile/screens/billing.js.map +1 -1
  49. package/dist/notifications-dropdown.js +1 -11
  50. package/dist/notifications-dropdown.js.map +1 -1
  51. package/dist/shell/notification-kinds.d.ts +2 -11
  52. package/dist/shell/notification-kinds.js +1 -16
  53. package/dist/shell/notification-kinds.js.map +1 -1
  54. package/dist/shell/notification-row.d.ts +2 -6
  55. package/dist/shell/notification-row.js +33 -59
  56. package/dist/shell/notification-row.js.map +1 -1
  57. package/dist/shell/product-switcher.js +0 -3
  58. package/dist/shell/product-switcher.js.map +1 -1
  59. package/dist/shell/settings-modal-context.d.ts +0 -2
  60. package/dist/shell/settings-modal-context.js +2 -4
  61. package/dist/shell/settings-modal-context.js.map +1 -1
  62. package/dist/shell/settings-panels.js +9 -29
  63. package/dist/shell/settings-panels.js.map +1 -1
  64. package/dist/shell/settings-rows.d.ts +2 -7
  65. package/dist/shell/settings-rows.js +36 -93
  66. package/dist/shell/settings-rows.js.map +1 -1
  67. package/dist/shell/shell.css +0 -192
  68. package/dist/shell/sidebar-footer.js +2 -6
  69. package/dist/shell/sidebar-footer.js.map +1 -1
  70. package/dist/shell/unified-settings-modal.d.ts +2 -3
  71. package/dist/shell/unified-settings-modal.js +74 -151
  72. package/dist/shell/unified-settings-modal.js.map +1 -1
  73. package/dist/sidebar/config.js +3 -19
  74. package/dist/sidebar/config.js.map +1 -1
  75. package/dist/sidebar/more-group.js +1 -1
  76. package/dist/sidebar/more-group.js.map +1 -1
  77. package/dist/sidebar/nav-renderers.js +0 -2
  78. package/dist/sidebar/nav-renderers.js.map +1 -1
  79. package/dist/sidebar/nav-section.js +3 -5
  80. package/dist/sidebar/nav-section.js.map +1 -1
  81. package/dist/sidebar/setup-progress.d.ts +1 -3
  82. package/dist/sidebar/setup-progress.js +2 -2
  83. package/dist/sidebar/setup-progress.js.map +1 -1
  84. package/dist/sidebar/spine-groups.js +1 -7
  85. package/dist/sidebar/spine-groups.js.map +1 -1
  86. package/dist/sidebar.js +5 -5
  87. package/dist/sidebar.js.map +1 -1
  88. package/dist/templates/template-live-thumb.js +5 -16
  89. package/dist/templates/template-live-thumb.js.map +1 -1
  90. package/package.json +5 -5
  91. package/dist/dashboard/activity-paid.d.ts +0 -10
  92. package/dist/dashboard/activity-paid.js +0 -7
  93. package/dist/dashboard/activity-paid.js.map +0 -1
  94. package/dist/dashboard/home/host-quick-actions.d.ts +0 -19
  95. package/dist/dashboard/home/host-quick-actions.js +0 -12
  96. package/dist/dashboard/home/host-quick-actions.js.map +0 -1
  97. package/dist/dashboard/home/widgets/host-widgets.d.ts +0 -6
  98. package/dist/dashboard/home/widgets/host-widgets.js +0 -16
  99. package/dist/dashboard/home/widgets/host-widgets.js.map +0 -1
  100. package/dist/dashboard/home/widgets/member-label.d.ts +0 -11
  101. package/dist/dashboard/home/widgets/member-label.js +0 -10
  102. package/dist/dashboard/home/widgets/member-label.js.map +0 -1
  103. package/dist/dashboard/home/widgets/middle-ellipsis.d.ts +0 -5
  104. package/dist/dashboard/home/widgets/middle-ellipsis.js +0 -11
  105. package/dist/dashboard/home/widgets/middle-ellipsis.js.map +0 -1
  106. package/dist/dashboard/home/widgets/revenue-series.d.ts +0 -12
  107. package/dist/dashboard/home/widgets/revenue-series.js +0 -26
  108. package/dist/dashboard/home/widgets/revenue-series.js.map +0 -1
  109. package/dist/dashboard/page-transition-key.d.ts +0 -7
  110. package/dist/dashboard/page-transition-key.js +0 -11
  111. package/dist/dashboard/page-transition-key.js.map +0 -1
  112. package/dist/features/gift-cards/gift-card-logic.d.ts +0 -41
  113. package/dist/features/gift-cards/gift-card-logic.js +0 -65
  114. package/dist/features/gift-cards/gift-card-logic.js.map +0 -1
  115. package/dist/features/gift-cards/hint.d.ts +0 -9
  116. package/dist/features/gift-cards/hint.js +0 -25
  117. package/dist/features/gift-cards/hint.js.map +0 -1
  118. package/dist/shell/notification-actions.d.ts +0 -12
  119. package/dist/shell/notification-actions.js +0 -18
  120. package/dist/shell/notification-actions.js.map +0 -1
  121. package/dist/shell/settings-groups.d.ts +0 -23
  122. package/dist/shell/settings-groups.js +0 -22
  123. package/dist/shell/settings-groups.js.map +0 -1
  124. package/dist/shell/settings-host.d.ts +0 -39
  125. package/dist/shell/settings-host.js +0 -37
  126. package/dist/shell/settings-host.js.map +0 -1
  127. package/dist/shell/sidebar-cards.d.ts +0 -32
  128. package/dist/shell/sidebar-cards.js +0 -37
  129. package/dist/shell/sidebar-cards.js.map +0 -1
  130. package/dist/templates/template-tile-source.d.ts +0 -24
  131. package/dist/templates/template-tile-source.js +0 -18
  132. package/dist/templates/template-tile-source.js.map +0 -1
@@ -1,20 +1,21 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { useCallback, useEffect, useId, useRef, useState } from "react";
4
- import { Copy, Download, Gift, History, Mail, Plus, Search } from "lucide-react";
3
+ import { useCallback, useEffect, useRef, useState } from "react";
4
+ import {
5
+ Copy,
6
+ Download,
7
+ Gift,
8
+ History,
9
+ Mail,
10
+ Plus,
11
+ Search,
12
+ X
13
+ } from "lucide-react";
5
14
  import { useAuth } from "@withpotter/lib/auth-context";
6
15
  import { normalizeCurrencyCode } from "@withpotter/lib/utils";
7
- import { Button } from "@withpotter/ui-kit/button";
8
- import { Field } from "@withpotter/ui-kit/field";
9
- import { FormDialog } from "@withpotter/ui-kit/form-dialog";
10
16
  import { InlineDeleteButton } from "@withpotter/ui-kit/inline-delete-button";
11
- import { Input } from "@withpotter/ui-kit/input";
12
- import { ListPage } from "@withpotter/ui-kit/list-page";
13
- import { Textarea } from "@withpotter/ui-kit/textarea";
14
- import { Tooltip } from "@withpotter/ui-kit/tooltip";
15
17
  import {
16
18
  giftCardsApi,
17
- giftcardsApi,
18
19
  communicationsApi
19
20
  } from "@withpotter/lib/api";
20
21
  import { useFormatCurrency } from "@withpotter/hooks/use-format-currency";
@@ -33,15 +34,6 @@ import {
33
34
  GiftCardArtwork,
34
35
  GIFT_CARD_PRESETS
35
36
  } from "../gift-card-artwork";
36
- import {
37
- createInFlightDeduper,
38
- currencySymbol,
39
- isFirstRun,
40
- PAGE_HINT_LINES,
41
- STATUS_FILTERS,
42
- STATUS_LABEL
43
- } from "./gift-card-logic";
44
- import { Hint } from "./hint";
45
37
  const PAGE_SIZE = 20;
46
38
  const LIVE = process.env.NEXT_PUBLIC_BOX_GIFT_CARDS_LIVE === "true";
47
39
  const LIVE_REFRESH_MS = 2e3;
@@ -73,6 +65,24 @@ function statusClass(status) {
73
65
  return "bg-[var(--bg-muted)] text-[var(--text-tertiary)]";
74
66
  }
75
67
  }
68
+ function Modal({ title, onClose, children }) {
69
+ return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-end justify-center bg-black/40 sm:items-center sm:p-4", children: /* @__PURE__ */ jsxs("div", { className: "max-h-[92vh] w-full overflow-y-auto bg-[var(--bg-base)] sm:max-w-xl sm:rounded-md sm:border sm:border-[var(--border-default)]", children: [
70
+ /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-10 flex items-center justify-between border-b border-[var(--border-default)] bg-[var(--bg-base)] px-4 py-3", children: [
71
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-[var(--text-primary)]", children: title }),
72
+ /* @__PURE__ */ jsx(
73
+ "button",
74
+ {
75
+ type: "button",
76
+ onClick: onClose,
77
+ className: "rounded-md p-2 text-[var(--text-tertiary)] hover:bg-[var(--interactive-hover)]",
78
+ "aria-label": "Close",
79
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
80
+ }
81
+ )
82
+ ] }),
83
+ children
84
+ ] }) });
85
+ }
76
86
  function IssueGiftCardModal({
77
87
  currency,
78
88
  merchantName,
@@ -80,16 +90,6 @@ function IssueGiftCardModal({
80
90
  onCreated
81
91
  }) {
82
92
  const { tenant } = useAuth();
83
- const formId = useId();
84
- const ids = {
85
- amount: `${formId}-amount`,
86
- recipientName: `${formId}-recipient-name`,
87
- recipientEmail: `${formId}-recipient-email`,
88
- purchaserName: `${formId}-purchaser-name`,
89
- purchaserEmail: `${formId}-purchaser-email`,
90
- message: `${formId}-message`,
91
- expiresAt: `${formId}-expires-at`
92
- };
93
93
  const [form, setForm] = useState({
94
94
  originalAmount: 0,
95
95
  currency,
@@ -115,233 +115,178 @@ function IssueGiftCardModal({
115
115
  setSaving(false);
116
116
  }
117
117
  };
118
- const symbol = currencySymbol(form.currency || currency);
119
- return /* @__PURE__ */ jsx(
120
- FormDialog,
121
- {
122
- title: "Issue gift card",
123
- description: "We create the code for you. Fields marked * are required.",
124
- size: "lg",
125
- className: "max-w-4xl",
126
- onClose,
127
- footer: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
128
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", onClick: onClose, children: "Cancel" }),
118
+ const inputClass = "w-full rounded-md border border-[var(--border-default)] bg-[var(--bg-base)] px-3 py-2 text-sm text-[var(--text-primary)] focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20";
119
+ return /* @__PURE__ */ jsx(Modal, { title: "Issue gift card", onClose, children: /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-5 p-4", children: [
120
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)] sm:items-start", children: [
121
+ /* @__PURE__ */ jsx(
122
+ GiftCardArtwork,
123
+ {
124
+ design: form.design ?? GIFT_CARD_PRESETS[0],
125
+ merchantName,
126
+ amount: form.originalAmount > 0 ? new Intl.NumberFormat(void 0, {
127
+ style: "currency",
128
+ currency: form.currency || currency
129
+ }).format(form.originalAmount) : void 0,
130
+ recipientName: form.recipientName,
131
+ senderName: form.purchaserName
132
+ }
133
+ ),
134
+ /* @__PURE__ */ jsxs("fieldset", { children: [
135
+ /* @__PURE__ */ jsx("legend", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Design" }),
136
+ /* @__PURE__ */ jsx("div", { className: "mt-2 grid grid-cols-4 gap-2 sm:grid-cols-1", children: GIFT_CARD_PRESETS.map((design) => {
137
+ const selected = form.design?.designId === design.designId;
138
+ return /* @__PURE__ */ jsxs(
139
+ "button",
140
+ {
141
+ type: "button",
142
+ onClick: () => setField("design", design),
143
+ className: `flex min-w-0 items-center gap-2 rounded-md border p-2 text-left text-xs font-medium ${selected ? "border-brand-500 bg-brand-500/10 text-[var(--text-primary)]" : "border-[var(--border-default)] text-[var(--text-secondary)] hover:bg-[var(--interactive-hover)]"}`,
144
+ "aria-label": design.name,
145
+ "aria-pressed": selected,
146
+ children: [
147
+ /* @__PURE__ */ jsx(
148
+ "span",
149
+ {
150
+ className: "h-5 w-5 shrink-0 rounded-sm border border-black/10",
151
+ style: { backgroundColor: design.palette.background }
152
+ }
153
+ ),
154
+ /* @__PURE__ */ jsx("span", { className: "hidden truncate sm:block", children: design.name })
155
+ ]
156
+ },
157
+ design.designId
158
+ );
159
+ }) })
160
+ ] })
161
+ ] }),
162
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
163
+ /* @__PURE__ */ jsxs("label", { className: "space-y-1.5", children: [
164
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Amount" }),
165
+ /* @__PURE__ */ jsx(
166
+ "input",
167
+ {
168
+ className: inputClass,
169
+ type: "number",
170
+ min: "0.01",
171
+ step: "0.01",
172
+ required: true,
173
+ value: form.originalAmount || "",
174
+ onChange: (event) => setField("originalAmount", Number(event.target.value))
175
+ }
176
+ )
177
+ ] }),
178
+ /* @__PURE__ */ jsxs("label", { className: "space-y-1.5", children: [
179
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Currency" }),
180
+ /* @__PURE__ */ jsx(
181
+ "input",
182
+ {
183
+ className: inputClass,
184
+ readOnly: true,
185
+ required: true,
186
+ value: form.currency
187
+ }
188
+ )
189
+ ] }),
190
+ /* @__PURE__ */ jsxs("label", { className: "space-y-1.5", children: [
191
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Recipient name" }),
192
+ /* @__PURE__ */ jsx(
193
+ "input",
194
+ {
195
+ className: inputClass,
196
+ value: form.recipientName ?? "",
197
+ onChange: (event) => setField("recipientName", event.target.value)
198
+ }
199
+ ),
200
+ /* @__PURE__ */ jsx("span", { className: "block text-xs text-[var(--text-muted)]", children: "The person who receives the gift card and spends it." })
201
+ ] }),
202
+ /* @__PURE__ */ jsxs("label", { className: "space-y-1.5", children: [
203
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Recipient email" }),
129
204
  /* @__PURE__ */ jsx(
130
- Button,
205
+ "input",
131
206
  {
132
- type: "submit",
133
- form: formId,
134
- disabled: saving || form.originalAmount <= 0,
135
- children: saving ? "Issuing..." : "Issue gift card"
207
+ className: inputClass,
208
+ type: "email",
209
+ value: form.recipientEmail ?? "",
210
+ onChange: (event) => setField("recipientEmail", event.target.value)
136
211
  }
137
212
  )
138
213
  ] }),
139
- children: /* @__PURE__ */ jsxs(
140
- "form",
214
+ /* @__PURE__ */ jsxs("label", { className: "space-y-1.5", children: [
215
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Purchaser name" }),
216
+ /* @__PURE__ */ jsx(
217
+ "input",
218
+ {
219
+ className: inputClass,
220
+ value: form.purchaserName ?? "",
221
+ onChange: (event) => setField("purchaserName", event.target.value)
222
+ }
223
+ ),
224
+ /* @__PURE__ */ jsx("span", { className: "block text-xs text-[var(--text-muted)]", children: "The person paying for the gift card." })
225
+ ] }),
226
+ /* @__PURE__ */ jsxs("label", { className: "space-y-1.5", children: [
227
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Purchaser email" }),
228
+ /* @__PURE__ */ jsx(
229
+ "input",
230
+ {
231
+ className: inputClass,
232
+ type: "email",
233
+ value: form.purchaserEmail ?? "",
234
+ onChange: (event) => setField("purchaserEmail", event.target.value)
235
+ }
236
+ )
237
+ ] })
238
+ ] }),
239
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
240
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Personal message" }),
241
+ /* @__PURE__ */ jsx(
242
+ "textarea",
141
243
  {
142
- id: formId,
143
- onSubmit: submit,
144
- className: "grid gap-6 md:grid-cols-[17rem_minmax(0,1fr)]",
145
- children: [
146
- /* @__PURE__ */ jsxs("div", { className: "space-y-4 md:self-start", children: [
147
- /* @__PURE__ */ jsx(
148
- GiftCardArtwork,
149
- {
150
- design: form.design ?? GIFT_CARD_PRESETS[0],
151
- merchantName,
152
- amount: form.originalAmount > 0 ? new Intl.NumberFormat(void 0, {
153
- style: "currency",
154
- currency: form.currency || currency
155
- }).format(form.originalAmount) : void 0,
156
- recipientName: form.recipientName,
157
- senderName: form.purchaserName
158
- }
159
- ),
160
- /* @__PURE__ */ jsxs("fieldset", { children: [
161
- /* @__PURE__ */ jsx("legend", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Design" }),
162
- /* @__PURE__ */ jsx("div", { className: "mt-2 grid grid-cols-4 gap-2 md:grid-cols-2", children: GIFT_CARD_PRESETS.map((design) => {
163
- const selected = form.design?.designId === design.designId;
164
- return /* @__PURE__ */ jsxs(
165
- "button",
166
- {
167
- type: "button",
168
- onClick: () => setField("design", design),
169
- className: `flex min-w-0 items-center gap-2 rounded-md border p-2 text-left text-xs font-medium ${selected ? "border-brand-500 bg-brand-500/10 text-[var(--text-primary)]" : "border-[var(--border-default)] text-[var(--text-secondary)] hover:bg-[var(--interactive-hover)]"}`,
170
- "aria-label": design.name,
171
- "aria-pressed": selected,
172
- children: [
173
- /* @__PURE__ */ jsx(
174
- "span",
175
- {
176
- className: "h-5 w-5 shrink-0 rounded-sm border border-black/10",
177
- style: { backgroundColor: design.palette.background }
178
- }
179
- ),
180
- /* @__PURE__ */ jsx("span", { className: "hidden truncate md:block", children: design.name })
181
- ]
182
- },
183
- design.designId
184
- );
185
- }) })
186
- ] })
187
- ] }),
188
- /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
189
- /* @__PURE__ */ jsx(
190
- Field,
191
- {
192
- label: "Amount",
193
- htmlFor: ids.amount,
194
- required: true,
195
- hint: `In ${form.currency || currency}, your business currency. It cannot be changed here.`,
196
- children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
197
- /* @__PURE__ */ jsx(
198
- "span",
199
- {
200
- "aria-hidden": true,
201
- className: "pointer-events-none absolute inset-y-0 left-3 flex items-center text-sm text-[var(--text-tertiary)]",
202
- children: symbol
203
- }
204
- ),
205
- /* @__PURE__ */ jsx(
206
- Input,
207
- {
208
- id: ids.amount,
209
- type: "number",
210
- min: "0.01",
211
- step: "0.01",
212
- required: true,
213
- "aria-required": true,
214
- className: symbol.length > 2 ? "pl-14" : "pl-8",
215
- value: form.originalAmount || "",
216
- onChange: (event) => setField("originalAmount", Number(event.target.value))
217
- }
218
- )
219
- ] })
220
- }
221
- ),
222
- /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
223
- /* @__PURE__ */ jsx(
224
- Field,
225
- {
226
- label: "Recipient name",
227
- htmlFor: ids.recipientName,
228
- hint: "Optional. Who receives and spends the card.",
229
- children: /* @__PURE__ */ jsx(
230
- Input,
231
- {
232
- id: ids.recipientName,
233
- value: form.recipientName ?? "",
234
- onChange: (event) => setField("recipientName", event.target.value)
235
- }
236
- )
237
- }
238
- ),
239
- /* @__PURE__ */ jsx(
240
- Field,
241
- {
242
- label: "Recipient email",
243
- htmlFor: ids.recipientEmail,
244
- hint: "Optional. Nothing is emailed when you issue. Send it from the card's details.",
245
- children: /* @__PURE__ */ jsx(
246
- Input,
247
- {
248
- id: ids.recipientEmail,
249
- type: "email",
250
- value: form.recipientEmail ?? "",
251
- onChange: (event) => setField("recipientEmail", event.target.value)
252
- }
253
- )
254
- }
255
- ),
256
- /* @__PURE__ */ jsx(
257
- Field,
258
- {
259
- label: "Purchaser name",
260
- htmlFor: ids.purchaserName,
261
- hint: "Optional. Who is paying for the card.",
262
- children: /* @__PURE__ */ jsx(
263
- Input,
264
- {
265
- id: ids.purchaserName,
266
- value: form.purchaserName ?? "",
267
- onChange: (event) => setField("purchaserName", event.target.value)
268
- }
269
- )
270
- }
271
- ),
272
- /* @__PURE__ */ jsx(
273
- Field,
274
- {
275
- label: "Purchaser email",
276
- htmlFor: ids.purchaserEmail,
277
- hint: "Optional.",
278
- children: /* @__PURE__ */ jsx(
279
- Input,
280
- {
281
- id: ids.purchaserEmail,
282
- type: "email",
283
- value: form.purchaserEmail ?? "",
284
- onChange: (event) => setField("purchaserEmail", event.target.value)
285
- }
286
- )
287
- }
288
- )
289
- ] }),
290
- /* @__PURE__ */ jsx(
291
- Field,
292
- {
293
- label: "Personal message",
294
- htmlFor: ids.message,
295
- hint: "Optional. Up to 500 characters.",
296
- children: /* @__PURE__ */ jsx(
297
- Textarea,
298
- {
299
- id: ids.message,
300
- rows: 3,
301
- maxLength: 500,
302
- value: form.personalMessage ?? "",
303
- onChange: (event) => setField("personalMessage", event.target.value)
304
- }
305
- )
306
- }
307
- ),
308
- /* @__PURE__ */ jsx(
309
- Field,
310
- {
311
- label: "Expiration date",
312
- htmlFor: ids.expiresAt,
313
- hint: "Optional. Leave it empty and the card has no expiry date.",
314
- children: /* @__PURE__ */ jsx(
315
- Input,
316
- {
317
- id: ids.expiresAt,
318
- type: "date",
319
- min: minimumExpirationDate(),
320
- value: form.expiresAt ?? "",
321
- onChange: (event) => setField("expiresAt", event.target.value)
322
- }
323
- )
324
- }
325
- ),
326
- error && /* @__PURE__ */ jsx(
327
- "p",
328
- {
329
- role: "alert",
330
- className: "rounded-md bg-[var(--error-bg)] px-3 py-2 text-sm text-[var(--error)]",
331
- children: error
332
- }
333
- )
334
- ] })
335
- ]
244
+ className: `${inputClass} min-h-24 resize-y`,
245
+ maxLength: 500,
246
+ value: form.personalMessage ?? "",
247
+ onChange: (event) => setField("personalMessage", event.target.value)
336
248
  }
337
249
  )
338
- }
339
- );
250
+ ] }),
251
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
252
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Expiration date" }),
253
+ /* @__PURE__ */ jsx(
254
+ "input",
255
+ {
256
+ className: inputClass,
257
+ type: "date",
258
+ min: minimumExpirationDate(),
259
+ value: form.expiresAt ?? "",
260
+ onChange: (event) => setField("expiresAt", event.target.value)
261
+ }
262
+ )
263
+ ] }),
264
+ error && /* @__PURE__ */ jsx("p", { className: "rounded-md bg-[var(--error-bg)] px-3 py-2 text-sm text-[var(--error)]", children: error }),
265
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 border-t border-[var(--border-default)] pt-4", children: [
266
+ /* @__PURE__ */ jsx(
267
+ "button",
268
+ {
269
+ type: "button",
270
+ onClick: onClose,
271
+ className: "rounded-md border border-[var(--border-default)] px-4 py-2 text-sm font-medium text-[var(--text-secondary)] hover:bg-[var(--interactive-hover)]",
272
+ children: "Cancel"
273
+ }
274
+ ),
275
+ /* @__PURE__ */ jsx(
276
+ "button",
277
+ {
278
+ type: "submit",
279
+ disabled: saving || form.originalAmount <= 0,
280
+ className: "rounded-md bg-brand-500 px-4 py-2 text-sm font-medium text-[var(--text-inverse)] hover:bg-brand-600 disabled:opacity-50",
281
+ children: saving ? "Issuing..." : "Issue gift card"
282
+ }
283
+ )
284
+ ] })
285
+ ] }) });
340
286
  }
341
287
  function BalanceModal({ onClose, initialCode = "" }) {
342
288
  const { tenant } = useAuth();
343
289
  const formatCurrency = useFormatCurrency();
344
- const codeId = useId();
345
290
  const [code, setCode] = useState(initialCode);
346
291
  const [checking, setChecking] = useState(false);
347
292
  const [result, setResult] = useState(null);
@@ -359,36 +304,35 @@ function BalanceModal({ onClose, initialCode = "" }) {
359
304
  setChecking(false);
360
305
  }
361
306
  };
362
- return /* @__PURE__ */ jsx(FormDialog, { title: "Check gift card balance", size: "sm", onClose, children: /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-4", children: [
363
- /* @__PURE__ */ jsx(Field, { label: "Gift card code", htmlFor: codeId, required: true, children: /* @__PURE__ */ jsx(
364
- Input,
365
- {
366
- id: codeId,
367
- required: true,
368
- "aria-required": true,
369
- autoComplete: "off",
370
- spellCheck: false,
371
- className: "font-mono uppercase",
372
- value: code,
373
- onChange: (event) => {
374
- setCode(event.target.value.toUpperCase());
375
- setResult(null);
307
+ return /* @__PURE__ */ jsx(Modal, { title: "Check gift card balance", onClose, children: /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-4 p-4", children: [
308
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
309
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Gift card code" }),
310
+ /* @__PURE__ */ jsx(
311
+ "input",
312
+ {
313
+ autoFocus: true,
314
+ className: "w-full rounded-md border border-[var(--border-default)] bg-[var(--bg-base)] px-3 py-2 font-mono text-sm uppercase text-[var(--text-primary)] focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20",
315
+ value: code,
316
+ onChange: (event) => {
317
+ setCode(event.target.value.toUpperCase());
318
+ setResult(null);
319
+ }
376
320
  }
377
- }
378
- ) }),
379
- /* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", children: result && /* @__PURE__ */ jsx(
321
+ )
322
+ ] }),
323
+ result && /* @__PURE__ */ jsx(
380
324
  "div",
381
325
  {
382
326
  className: `rounded-md p-4 ${result.valid ? "bg-[var(--success-bg)] text-[var(--success)]" : "bg-[var(--error-bg)] text-[var(--error)]"}`,
383
327
  children: result.valid ? `Available balance: ${formatCurrency(result.balance ?? 0)}` : result.error || "This gift card is not valid."
384
328
  }
385
- ) }),
329
+ ),
386
330
  /* @__PURE__ */ jsx(
387
- Button,
331
+ "button",
388
332
  {
389
333
  type: "submit",
390
- className: "w-full",
391
334
  disabled: checking || !code.trim(),
335
+ className: "w-full rounded-md bg-brand-500 px-4 py-2 text-sm font-medium text-[var(--text-inverse)] hover:bg-brand-600 disabled:opacity-50",
392
336
  children: checking ? "Checking..." : "Check balance"
393
337
  }
394
338
  )
@@ -465,7 +409,7 @@ function GiftCardDetailModal({
465
409
  if (!tenant?.slug) return;
466
410
  setSaving(true);
467
411
  try {
468
- await giftcardsApi.cancel(tenant.slug, giftCard.id);
412
+ await giftCardsApi.delete(tenant.slug, giftCard.id);
469
413
  toast({ title: "Gift card cancelled" });
470
414
  onChanged();
471
415
  onClose();
@@ -474,63 +418,60 @@ function GiftCardDetailModal({
474
418
  setSaving(false);
475
419
  }
476
420
  };
477
- return /* @__PURE__ */ jsx(FormDialog, { title: "Gift card details", onClose, children: /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
421
+ return /* @__PURE__ */ jsx(Modal, { title: "Gift card details", onClose, children: /* @__PURE__ */ jsxs("div", { className: "space-y-5 p-4", children: [
478
422
  /* @__PURE__ */ jsx(GiftCardArtwork, { ...artworkData }),
479
423
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
480
- /* @__PURE__ */ jsx(
481
- Button,
424
+ /* @__PURE__ */ jsxs(
425
+ "button",
482
426
  {
483
427
  type: "button",
484
- variant: "secondary",
485
- icon: /* @__PURE__ */ jsx(Download, {}),
486
428
  onClick: () => downloadGiftCardArtwork(artworkData),
487
- children: "Download"
429
+ className: "flex items-center justify-center gap-2 rounded-md border border-[var(--border-default)] px-3 py-2 text-sm font-medium text-[var(--text-secondary)] hover:bg-[var(--interactive-hover)]",
430
+ children: [
431
+ /* @__PURE__ */ jsx(Download, { className: "h-4 w-4" }),
432
+ "Download"
433
+ ]
488
434
  }
489
435
  ),
490
- /* @__PURE__ */ jsx(
491
- Tooltip,
436
+ /* @__PURE__ */ jsxs(
437
+ "button",
492
438
  {
493
- label: giftCard.recipientEmail ? "" : "Add a recipient email to send this card",
494
- children: /* @__PURE__ */ jsx("span", { className: "block", children: /* @__PURE__ */ jsx(
495
- Button,
496
- {
497
- type: "button",
498
- variant: "secondary",
499
- icon: /* @__PURE__ */ jsx(Mail, {}),
500
- className: "w-full",
501
- onClick: sendByEmail,
502
- disabled: sharing || !giftCard.recipientEmail,
503
- children: sharing ? "Sending..." : "Send by email"
504
- }
505
- ) })
439
+ type: "button",
440
+ onClick: sendByEmail,
441
+ disabled: sharing || !giftCard.recipientEmail,
442
+ title: giftCard.recipientEmail ? void 0 : "Add a recipient email to send this card",
443
+ className: "flex items-center justify-center gap-2 rounded-md bg-brand-500 px-3 py-2 text-sm font-medium text-[var(--text-inverse)] hover:bg-brand-600 disabled:cursor-not-allowed disabled:opacity-50",
444
+ children: [
445
+ /* @__PURE__ */ jsx(Mail, { className: "h-4 w-4" }),
446
+ sharing ? "Sending..." : "Send by email"
447
+ ]
506
448
  }
507
449
  )
508
450
  ] }),
509
451
  /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-[var(--border-default)] bg-[var(--bg-subtle)] p-4", children: [
510
452
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
511
453
  /* @__PURE__ */ jsxs("div", { children: [
512
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-[var(--text-muted)]", children: "Code" }),
454
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase text-[var(--text-muted)]", children: "Code" }),
513
455
  /* @__PURE__ */ jsx("p", { className: "mt-1 font-mono text-xl font-semibold text-[var(--text-primary)]", children: giftCard.code })
514
456
  ] }),
515
457
  /* @__PURE__ */ jsx(
516
- Button,
458
+ "button",
517
459
  {
518
460
  type: "button",
519
- variant: "secondary",
520
- size: "icon-sm",
521
- "aria-label": "Copy code",
522
461
  onClick: copyCode,
523
- children: /* @__PURE__ */ jsx(Copy, {})
462
+ className: "rounded-md border border-[var(--border-default)] bg-[var(--bg-base)] p-2 text-[var(--text-secondary)] hover:bg-[var(--interactive-hover)]",
463
+ title: "Copy code",
464
+ children: /* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" })
524
465
  }
525
466
  )
526
467
  ] }),
527
468
  /* @__PURE__ */ jsxs("div", { className: "mt-4 grid grid-cols-2 gap-4", children: [
528
469
  /* @__PURE__ */ jsxs("div", { children: [
529
- /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-muted)]", children: "Balance left" }),
470
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-muted)]", children: "Balance" }),
530
471
  /* @__PURE__ */ jsx("p", { className: "font-semibold text-[var(--text-primary)]", children: formatCurrency(Number(giftCard.balance), giftCard.currency) })
531
472
  ] }),
532
473
  /* @__PURE__ */ jsxs("div", { children: [
533
- /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-muted)]", children: "Original value" }),
474
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-muted)]", children: "Issued value" }),
534
475
  /* @__PURE__ */ jsx("p", { className: "font-semibold text-[var(--text-primary)]", children: formatCurrency(
535
476
  Number(giftCard.originalAmount),
536
477
  giftCard.currency
@@ -550,41 +491,44 @@ function GiftCardDetailModal({
550
491
  /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-[var(--text-primary)]", children: "Redeem value" }),
551
492
  /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
552
493
  /* @__PURE__ */ jsx(
553
- Input,
494
+ "input",
554
495
  {
555
- label: "Amount",
556
496
  type: "number",
557
497
  min: "0.01",
558
498
  max: Number(giftCard.balance),
559
499
  step: "0.01",
560
500
  required: true,
561
- "aria-required": true,
501
+ placeholder: "Amount",
562
502
  value: amount,
563
- onChange: (event) => setAmount(event.target.value)
503
+ onChange: (event) => setAmount(event.target.value),
504
+ className: "rounded-md border border-[var(--border-default)] bg-[var(--bg-base)] px-3 py-2 text-sm focus:border-brand-500 focus:outline-none"
564
505
  }
565
506
  ),
566
507
  /* @__PURE__ */ jsx(
567
- Input,
508
+ "input",
568
509
  {
569
- label: "Order or reference ID (optional)",
510
+ placeholder: "Order or reference ID",
570
511
  value: referenceId,
571
- onChange: (event) => setReferenceId(event.target.value)
512
+ onChange: (event) => setReferenceId(event.target.value),
513
+ className: "rounded-md border border-[var(--border-default)] bg-[var(--bg-base)] px-3 py-2 text-sm focus:border-brand-500 focus:outline-none"
572
514
  }
573
515
  )
574
516
  ] }),
575
517
  /* @__PURE__ */ jsx(
576
- Input,
518
+ "input",
577
519
  {
578
- label: "Note (optional)",
520
+ placeholder: "Note (optional)",
579
521
  value: note,
580
- onChange: (event) => setNote(event.target.value)
522
+ onChange: (event) => setNote(event.target.value),
523
+ className: "w-full rounded-md border border-[var(--border-default)] bg-[var(--bg-base)] px-3 py-2 text-sm focus:border-brand-500 focus:outline-none"
581
524
  }
582
525
  ),
583
526
  /* @__PURE__ */ jsx(
584
- Button,
527
+ "button",
585
528
  {
586
529
  type: "submit",
587
530
  disabled: saving || !amount || Number(amount) <= 0,
531
+ className: "rounded-md bg-brand-500 px-4 py-2 text-sm font-medium text-[var(--text-inverse)] hover:bg-brand-600 disabled:opacity-50",
588
532
  children: saving ? "Redeeming..." : "Redeem gift card"
589
533
  }
590
534
  )
@@ -612,15 +556,8 @@ function GiftCardDetailModal({
612
556
  redemption.id
613
557
  )) })
614
558
  ] }),
615
- error && /* @__PURE__ */ jsx(
616
- "p",
617
- {
618
- role: "alert",
619
- className: "rounded-md bg-[var(--error-bg)] px-3 py-2 text-sm text-[var(--error)]",
620
- children: error
621
- }
622
- ),
623
- giftCard.status !== "cancelled" && /* @__PURE__ */ jsx("div", { className: "flex justify-end border-t border-[var(--border-default)] pt-4", children: /* @__PURE__ */ jsx(
559
+ error && /* @__PURE__ */ jsx("p", { className: "rounded-md bg-[var(--error-bg)] px-3 py-2 text-sm text-[var(--error)]", children: error }),
560
+ /* @__PURE__ */ jsx("div", { className: "flex justify-end border-t border-[var(--border-default)] pt-4", children: /* @__PURE__ */ jsx(
624
561
  InlineDeleteButton,
625
562
  {
626
563
  onDelete: remove,
@@ -636,14 +573,12 @@ function GiftCardsFeature() {
636
573
  const { tenant } = useAuth();
637
574
  const formatCurrency = useFormatCurrency();
638
575
  const { toast } = useToast();
639
- const slug = tenant?.slug;
640
576
  const currency = normalizeCurrencyCode(
641
577
  tenant?.settings?.currency
642
578
  );
643
579
  const [giftCards, setGiftCards] = useState([]);
644
580
  const [stats, setStats] = useState(null);
645
581
  const [loading, setLoading] = useState(true);
646
- const [loaded, setLoaded] = useState(false);
647
582
  const [search, setSearch] = useState("");
648
583
  const [status, setStatus] = useState("");
649
584
  const [page, setPage] = useState(1);
@@ -651,386 +586,313 @@ function GiftCardsFeature() {
651
586
  const [showIssue, setShowIssue] = useState(false);
652
587
  const [showBalance, setShowBalance] = useState(false);
653
588
  const [selected, setSelected] = useState(null);
654
- const [dedupe] = useState(createInFlightDeduper);
655
- const toastRef = useRef(toast);
656
- useEffect(() => {
657
- toastRef.current = toast;
658
- });
659
589
  const latestRead = useRef(0);
660
590
  const readGiftCards = useCallback(
661
591
  async (quiet) => {
662
- if (!slug) return;
592
+ if (!tenant?.slug) return;
663
593
  const read = quiet ? latestRead.current : ++latestRead.current;
664
594
  if (!quiet) setLoading(true);
665
- const query = {
666
- ...status ? { status } : {},
667
- ...search.trim() ? { search: search.trim() } : {},
668
- page,
669
- limit: PAGE_SIZE
670
- };
671
595
  try {
672
- const list = await dedupe.run(
673
- `list:${slug}:${JSON.stringify(query)}`,
674
- () => giftCardsApi.list(slug, query)
675
- );
596
+ const [list, giftCardStats] = await Promise.all([
597
+ giftCardsApi.list(tenant.slug, {
598
+ ...status ? { status } : {},
599
+ ...search.trim() ? { search: search.trim() } : {},
600
+ page,
601
+ limit: PAGE_SIZE
602
+ }),
603
+ giftCardsApi.stats(tenant.slug)
604
+ ]);
676
605
  if (read !== latestRead.current) return;
677
606
  setGiftCards(list.rows);
678
607
  setCount(list.count);
608
+ setStats(giftCardStats);
679
609
  } catch (loadError) {
680
610
  if (quiet) throw loadError;
681
- toastRef.current({
611
+ toast({
682
612
  title: "Unable to load gift cards",
683
613
  description: errorMessage(loadError)
684
614
  });
685
615
  } finally {
686
- if (!quiet && read === latestRead.current) {
687
- setLoading(false);
688
- setLoaded(true);
689
- }
690
- }
691
- },
692
- [dedupe, page, search, slug, status]
693
- );
694
- const readStats = useCallback(
695
- async (quiet) => {
696
- if (!slug) return;
697
- try {
698
- setStats(await dedupe.run(`stats:${slug}`, () => giftCardsApi.stats(slug)));
699
- } catch (statsError) {
700
- if (quiet) throw statsError;
616
+ if (!quiet) setLoading(false);
701
617
  }
702
618
  },
703
- [dedupe, slug]
704
- );
705
- const reloadAll = useCallback(
706
- () => Promise.all([readGiftCards(false), readStats(false)]),
707
- [readGiftCards, readStats]
619
+ [page, search, status, tenant?.slug, toast]
708
620
  );
621
+ const loadGiftCards = useCallback(() => readGiftCards(false), [readGiftCards]);
709
622
  useEffect(() => {
710
- readGiftCards(false);
711
- }, [readGiftCards]);
712
- useEffect(() => {
713
- readStats(false);
714
- }, [readStats]);
623
+ loadGiftCards();
624
+ }, [loadGiftCards]);
715
625
  useQuietPoll(
716
- useCallback(
717
- () => Promise.all([readGiftCards(true), readStats(true)]),
718
- [readGiftCards, readStats]
719
- ),
626
+ useCallback(() => readGiftCards(true), [readGiftCards]),
720
627
  LIVE_REFRESH_MS,
721
628
  LIVE
722
629
  );
723
- useRegisterRefresh(reloadAll);
630
+ useRegisterRefresh(loadGiftCards);
724
631
  const copyCode = async (event, code) => {
725
632
  event.stopPropagation();
726
633
  await navigator.clipboard.writeText(code);
727
634
  toast({ title: "Gift card code copied", description: code });
728
635
  };
729
636
  const totalPages = Math.max(1, Math.ceil(count / PAGE_SIZE));
730
- const hasFilters = Boolean(search.trim() || status);
731
- const firstRun = loaded && isFirstRun({
732
- loading,
733
- search,
734
- status,
735
- count,
736
- totalIssued: stats?.totalIssued
737
- });
738
- const hasCards = loaded && !firstRun;
739
- const showStats = hasCards && stats !== null;
740
- const openIssue = () => setShowIssue(true);
741
- const openBalance = () => setShowBalance(true);
742
- return /* @__PURE__ */ jsxs(
743
- ListPage,
744
- {
745
- largeTitle: true,
746
- title: "Gift cards",
747
- mobileHeader: /* @__PURE__ */ jsx(
748
- MobilePageHeader,
637
+ const filters = [
638
+ { value: "", label: "All" },
639
+ { value: "active", label: "Active" },
640
+ { value: "used", label: "Used" },
641
+ { value: "expired", label: "Expired" },
642
+ { value: "cancelled", label: "Cancelled" }
643
+ ];
644
+ return /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-7xl space-y-5 lg:space-y-6", children: [
645
+ /* @__PURE__ */ jsx(
646
+ MobilePageHeader,
647
+ {
648
+ title: "Gift cards",
649
+ action: { label: "Issue gift card", onClick: () => setShowIssue(true) }
650
+ }
651
+ ),
652
+ /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-between gap-3 lg:flex", children: [
653
+ /* @__PURE__ */ jsxs("div", { children: [
654
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-semibold text-[var(--text-primary)]", children: "Gift cards" }),
655
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-[var(--text-tertiary)]", children: "Credit a customer pays for now and spends later. Discounts and loyalty points cost the customer nothing." })
656
+ ] }),
657
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
658
+ !LIVE && /* @__PURE__ */ jsx(RefreshButton, { onClick: loadGiftCards, refreshing: loading }),
659
+ /* @__PURE__ */ jsxs(
660
+ "button",
661
+ {
662
+ type: "button",
663
+ onClick: () => setShowBalance(true),
664
+ className: "flex items-center gap-2 rounded-md border border-[var(--border-default)] px-3 py-2 text-sm font-medium text-[var(--text-secondary)] hover:bg-[var(--interactive-hover)]",
665
+ children: [
666
+ /* @__PURE__ */ jsx(Search, { className: "h-4 w-4" }),
667
+ "Check balance"
668
+ ]
669
+ }
670
+ ),
671
+ /* @__PURE__ */ jsxs(
672
+ "button",
673
+ {
674
+ type: "button",
675
+ onClick: () => setShowIssue(true),
676
+ className: "flex items-center gap-2 rounded-md bg-brand-500 px-4 py-2 text-sm font-medium text-[var(--text-inverse)] hover:bg-brand-600",
677
+ children: [
678
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
679
+ "Issue gift card"
680
+ ]
681
+ }
682
+ )
683
+ ] })
684
+ ] }),
685
+ /* @__PURE__ */ jsx("div", { className: "hidden lg:block", children: /* @__PURE__ */ jsxs(MetricRow, { children: [
686
+ /* @__PURE__ */ jsx(
687
+ MetricTile,
749
688
  {
750
- title: "Gift cards",
751
- action: hasCards ? { label: "Issue gift card", onClick: openIssue } : void 0
689
+ label: "Issued value",
690
+ value: formatCurrency(stats?.totalIssued ?? 0, currency)
752
691
  }
753
692
  ),
754
- actions: /* @__PURE__ */ jsxs(Fragment, { children: [
755
- /* @__PURE__ */ jsx(Hint, { lines: PAGE_HINT_LINES, topic: "gift cards" }),
756
- !LIVE && /* @__PURE__ */ jsx(RefreshButton, { onClick: reloadAll, refreshing: loading }),
757
- hasCards && /* @__PURE__ */ jsxs(Fragment, { children: [
758
- /* @__PURE__ */ jsx(
759
- Button,
760
- {
761
- type: "button",
762
- variant: "secondary",
763
- icon: /* @__PURE__ */ jsx(Search, {}),
764
- onClick: openBalance,
765
- children: "Check balance"
766
- }
767
- ),
768
- /* @__PURE__ */ jsx(Button, { type: "button", icon: /* @__PURE__ */ jsx(Plus, {}), onClick: openIssue, children: "Issue gift card" })
769
- ] })
693
+ /* @__PURE__ */ jsx(
694
+ MetricTile,
695
+ {
696
+ label: "Outstanding",
697
+ value: formatCurrency(stats?.outstanding ?? 0, currency)
698
+ }
699
+ ),
700
+ /* @__PURE__ */ jsx(
701
+ MetricTile,
702
+ {
703
+ label: "Redeemed",
704
+ value: formatCurrency(stats?.redeemed ?? 0, currency)
705
+ }
706
+ ),
707
+ /* @__PURE__ */ jsx(MetricTile, { label: "Active cards", value: stats?.activeCards ?? 0 })
708
+ ] }) }),
709
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-px overflow-hidden rounded-md bg-[var(--border-default)] lg:hidden", children: [
710
+ /* @__PURE__ */ jsxs("div", { className: "bg-[var(--bg-subtle)] p-4", children: [
711
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-muted)]", children: "Outstanding" }),
712
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-lg font-semibold text-[var(--text-primary)]", children: formatCurrency(stats?.outstanding ?? 0, currency) })
770
713
  ] }),
771
- children: [
772
- showStats && /* @__PURE__ */ jsxs(Fragment, { children: [
773
- /* @__PURE__ */ jsx("div", { className: "hidden lg:block", children: /* @__PURE__ */ jsxs(MetricRow, { children: [
774
- /* @__PURE__ */ jsx(
775
- MetricTile,
776
- {
777
- label: "Total sold",
778
- value: formatCurrency(stats?.totalIssued ?? 0, currency)
779
- }
780
- ),
781
- /* @__PURE__ */ jsx(
782
- MetricTile,
783
- {
784
- label: "Still to spend",
785
- value: formatCurrency(stats?.outstanding ?? 0, currency)
786
- }
787
- ),
788
- /* @__PURE__ */ jsx(
789
- MetricTile,
790
- {
791
- label: "Spent",
792
- value: formatCurrency(stats?.redeemed ?? 0, currency)
793
- }
794
- ),
795
- /* @__PURE__ */ jsx(MetricTile, { label: "Cards in use", value: stats?.activeCards ?? 0 })
796
- ] }) }),
797
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-px overflow-hidden rounded-md bg-[var(--border-default)] lg:hidden", children: [
798
- /* @__PURE__ */ jsxs("div", { className: "bg-[var(--bg-subtle)] p-4", children: [
799
- /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-muted)]", children: "Still to spend" }),
800
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-lg font-semibold text-[var(--text-primary)]", children: formatCurrency(stats?.outstanding ?? 0, currency) })
801
- ] }),
802
- /* @__PURE__ */ jsxs("div", { className: "bg-[var(--bg-subtle)] p-4", children: [
803
- /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-muted)]", children: "Cards in use" }),
804
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-lg font-semibold text-[var(--text-primary)]", children: stats?.activeCards ?? 0 })
805
- ] })
806
- ] })
807
- ] }),
808
- hasCards && /* @__PURE__ */ jsx("div", { className: "flex gap-2 overflow-x-auto lg:hidden", children: /* @__PURE__ */ jsx(
809
- Button,
714
+ /* @__PURE__ */ jsxs("div", { className: "bg-[var(--bg-subtle)] p-4", children: [
715
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-muted)]", children: "Active cards" }),
716
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-lg font-semibold text-[var(--text-primary)]", children: stats?.activeCards ?? 0 })
717
+ ] })
718
+ ] }),
719
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2 overflow-x-auto lg:hidden", children: [
720
+ /* @__PURE__ */ jsxs(
721
+ "button",
722
+ {
723
+ type: "button",
724
+ onClick: () => setShowIssue(true),
725
+ className: "flex shrink-0 items-center gap-1.5 rounded-full bg-brand-500 px-3.5 py-2 text-sm font-medium text-[var(--text-inverse)]",
726
+ children: [
727
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
728
+ "Issue gift card"
729
+ ]
730
+ }
731
+ ),
732
+ /* @__PURE__ */ jsxs(
733
+ "button",
734
+ {
735
+ type: "button",
736
+ onClick: () => setShowBalance(true),
737
+ className: "flex shrink-0 items-center gap-1.5 rounded-full bg-[var(--bg-subtle)] px-3.5 py-2 text-sm font-medium text-[var(--text-secondary)]",
738
+ children: [
739
+ /* @__PURE__ */ jsx(Search, { className: "h-4 w-4" }),
740
+ "Check balance"
741
+ ]
742
+ }
743
+ )
744
+ ] }),
745
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 lg:flex-row lg:items-center", children: [
746
+ /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
747
+ /* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[var(--text-muted)]" }),
748
+ /* @__PURE__ */ jsx(
749
+ "input",
810
750
  {
811
- type: "button",
812
- variant: "secondary",
813
- shape: "pill",
814
- icon: /* @__PURE__ */ jsx(Search, {}),
815
- onClick: openBalance,
816
- children: "Check balance"
751
+ type: "search",
752
+ placeholder: "Search code, recipient, or email",
753
+ value: search,
754
+ onChange: (event) => {
755
+ setSearch(event.target.value);
756
+ setPage(1);
757
+ },
758
+ className: "w-full rounded-md border border-[var(--border-default)] bg-[var(--bg-base)] py-2 pl-10 pr-3 text-sm focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20"
817
759
  }
818
- ) }),
819
- !firstRun && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 lg:flex-row lg:items-center", children: [
820
- /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
821
- /* @__PURE__ */ jsx(
822
- Search,
823
- {
824
- "aria-hidden": true,
825
- className: "pointer-events-none absolute left-3 top-1/2 z-10 h-4 w-4 -translate-y-1/2 text-[var(--text-muted)]"
826
- }
827
- ),
828
- /* @__PURE__ */ jsx(
829
- Input,
830
- {
831
- type: "search",
832
- "aria-label": "Search gift cards",
833
- placeholder: "Search code, recipient, or email",
834
- value: search,
835
- onChange: (event) => {
836
- setSearch(event.target.value);
837
- setPage(1);
838
- },
839
- className: "pl-10"
840
- }
841
- )
842
- ] }),
843
- /* @__PURE__ */ jsx(
844
- "div",
760
+ )
761
+ ] }),
762
+ /* @__PURE__ */ jsx("div", { className: "flex gap-2 overflow-x-auto", children: filters.map((filter) => /* @__PURE__ */ jsx(
763
+ "button",
764
+ {
765
+ type: "button",
766
+ onClick: () => {
767
+ setStatus(filter.value);
768
+ setPage(1);
769
+ },
770
+ className: `shrink-0 rounded-md px-3 py-2 text-sm font-medium ${status === filter.value ? "bg-brand-500 text-[var(--text-inverse)]" : "border border-[var(--border-default)] bg-[var(--bg-base)] text-[var(--text-secondary)] hover:bg-[var(--interactive-hover)]"}`,
771
+ children: filter.label
772
+ },
773
+ filter.value
774
+ )) })
775
+ ] }),
776
+ loading && giftCards.length === 0 && /* @__PURE__ */ jsx(InlineListSkeleton, {}),
777
+ !loading && giftCards.length === 0 && /* @__PURE__ */ jsx(
778
+ TableEmptyState,
779
+ {
780
+ icon: Gift,
781
+ title: search || status ? "No gift cards found" : "Issue your first gift card",
782
+ description: search || status ? "Try changing the search or status filter" : "Create a stored-value card for a customer or walk-in purchase"
783
+ }
784
+ ),
785
+ giftCards.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
786
+ /* @__PURE__ */ jsx("div", { className: "space-y-2 lg:hidden", children: giftCards.map((giftCard) => /* @__PURE__ */ jsxs(
787
+ "button",
788
+ {
789
+ type: "button",
790
+ onClick: () => setSelected(giftCard),
791
+ className: "flex w-full items-center justify-between gap-3 rounded-md border border-[var(--border-default)] bg-[var(--bg-base)] p-4 text-left",
792
+ children: [
793
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
794
+ /* @__PURE__ */ jsx("p", { className: "truncate font-mono text-sm font-semibold text-[var(--text-primary)]", children: giftCard.code }),
795
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm text-[var(--text-tertiary)]", children: giftCard.recipientName || giftCard.recipientEmail || "Walk-in" })
796
+ ] }),
797
+ /* @__PURE__ */ jsxs("div", { className: "shrink-0 text-right", children: [
798
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-[var(--text-primary)]", children: formatCurrency(Number(giftCard.balance), giftCard.currency) }),
799
+ /* @__PURE__ */ jsx("span", { className: `text-xs capitalize ${statusClass(giftCard.status)}`, children: giftCard.status })
800
+ ] })
801
+ ]
802
+ },
803
+ giftCard.id
804
+ )) }),
805
+ /* @__PURE__ */ jsx("div", { className: "hidden overflow-x-auto rounded-md border border-[var(--border-default)] bg-[var(--bg-base)] lg:block", children: /* @__PURE__ */ jsxs("table", { className: "w-full min-w-[760px]", children: [
806
+ /* @__PURE__ */ jsx("thead", { className: "border-b border-[var(--border-default)] bg-[var(--bg-subtle)]", children: /* @__PURE__ */ jsx("tr", { children: ["Code", "Recipient", "Issued", "Balance", "Expires", "Status"].map(
807
+ (heading) => /* @__PURE__ */ jsx(
808
+ "th",
845
809
  {
846
- role: "group",
847
- "aria-label": "Filter by status",
848
- className: "flex gap-1 overflow-x-auto",
849
- children: STATUS_FILTERS.map((filter) => {
850
- const pressed = status === filter.value;
851
- return /* @__PURE__ */ jsx(Tooltip, { label: filter.hint, children: /* @__PURE__ */ jsx(
852
- Button,
810
+ className: "px-4 py-3 text-left text-xs font-medium uppercase text-[var(--text-tertiary)]",
811
+ children: heading
812
+ },
813
+ heading
814
+ )
815
+ ) }) }),
816
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-[var(--border-default)]", children: giftCards.map((giftCard) => /* @__PURE__ */ jsxs(
817
+ "tr",
818
+ {
819
+ onClick: () => setSelected(giftCard),
820
+ className: "cursor-pointer hover:bg-[var(--interactive-hover)]",
821
+ children: [
822
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
823
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-sm font-medium text-[var(--text-primary)]", children: giftCard.code }),
824
+ /* @__PURE__ */ jsx(
825
+ "button",
853
826
  {
854
827
  type: "button",
855
- size: "sm",
856
- variant: pressed ? "secondary" : "ghost",
857
- "aria-pressed": pressed,
858
- className: "shrink-0",
859
- onClick: () => {
860
- setStatus(filter.value);
861
- setPage(1);
862
- },
863
- children: filter.label
828
+ onClick: (event) => copyCode(event, giftCard.code),
829
+ className: "rounded p-1 text-[var(--text-muted)] hover:text-[var(--text-primary)]",
830
+ title: "Copy code",
831
+ children: /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" })
864
832
  }
865
- ) }, filter.value);
866
- })
867
- }
868
- )
869
- ] }),
870
- /* @__PURE__ */ jsx("h2", { className: "sr-only", children: "Issued gift cards" }),
871
- !loaded && /* @__PURE__ */ jsx(InlineListSkeleton, {}),
872
- loading && loaded && giftCards.length === 0 && /* @__PURE__ */ jsx(InlineListSkeleton, {}),
873
- firstRun && /* @__PURE__ */ jsxs("div", { children: [
874
- /* @__PURE__ */ jsx(
875
- TableEmptyState,
876
- {
877
- icon: Gift,
878
- title: "Issue your first gift card",
879
- description: "Create a stored-value card for a customer or walk-in purchase",
880
- action: { label: "Issue gift card", onClick: openIssue }
881
- }
882
- ),
883
- /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
884
- Button,
885
- {
886
- type: "button",
887
- variant: "ghost",
888
- icon: /* @__PURE__ */ jsx(Search, {}),
889
- onClick: openBalance,
890
- children: "Check balance"
891
- }
892
- ) })
893
- ] }),
894
- loaded && !loading && !firstRun && giftCards.length === 0 && /* @__PURE__ */ jsx(
895
- TableEmptyState,
896
- {
897
- icon: Gift,
898
- title: "No gift cards found",
899
- description: "Try changing the search or status filter",
900
- action: hasFilters ? {
901
- label: "Clear search and filters",
902
- onClick: () => {
903
- setSearch("");
904
- setStatus("");
905
- setPage(1);
906
- }
907
- } : void 0
908
- }
909
- ),
910
- giftCards.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
911
- /* @__PURE__ */ jsx("div", { className: "space-y-2 lg:hidden", children: giftCards.map((giftCard) => /* @__PURE__ */ jsxs(
912
- "button",
913
- {
914
- type: "button",
915
- onClick: () => setSelected(giftCard),
916
- className: "flex w-full items-center justify-between gap-3 rounded-md border border-[var(--border-default)] bg-[var(--bg-base)] p-4 text-left",
917
- children: [
918
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
919
- /* @__PURE__ */ jsx("p", { className: "truncate font-mono text-sm font-semibold text-[var(--text-primary)]", children: giftCard.code }),
920
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm text-[var(--text-tertiary)]", children: giftCard.recipientName || giftCard.recipientEmail || "Walk-in" })
921
- ] }),
922
- /* @__PURE__ */ jsxs("div", { className: "shrink-0 text-right", children: [
923
- /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-[var(--text-primary)]", children: formatCurrency(Number(giftCard.balance), giftCard.currency) }),
924
- /* @__PURE__ */ jsx("span", { className: `text-xs ${statusClass(giftCard.status)}`, children: STATUS_LABEL[giftCard.status] })
925
- ] })
926
- ]
927
- },
928
- giftCard.id
929
- )) }),
930
- /* @__PURE__ */ jsx("div", { className: "hidden overflow-x-auto rounded-md border border-[var(--border-default)] bg-[var(--bg-base)] lg:block", children: /* @__PURE__ */ jsxs("table", { className: "w-full min-w-[760px]", children: [
931
- /* @__PURE__ */ jsx("thead", { className: "border-b border-[var(--border-default)] bg-[var(--bg-subtle)]", children: /* @__PURE__ */ jsx("tr", { children: ["Code", "Recipient", "Issued", "Balance", "Expires", "Status"].map(
932
- (heading) => /* @__PURE__ */ jsx(
933
- "th",
833
+ )
834
+ ] }) }),
835
+ /* @__PURE__ */ jsxs("td", { className: "px-4 py-3", children: [
836
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--text-primary)]", children: giftCard.recipientName || "Walk-in" }),
837
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-muted)]", children: giftCard.recipientEmail })
838
+ ] }),
839
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-sm text-[var(--text-secondary)]", children: formatCurrency(
840
+ Number(giftCard.originalAmount),
841
+ giftCard.currency
842
+ ) }),
843
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-sm font-medium text-[var(--text-primary)]", children: formatCurrency(Number(giftCard.balance), giftCard.currency) }),
844
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-sm text-[var(--text-secondary)]", children: dateLabel(giftCard.expiresAt) }),
845
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx(
846
+ "span",
934
847
  {
935
- scope: "col",
936
- className: "px-4 py-3 text-left text-xs font-medium uppercase text-[var(--text-tertiary)]",
937
- children: heading
938
- },
939
- heading
940
- )
941
- ) }) }),
942
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-[var(--border-default)]", children: giftCards.map((giftCard) => /* @__PURE__ */ jsxs(
943
- "tr",
944
- {
945
- tabIndex: 0,
946
- "aria-label": `Open gift card ${giftCard.code}`,
947
- onClick: () => setSelected(giftCard),
948
- onKeyDown: (event) => {
949
- if (event.target !== event.currentTarget) return;
950
- if (event.key === "Enter" || event.key === " ") {
951
- event.preventDefault();
952
- setSelected(giftCard);
953
- }
954
- },
955
- className: "cursor-pointer hover:bg-[var(--interactive-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--focus-ring)]",
956
- children: [
957
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
958
- /* @__PURE__ */ jsx("span", { className: "font-mono text-sm font-medium text-[var(--text-primary)]", children: giftCard.code }),
959
- /* @__PURE__ */ jsx(
960
- Button,
961
- {
962
- type: "button",
963
- variant: "ghost",
964
- size: "icon-sm",
965
- "aria-label": `Copy code ${giftCard.code}`,
966
- onClick: (event) => copyCode(event, giftCard.code),
967
- children: /* @__PURE__ */ jsx(Copy, {})
968
- }
969
- )
970
- ] }) }),
971
- /* @__PURE__ */ jsxs("td", { className: "px-4 py-3", children: [
972
- /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--text-primary)]", children: giftCard.recipientName || "Walk-in" }),
973
- /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-muted)]", children: giftCard.recipientEmail })
974
- ] }),
975
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-sm text-[var(--text-secondary)]", children: formatCurrency(
976
- Number(giftCard.originalAmount),
977
- giftCard.currency
978
- ) }),
979
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-sm font-medium text-[var(--text-primary)]", children: formatCurrency(Number(giftCard.balance), giftCard.currency) }),
980
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-sm text-[var(--text-secondary)]", children: dateLabel(giftCard.expiresAt) }),
981
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx(
982
- "span",
983
- {
984
- className: `inline-flex rounded-full px-2.5 py-1 text-xs font-medium ${statusClass(giftCard.status)}`,
985
- children: STATUS_LABEL[giftCard.status]
986
- }
987
- ) })
988
- ]
989
- },
990
- giftCard.id
991
- )) })
992
- ] }) }),
993
- /* @__PURE__ */ jsx(
994
- TablePagination,
995
- {
996
- page,
997
- totalPages,
998
- pageSize: PAGE_SIZE,
999
- totalItems: count,
1000
- entityName: "gift cards",
1001
- onPageChange: setPage
1002
- }
1003
- )
1004
- ] }),
1005
- showIssue && /* @__PURE__ */ jsx(
1006
- IssueGiftCardModal,
1007
- {
1008
- currency,
1009
- merchantName: tenant?.businessName || "Gift card",
1010
- onClose: () => setShowIssue(false),
1011
- onCreated: (giftCard) => {
1012
- setShowIssue(false);
1013
- setSelected(giftCard);
1014
- toast({
1015
- title: "Gift card issued",
1016
- description: giftCard.code
1017
- });
1018
- reloadAll();
1019
- }
1020
- }
1021
- ),
1022
- showBalance && /* @__PURE__ */ jsx(BalanceModal, { onClose: () => setShowBalance(false) }),
1023
- selected && /* @__PURE__ */ jsx(
1024
- GiftCardDetailModal,
1025
- {
1026
- giftCard: selected,
1027
- onClose: () => setSelected(null),
1028
- onChanged: reloadAll
1029
- }
1030
- )
1031
- ]
1032
- }
1033
- );
848
+ className: `inline-flex rounded-full px-2.5 py-1 text-xs font-medium capitalize ${statusClass(giftCard.status)}`,
849
+ children: giftCard.status
850
+ }
851
+ ) })
852
+ ]
853
+ },
854
+ giftCard.id
855
+ )) })
856
+ ] }) }),
857
+ /* @__PURE__ */ jsx(
858
+ TablePagination,
859
+ {
860
+ page,
861
+ totalPages,
862
+ pageSize: PAGE_SIZE,
863
+ totalItems: count,
864
+ entityName: "gift cards",
865
+ onPageChange: setPage
866
+ }
867
+ )
868
+ ] }),
869
+ showIssue && /* @__PURE__ */ jsx(
870
+ IssueGiftCardModal,
871
+ {
872
+ currency,
873
+ merchantName: tenant?.businessName || "Gift card",
874
+ onClose: () => setShowIssue(false),
875
+ onCreated: (giftCard) => {
876
+ setShowIssue(false);
877
+ setSelected(giftCard);
878
+ toast({
879
+ title: "Gift card issued",
880
+ description: giftCard.code
881
+ });
882
+ loadGiftCards();
883
+ }
884
+ }
885
+ ),
886
+ showBalance && /* @__PURE__ */ jsx(BalanceModal, { onClose: () => setShowBalance(false) }),
887
+ selected && /* @__PURE__ */ jsx(
888
+ GiftCardDetailModal,
889
+ {
890
+ giftCard: selected,
891
+ onClose: () => setSelected(null),
892
+ onChanged: loadGiftCards
893
+ }
894
+ )
895
+ ] });
1034
896
  }
1035
897
  export {
1036
898
  GiftCardsFeature