@gelabs/ovr 0.2.2 → 0.4.0

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 (90) hide show
  1. package/dist/auth-auth.js +1 -1
  2. package/dist/auth.js +1 -1
  3. package/dist/{chunk-MDTRBOPQ.js → chunk-2C3VCTYJ.js} +1 -1
  4. package/dist/chunk-3YKVH4Y7.js +126 -0
  5. package/dist/chunk-6YFZLXFP.js +84 -0
  6. package/dist/{chunk-3NZ2XUBO.js → chunk-AJ2RZTVX.js} +9 -2
  7. package/dist/chunk-BI4EGLPG.js +298 -0
  8. package/dist/{chunk-3KIDW4LT.js → chunk-BVI5XDDA.js} +1 -1
  9. package/dist/chunk-DJMUW5T2.js +298 -0
  10. package/dist/{chunk-BIQ2J75Y.js → chunk-GLIK5BHP.js} +2 -2
  11. package/dist/{chunk-JEYT63LE.js → chunk-IBZVIUNI.js} +1 -1
  12. package/dist/{chunk-4SZXBT56.js → chunk-NT72CQAI.js} +2 -2
  13. package/dist/{chunk-E2D7QT6N.js → chunk-TJSNVTVB.js} +1 -1
  14. package/dist/{chunk-5Z2IAD5I.js → chunk-TLG4C2XI.js} +2 -2
  15. package/dist/chunk-V7VQVDWS.js +237 -0
  16. package/dist/chunk-WUNTHINH.js +98 -0
  17. package/dist/{chunk-IF5UAVIE.js → chunk-YC7G2IOZ.js} +1 -1
  18. package/dist/{chunk-IB4JVGKJ.js → chunk-YGYA7KEG.js} +47 -3
  19. package/dist/{chunk-GDOCD7LT.js → chunk-ZUMEOZ22.js} +5 -5
  20. package/dist/core-i18n.d.ts +2 -2
  21. package/dist/core-i18n.js +1 -1
  22. package/dist/core.d.ts +61 -1
  23. package/dist/core.js +1 -1
  24. package/dist/data-mock-store.js +330 -12
  25. package/dist/data-prisma-store.js +319 -9
  26. package/dist/data-seed-runner.js +18 -15
  27. package/dist/data.d.ts +64 -3
  28. package/dist/generated/client/edge.js +31 -10
  29. package/dist/generated/client/index-browser.js +28 -7
  30. package/dist/generated/client/index.d.ts +3583 -577
  31. package/dist/generated/client/index.js +31 -10
  32. package/dist/generated/client/package.json +1 -1
  33. package/dist/generated/client/schema.prisma +48 -9
  34. package/dist/generated/client/wasm.js +31 -10
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.js +1 -1
  37. package/dist/offline.d.ts +34 -1
  38. package/dist/offline.js +2 -2
  39. package/dist/types-B8MopM4b.d.ts +281 -0
  40. package/dist/types.d.ts +104 -1
  41. package/dist/types.js +1 -1
  42. package/dist/ui-components-admin/accounts-manager.d.ts +52 -0
  43. package/dist/ui-components-admin/accounts-manager.js +471 -0
  44. package/dist/ui-components-admin/admin-nav.d.ts +15 -1
  45. package/dist/ui-components-admin/admin-nav.js +388 -60
  46. package/dist/ui-components-admin/issuance-form.js +72 -13
  47. package/dist/ui-components-admin/logs-viewer.d.ts +13 -0
  48. package/dist/ui-components-admin/logs-viewer.js +102 -0
  49. package/dist/ui-components-admin/notifications-list.d.ts +5 -0
  50. package/dist/ui-components-admin/notifications-list.js +70 -0
  51. package/dist/ui-components-admin/officers-manager.d.ts +27 -0
  52. package/dist/ui-components-admin/officers-manager.js +271 -0
  53. package/dist/ui-components-admin/roles-manager.d.ts +37 -0
  54. package/dist/ui-components-admin/roles-manager.js +406 -0
  55. package/dist/ui-components-admin/ticket-preview.js +7 -7
  56. package/dist/ui-components-admin/tickets-table.js +56 -33
  57. package/dist/ui-components-admin/violations-manager.d.ts +32 -0
  58. package/dist/ui-components-admin/violations-manager.js +385 -0
  59. package/dist/ui-components-citizen/citizen-nav.js +2 -2
  60. package/dist/ui-components-citizen/payment-form.js +5 -5
  61. package/dist/ui-components-citizen/payment-qr-dialog.js +4 -4
  62. package/dist/ui-components-citizen/ticket-not-found.js +2 -2
  63. package/dist/ui-components-citizen/violation-history-table.js +3 -3
  64. package/dist/ui-components-shared/amount-summary.js +4 -4
  65. package/dist/ui-components-shared/money.js +3 -3
  66. package/dist/ui-components-shared/municipal-seal.js +3 -3
  67. package/dist/ui-components-shared/official-header.js +4 -4
  68. package/dist/ui-components-shared/site-header.js +4 -4
  69. package/dist/ui-components-shared/sonner.js +2 -2
  70. package/dist/ui-components-shared/theme-toggle.js +3 -3
  71. package/dist/ui-components-shared/ticket-receipt.js +13 -6
  72. package/dist/ui-components-shared/violations-table.js +4 -4
  73. package/dist/ui-components-ui/badge.d.ts +1 -1
  74. package/dist/ui-components-ui/button.d.ts +1 -1
  75. package/dist/ui-components-ui/dropdown-menu.js +2 -237
  76. package/dist/ui-components-ui/sheet.js +3 -126
  77. package/dist/ui-config.d.ts +1 -1
  78. package/dist/ui-config.js +2 -2
  79. package/dist/ui-server.d.ts +1 -1
  80. package/dist/ui-server.js +2 -2
  81. package/package.json +6 -6
  82. package/prisma/migrations/20260622010000_add_super_admin_role/migration.sql +3 -0
  83. package/prisma/migrations/20260622020000_add_apprehending_enforcer/migration.sql +4 -0
  84. package/prisma/migrations/20260622030000_custom_roles/migration.sql +30 -0
  85. package/prisma/migrations/20260622040000_add_activity_log/migration.sql +18 -0
  86. package/prisma/migrations/20260622050000_violation_catalog_management/migration.sql +5 -0
  87. package/prisma/schema.prisma +48 -9
  88. package/dist/chunk-5YYR37CF.js +0 -146
  89. package/dist/chunk-B634JHKZ.js +0 -181
  90. package/dist/types-CtBC5-TW.d.ts +0 -129
