@gelabs/ovr 0.4.0 → 0.4.1

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 (34) hide show
  1. package/dist/{chunk-DJMUW5T2.js → chunk-6AXIWTMW.js} +3 -0
  2. package/dist/{chunk-WUNTHINH.js → chunk-QZRRFE6E.js} +4 -2
  3. package/dist/{chunk-ZUMEOZ22.js → chunk-VH4J2SIV.js} +2 -2
  4. package/dist/core-i18n.d.ts +2 -2
  5. package/dist/core-i18n.js +1 -1
  6. package/dist/data-mock-store.js +23 -1
  7. package/dist/data-prisma-store.js +19 -1
  8. package/dist/data.d.ts +4 -0
  9. package/dist/{types-B8MopM4b.d.ts → types-DNEO6wrO.d.ts} +3 -0
  10. package/dist/types.d.ts +1 -1
  11. package/dist/types.js +1 -1
  12. package/dist/ui-components-admin/accounts-manager.js +5 -5
  13. package/dist/ui-components-admin/admin-nav.js +2 -2
  14. package/dist/ui-components-admin/issuance-form.js +10 -10
  15. package/dist/ui-components-admin/logs-viewer.js +4 -4
  16. package/dist/ui-components-admin/notifications-list.js +1 -1
  17. package/dist/ui-components-admin/officers-manager.js +3 -3
  18. package/dist/ui-components-admin/roles-manager.js +4 -4
  19. package/dist/ui-components-admin/ticket-preview.js +6 -6
  20. package/dist/ui-components-admin/tickets-table.js +3 -3
  21. package/dist/ui-components-admin/violations-manager.d.ts +5 -1
  22. package/dist/ui-components-admin/violations-manager.js +77 -8
  23. package/dist/ui-components-citizen/payment-form.js +3 -3
  24. package/dist/ui-components-citizen/payment-qr-dialog.js +2 -2
  25. package/dist/ui-components-citizen/violation-history-table.js +2 -2
  26. package/dist/ui-components-shared/site-header.js +1 -1
  27. package/dist/ui-components-shared/ticket-receipt.js +4 -4
  28. package/dist/ui-components-shared/violations-table.js +2 -2
  29. package/dist/ui-config.d.ts +1 -1
  30. package/dist/ui-server.d.ts +1 -1
  31. package/dist/ui-server.js +1 -1
  32. package/package.json +7 -7
  33. package/dist/{chunk-IBZVIUNI.js → chunk-6BH4EFP3.js} +1 -1
  34. package/dist/{chunk-TLG4C2XI.js → chunk-QCAURREW.js} +1 -1
@@ -225,6 +225,9 @@ var baseCopy = {
225
225
  restore: "Restore",
226
226
  archiveConfirmTitle: "Archive this violation?",
227
227
  archiveConfirmBody: "It will be hidden from the Issue-Ticket form. Already-issued tickets keep their copy, and you can restore it anytime.",
228
+ delete: "Delete",
229
+ deleteConfirmTitle: "Delete this violation permanently?",
230
+ deleteConfirmBody: "This can't be undone. Only possible because no ticket has used it \u2014 used violations can only be archived.",
228
231
  empty: "No violations yet \u2014 add the first one.",
229
232
  actions: "Actions"
230
233
  },
@@ -72,7 +72,8 @@ var ACTIVITY_ACTIONS = [
72
72
  "officer.delete",
73
73
  "violation.create",
74
74
  "violation.update",
75
- "violation.delete"
75
+ "violation.delete",
76
+ "violation.purge"
76
77
  ];
