@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,298 @@
1
+ // ../ovr-core/src/i18n/base.ts
2
+ var baseCopy = {
3
+ app: {
4
+ name: "e-OVR",
5
+ tagline: "Online Ordinance Violation Receipt",
6
+ description: "Issue, look up, and settle traffic and ordinance violation tickets online."
7
+ },
8
+ common: {
9
+ search: "Search",
10
+ clear: "Clear",
11
+ cancel: "Cancel",
12
+ confirm: "Confirm",
13
+ back: "Back",
14
+ print: "Print",
15
+ payNow: "Pay now",
16
+ payFine: "Pay fine",
17
+ loading: "Loading\u2026",
18
+ notFound: "Not found",
19
+ amountDue: "Amount due",
20
+ totalDue: "Total amount due",
21
+ dueDate: "Due date",
22
+ status: "Status"
23
+ },
24
+ landing: {
25
+ heroTitle: "Settle violations online \u2014 fast, clear, and official.",
26
+ heroSubtitle: "The {municipality}'s modern portal for traffic and ordinance violation receipts.",
27
+ citizenCardTitle: "I have a ticket",
28
+ citizenCardBody: "Look up your Ordinance Violation Receipt, review the details, and pay your fine online.",
29
+ citizenCardCta: "Find my ticket",
30
+ adminCardTitle: "I'm an enforcer",
31
+ adminCardBody: "Issue a violation ticket on the spot and manage issued receipts.",
32
+ adminCardCta: "Open enforcer portal"
33
+ },
34
+ citizen: {
35
+ searchTitle: "OVR Ticket Search",
36
+ searchHelp: "Enter your OVR ticket number and last name to retrieve your violation record.",
37
+ ticketNoLabel: "OVR Ticket No.",
38
+ lastNameLabel: "Last name",
39
+ euaLabel: "I accept the End-User Agreement",
40
+ searchCta: "Search ticket",
41
+ notFoundTitle: "No matching ticket",
42
+ notFoundBody: "We couldn't find a ticket with that number and last name. Check your details and try again.",
43
+ home: {
44
+ title: "Find and settle your violation receipt",
45
+ subtitle: "Enter your OVR ticket number and last name to view your Order of Payment and pay online.",
46
+ searchCta: "Find my ticket",
47
+ step1Title: "Find your ticket",
48
+ step1Body: "Search using your OVR ticket number and last name.",
49
+ step2Title: "Review the details",
50
+ step2Body: "Check the violation, the basic fines, and any surcharge.",
51
+ step3Title: "Pay online",
52
+ step3Body: "Settle via GCash, Maya, or Landbank and keep your receipt."
53
+ },
54
+ ticket: {
55
+ orderOfPayment: "Order of Payment",
56
+ violationDetails: "Violation details",
57
+ reminders: "Reminders & end-user notice",
58
+ payFine: "Pay fine",
59
+ printReceipt: "Print receipt",
60
+ viewReceipt: "View / print receipt",
61
+ backToSearch: "Back to search",
62
+ alreadyPaid: "This ticket has already been paid.",
63
+ history: {
64
+ title: "Violation history",
65
+ subtitle: "All OVR tickets on record under this name.",
66
+ current: "Current",
67
+ empty: "No other violation records found under this name.",
68
+ colTicketNo: "OVR Ticket No.",
69
+ colDate: "Apprehended",
70
+ colViolations: "Violation(s)",
71
+ colStatus: "Status",
72
+ colAmount: "Amount"
73
+ }
74
+ },
75
+ pay: {
76
+ title: "Pay your fine",
77
+ subtitle: "Choose a payment method to settle this violation.",
78
+ choose: "Choose payment method",
79
+ payNow: "Pay",
80
+ processing: "Processing payment\u2026",
81
+ secure: "Simulated checkout \u2014 no real payment is processed.",
82
+ success: "Payment successful \u2014 your receipt is ready.",
83
+ qr: {
84
+ title: "Scan to pay",
85
+ instruction: "Open your e-wallet app, scan this QR, then tap below once your payment is complete.",
86
+ placeholderNote: "Demo placeholder \u2014 the official merchant QR will appear here once the payment gateway is live.",
87
+ amountToPay: "Amount to pay",
88
+ confirm: "I've completed payment",
89
+ cancel: "Cancel"
90
+ }
91
+ }
92
+ },
93
+ admin: {
94
+ portal: "Enforcer Portal",
95
+ dashboard: "Dashboard",
96
+ tickets: "Tickets",
97
+ issueTicket: "Issue ticket",
98
+ accounts: "Accounts",
99
+ roles: "Roles",
100
+ officers: "Officers",
101
+ violations: "Violations",
102
+ logs: "Activity log",
103
+ more: "More",
104
+ signOut: "Sign out",
105
+ signOutConfirmTitle: "Sign out?",
106
+ signOutConfirmBody: "You'll need to sign in again to issue or manage tickets.",
107
+ cancel: "Cancel",
108
+ newTicketTitle: "Issue Violation Ticket",
109
+ accountsPage: {
110
+ title: "Accounts",
111
+ subtitle: "Create and manage who can sign in to the enforcer portal. Each account's role decides what it can see and do.",
112
+ newAccount: "New account",
113
+ edit: "Edit",
114
+ editTitle: "Edit account",
115
+ saveChanges: "Save changes",
116
+ username: "Username",
117
+ password: "Password",
118
+ role: "Role",
119
+ officer: "Linked officer",
120
+ officerNone: "\u2014 None \u2014",
121
+ officerHint: "Link an enforcer to an officer record so issued tickets are attributed.",
122
+ status: "Status",
123
+ active: "Active",
124
+ inactive: "Inactive",
125
+ created: "Created",
126
+ actions: "Actions",
127
+ create: "Create account",
128
+ creating: "Creating\u2026",
129
+ deactivate: "Deactivate",
130
+ activate: "Activate",
131
+ resetPassword: "Reset password",
132
+ newPassword: "New password",
133
+ save: "Save",
134
+ saving: "Saving\u2026",
135
+ cancel: "Cancel",
136
+ empty: "No accounts yet \u2014 create the first one.",
137
+ you: "You"
138
+ },
139
+ rolesPage: {
140
+ title: "Roles & permissions",
141
+ subtitle: "Define what each role can do. Create custom roles, set their permissions, then assign them to accounts.",
142
+ newRole: "New role",
143
+ roleName: "Role name",
144
+ roleNamePlaceholder: "e.g. Cashier, Supervisor",
145
+ permissions: "Permissions",
146
+ editPermissions: "Edit permissions",
147
+ noPermissions: "No permissions",
148
+ permissionsCount: "permissions",
149
+ system: "System",
150
+ custom: "Custom",
151
+ create: "Create role",
152
+ creating: "Creating\u2026",
153
+ save: "Save",
154
+ saving: "Saving\u2026",
155
+ saved: "Saved",
156
+ cancel: "Cancel",
157
+ delete: "Delete",
158
+ deleteConfirmTitle: "Delete this role?",
159
+ deleteConfirmBody: "Move any accounts off this role first. This can't be undone.",
160
+ lockedHint: "Super Admin always keeps account & role management.",
161
+ empty: "No roles yet \u2014 create the first one.",
162
+ inUseSuffix: "in use"
163
+ },
164
+ logsPage: {
165
+ title: "Activity log",
166
+ subtitle: "Audit trail of what accounts did \u2014 sign-ins, ticket issuance, and account & role changes.",
167
+ allActions: "All actions",
168
+ search: "Search actor or detail\u2026",
169
+ actor: "Actor",
170
+ action: "Action",
171
+ detail: "Detail",
172
+ when: "When",
173
+ empty: "No activity recorded yet.",
174
+ system: "system"
175
+ },
176
+ officersPage: {
177
+ title: "Apprehending officers",
178
+ subtitle: "Officers who apprehend violations \u2014 shown in the Issue-Ticket form and linked to enforcer accounts.",
179
+ newOfficer: "New officer",
180
+ name: "Full name",
181
+ namePlaceholder: "e.g. DELA CRUZ, JUAN P.",
182
+ badge: "Badge no.",
183
+ badgePlaceholder: "e.g. A176",
184
+ office: "Office",
185
+ officePlaceholder: "e.g. POSO",
186
+ edit: "Edit",
187
+ editTitle: "Edit officer",
188
+ create: "Add officer",
189
+ creating: "Adding\u2026",
190
+ save: "Save",
191
+ saving: "Saving\u2026",
192
+ cancel: "Cancel",
193
+ delete: "Remove",
194
+ deleteConfirmTitle: "Remove this officer?",
195
+ deleteConfirmBody: "This can't be undone. Officers with issued tickets or a linked account can't be removed.",
196
+ empty: "No officers yet \u2014 add the first one.",
197
+ actions: "Actions"
198
+ },
199
+ violationsPage: {
200
+ title: "Violation catalog",
201
+ subtitle: "The ordinance / violation schedule enforcers issue against. Archived entries are hidden from the Issue-Ticket form but kept for old tickets.",
202
+ newViolation: "New violation",
203
+ code: "Code",
204
+ codePlaceholder: "e.g. ORD 2021-05 S.4",
205
+ titleLabel: "Title",
206
+ titlePlaceholder: "e.g. No helmet (driver)",
207
+ category: "Category",
208
+ categoryTraffic: "Traffic",
209
+ categoryOrdinance: "Ordinance",
210
+ fine: "Basic fine (\u20B1)",
211
+ finePlaceholder: "e.g. 500",
212
+ legalText: "Legal basis (optional)",
213
+ legalTextPlaceholder: "e.g. Sec. 4, Municipal Ordinance No. 2021-05",
214
+ status: "Status",
215
+ active: "Active",
216
+ archived: "Archived",
217
+ edit: "Edit",
218
+ editTitle: "Edit violation",
219
+ create: "Add violation",
220
+ creating: "Adding\u2026",
221
+ save: "Save",
222
+ saving: "Saving\u2026",
223
+ cancel: "Cancel",
224
+ archive: "Archive",
225
+ restore: "Restore",
226
+ archiveConfirmTitle: "Archive this violation?",
227
+ archiveConfirmBody: "It will be hidden from the Issue-Ticket form. Already-issued tickets keep their copy, and you can restore it anytime.",
228
+ empty: "No violations yet \u2014 add the first one.",
229
+ actions: "Actions"
230
+ },
231
+ notifications: {
232
+ title: "Notifications",
233
+ subtitle: "Tickets that need attention \u2014 overdue and outstanding.",
234
+ empty: "You're all caught up.",
235
+ overdue: "Overdue",
236
+ outstanding: "Outstanding",
237
+ viewAll: "View all"
238
+ },
239
+ changePassword: {
240
+ title: "Change password",
241
+ subtitle: "Enter your current password, then your new one.",
242
+ current: "Current password",
243
+ new: "New password",
244
+ confirm: "Confirm new password",
245
+ submit: "Update password",
246
+ saving: "Updating\u2026",
247
+ cancel: "Cancel",
248
+ mismatch: "New passwords don't match.",
249
+ success: "Password updated."
250
+ },
251
+ sync: {
252
+ offline: "Offline",
253
+ syncing: "Syncing\u2026",
254
+ synced: "Synced",
255
+ pending: "pending sync",
256
+ // e.g. "3 pending sync"
257
+ notSynced: "Not synced",
258
+ willSync: "Saved on this device \u2014 will sync when back online."
259
+ }
260
+ }
261
+ };
262
+
263
+ // ../ovr-core/src/i18n/merge.ts
264
+ function isObject(v) {
265
+ return typeof v === "object" && v !== null && !Array.isArray(v);
266
+ }
267
+ function deepMerge(base, override) {
268
+ if (!isObject(base) || !isObject(override)) {
269
+ return override === void 0 ? base : override;
270
+ }
271
+ const out = { ...base };
272
+ for (const k of Object.keys(override)) {
273
+ out[k] = deepMerge(
274
+ base[k],
275
+ override[k]
276
+ );
277
+ }
278
+ return out;
279
+ }
280
+ function interpolate(node, vars) {
281
+ if (typeof node === "string") {
282
+ return node.replace(/\{(\w+)\}/g, (_, k) => vars[k] ?? `{${k}}`);
283
+ }
284
+ if (isObject(node)) {
285
+ const out = {};
286
+ for (const k of Object.keys(node)) {
287
+ out[k] = interpolate(node[k], vars);
288
+ }
289
+ return out;
290
+ }
291
+ return node;
292
+ }
293
+ function mergeCopy(overrides = {}, municipality) {
294
+ const merged = deepMerge(baseCopy, overrides);
295
+ return interpolate(merged, { municipality: municipality?.name ?? "" });
296
+ }
297
+
298
+ export { baseCopy, mergeCopy };
@@ -1,6 +1,6 @@
1
1
  import { Separator } from './chunk-NSCIBSCW.js';
