@gelabs/ovr 0.4.0 → 0.4.2
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.
- package/dist/{chunk-DJMUW5T2.js → chunk-6AXIWTMW.js} +3 -0
- package/dist/{chunk-WUNTHINH.js → chunk-QZRRFE6E.js} +4 -2
- package/dist/core-i18n.d.ts +2 -2
- package/dist/core-i18n.js +1 -1
- package/dist/data-mock-store.js +23 -1
- package/dist/data-prisma-store.js +19 -1
- package/dist/data.d.ts +4 -0
- package/dist/{types-B8MopM4b.d.ts → types-DNEO6wrO.d.ts} +3 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/ui-components-admin/accounts-manager.js +10 -6
- package/dist/ui-components-admin/admin-nav.js +3 -3
- package/dist/ui-components-admin/issuance-form.js +1 -1
- package/dist/ui-components-admin/logs-viewer.js +1 -1
- package/dist/ui-components-admin/officers-manager.js +1 -1
- package/dist/ui-components-admin/roles-manager.js +2 -2
- package/dist/ui-components-admin/violations-manager.d.ts +5 -1
- package/dist/ui-components-admin/violations-manager.js +73 -4
- package/dist/ui-components-shared/site-header.js +1 -1
- package/dist/ui-config.d.ts +1 -1
- package/dist/ui-server.d.ts +1 -1
- package/dist/ui-server.js +1 -1
- package/package.json +6 -6
|
@@ -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 };
|
package/dist/core-i18n.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as CopyOverrides, D as Dictionary } from './types-
|
|
2
|
-
export { b as baseCopy } from './types-
|
|
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-
|
|
1
|
+
export { baseCopy, mergeCopy } from './chunk-6AXIWTMW.js';
|
package/dist/data-mock-store.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SUPER_ADMIN_LOCKED_PERMISSIONS, ALL_PERMISSIONS } from './chunk-
|
|
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-
|
|
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-
|
|
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';
|
|
@@ -3,13 +3,13 @@ import { Card, CardContent } from '../chunk-SETIN6XP.js';
|
|
|
3
3
|
import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
|
|
4
4
|
import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
|
|
5
5
|
import { Badge } from '../chunk-55FQP2DO.js';
|
|
6
|
-
import { Label } from '../chunk-XQTVSNHC.js';
|
|
7
6
|
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
|
|
7
|
+
import { Label } from '../chunk-XQTVSNHC.js';
|
|
8
8
|
import { Input } from '../chunk-K3KIBHJF.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-
|
|
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';
|
|
@@ -150,14 +150,15 @@ function NewAccountDialog({
|
|
|
150
150
|
onCreated
|
|
151
151
|
}) {
|
|
152
152
|
const t = useCopy().admin.accountsPage;
|
|
153
|
-
const
|
|
153
|
+
const assignableRoles = roles.filter((r) => r.name !== "SUPER_ADMIN");
|
|
154
|
+
const defaultRole = assignableRoles.find((r) => r.name === "ENFORCER")?.name ?? assignableRoles[0]?.name ?? "";
|
|
154
155
|
const [open, setOpen] = React.useState(false);
|
|
155
156
|
const [username, setUsername] = React.useState("");
|
|
156
157
|
const [password, setPassword] = React.useState("");
|
|
157
158
|
const [role, setRole] = React.useState(defaultRole);
|
|
158
159
|
const [officerId, setOfficerId] = React.useState("");
|
|
159
160
|
const [submitting, setSubmitting] = React.useState(false);
|
|
160
|
-
const selectedRole =
|
|
161
|
+
const selectedRole = assignableRoles.find((r) => r.name === role);
|
|
161
162
|
const showOfficer = hasPermission(selectedRole?.permissions, "tickets:create");
|
|
162
163
|
function reset() {
|
|
163
164
|
setUsername("");
|
|
@@ -237,7 +238,7 @@ function NewAccountDialog({
|
|
|
237
238
|
value: role,
|
|
238
239
|
onChange: (e) => setRole(e.target.value),
|
|
239
240
|
className: fieldClass,
|
|
240
|
-
children:
|
|
241
|
+
children: assignableRoles.map((r) => /* @__PURE__ */ jsx("option", { value: r.name, children: r.label }, r.name))
|
|
241
242
|
}
|
|
242
243
|
)
|
|
243
244
|
] }),
|
|
@@ -357,6 +358,8 @@ function EditAccountDialog({
|
|
|
357
358
|
const [role, setRole] = React.useState(user.role);
|
|
358
359
|
const [officerId, setOfficerId] = React.useState(user.officerId ?? "");
|
|
359
360
|
const [submitting, setSubmitting] = React.useState(false);
|
|
361
|
+
const isSuperAdmin = user.role === "SUPER_ADMIN";
|
|
362
|
+
const assignableRoles = roles.filter((r) => r.name !== "SUPER_ADMIN");
|
|
360
363
|
const selectedRole = roles.find((r) => r.name === role);
|
|
361
364
|
const showOfficer = hasPermission(selectedRole?.permissions, "tickets:create");
|
|
362
365
|
async function submit(e) {
|
|
@@ -430,7 +433,8 @@ function EditAccountDialog({
|
|
|
430
433
|
value: role,
|
|
431
434
|
onChange: (e) => setRole(e.target.value),
|
|
432
435
|
className: fieldClass,
|
|
433
|
-
|
|
436
|
+
disabled: isSuperAdmin,
|
|
437
|
+
children: isSuperAdmin ? /* @__PURE__ */ jsx("option", { value: user.role, children: user.roleLabel ?? user.role }) : assignableRoles.map((r) => /* @__PURE__ */ jsx("option", { value: r.name, children: r.label }, r.name))
|
|
434
438
|
}
|
|
435
439
|
)
|
|
436
440
|
] }),
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter } from '../chunk-3YKVH4Y7.js';
|
|
3
2
|
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from '../chunk-V7VQVDWS.js';
|
|
4
|
-
import {
|
|
3
|
+
import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter } from '../chunk-3YKVH4Y7.js';
|
|
5
4
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
|
|
5
|
+
import { Label } from '../chunk-XQTVSNHC.js';
|
|
6
6
|
import { Input } from '../chunk-K3KIBHJF.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-
|
|
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';
|
|
@@ -12,8 +12,8 @@ import '../chunk-BVI5XDDA.js';
|
|
|
12
12
|
import { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../chunk-SETIN6XP.js';
|
|
13
13
|
import '../chunk-OWCGEEAZ.js';
|
|
14
14
|
import '../chunk-55FQP2DO.js';
|
|
15
|
-
import { Label } from '../chunk-XQTVSNHC.js';
|
|
16
15
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
|
|
16
|
+
import { Label } from '../chunk-XQTVSNHC.js';
|
|
17
17
|
import { Input } from '../chunk-K3KIBHJF.js';
|
|
18
18
|
import { Button } from '../chunk-I4WDVYHX.js';
|
|
19
19
|
import { useFormatters, useOvrConfig } from '../chunk-TJSNVTVB.js';
|
|
@@ -7,7 +7,7 @@ import { Input } from '../chunk-K3KIBHJF.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-
|
|
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';
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { Card, CardContent } from '../chunk-SETIN6XP.js';
|
|
3
3
|
import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
|
|
4
4
|
import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
|
|
5
|
-
import { Label } from '../chunk-XQTVSNHC.js';
|
|
6
5
|
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
|
|
6
|
+
import { Label } from '../chunk-XQTVSNHC.js';
|
|
7
7
|
import { Input } from '../chunk-K3KIBHJF.js';
|
|
8
8
|
import { Button } from '../chunk-I4WDVYHX.js';
|
|
9
9
|
import { useCopy } from '../chunk-TJSNVTVB.js';
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import { Checkbox } from '../chunk-BBQBKQA4.js';
|
|
3
3
|
import { Card, CardContent } from '../chunk-SETIN6XP.js';
|
|
4
4
|
import { Badge } from '../chunk-55FQP2DO.js';
|
|
5
|
-
import { Label } from '../chunk-XQTVSNHC.js';
|
|
6
5
|
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
|
|
6
|
+
import { Label } from '../chunk-XQTVSNHC.js';
|
|
7
7
|
import { Input } from '../chunk-K3KIBHJF.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-
|
|
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';
|
|
@@ -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 };
|
|
@@ -5,8 +5,8 @@ import { Card, CardContent } from '../chunk-SETIN6XP.js';
|
|
|
5
5
|
import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
|
|
6
6
|
import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
|
|
7
7
|
import { Badge } from '../chunk-55FQP2DO.js';
|
|
8
|
-
import { Label } from '../chunk-XQTVSNHC.js';
|
|
9
8
|
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
|
|
9
|
+
import { Label } from '../chunk-XQTVSNHC.js';
|
|
10
10
|
import { Input } from '../chunk-K3KIBHJF.js';
|
|
11
11
|
import { Button } from '../chunk-I4WDVYHX.js';
|
|
12
12
|
import { useCopy } from '../chunk-TJSNVTVB.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,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';
|
package/dist/ui-config.d.ts
CHANGED
|
@@ -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-
|
|
4
|
+
import { D as Dictionary } from './types-DNEO6wrO.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import './types.js';
|
|
7
7
|
|
package/dist/ui-server.d.ts
CHANGED
|
@@ -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-
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gelabs/ovr",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
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",
|
|
@@ -158,14 +158,14 @@
|
|
|
158
158
|
"react-dom": "19.2.4",
|
|
159
159
|
"tsup": "^8.4.0",
|
|
160
160
|
"typescript": "^5",
|
|
161
|
-
"@gelabs/ovr-
|
|
161
|
+
"@gelabs/ovr-auth": "0.0.0",
|
|
162
|
+
"@gelabs/ovr-data": "0.0.0",
|
|
163
|
+
"@gelabs/ovr-types": "0.0.0",
|
|
162
164
|
"@gelabs/ovr-offline": "0.0.0",
|
|
163
165
|
"@gelabs/ovr-core": "0.0.0",
|
|
164
166
|
"@gelabs/ovr-ui": "0.0.0",
|
|
165
|
-
"@gelabs/ovr-
|
|
166
|
-
"@gelabs/ovr-
|
|
167
|
-
"@gelabs/ovr-runtime": "0.0.0",
|
|
168
|
-
"@gelabs/ovr-auth": "0.0.0"
|
|
167
|
+
"@gelabs/ovr-config": "0.0.0",
|
|
168
|
+
"@gelabs/ovr-runtime": "0.0.0"
|
|
169
169
|
},
|
|
170
170
|
"scripts": {
|
|
171
171
|
"build": "tsup && node scripts/copy-assets.mjs",
|