77
78
  var ACTIVITY_ACTION_LABELS = {
78
79
  "auth.login": "Signed in",
@@ -92,7 +93,8 @@ var ACTIVITY_ACTION_LABELS = {
92
93
  "officer.delete": "Removed officer",
93
94
  "violation.create": "Added violation",
94
95
  "violation.update": "Updated violation",
95
- "violation.delete": "Archived violation"
96
+ "violation.delete": "Archived violation",
97
+ "violation.purge": "Deleted violation"
96
98
  };
97
99
 
98
100
  export { ACTIVITY_ACTIONS, ACTIVITY_ACTION_LABELS, ALL_PERMISSIONS, DEFAULT_ROLE_NAME, PERMISSION_CATALOG, SUPER_ADMIN_LOCKED_PERMISSIONS, SYSTEM_ROLES, hasPermission };
@@ -1,6 +1,6 @@
1
- import { ViolationsTable } from './chunk-IBZVIUNI.js';
2
- import { AmountSummary } from './chunk-GLIK5BHP.js';
1
+ import { ViolationsTable } from './chunk-6BH4EFP3.js';
3
2
  import { StatusBadge } from './chunk-OE525ZER.js';
3
+ import { AmountSummary } from './chunk-GLIK5BHP.js';
4
4
  import { Card, CardHeader, CardTitle, CardContent } from './chunk-SETIN6XP.js';
5
5
  import { useFormatters } from './chunk-TJSNVTVB.js';
6
6
  import { formalName, formatAddress } from './chunk-BI4EGLPG.js';
@@ -1,5 +1,5 @@
1
- import { C as CopyOverrides, D as Dictionary } from './types-B8MopM4b.js';
2
- export { b as baseCopy } from './types-B8MopM4b.js';
1
+ import { C as CopyOverrides, D as Dictionary } from './types-DNEO6wrO.js';
2
+ export { b as baseCopy } from './types-DNEO6wrO.js';
3
3
  import { M as MunicipalityConfig } from './schema-CdsFQxIg.js';
4
4
  import 'zod';
5
5
 
package/dist/core-i18n.js CHANGED
@@ -1 +1 @@
1
- export { baseCopy, mergeCopy } from './chunk-DJMUW5T2.js';
1
+ export { baseCopy, mergeCopy } from './chunk-6AXIWTMW.js';
@@ -1,4 +1,4 @@
1
- import { SUPER_ADMIN_LOCKED_PERMISSIONS, ALL_PERMISSIONS } from './chunk-WUNTHINH.js';
1
+ import { SUPER_ADMIN_LOCKED_PERMISSIONS, ALL_PERMISSIONS } from './chunk-QZRRFE6E.js';
2
2
  import { round2, computeCharges, makePaymentRef, fullName, addDays, makeBillNo, makeOrderOfPaymentNo, makeOvrTicketNo, enrich } from './chunk-BI4EGLPG.js';
3
3
  import 'server-only';
4
4
  import { promises } from 'fs';
@@ -118,6 +118,28 @@ function createMockStore(rules, seed) {
118
118
  c.active = false;
119
119
  await writeStore(data);
120
120
  },
121
+ async usedViolationCodes() {
122
+ const data = await readStore();
123
+ const used = /* @__PURE__ */ new Set();
124
+ for (const t of data.tickets)
125
+ for (const v of t.violations) used.add(v.catalogCode);
126
+ return [...used];
127
+ },
128
+ async purgeViolation(code) {
129
+ const data = await readStore();
130
+ const c = data.catalog.find((x) => x.code === code);
131
+ if (!c) throw new Error("Violation not found.");
132
+ const uses = data.tickets.filter(
133
+ (t) => t.violations.some((v) => v.catalogCode === code)
134
+ ).length;
135
+ if (uses > 0) {
136
+ throw new Error(
137
+ `Can't delete \u2014 used by ${uses} ticket(s). Archive it instead.`
138
+ );
139
+ }
140
+ data.catalog = data.catalog.filter((x) => x.code !== code);
141
+ await writeStore(data);
142
+ },
121
143
  async listOfficers() {
122
144
  const data = await readStore();
123
145
  return structuredClone(data.officers);
@@ -1,5 +1,5 @@
1
1
  import { prisma } from './chunk-MKALJTAU.js';
2
- import { SUPER_ADMIN_LOCKED_PERMISSIONS, ALL_PERMISSIONS } from './chunk-WUNTHINH.js';
2
+ import { SUPER_ADMIN_LOCKED_PERMISSIONS, ALL_PERMISSIONS } from './chunk-QZRRFE6E.js';
3
3
  import { round2, computeCharges, makePaymentRef, fullName, addDays, makeBillNo, makeOrderOfPaymentNo, makeOvrTicketNo, enrich } from './chunk-BI4EGLPG.js';
4
4
  import 'server-only';
5
5
 
@@ -166,6 +166,24 @@ function createPrismaStore(rules) {
166
166
  data: { active: false }
167
167
  });
168
168
  },