@@ -0,0 +1,385 @@
1
+ "use client";
2
+ import { Textarea } from '../chunk-QCRVT2SS.js';
3
+ import { Money } from '../chunk-BVI5XDDA.js';
4
+ import { Card, CardContent } from '../chunk-SETIN6XP.js';
5
+ import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
6
+ import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
7
+ import { Badge } from '../chunk-55FQP2DO.js';
8
+ import { Label } from '../chunk-XQTVSNHC.js';
9
+ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
10
+ import { Input } from '../chunk-K3KIBHJF.js';
11
+ import { Button } from '../chunk-I4WDVYHX.js';
12
+ import { useCopy } from '../chunk-TJSNVTVB.js';
13
+ import { cn } from '../chunk-77QBZC7J.js';
14
+ import '../chunk-BI4EGLPG.js';
15
+ import * as React from 'react';
16
+ import { toast } from 'sonner';
17
+ import { useRouter } from 'next/navigation';
18
+ import { Plus, Pencil, Loader2, Archive, ArchiveRestore } from 'lucide-react';
19
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
20
+
21
+ var fieldClass = "h-9 w-full rounded-lg border border-input bg-transparent px-2.5 text-sm shadow-xs outline-none transition-colors focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:opacity-50 dark:bg-input/30";
22
+ function ViolationsManager({
23
+ violations,
24
+ createAction,
25
+ updateAction,
26
+ deleteAction
27
+ }) {
28
+ const t = useCopy().admin.violationsPage;
29
+ const router = useRouter();
30
+ const { pageItems, page, setPage, totalPages, from, to, total } = usePagination(violations, 12);
31
+ const categoryLabel = (c) => c === "TRAFFIC" ? t.categoryTraffic : t.categoryOrdinance;
32
+ return /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-5xl p-4 sm:p-6 lg:p-8", children: [
33
+ /* @__PURE__ */ jsxs("div", { className: "mb-6 flex items-center justify-between gap-3", children: [
34
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
35
+ /* @__PURE__ */ jsx("h1", { className: "font-heading text-2xl font-semibold tracking-tight", children: t.title }),
36
+ /* @__PURE__ */ jsx("p", { className: "max-w-2xl text-sm text-muted-foreground", children: t.subtitle })
37
+ ] }),
38
+ /* @__PURE__ */ jsx(
39
+ ViolationDialog,
40
+ {
41
+ mode: "create",
42
+ createAction,
43
+ onDone: () => router.refresh()
44
+ }
45
+ )
46
+ ] }),
47
+ /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, { className: "p-0", children: violations.length === 0 ? /* @__PURE__ */ jsx("p", { className: "p-8 text-center text-sm text-muted-foreground", children: t.empty }) : /* @__PURE__ */ jsxs(Fragment, { children: [
48
+ /* @__PURE__ */ jsxs(Table, { children: [
49
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
50
+ /* @__PURE__ */ jsx(TableHead, { children: t.code }),
51
+ /* @__PURE__ */ jsx(TableHead, { children: t.titleLabel }),
52
+ /* @__PURE__ */ jsx(TableHead, { className: "hidden sm:table-cell", children: t.category }),
53
+ /* @__PURE__ */ jsx(TableHead, { className: "text-right", children: t.fine }),
54
+ /* @__PURE__ */ jsx(TableHead, { children: t.status }),
55
+ /* @__PURE__ */ jsx(TableHead, { className: "text-right", children: t.actions })
56
+ ] }) }),
57
+ /* @__PURE__ */ jsx(TableBody, { children: pageItems.map((v) => {
58
+ const archived = v.active === false;
59
+ return /* @__PURE__ */ jsxs(TableRow, { className: cn(archived && "opacity-60"), children: [
60
+ /* @__PURE__ */ jsx(TableCell, { className: "font-mono text-xs", children: v.code }),
61
+ /* @__PURE__ */ jsx(TableCell, { className: "font-medium", children: v.title }),
62
+ /* @__PURE__ */ jsx(TableCell, { className: "hidden text-muted-foreground sm:table-cell", children: categoryLabel(v.category) }),
63
+ /* @__PURE__ */ jsx(TableCell, { className: "text-right", children: /* @__PURE__ */ jsx(Money, { value: v.basicFine }) }),
64
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Badge, { variant: archived ? "outline" : "secondary", children: archived ? t.archived : t.active }) }),
65
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-1.5", children: [
66
+ /* @__PURE__ */ jsx(
67
+ ViolationDialog,
68
+ {
69
+ mode: "edit",
70
+ violation: v,
71
+ updateAction,
72
+ onDone: () => router.refresh()
73
+ }
74
+ ),
75
+ archived ? /* @__PURE__ */ jsx(
76
+ RestoreButton,
77
+ {
78
+ violation: v,
79
+ updateAction,
80
+ onDone: () => router.refresh()
81
+ }
82
+ ) : /* @__PURE__ */ jsx(
83
+ ArchiveButton,
84
+ {
85
+ violation: v,
86
+ deleteAction,
87
+ onDone: () => router.refresh()
88
+ }
89
+ )
90
+ ] }) })
91
+ ] }, v.code);
92
+ }) })
93
+ ] }),
94
+ /* @__PURE__ */ jsx(
95
+ Pagination,
96
+ {
97
+ page,
98
+ totalPages,
99
+ from,
100
+ to,
101
+ total,
102
+ onPage: setPage
103
+ }
104
+ )
105
+ ] }) }) })
106
+ ] });
107
+ }
108
+ function ViolationDialog({
109
+ mode,
110
+ violation,
111
+ createAction,
112
+ updateAction,
113
+ onDone
114
+ }) {
115
+ const t = useCopy().admin.violationsPage;
116
+ const [open, setOpen] = React.useState(false);
117
+ const [code, setCode] = React.useState(violation?.code ?? "");
118
+ const [title, setTitle] = React.useState(violation?.title ?? "");
119
+ const [category, setCategory] = React.useState(
120
+ violation?.category ?? "TRAFFIC"
121
+ );
122
+ const [fine, setFine] = React.useState(
123
+ violation ? String(violation.basicFine) : ""
124
+ );
125
+ const [legalText, setLegalText] = React.useState(violation?.legalText ?? "");
126
+ const [submitting, setSubmitting] = React.useState(false);
127
+ function resetTo(v) {
128
+ setCode(v?.code ?? "");
129
+ setTitle(v?.title ?? "");
130
+ setCategory(v?.category ?? "TRAFFIC");
131
+ setFine(v ? String(v.basicFine) : "");
132
+ setLegalText(v?.legalText ?? "");
133
+ }
134
+ async function submit(e) {
135
+ e.preventDefault();
136
+ if (mode === "create" && !code.trim())
137
+ return toast.error(`${t.code} is required.`);
138
+ if (!title.trim()) return toast.error(`${t.titleLabel} is required.`);
139
+ const fineNum = Number(fine);
140
+ if (!Number.isFinite(fineNum) || fineNum < 0)
141
+ return toast.error(`${t.fine} must be a number \u2265 0.`);
142
+ setSubmitting(true);
143
+ try {
144
+ let res;
145
+ if (mode === "create") {
146
+ const input = {
147
+ code: code.trim(),
148
+ title: title.trim(),
149
+ category,
150
+ basicFine: fineNum,
151
+ legalText: legalText.trim() || void 0
152
+ };
153
+ res = await createAction?.(input);
154
+ } else {
155
+ res = await updateAction?.(violation.code, {
156
+ title: title.trim(),
157
+ category,
158
+ basicFine: fineNum,
159
+ legalText: legalText.trim() || void 0
160
+ });
161
+ }
162
+ if (res?.error) {
163
+ toast.error(res.error);
164
+ return;
165
+ }
166
+ toast.success(
167
+ `${mode === "create" ? t.create : t.editTitle}: ${title.trim()}`
168
+ );
169
+ setOpen(false);
170
+ onDone();
171
+ } finally {
172
+ setSubmitting(false);
173
+ }
174
+ }
175
+ return /* @__PURE__ */ jsxs(
176
+ Dialog,
177
+ {
178
+ open,
179
+ onOpenChange: (o) => {
180
+ if (o) resetTo(violation);
181
+ setOpen(o);
182
+ },
183
+ children: [
184
+ /* @__PURE__ */ jsxs(
185
+ DialogTrigger,
186
+ {
187
+ render: mode === "create" ? /* @__PURE__ */ jsx(Button, { className: "gap-1.5" }) : /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: "gap-1.5" }),
188
+ children: [
189
+ mode === "create" ? /* @__PURE__ */ jsx(Plus, { className: "size-4" }) : /* @__PURE__ */ jsx(Pencil, { className: "size-3.5" }),
190
+ /* @__PURE__ */ jsx("span", { className: mode === "create" ? "" : "hidden sm:inline", children: mode === "create" ? t.newViolation : t.edit })
191
+ ]
192
+ }
193
+ ),
194
+ /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
195
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
196
+ /* @__PURE__ */ jsx(DialogTitle, { children: mode === "create" ? t.newViolation : t.editTitle }),
197
+ /* @__PURE__ */ jsx(DialogDescription, { children: t.subtitle })
198
+ ] }),
199
+ /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-4", children: [
200
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
201
+ /* @__PURE__ */ jsx(Label, { htmlFor: "vio-code", children: t.code }),
202
+ /* @__PURE__ */ jsx(
203
+ Input,
204
+ {
205
+ id: "vio-code",
206
+ value: code,
207
+ onChange: (e) => setCode(e.target.value),
208
+ placeholder: t.codePlaceholder,
209
+ autoComplete: "off",
210
+ disabled: mode === "edit",
211
+ autoFocus: mode === "create"
212
+ }
213
+ )
214
+ ] }),
215
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
216
+ /* @__PURE__ */ jsx(Label, { htmlFor: "vio-title", children: t.titleLabel }),
217
+ /* @__PURE__ */ jsx(
218
+ Input,
219
+ {
220
+ id: "vio-title",
221
+ value: title,
222
+ onChange: (e) => setTitle(e.target.value),
223
+ placeholder: t.titlePlaceholder,
224
+ autoComplete: "off",
225
+ autoFocus: mode === "edit"
226
+ }
227
+ )
228
+ ] }),
229
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
230
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
231
+ /* @__PURE__ */ jsx(Label, { htmlFor: "vio-category", children: t.category }),
232
+ /* @__PURE__ */ jsxs(
233
+ "select",
234
+ {
235
+ id: "vio-category",
236
+ value: category,
237
+ onChange: (e) => setCategory(e.target.value),
238
+ className: fieldClass,
239
+ children: [
240
+ /* @__PURE__ */ jsx("option", { value: "TRAFFIC", children: t.categoryTraffic }),
241
+ /* @__PURE__ */ jsx("option", { value: "ORDINANCE", children: t.categoryOrdinance })
242
+ ]
243
+ }
244
+ )
245
+ ] }),
246
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
247
+ /* @__PURE__ */ jsx(Label, { htmlFor: "vio-fine", children: t.fine }),
248
+ /* @__PURE__ */ jsx(
249
+ Input,
250
+ {
251
+ id: "vio-fine",
252
+ type: "number",
253
+ min: "0",
254
+ step: "1",
255
+ inputMode: "numeric",
256
+ value: fine,
257
+ onChange: (e) => setFine(e.target.value),
258
+ placeholder: t.finePlaceholder,
259
+ autoComplete: "off"
260
+ }
261
+ )
262
+ ] })
263
+ ] }),
264
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
265
+ /* @__PURE__ */ jsx(Label, { htmlFor: "vio-legal", children: t.legalText }),
266
+ /* @__PURE__ */ jsx(
267
+ Textarea,
268
+ {
269
+ id: "vio-legal",
270
+ value: legalText,
271
+ onChange: (e) => setLegalText(e.target.value),
272
+ placeholder: t.legalTextPlaceholder,
273
+ rows: 2
274
+ }
275
+ )
276
+ ] }),
277
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
278
+ /* @__PURE__ */ jsx(DialogClose, { render: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline" }), children: t.cancel }),
279
+ /* @__PURE__ */ jsxs(Button, { type: "submit", disabled: submitting, className: "gap-1.5", children: [
280
+ submitting ? /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin" }) : null,
281
+ submitting ? mode === "create" ? t.creating : t.saving : mode === "create" ? t.create : t.save
282
+ ] })
283
+ ] })
284
+ ] })
285
+ ] })
286
+ ]
287
+ }
288
+ );
289
+ }
290
+ function ArchiveButton({
291
+ violation,
292
+ deleteAction,
293
+ onDone
294
+ }) {
295
+ const t = useCopy().admin.violationsPage;
296
+ const [busy, setBusy] = React.useState(false);
297
+ async function archive() {
298
+ setBusy(true);
299
+ try {
300
+ const res = await deleteAction(violation.code);
301
+ if (res?.error) {
302
+ toast.error(res.error);
303
+ return;
304
+ }
305
+ toast.success(`${t.archive}: ${violation.title}`);
306
+ onDone();
307
+ } finally {
308
+ setBusy(false);
309
+ }
310
+ }
311
+ return /* @__PURE__ */ jsxs(Dialog, { children: [
312
+ /* @__PURE__ */ jsxs(
313
+ DialogTrigger,
314
+ {
315
+ render: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: "gap-1.5" }),
316
+ children: [
317
+ /* @__PURE__ */ jsx(Archive, { className: "size-3.5" }),
318
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: t.archive })
319
+ ]
320
+ }
321
+ ),
322
+ /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-sm", children: [
323
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
324
+ /* @__PURE__ */ jsx(DialogTitle, { children: t.archiveConfirmTitle }),
325
+ /* @__PURE__ */ jsxs(DialogDescription, { children: [
326
+ violation.title,
327
+ " \u2014 ",
328
+ t.archiveConfirmBody
329
+ ] })
330
+ ] }),
331
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
332
+ /* @__PURE__ */ jsx(DialogClose, { render: /* @__PURE__ */ jsx(Button, { variant: "outline" }), children: t.cancel }),
333
+ /* @__PURE__ */ jsxs(
334
+ DialogClose,
335
+ {
336
+ render: /* @__PURE__ */ jsx(Button, { className: "gap-2", disabled: busy }),
337
+ onClick: archive,
338
+ children: [
339
+ /* @__PURE__ */ jsx(Archive, { className: "size-4" }),
340
+ t.archive
341
+ ]
342
+ }
343
+ )
344
+ ] })
345
+ ] })
346
+ ] });
347
+ }
348
+ function RestoreButton({
349
+ violation,
350
+ updateAction,
351
+ onDone
352
+ }) {
353
+ const t = useCopy().admin.violationsPage;
354
+ const [busy, setBusy] = React.useState(false);
355
+ async function restore() {
356
+ setBusy(true);
357
+ try {
358
+ const res = await updateAction(violation.code, { active: true });
359
+ if (res?.error) {
360
+ toast.error(res.error);
361
+ return;
362
+ }
363
+ toast.success(`${t.restore}: ${violation.title}`);
364
+ onDone();
365
+ } finally {
366
+ setBusy(false);
367
+ }
368
+ }
369
+ return /* @__PURE__ */ jsxs(
370
+ Button,
371
+ {
372
+ variant: "outline",
373
+ size: "sm",
374
+ className: "gap-1.5",
375
+ disabled: busy,
376
+ onClick: restore,
377
+ children: [
378
+ busy ? /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsx(ArchiveRestore, { className: "size-3.5" }),
379
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: t.restore })
380
+ ]
381
+ }
382
+ );
383
+ }
384
+
385
+ export { ViolationsManager };
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { useCopy } from '../chunk-E2D7QT6N.js';
2
+ import { useCopy } from '../chunk-TJSNVTVB.js';
3
3
  import { cn } from '../chunk-77QBZC7J.js';