2
- import { Money } from './chunk-3KIDW4LT.js';
3
- import { useFormatters, useOvrConfig } from './chunk-E2D7QT6N.js';
2
+ import { Money } from './chunk-BVI5XDDA.js';
3
+ import { useFormatters, useOvrConfig } from './chunk-TJSNVTVB.js';
4
4
  import { cn } from './chunk-77QBZC7J.js';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
6
6
 
@@ -1,5 +1,5 @@
1
+ import { Money } from './chunk-BVI5XDDA.js';
1
2
  import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from './chunk-OWCGEEAZ.js';
2
- import { Money } from './chunk-3KIDW4LT.js';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
 
5
5
  function ViolationsTable({
@@ -1,5 +1,5 @@
1
- import { MunicipalSeal } from './chunk-IF5UAVIE.js';
2
- import { useOvrConfig } from './chunk-E2D7QT6N.js';
1
+ import { MunicipalSeal } from './chunk-YC7G2IOZ.js';
2
+ import { useOvrConfig } from './chunk-TJSNVTVB.js';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
 
5
5
  function OfficialHeader() {
@@ -1,4 +1,4 @@
1
- import { createFormatters } from './chunk-B634JHKZ.js';
1
+ import { createFormatters } from './chunk-BI4EGLPG.js';
2
2
  import * as React2 from 'react';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
@@ -1,8 +1,8 @@
1
1
  import { Alert, AlertDescription } from './chunk-EYFZWQ4J.js';
2
- import { Money } from './chunk-3KIDW4LT.js';
2
+ import { Money } from './chunk-BVI5XDDA.js';
3
3
  import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from './chunk-M35R6JLA.js';
4
4
  import { Button } from './chunk-I4WDVYHX.js';
5
- import { useCopy } from './chunk-E2D7QT6N.js';
5
+ import { useCopy } from './chunk-TJSNVTVB.js';
6
6
  import * as React from 'react';
7
7
  import { toast } from 'sonner';
8
8
  import { QrCode, Loader2, Lock } from 'lucide-react';
@@ -0,0 +1,237 @@
1
+ import { cn } from './chunk-77QBZC7J.js';
2
+ import { Menu } from '@base-ui/react/menu';
3
+ import { ChevronRightIcon, CheckIcon } from 'lucide-react';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ function DropdownMenu({ ...props }) {
7
+ return /* @__PURE__ */ jsx(Menu.Root, { "data-slot": "dropdown-menu", ...props });
8
+ }
9
+ function DropdownMenuPortal({ ...props }) {
10
+ return /* @__PURE__ */ jsx(Menu.Portal, { "data-slot": "dropdown-menu-portal", ...props });
11
+ }
12
+ function DropdownMenuTrigger({ ...props }) {
13
+ return /* @__PURE__ */ jsx(Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
14
+ }
15
+ function DropdownMenuContent({
16
+ align = "start",
17
+ alignOffset = 0,
18
+ side = "bottom",
19
+ sideOffset = 4,
20
+ className,
21
+ ...props
22
+ }) {
23
+ return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(
24
+ Menu.Positioner,
25
+ {
26
+ className: "isolate z-50 outline-none",
27
+ align,
28
+ alignOffset,
29
+ side,
30
+ sideOffset,
31
+ children: /* @__PURE__ */ jsx(
32
+ Menu.Popup,
33
+ {
34
+ "data-slot": "dropdown-menu-content",
35
+ className: cn("z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95", className),
36
+ ...props
37
+ }
38
+ )
39
+ }
40
+ ) });
41
+ }
42
+ function DropdownMenuGroup({ ...props }) {
43
+ return /* @__PURE__ */ jsx(Menu.Group, { "data-slot": "dropdown-menu-group", ...props });
44
+ }
45
+ function DropdownMenuLabel({
46
+ className,
47
+ inset,
48
+ ...props
49
+ }) {
50
+ return /* @__PURE__ */ jsx(
51
+ Menu.GroupLabel,
52
+ {
53
+ "data-slot": "dropdown-menu-label",
54
+ "data-inset": inset,
55
+ className: cn(
56
+ "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
57
+ className
58
+ ),
59
+ ...props
60
+ }
61
+ );
62
+ }
63
+ function DropdownMenuItem({
64
+ className,
65
+ inset,
66
+ variant = "default",
67
+ ...props
68
+ }) {
69
+ return /* @__PURE__ */ jsx(
70
+ Menu.Item,
71
+ {
72
+ "data-slot": "dropdown-menu-item",
73
+ "data-inset": inset,
74
+ "data-variant": variant,
75
+ className: cn(
76
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
77
+ className
78
+ ),
79
+ ...props
80
+ }
81
+ );
82
+ }
83
+ function DropdownMenuSub({ ...props }) {
84
+ return /* @__PURE__ */ jsx(Menu.SubmenuRoot, { "data-slot": "dropdown-menu-sub", ...props });
85
+ }
86
+ function DropdownMenuSubTrigger({
87
+ className,
88
+ inset,
89
+ children,
90
+ ...props
91
+ }) {
92
+ return /* @__PURE__ */ jsxs(
93
+ Menu.SubmenuTrigger,
94
+ {
95
+ "data-slot": "dropdown-menu-sub-trigger",
96
+ "data-inset": inset,
97
+ className: cn(
98
+ "flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-popup-open:bg-accent data-popup-open:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
99
+ className
100
+ ),
101
+ ...props,
102
+ children: [
103
+ children,
104
+ /* @__PURE__ */ jsx(ChevronRightIcon, { className: "ml-auto" })
105
+ ]
106
+ }
107
+ );
108
+ }
109
+ function DropdownMenuSubContent({
110
+ align = "start",
111
+ alignOffset = -3,
112
+ side = "right",
113
+ sideOffset = 0,
114
+ className,
115
+ ...props
116
+ }) {
117
+ return /* @__PURE__ */ jsx(
118
+ DropdownMenuContent,
119
+ {
120
+ "data-slot": "dropdown-menu-sub-content",
121
+ className: cn("w-auto min-w-[96px] rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className),
122
+ align,
123
+ alignOffset,
124
+ side,
125
+ sideOffset,
126
+ ...props
127
+ }
128
+ );
129
+ }
130
+ function DropdownMenuCheckboxItem({
131
+ className,
132
+ children,
133
+ checked,
134
+ inset,
135
+ ...props
136
+ }) {
137
+ return /* @__PURE__ */ jsxs(
138
+ Menu.CheckboxItem,
139
+ {
140
+ "data-slot": "dropdown-menu-checkbox-item",
141
+ "data-inset": inset,
142
+ className: cn(
143
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
144
+ className
145
+ ),
146
+ checked,
147
+ ...props,
148
+ children: [
149
+ /* @__PURE__ */ jsx(
150
+ "span",
151
+ {
152
+ className: "pointer-events-none absolute right-2 flex items-center justify-center",
153
+ "data-slot": "dropdown-menu-checkbox-item-indicator",
154
+ children: /* @__PURE__ */ jsx(Menu.CheckboxItemIndicator, { children: /* @__PURE__ */ jsx(
155
+ CheckIcon,
156
+ {}
157
+ ) })
158
+ }
159
+ ),
160
+ children
161
+ ]
162
+ }
163
+ );
164
+ }
165
+ function DropdownMenuRadioGroup({ ...props }) {
166
+ return /* @__PURE__ */ jsx(
167
+ Menu.RadioGroup,
168
+ {
169
+ "data-slot": "dropdown-menu-radio-group",
170
+ ...props
171
+ }
172
+ );
173
+ }
174
+ function DropdownMenuRadioItem({
175
+ className,
176
+ children,
177
+ inset,
178
+ ...props
179
+ }) {
180
+ return /* @__PURE__ */ jsxs(
181
+ Menu.RadioItem,
182
+ {
183
+ "data-slot": "dropdown-menu-radio-item",
184
+ "data-inset": inset,
185
+ className: cn(
186
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
187
+ className
188
+ ),
189
+ ...props,
190
+ children: [
191
+ /* @__PURE__ */ jsx(
192
+ "span",
193
+ {
194
+ className: "pointer-events-none absolute right-2 flex items-center justify-center",
195
+ "data-slot": "dropdown-menu-radio-item-indicator",
196
+ children: /* @__PURE__ */ jsx(Menu.RadioItemIndicator, { children: /* @__PURE__ */ jsx(
197
+ CheckIcon,
198
+ {}
199
+ ) })
200
+ }
201
+ ),
202
+ children
203
+ ]
204
+ }
205
+ );
206
+ }
207
+ function DropdownMenuSeparator({
208
+ className,
209
+ ...props
210
+ }) {
211
+ return /* @__PURE__ */ jsx(
212
+ Menu.Separator,
213
+ {
214
+ "data-slot": "dropdown-menu-separator",
215
+ className: cn("-mx-1 my-1 h-px bg-border", className),
216
+ ...props
217
+ }
218
+ );
219
+ }
220
+ function DropdownMenuShortcut({
221
+ className,
222
+ ...props
223
+ }) {
224
+ return /* @__PURE__ */ jsx(
225
+ "span",
226
+ {
227
+ "data-slot": "dropdown-menu-shortcut",
228
+ className: cn(
229
+ "ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground",
230
+ className
231
+ ),
232
+ ...props
233
+ }
234
+ );
235
+ }
236
+
237
+ export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger };
@@ -0,0 +1,98 @@
1
+ // ../ovr-types/src/index.ts
2
+ var PERMISSION_CATALOG = [
3
+ { key: "dashboard:view", label: "View dashboard", description: "See the admin dashboard and statistics." },
4
+ { key: "tickets:view", label: "View tickets", description: "Browse and search issued tickets." },
5
+ { key: "tickets:create", label: "Issue tickets", description: "Create new violation tickets." },
6
+ { key: "accounts:manage", label: "Manage accounts", description: "Create and manage user accounts." },
7
+ { key: "roles:manage", label: "Manage roles", description: "Create roles and set their permissions." },
8
+ { key: "officers:manage", label: "Manage officers", description: "Add, edit, and remove apprehending officers." },
9
+ { key: "violations:manage", label: "Manage violations", description: "Add, edit, and archive the violation / ordinance catalog." },
10
+ { key: "logs:view", label: "View activity logs", description: "Browse the audit trail of account actions." },
11
+ { key: "notifications:view", label: "View notifications", description: "See the alert bell for overdue / pending tickets." }
12
+ ];
13
+ var ALL_PERMISSIONS = PERMISSION_CATALOG.map((p) => p.key);
14
+ var SYSTEM_ROLES = [
15
+ {
16
+ name: "SUPER_ADMIN",
17
+ label: "Super Admin",
18
+ isSystem: true,
19
+ permissions: [
20
+ "dashboard:view",
21
+ "tickets:view",
22
+ "tickets:create",
23
+ "accounts:manage",
24
+ "roles:manage",
25
+ "officers:manage",
26
+ "violations:manage",
27
+ "logs:view",
28
+ "notifications:view"
29
+ ]
30
+ },
31
+ {
32
+ name: "ADMIN",
33
+ label: "Administrator",
34
+ isSystem: true,
35
+ permissions: [
36
+ "dashboard:view",
37
+ "tickets:view",
38
+ "tickets:create",
39
+ "officers:manage",
40
+ "violations:manage",
41
+ "logs:view",
42
+ "notifications:view"
43
+ ]
44
+ },
45
+ {
46
+ name: "ENFORCER",
47
+ label: "Enforcer",
48
+ isSystem: true,
49
+ permissions: ["tickets:view", "tickets:create", "notifications:view"]
50
+ }
51
+ ];
52
+ var DEFAULT_ROLE_NAME = "ENFORCER";
53
+ var SUPER_ADMIN_LOCKED_PERMISSIONS = ["accounts:manage", "roles:manage"];
54
+ function hasPermission(permissions, permission) {
55
+ return !!permissions && permissions.includes(permission);
56
+ }
57
+ var ACTIVITY_ACTIONS = [
58
+ "auth.login",
59
+ "auth.logout",
60
+ "ticket.issued",
61
+ "account.create",
62
+ "account.update",
63
+ "account.activate",
64
+ "account.deactivate",
65
+ "account.password_reset",
66
+ "account.password_change",
67
+ "role.create",
68
+ "role.update",
69
+ "role.delete",
70
+ "officer.create",
71
+ "officer.update",
72
+ "officer.delete",
73
+ "violation.create",
74
+ "violation.update",
75
+ "violation.delete"
76
+ ];
77
+ var ACTIVITY_ACTION_LABELS = {
78
+ "auth.login": "Signed in",
79
+ "auth.logout": "Signed out",
80
+ "ticket.issued": "Issued ticket",
81
+ "account.create": "Created account",
82
+ "account.update": "Updated account",
83
+ "account.activate": "Activated account",
84
+ "account.deactivate": "Deactivated account",
85
+ "account.password_reset": "Reset password",
86
+ "account.password_change": "Changed own password",
87
+ "role.create": "Created role",
88
+ "role.update": "Updated role",
89
+ "role.delete": "Deleted role",
90
+ "officer.create": "Added officer",
91
+ "officer.update": "Updated officer",
92
+ "officer.delete": "Removed officer",
93
+ "violation.create": "Added violation",
94
+ "violation.update": "Updated violation",
95
+ "violation.delete": "Archived violation"
96
+ };
97
+
98
+ export { ACTIVITY_ACTIONS, ACTIVITY_ACTION_LABELS, ALL_PERMISSIONS, DEFAULT_ROLE_NAME, PERMISSION_CATALOG, SUPER_ADMIN_LOCKED_PERMISSIONS, SYSTEM_ROLES, hasPermission };
@@ -1,5 +1,5 @@
1
1
  import { Seal } from './chunk-WOPU6DI7.js';
2
- import { useOvrConfig } from './chunk-E2D7QT6N.js';
2
+ import { useOvrConfig } from './chunk-TJSNVTVB.js';
3
3
  import { cn } from './chunk-77QBZC7J.js';
4
4
  import * as React from 'react';
5
5
  import { jsx } from 'react/jsx-runtime';