169
+ async usedViolationCodes() {
170
+ const rows = await prisma.ticketViolation.findMany({
171
+ distinct: ["catalogCode"],
172
+ select: { catalogCode: true }
173
+ });
174
+ return rows.map((r) => r.catalogCode);
175
+ },
176
+ async purgeViolation(code) {
177
+ const uses = await prisma.ticketViolation.count({
178
+ where: { catalogCode: code }
179
+ });
180
+ if (uses > 0) {
181
+ throw new Error(
182
+ `Can't delete \u2014 used by ${uses} ticket(s). Archive it instead.`
183
+ );
184
+ }
185
+ await prisma.violationCatalog.delete({ where: { code } });
186
+ },
169
187
  async listOfficers() {
170
188
  const officers = await prisma.officer.findMany({
171
189
  orderBy: { name: "asc" }
package/dist/data.d.ts CHANGED
@@ -56,6 +56,10 @@ interface DataStore {
56
56
  }): Promise<ViolationCatalogItem>;
57
57
  /** Archive an entry (soft-delete: active=false) so old tickets stay resolvable. */
58
58
  deleteViolation(code: string): Promise<void>;
59
+ /** Distinct catalog codes referenced by at least one issued ticket. */
60
+ usedViolationCodes(): Promise<string[]>;
61
+ /** Permanently remove an entry. Throws if any ticket has used it (archive instead). */
62
+ purgeViolation(code: string): Promise<void>;
59
63
  listOfficers(): Promise<Officer[]>;
60
64
  getOfficer(id: string): Promise<Officer | null>;
61
65
  /** Add an apprehending officer (id is slugified from the name; must be unique). */
@@ -231,6 +231,9 @@ declare const baseCopy: {
231
231
  readonly restore: "Restore";
232
232
  readonly archiveConfirmTitle: "Archive this violation?";
233
233
  readonly archiveConfirmBody: "It will be hidden from the Issue-Ticket form. Already-issued tickets keep their copy, and you can restore it anytime.";
234
+ readonly delete: "Delete";
235
+ readonly deleteConfirmTitle: "Delete this violation permanently?";
236
+ readonly deleteConfirmBody: "This can't be undone. Only possible because no ticket has used it — used violations can only be archived.";
234
237
  readonly empty: "No violations yet — add the first one.";
235
238
  readonly actions: "Actions";
236
239
  };
package/dist/types.d.ts CHANGED
@@ -150,7 +150,7 @@ interface NewUserInput {
150
150
  officerId?: string | null;
151
151
  }
152
152
  /** The recorded action kinds (extensible; stored as a string for forward-compat). */
153
- declare const ACTIVITY_ACTIONS: readonly ["auth.login", "auth.logout", "ticket.issued", "account.create", "account.update", "account.activate", "account.deactivate", "account.password_reset", "account.password_change", "role.create", "role.update", "role.delete", "officer.create", "officer.update", "officer.delete", "violation.create", "violation.update", "violation.delete"];
153
+ declare const ACTIVITY_ACTIONS: readonly ["auth.login", "auth.logout", "ticket.issued", "account.create", "account.update", "account.activate", "account.deactivate", "account.password_reset", "account.password_change", "role.create", "role.update", "role.delete", "officer.create", "officer.update", "officer.delete", "violation.create", "violation.update", "violation.delete", "violation.purge"];
154
154
  type ActivityAction = (typeof ACTIVITY_ACTIONS)[number];
155
155
  declare const ACTIVITY_ACTION_LABELS: Record<ActivityAction, string>;
156
156
  /** One audit-trail entry: who did what, when. */
package/dist/types.js CHANGED
@@ -1 +1 @@
1
- export { ACTIVITY_ACTIONS, ACTIVITY_ACTION_LABELS, ALL_PERMISSIONS, DEFAULT_ROLE_NAME, PERMISSION_CATALOG, SUPER_ADMIN_LOCKED_PERMISSIONS, SYSTEM_ROLES, hasPermission } from './chunk-WUNTHINH.js';
1
+ export { ACTIVITY_ACTIONS, ACTIVITY_ACTION_LABELS, ALL_PERMISSIONS, DEFAULT_ROLE_NAME, PERMISSION_CATALOG, SUPER_ADMIN_LOCKED_PERMISSIONS, SYSTEM_ROLES, hasPermission } from './chunk-QZRRFE6E.js';
@@ -1,15 +1,15 @@
1
1
  "use client";
2
- import { Card, CardContent } from '../chunk-SETIN6XP.js';
3
2
  import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
4
- import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
5
- import { Badge } from '../chunk-55FQP2DO.js';
6
3
  import { Label } from '../chunk-XQTVSNHC.js';
7
- import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
8
4
  import { Input } from '../chunk-K3KIBHJF.js';
5
+ import { Badge } from '../chunk-55FQP2DO.js';
6
+ import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
7
+ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
8
+ import { Card, CardContent } from '../chunk-SETIN6XP.js';
9
9
  import { Button } from '../chunk-I4WDVYHX.js';
10
10
  import { useCopy, useOvrConfig } from '../chunk-TJSNVTVB.js';
11
11
  import '../chunk-77QBZC7J.js';
12
- import { hasPermission } from '../chunk-WUNTHINH.js';
12
+ import { hasPermission } from '../chunk-QZRRFE6E.js';
13
13
  import '../chunk-BI4EGLPG.js';
14
14
  import * as React from 'react';
15
15
  import { toast } from 'sonner';
@@ -2,12 +2,12 @@
2
2
  import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter } from '../chunk-3YKVH4Y7.js';
3
3
  import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from '../chunk-V7VQVDWS.js';
4
4
  import { Label } from '../chunk-XQTVSNHC.js';
5
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
6
5
  import { Input } from '../chunk-K3KIBHJF.js';
6
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
7
7
  import { Button } from '../chunk-I4WDVYHX.js';
8
8
  import { useCopy } from '../chunk-TJSNVTVB.js';
9
9
  import { cn } from '../chunk-77QBZC7J.js';
10
- import { hasPermission } from '../chunk-WUNTHINH.js';
10
+ import { hasPermission } from '../chunk-QZRRFE6E.js';
11
11
  import { useIdentity, useNotificationsState, cacheCredential } from '../chunk-YGYA7KEG.js';
12
12
  import '../chunk-BI4EGLPG.js';
13
13
  import * as React from 'react';
@@ -1,20 +1,20 @@
1
1
  "use client";
2
2
  import { Skeleton } from '../chunk-EGKFELO3.js';
3
3
  import { Textarea } from '../chunk-QCRVT2SS.js';
4
- import { Alert, AlertDescription } from '../chunk-EYFZWQ4J.js';
5
4
  import { Checkbox } from '../chunk-BBQBKQA4.js';
6
- import { TicketPreview } from '../chunk-ZUMEOZ22.js';
7
- import '../chunk-IBZVIUNI.js';
8
- import '../chunk-GLIK5BHP.js';
9
- import '../chunk-NSCIBSCW.js';
5
+ import { TicketPreview } from '../chunk-VH4J2SIV.js';
6
+ import '../chunk-6BH4EFP3.js';
7
+ import { Label } from '../chunk-XQTVSNHC.js';
8
+ import { Input } from '../chunk-K3KIBHJF.js';
10
9
  import '../chunk-OE525ZER.js';
11
- import '../chunk-BVI5XDDA.js';
12
- import { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../chunk-SETIN6XP.js';
13
- import '../chunk-OWCGEEAZ.js';
14
10
  import '../chunk-55FQP2DO.js';
15
- import { Label } from '../chunk-XQTVSNHC.js';
11
+ import '../chunk-OWCGEEAZ.js';
12
+ import '../chunk-GLIK5BHP.js';
13
+ import { Alert, AlertDescription } from '../chunk-EYFZWQ4J.js';
16
14
  import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
17
- import { Input } from '../chunk-K3KIBHJF.js';
15
+ import { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../chunk-SETIN6XP.js';
16
+ import '../chunk-NSCIBSCW.js';
17
+ import '../chunk-BVI5XDDA.js';
18
18
  import { Button } from '../chunk-I4WDVYHX.js';
19
19
  import { useFormatters, useOvrConfig } from '../chunk-TJSNVTVB.js';
20
20
  import { cn } from '../chunk-77QBZC7J.js';
@@ -1,13 +1,13 @@
1
1
  "use client";
2
- import { Card, CardContent } from '../chunk-SETIN6XP.js';
3
2
  import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
4
- import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
5
- import { Badge } from '../chunk-55FQP2DO.js';
6
3
  import { Input } from '../chunk-K3KIBHJF.js';
4
+ import { Badge } from '../chunk-55FQP2DO.js';
5
+ import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
6
+ import { Card, CardContent } from '../chunk-SETIN6XP.js';
7
7
  import '../chunk-I4WDVYHX.js';
8
8
  import { useCopy, useOvrConfig } from '../chunk-TJSNVTVB.js';
9
9
  import '../chunk-77QBZC7J.js';
10
- import { ACTIVITY_ACTION_LABELS } from '../chunk-WUNTHINH.js';
10
+ import { ACTIVITY_ACTION_LABELS } from '../chunk-QZRRFE6E.js';
11
11
  import '../chunk-BI4EGLPG.js';
12
12
  import * as React from 'react';
13
13
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { Card, CardContent } from '../chunk-SETIN6XP.js';
3
2
  import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
4
3
  import { Badge } from '../chunk-55FQP2DO.js';
4
+ import { Card, CardContent } from '../chunk-SETIN6XP.js';
5
5
  import '../chunk-I4WDVYHX.js';
6
6
  import { useCopy, useOvrConfig } from '../chunk-TJSNVTVB.js';
7
7
  import '../chunk-77QBZC7J.js';
@@ -1,10 +1,10 @@
1
1
  "use client";
2
- import { Card, CardContent } from '../chunk-SETIN6XP.js';
3
2
  import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
4
- import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
5
3
  import { Label } from '../chunk-XQTVSNHC.js';
6
- import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
7
4
  import { Input } from '../chunk-K3KIBHJF.js';
5
+ import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
6
+ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
7
+ import { Card, CardContent } from '../chunk-SETIN6XP.js';
8
8
  import { Button } from '../chunk-I4WDVYHX.js';
9
9
  import { useCopy } from '../chunk-TJSNVTVB.js';
10
10
  import '../chunk-77QBZC7J.js';
@@ -1,14 +1,14 @@
1
1
  "use client";
2
2
  import { Checkbox } from '../chunk-BBQBKQA4.js';
3
- import { Card, CardContent } from '../chunk-SETIN6XP.js';
4
- import { Badge } from '../chunk-55FQP2DO.js';
5
3
  import { Label } from '../chunk-XQTVSNHC.js';
6
- import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
7
4
  import { Input } from '../chunk-K3KIBHJF.js';
5
+ import { Badge } from '../chunk-55FQP2DO.js';
6
+ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
7
+ import { Card, CardContent } from '../chunk-SETIN6XP.js';
8
8
  import { Button } from '../chunk-I4WDVYHX.js';
9
9
  import { useCopy } from '../chunk-TJSNVTVB.js';
10
10
  import '../chunk-77QBZC7J.js';
11
- import { PERMISSION_CATALOG, SUPER_ADMIN_LOCKED_PERMISSIONS } from '../chunk-WUNTHINH.js';
11
+ import { PERMISSION_CATALOG, SUPER_ADMIN_LOCKED_PERMISSIONS } from '../chunk-QZRRFE6E.js';
12
12
  import '../chunk-BI4EGLPG.js';
13
13
  import * as React from 'react';
14
14
  import { toast } from 'sonner';
@@ -1,13 +1,13 @@
1
1
  "use client";
2
- export { TicketPreview } from '../chunk-ZUMEOZ22.js';
3
- import '../chunk-IBZVIUNI.js';
2
+ export { TicketPreview } from '../chunk-VH4J2SIV.js';
3
+ import '../chunk-6BH4EFP3.js';
4
+ import '../chunk-OE525ZER.js';
5
+ import '../chunk-55FQP2DO.js';
6
+ import '../chunk-OWCGEEAZ.js';
4
7
  import '../chunk-GLIK5BHP.js';
8
+ import '../chunk-SETIN6XP.js';
5
9
  import '../chunk-NSCIBSCW.js';
6
- import '../chunk-OE525ZER.js';
7
10
  import '../chunk-BVI5XDDA.js';
8
- import '../chunk-SETIN6XP.js';
9
- import '../chunk-OWCGEEAZ.js';
10
- import '../chunk-55FQP2DO.js';
11
11
  import '../chunk-TJSNVTVB.js';
12
12
  import '../chunk-77QBZC7J.js';
13
13
  import '../chunk-BI4EGLPG.js';
@@ -1,9 +1,9 @@
1
1
  "use client";
2
- import { StatusBadge } from '../chunk-OE525ZER.js';
3
- import { Money } from '../chunk-BVI5XDDA.js';
4
2
  import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
5
- import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
3
+ import { StatusBadge } from '../chunk-OE525ZER.js';
6
4
  import '../chunk-55FQP2DO.js';
5
+ import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
6
+ import { Money } from '../chunk-BVI5XDDA.js';
7
7
  import '../chunk-I4WDVYHX.js';
8
8
  import { useFormatters } from '../chunk-TJSNVTVB.js';
9
9
  import '../chunk-77QBZC7J.js';
@@ -26,7 +26,11 @@ interface ViolationsManagerProps {
26
26
  createAction: CreateViolationAction;
27
27
  updateAction: UpdateViolationAction;
28
28
  deleteAction: DeleteViolationAction;
29
+ /** Catalog codes used by ≥1 ticket — those can only be archived, not deleted. */
30
+ usedCodes?: string[];
31
+ /** Permanent delete (only offered for never-used entries). */
32
+ purgeAction?: DeleteViolationAction;
29
33
  }
30
- declare function ViolationsManager({ violations, createAction, updateAction, deleteAction, }: ViolationsManagerProps): React.JSX.Element;
34
+ declare function ViolationsManager({ violations, createAction, updateAction, deleteAction, usedCodes, purgeAction, }: ViolationsManagerProps): React.JSX.Element;
31
35
 
32
36
  export { type CreateViolationAction, type DeleteViolationAction, type UpdateViolationAction, ViolationsManager, type ViolationsManagerProps };
@@ -1,13 +1,13 @@
1
1
  "use client";
2
2
  import { Textarea } from '../chunk-QCRVT2SS.js';
3
- import { Money } from '../chunk-BVI5XDDA.js';
4
- import { Card, CardContent } from '../chunk-SETIN6XP.js';
5
3
  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
4
  import { Label } from '../chunk-XQTVSNHC.js';
9
- import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
10
5
  import { Input } from '../chunk-K3KIBHJF.js';
6
+ import { Badge } from '../chunk-55FQP2DO.js';
7
+ import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
8
+ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
9
+ import { Card, CardContent } from '../chunk-SETIN6XP.js';
10
+ import { Money } from '../chunk-BVI5XDDA.js';
11
11
  import { Button } from '../chunk-I4WDVYHX.js';
12
12
  import { useCopy } from '../chunk-TJSNVTVB.js';
13
13
  import { cn } from '../chunk-77QBZC7J.js';
@@ -15,7 +15,7 @@ import '../chunk-BI4EGLPG.js';
15
15
  import * as React from 'react';
16
16
  import { toast } from 'sonner';
17
17
  import { useRouter } from 'next/navigation';
18
- import { Plus, Pencil, Loader2, Archive, ArchiveRestore } from 'lucide-react';
18
+ import { Plus, Pencil, Loader2, Archive, ArchiveRestore, Trash2 } from 'lucide-react';
19
19
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
20
20
 
21
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";
@@ -23,10 +23,13 @@ function ViolationsManager({
23
23
  violations,
24
24
  createAction,
25
25
  updateAction,
26
- deleteAction
26
+ deleteAction,
27
+ usedCodes = [],
28
+ purgeAction
27
29
  }) {
28
30
  const t = useCopy().admin.violationsPage;
29
31
  const router = useRouter();
32
+ const used = React.useMemo(() => new Set(usedCodes), [usedCodes]);
30
33
  const { pageItems, page, setPage, totalPages, from, to, total } = usePagination(violations, 12);
31
34
  const categoryLabel = (c) => c === "TRAFFIC" ? t.categoryTraffic : t.categoryOrdinance;
32
35
  return /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-5xl p-4 sm:p-6 lg:p-8", children: [
@@ -86,7 +89,15 @@ function ViolationsManager({
86
89
  deleteAction,
87
90
  onDone: () => router.refresh()
88
91
  }
89
- )
92
+ ),
93
+ purgeAction && !used.has(v.code) ? /* @__PURE__ */ jsx(
94
+ DeleteButton,
95
+ {
96
+ violation: v,
97
+ purgeAction,
98
+ onDone: () => router.refresh()
99
+ }
100
+ ) : null
90
101
  ] }) })