4
- import '../chunk-B634JHKZ.js';
4
+ import '../chunk-BI4EGLPG.js';
5
5
  import Link from 'next/link';
6
6
  import { usePathname } from 'next/navigation';
7
7
  import { jsx } from 'react/jsx-runtime';
@@ -1,14 +1,14 @@
1
1
  "use client";
2
- import { PaymentQrDialog } from '../chunk-5Z2IAD5I.js';
3
- import { Separator } from '../chunk-NSCIBSCW.js';
2
+ import { PaymentQrDialog } from '../chunk-TLG4C2XI.js';
4
3
  import { Alert, AlertDescription } from '../chunk-EYFZWQ4J.js';
4
+ import { Separator } from '../chunk-NSCIBSCW.js';
5
+ import { Money } from '../chunk-BVI5XDDA.js';
5
6
  import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '../chunk-SETIN6XP.js';
6
- import { Money } from '../chunk-3KIDW4LT.js';
7
7
  import '../chunk-M35R6JLA.js';
8
8
  import { Button } from '../chunk-I4WDVYHX.js';
9
- import { useOvrConfig, useCopy } from '../chunk-E2D7QT6N.js';
9
+ import { useOvrConfig, useCopy } from '../chunk-TJSNVTVB.js';
10
10
  import { cn } from '../chunk-77QBZC7J.js';