91
102
  ] }, v.code);
92
103
  }) })
@@ -381,5 +392,63 @@ function RestoreButton({
381
392
  }
382
393
  );
383
394
  }
395
+ function DeleteButton({
396
+ violation,
397
+ purgeAction,
398
+ onDone
399
+ }) {
400
+ const t = useCopy().admin.violationsPage;
401
+ const [busy, setBusy] = React.useState(false);
402
+ async function purge() {
403
+ setBusy(true);
404
+ try {
405
+ const res = await purgeAction(violation.code);
406
+ if (res?.error) {
407
+ toast.error(res.error);
408
+ return;
409
+ }
410
+ toast.success(`${t.delete}: ${violation.title}`);
411
+ onDone();
412
+ } finally {
413
+ setBusy(false);
414
+ }
415
+ }
416
+ return /* @__PURE__ */ jsxs(Dialog, { children: [
417
+ /* @__PURE__ */ jsxs(
418
+ DialogTrigger,
419
+ {
420
+ render: /* @__PURE__ */ jsx(Button, { variant: "destructive", size: "sm", className: "gap-1.5" }),
421
+ children: [
422
+ /* @__PURE__ */ jsx(Trash2, { className: "size-3.5" }),
423
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: t.delete })
424
+ ]
425
+ }
426
+ ),
427
+ /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-sm", children: [
428
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
429
+ /* @__PURE__ */ jsx(DialogTitle, { children: t.deleteConfirmTitle }),
430
+ /* @__PURE__ */ jsxs(DialogDescription, { children: [
431
+ violation.title,
432
+ " \u2014 ",
433
+ t.deleteConfirmBody
434
+ ] })
435
+ ] }),
436
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
437
+ /* @__PURE__ */ jsx(DialogClose, { render: /* @__PURE__ */ jsx(Button, { variant: "outline" }), children: t.cancel }),
438
+ /* @__PURE__ */ jsxs(
439
+ DialogClose,
440
+ {
441
+ render: /* @__PURE__ */ jsx(Button, { variant: "destructive", className: "gap-2", disabled: busy }),
442
+ onClick: purge,
443
+ children: [
444
+ /* @__PURE__ */ jsx(Trash2, { className: "size-4" }),
445
+ t.delete
446
+ ]
447
+ }
448
+ )
449
+ ] })
450
+ ] })
451
+ ] });
452
+ }
384
453
 
385
454
  export { ViolationsManager };
@@ -1,10 +1,10 @@
1
1
  "use client";
2
- import { PaymentQrDialog } from '../chunk-TLG4C2XI.js';
2
+ import { PaymentQrDialog } from '../chunk-QCAURREW.js';
3
3
  import { Alert, AlertDescription } from '../chunk-EYFZWQ4J.js';
4
+ import '../chunk-M35R6JLA.js';
5
+ import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '../chunk-SETIN6XP.js';
4
6
  import { Separator } from '../chunk-NSCIBSCW.js';
5
7
  import { Money } from '../chunk-BVI5XDDA.js';
6
- import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '../chunk-SETIN6XP.js';
7
- import '../chunk-M35R6JLA.js';
8
8
  import { Button } from '../chunk-I4WDVYHX.js';
9
9
  import { useOvrConfig, useCopy } from '../chunk-TJSNVTVB.js';
10
10
  import { cn } from '../chunk-77QBZC7J.js';
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- export { PaymentQrDialog } from '../chunk-TLG4C2XI.js';
2
+ export { PaymentQrDialog } from '../chunk-QCAURREW.js';
3
3
  import '../chunk-EYFZWQ4J.js';
4
- import '../chunk-BVI5XDDA.js';
5
4
  import '../chunk-M35R6JLA.js';