11
- import '../chunk-B634JHKZ.js';
11
+ import '../chunk-BI4EGLPG.js';
12
12
  import * as React from 'react';
13
13
  import { toast } from 'sonner';
14
14
  import { Check, TriangleAlert, Loader2, Lock, Building2, Landmark, Smartphone, Wallet } from 'lucide-react';
@@ -1,9 +1,9 @@
1
1
  "use client";
2
- export { PaymentQrDialog } from '../chunk-5Z2IAD5I.js';
2
+ export { PaymentQrDialog } from '../chunk-TLG4C2XI.js';
3
3
  import '../chunk-EYFZWQ4J.js';
4
- import '../chunk-3KIDW4LT.js';
4
+ import '../chunk-BVI5XDDA.js';
5
5
  import '../chunk-M35R6JLA.js';
6
6
  import '../chunk-I4WDVYHX.js';
7
- import '../chunk-E2D7QT6N.js';
7
+ import '../chunk-TJSNVTVB.js';
8
8
  import '../chunk-77QBZC7J.js';
9
- import '../chunk-B634JHKZ.js';
9
+ import '../chunk-BI4EGLPG.js';
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { Card, CardContent } from '../chunk-SETIN6XP.js';
3
3
  import { buttonVariants } from '../chunk-I4WDVYHX.js';
4
- import { useCopy } from '../chunk-E2D7QT6N.js';
4
+ import { useCopy } from '../chunk-TJSNVTVB.js';
5
5
  import '../chunk-77QBZC7J.js';
6
- import '../chunk-B634JHKZ.js';
6
+ import '../chunk-BI4EGLPG.js';
7
7
  import Link from 'next/link';
8
8
  import { FileQuestion } from 'lucide-react';
9
9
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
  import { StatusBadge } from '../chunk-OE525ZER.js';
3
+ import { Money } from '../chunk-BVI5XDDA.js';
3
4
  import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
4
5
  import '../chunk-55FQP2DO.js';
5
- import { Money } from '../chunk-3KIDW4LT.js';
6
- import { useFormatters, useCopy } from '../chunk-E2D7QT6N.js';
6
+ import { useFormatters, useCopy } from '../chunk-TJSNVTVB.js';
7
7
  import { cn } from '../chunk-77QBZC7J.js';
8
- import '../chunk-B634JHKZ.js';
8
+ import '../chunk-BI4EGLPG.js';
9
9
  import Link from 'next/link';
10
10
  import { ChevronRight } from 'lucide-react';
11
11
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- export { AmountSummary } from '../chunk-BIQ2J75Y.js';
2
+ export { AmountSummary } from '../chunk-GLIK5BHP.js';
3
3
  import '../chunk-NSCIBSCW.js';