5
+ import '../chunk-BVI5XDDA.js';
6
6
  import '../chunk-I4WDVYHX.js';
7
7
  import '../chunk-TJSNVTVB.js';
8
8
  import '../chunk-77QBZC7J.js';
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { StatusBadge } from '../chunk-OE525ZER.js';
3
- import { Money } from '../chunk-BVI5XDDA.js';
4
- import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
5
3
  import '../chunk-55FQP2DO.js';
4
+ import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
5
+ import { Money } from '../chunk-BVI5XDDA.js';
6
6
  import { useFormatters, useCopy } from '../chunk-TJSNVTVB.js';
7
7
  import { cn } from '../chunk-77QBZC7J.js';
8
8
  import '../chunk-BI4EGLPG.js';
@@ -1,7 +1,7 @@
1
1
  "use client";
2
+ import { ThemeToggle } from '../chunk-2C3VCTYJ.js';
2
3
  import { MunicipalSeal } from '../chunk-YC7G2IOZ.js';
3
4
  import '../chunk-WOPU6DI7.js';
4
- import { ThemeToggle } from '../chunk-2C3VCTYJ.js';
5
5
  import '../chunk-I4WDVYHX.js';
6
6
  import { useOvrConfig, useCopy } from '../chunk-TJSNVTVB.js';
7
7
  import '../chunk-77QBZC7J.js';
@@ -1,13 +1,13 @@
1
1
  "use client";
2
+ import { ViolationsTable } from '../chunk-6BH4EFP3.js';
3
+ import { StatusBadge } from '../chunk-OE525ZER.js';
4
+ import '../chunk-55FQP2DO.js';
5
+ import '../chunk-OWCGEEAZ.js';
2
6
  import { OfficialHeader } from '../chunk-NT72CQAI.js';
3
7
  import '../chunk-YC7G2IOZ.js';
4
8
  import '../chunk-WOPU6DI7.js';
5
- import { ViolationsTable } from '../chunk-IBZVIUNI.js';
6
9
  import { Separator } from '../chunk-NSCIBSCW.js';
7
- import { StatusBadge } from '../chunk-OE525ZER.js';
8
10
  import { Money } from '../chunk-BVI5XDDA.js';
9
- import '../chunk-OWCGEEAZ.js';
10
- import '../chunk-55FQP2DO.js';
11
11
  import { useFormatters, useOvrConfig } from '../chunk-TJSNVTVB.js';
12
12
  import { cn } from '../chunk-77QBZC7J.js';
13
13
  import { formalName, formatAddress } from '../chunk-BI4EGLPG.js';
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- export { ViolationsTable } from '../chunk-IBZVIUNI.js';
3
- import '../chunk-BVI5XDDA.js';
2
+ export { ViolationsTable } from '../chunk-6BH4EFP3.js';
4
3
  import '../chunk-OWCGEEAZ.js';