4
- import '../chunk-3KIDW4LT.js';
5
- import '../chunk-E2D7QT6N.js';
4
+ import '../chunk-BVI5XDDA.js';
5
+ import '../chunk-TJSNVTVB.js';
6
6
  import '../chunk-77QBZC7J.js';
7
- import '../chunk-B634JHKZ.js';
7
+ import '../chunk-BI4EGLPG.js';
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- export { Money } from '../chunk-3KIDW4LT.js';
3
- import '../chunk-E2D7QT6N.js';
2
+ export { Money } from '../chunk-BVI5XDDA.js';
3
+ import '../chunk-TJSNVTVB.js';
4
4
  import '../chunk-77QBZC7J.js';
5
- import '../chunk-B634JHKZ.js';
5
+ import '../chunk-BI4EGLPG.js';
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- export { MunicipalSeal } from '../chunk-IF5UAVIE.js';
2
+ export { MunicipalSeal } from '../chunk-YC7G2IOZ.js';
3
3
  import '../chunk-WOPU6DI7.js';
4
- import '../chunk-E2D7QT6N.js';
4
+ import '../chunk-TJSNVTVB.js';
5
5
  import '../chunk-77QBZC7J.js';
6
- import '../chunk-B634JHKZ.js';
6
+ import '../chunk-BI4EGLPG.js';
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- export { OfficialHeader } from '../chunk-4SZXBT56.js';
3
- import '../chunk-IF5UAVIE.js';
2
+ export { OfficialHeader } from '../chunk-NT72CQAI.js';
3
+ import '../chunk-YC7G2IOZ.js';
4
4
  import '../chunk-WOPU6DI7.js';