4
+ import '../chunk-BVI5XDDA.js';
5
5
  import '../chunk-TJSNVTVB.js';
6
6
  import '../chunk-77QBZC7J.js';
7
7
  import '../chunk-BI4EGLPG.js';
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { b as OvrConfig } from './schema-CdsFQxIg.js';
3
3
  import { a as Formatters } from './format-C7MSwUHK.js';
4
- import { D as Dictionary } from './types-B8MopM4b.js';
4
+ import { D as Dictionary } from './types-DNEO6wrO.js';
5
5
  import 'zod';
6
6
  import './types.js';
7
7
 
@@ -1,6 +1,6 @@
1
1
  import { b as OvrConfig } from './schema-CdsFQxIg.js';
2
2
  import { a as Formatters } from './format-C7MSwUHK.js';
3
- import { D as Dictionary, C as CopyOverrides } from './types-B8MopM4b.js';
3
+ import { D as Dictionary, C as CopyOverrides } from './types-DNEO6wrO.js';
4
4
  import 'zod';
5
5
  import './types.js';
6
6
 
package/dist/ui-server.js CHANGED
@@ -1,4 +1,4 @@
1
- import { mergeCopy } from './chunk-DJMUW5T2.js';
1
+ import { mergeCopy } from './chunk-6AXIWTMW.js';
2
2
  import { createFormatters } from './chunk-BI4EGLPG.js';
3
3
  import 'server-only';
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gelabs/ovr",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "The @gelabs/ovr SDK — one self-contained package over the OVR (Online Ordinance Violation Receipt) platform. A standalone per-LGU app installs ONLY this package and imports from @gelabs/ovr/{config,core,data,runtime,auth,ui,...}; the seven @gelabs/ovr-* implementation packages are bundled in at build time.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -159,13 +159,13 @@
159
159
  "tsup": "^8.4.0",
160
160
  "typescript": "^5",
161
161
  "@gelabs/ovr-config": "0.0.0",
162
- "@gelabs/ovr-offline": "0.0.0",
163
- "@gelabs/ovr-core": "0.0.0",
164
- "@gelabs/ovr-ui": "0.0.0",
165
- "@gelabs/ovr-types": "0.0.0",
166
- "@gelabs/ovr-data": "0.0.0",
167
162
  "@gelabs/ovr-runtime": "0.0.0",
168
- "@gelabs/ovr-auth": "0.0.0"
163
+ "@gelabs/ovr-data": "0.0.0",
164
+ "@gelabs/ovr-types": "0.0.0",
165
+ "@gelabs/ovr-ui": "0.0.0",
166
+ "@gelabs/ovr-offline": "0.0.0",
167
+ "@gelabs/ovr-auth": "0.0.0",
168
+ "@gelabs/ovr-core": "0.0.0"
169
169
  },
170
170
  "scripts": {
171
171
  "build": "tsup && node scripts/copy-assets.mjs",
@@ -1,5 +1,5 @@
1
- import { Money } from './chunk-BVI5XDDA.js';
2
1
  import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from './chunk-OWCGEEAZ.js';
2
+ import { Money } from './chunk-BVI5XDDA.js';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
 
5
5
  function ViolationsTable({
@@ -1,6 +1,6 @@
1
1
  import { Alert, AlertDescription } from './chunk-EYFZWQ4J.js';
2
- import { Money } from './chunk-BVI5XDDA.js';
3
2
  import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from './chunk-M35R6JLA.js';
3
+ import { Money } from './chunk-BVI5XDDA.js';
4
4
  import { Button } from './chunk-I4WDVYHX.js';
5
5
  import { useCopy } from './chunk-TJSNVTVB.js';
6
6
  import * as React from 'react';