5
- import '../chunk-E2D7QT6N.js';
5
+ import '../chunk-TJSNVTVB.js';
6
6
  import '../chunk-77QBZC7J.js';
7
- import '../chunk-B634JHKZ.js';
7
+ import '../chunk-BI4EGLPG.js';
@@ -1,11 +1,11 @@
1
1
  "use client";
2
- import { ThemeToggle } from '../chunk-MDTRBOPQ.js';
3
- import { MunicipalSeal } from '../chunk-IF5UAVIE.js';
2
+ import { MunicipalSeal } from '../chunk-YC7G2IOZ.js';
4
3
  import '../chunk-WOPU6DI7.js';
4
+ import { ThemeToggle } from '../chunk-2C3VCTYJ.js';
5
5
  import '../chunk-I4WDVYHX.js';
6
- import { useOvrConfig, useCopy } from '../chunk-E2D7QT6N.js';
6
+ import { useOvrConfig, useCopy } from '../chunk-TJSNVTVB.js';
7
7
  import '../chunk-77QBZC7J.js';
8
- import '../chunk-B634JHKZ.js';
8
+ import '../chunk-BI4EGLPG.js';
9
9
  import Link from 'next/link';
10
10
  import { jsx, jsxs } from 'react/jsx-runtime';
11
11
 
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { useTheme } from '../chunk-E2D7QT6N.js';
3
- import '../chunk-B634JHKZ.js';
2
+ import { useTheme } from '../chunk-TJSNVTVB.js';
3
+ import '../chunk-BI4EGLPG.js';
4
4
  import { Toaster as Toaster$1 } from 'sonner';
5
5
  import { Loader2Icon, OctagonXIcon, TriangleAlertIcon, InfoIcon, CircleCheckIcon } from 'lucide-react';
6
6
  import { jsx } from 'react/jsx-runtime';
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- export { ThemeToggle } from '../chunk-MDTRBOPQ.js';
2
+ export { ThemeToggle } from '../chunk-2C3VCTYJ.js';
3
3
  import '../chunk-I4WDVYHX.js';
4
- import '../chunk-E2D7QT6N.js';
4
+ import '../chunk-TJSNVTVB.js';
5
5
  import '../chunk-77QBZC7J.js';
6
- import '../chunk-B634JHKZ.js';
6
+ import '../chunk-BI4EGLPG.js';
@@ -1,16 +1,16 @@
1
1
  "use client";
2
- import { OfficialHeader } from '../chunk-4SZXBT56.js';
3
- import '../chunk-IF5UAVIE.js';
2
+ import { OfficialHeader } from '../chunk-NT72CQAI.js';
3
+ import '../chunk-YC7G2IOZ.js';
4
4
  import '../chunk-WOPU6DI7.js';
5
- import { ViolationsTable } from '../chunk-JEYT63LE.js';
5
+ import { ViolationsTable } from '../chunk-IBZVIUNI.js';
6
6
  import { Separator } from '../chunk-NSCIBSCW.js';
7
7
  import { StatusBadge } from '../chunk-OE525ZER.js';
8
+ import { Money } from '../chunk-BVI5XDDA.js';
8
9
  import '../chunk-OWCGEEAZ.js';
9
10
  import '../chunk-55FQP2DO.js';
10
- import { Money } from '../chunk-3KIDW4LT.js';
11
- import { useFormatters, useOvrConfig } from '../chunk-E2D7QT6N.js';
11
+ import { useFormatters, useOvrConfig } from '../chunk-TJSNVTVB.js';
12
12
  import { cn } from '../chunk-77QBZC7J.js';
13
- import { formalName, formatAddress } from '../chunk-B634JHKZ.js';
13
+ import { formalName, formatAddress } from '../chunk-BI4EGLPG.js';
14
14
  import { jsxs, jsx } from 'react/jsx-runtime';
15
15
 
16
16
  function Field({ label, value }) {
@@ -64,6 +64,13 @@ function TicketReceipt({ ticket }) {
64
64
  value: `${ticket.officer.name}${ticket.officer.badgeNo ? ` (${ticket.officer.badgeNo})` : ""}`
65
65
  }
66
66
  ),
67
+ ticket.apprehendingEnforcerName ? /* @__PURE__ */ jsx(
68
+ Field,
69
+ {
70
+ label: "Apprehending Enforcer",
71
+ value: ticket.apprehendingEnforcerName
72
+ }
73
+ ) : null,
67
74
  ticket.issuedBy ? /* @__PURE__ */ jsx(Field, { label: "Issued By", value: ticket.issuedBy }) : null
68
75
  ] }),
69
76
  /* @__PURE__ */ jsxs("div", { className: "mt-6 print:mt-3", children: [
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- export { ViolationsTable } from '../chunk-JEYT63LE.js';
2
+ export { ViolationsTable } from '../chunk-IBZVIUNI.js';
3
+ import '../chunk-BVI5XDDA.js';
3
4
  import '../chunk-OWCGEEAZ.js';
4
- import '../chunk-3KIDW4LT.js';
5
- import '../chunk-E2D7QT6N.js';
5
+ import '../chunk-TJSNVTVB.js';
6
6
  import '../chunk-77QBZC7J.js';
7
- import '../chunk-B634JHKZ.js';
7
+ import '../chunk-BI4EGLPG.js';
@@ -4,7 +4,7 @@ import { useRender } from '@base-ui/react/use-render';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare const badgeVariants: (props?: ({
7
- variant?: "default" | "outline" | "secondary" | "ghost" | "destructive" | "link" | null | undefined;
7
+ variant?: "link" | "default" | "outline" | "secondary" | "ghost" | "destructive" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  declare function Badge({ className, variant, render, ...props }: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>;
10
10
 
@@ -4,7 +4,7 @@ import { Button as Button$1 } from '@base-ui/react/button';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare const buttonVariants: (props?: ({
7
- variant?: "default" | "outline" | "secondary" | "ghost" | "destructive" | "link" | null | undefined;
7
+ variant?: "link" | "default" | "outline" | "secondary" | "ghost" | "destructive" | null | undefined;
8
8
  size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
9
9
  } & class_variance_authority_types.ClassProp) | undefined) => string;
10
10
  declare function Button({ className, variant, size, ...props }: Button$1.Props & VariantProps<typeof buttonVariants>): React.JSX.Element;