@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
@@ -1,238 +1,3 @@
1
1
  "use client";
2
- import { cn } from '../chunk-77QBZC7J.js';
3
- import { Menu } from '@base-ui/react/menu';
4
- import { ChevronRightIcon, CheckIcon } from 'lucide-react';
5
- import { jsx, jsxs } from 'react/jsx-runtime';
6
-
7
- function DropdownMenu({ ...props }) {
8
- return /* @__PURE__ */ jsx(Menu.Root, { "data-slot": "dropdown-menu", ...props });
9
- }
10
- function DropdownMenuPortal({ ...props }) {
11
- return /* @__PURE__ */ jsx(Menu.Portal, { "data-slot": "dropdown-menu-portal", ...props });
12
- }
13
- function DropdownMenuTrigger({ ...props }) {
14
- return /* @__PURE__ */ jsx(Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
15
- }
16
- function DropdownMenuContent({
17
- align = "start",
18
- alignOffset = 0,
19
- side = "bottom",
20
- sideOffset = 4,
21
- className,
22
- ...props
23
- }) {
24
- return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(
25
- Menu.Positioner,
26
- {
27
- className: "isolate z-50 outline-none",
28
- align,
29
- alignOffset,
30
- side,
31
- sideOffset,
32
- children: /* @__PURE__ */ jsx(
33
- Menu.Popup,
34
- {
35
- "data-slot": "dropdown-menu-content",
36
- 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),
37
- ...props
38
- }
39
- )
40
- }
41
- ) });
42
- }
43
- function DropdownMenuGroup({ ...props }) {
44
- return /* @__PURE__ */ jsx(Menu.Group, { "data-slot": "dropdown-menu-group", ...props });
45
- }
46
- function DropdownMenuLabel({
47
- className,
48
- inset,
49
- ...props
50
- }) {
51
- return /* @__PURE__ */ jsx(
52
- Menu.GroupLabel,
53
- {
54
- "data-slot": "dropdown-menu-label",
55
- "data-inset": inset,
56
- className: cn(
57
- "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
58
- className
59
- ),
60
- ...props
61
- }
62
- );
63
- }
64
- function DropdownMenuItem({
65
- className,
66
- inset,
67
- variant = "default",
68
- ...props
69
- }) {
70
- return /* @__PURE__ */ jsx(
71
- Menu.Item,
72
- {
73
- "data-slot": "dropdown-menu-item",
74
- "data-inset": inset,
75
- "data-variant": variant,
76
- className: cn(
77
- "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",
78
- className
79
- ),
80
- ...props
81
- }
82
- );
83
- }
84
- function DropdownMenuSub({ ...props }) {
85
- return /* @__PURE__ */ jsx(Menu.SubmenuRoot, { "data-slot": "dropdown-menu-sub", ...props });
86
- }
87
- function DropdownMenuSubTrigger({
88
- className,
89
- inset,
90
- children,
91
- ...props
92
- }) {
93
- return /* @__PURE__ */ jsxs(
94
- Menu.SubmenuTrigger,
95
- {
96
- "data-slot": "dropdown-menu-sub-trigger",
97
- "data-inset": inset,
98
- className: cn(
99
- "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",
100
- className
101
- ),
102
- ...props,
103
- children: [
104
- children,
105
- /* @__PURE__ */ jsx(ChevronRightIcon, { className: "ml-auto" })
106
- ]
107
- }
108
- );
109
- }
110
- function DropdownMenuSubContent({
111
- align = "start",
112
- alignOffset = -3,
113
- side = "right",
114
- sideOffset = 0,
115
- className,
116
- ...props
117
- }) {
118
- return /* @__PURE__ */ jsx(
119
- DropdownMenuContent,
120
- {
121
- "data-slot": "dropdown-menu-sub-content",
122
- 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),
123
- align,
124
- alignOffset,
125
- side,
126
- sideOffset,
127
- ...props
128
- }
129
- );
130
- }
131
- function DropdownMenuCheckboxItem({
132
- className,
133
- children,
134
- checked,
135
- inset,
136
- ...props
137
- }) {
138
- return /* @__PURE__ */ jsxs(
139
- Menu.CheckboxItem,
140
- {
141
- "data-slot": "dropdown-menu-checkbox-item",
142
- "data-inset": inset,
143
- className: cn(
144
- "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",
145
- className
146
- ),
147
- checked,
148
- ...props,
149
- children: [
150
- /* @__PURE__ */ jsx(
151
- "span",
152
- {
153
- className: "pointer-events-none absolute right-2 flex items-center justify-center",
154
- "data-slot": "dropdown-menu-checkbox-item-indicator",
155
- children: /* @__PURE__ */ jsx(Menu.CheckboxItemIndicator, { children: /* @__PURE__ */ jsx(
156
- CheckIcon,
157
- {}
158
- ) })
159
- }
160
- ),
161
- children
162
- ]
163
- }
164
- );
165
- }
166
- function DropdownMenuRadioGroup({ ...props }) {
167
- return /* @__PURE__ */ jsx(
168
- Menu.RadioGroup,
169
- {
170
- "data-slot": "dropdown-menu-radio-group",
171
- ...props
172
- }
173
- );
174
- }
175
- function DropdownMenuRadioItem({
176
- className,
177
- children,
178
- inset,
179
- ...props
180
- }) {
181
- return /* @__PURE__ */ jsxs(
182
- Menu.RadioItem,
183
- {
184
- "data-slot": "dropdown-menu-radio-item",
185
- "data-inset": inset,
186
- className: cn(
187
- "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",
188
- className
189
- ),
190
- ...props,
191
- children: [
192
- /* @__PURE__ */ jsx(
193
- "span",
194
- {
195
- className: "pointer-events-none absolute right-2 flex items-center justify-center",
196
- "data-slot": "dropdown-menu-radio-item-indicator",
197
- children: /* @__PURE__ */ jsx(Menu.RadioItemIndicator, { children: /* @__PURE__ */ jsx(
198
- CheckIcon,
199
- {}
200
- ) })
201
- }
202
- ),
203
- children
204
- ]
205
- }
206
- );
207
- }
208
- function DropdownMenuSeparator({
209
- className,
210
- ...props
211
- }) {
212
- return /* @__PURE__ */ jsx(
213
- Menu.Separator,
214
- {
215
- "data-slot": "dropdown-menu-separator",
216
- className: cn("-mx-1 my-1 h-px bg-border", className),
217
- ...props
218
- }
219
- );
220
- }
221
- function DropdownMenuShortcut({
222
- className,
223
- ...props
224
- }) {
225
- return /* @__PURE__ */ jsx(
226
- "span",
227
- {
228
- "data-slot": "dropdown-menu-shortcut",
229
- className: cn(
230
- "ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground",
231
- className
232
- ),
233
- ...props
234
- }
235
- );
236
- }
237
-
238
- export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger };
2
+ export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from '../chunk-V7VQVDWS.js';
3
+ import '../chunk-77QBZC7J.js';
@@ -1,127 +1,4 @@
1
1
  "use client";
2
- import { Button } from '../chunk-I4WDVYHX.js';
3
- import { cn } from '../chunk-77QBZC7J.js';
4
- import { Dialog } from '@base-ui/react/dialog';
5
- import { XIcon } from 'lucide-react';
6
- import { jsx, jsxs } from 'react/jsx-runtime';
7
-
8
- function Sheet({ ...props }) {
9
- return /* @__PURE__ */ jsx(Dialog.Root, { "data-slot": "sheet", ...props });
10
- }
11
- function SheetTrigger({ ...props }) {
12
- return /* @__PURE__ */ jsx(Dialog.Trigger, { "data-slot": "sheet-trigger", ...props });
13
- }
14
- function SheetClose({ ...props }) {
15
- return /* @__PURE__ */ jsx(Dialog.Close, { "data-slot": "sheet-close", ...props });
16
- }
17
- function SheetPortal({ ...props }) {
18
- return /* @__PURE__ */ jsx(Dialog.Portal, { "data-slot": "sheet-portal", ...props });
19
- }
20
- function SheetOverlay({ className, ...props }) {
21
- return /* @__PURE__ */ jsx(
22
- Dialog.Backdrop,
23
- {
24
- "data-slot": "sheet-overlay",
25
- className: cn(
26
- "fixed inset-0 z-50 bg-black/10 transition-opacity duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs",
27
- className
28
- ),
29
- ...props
30
- }
31
- );
32
- }
33
- function SheetContent({
34
- className,
35
- children,
36
- side = "right",
37
- showCloseButton = true,
38
- ...props
39
- }) {
40
- return /* @__PURE__ */ jsxs(SheetPortal, { children: [
41
- /* @__PURE__ */ jsx(SheetOverlay, {}),
42
- /* @__PURE__ */ jsxs(
43
- Dialog.Popup,
44
- {
45
- "data-slot": "sheet-content",
46
- "data-side": side,
47
- className: cn(
48
- "fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
49
- className
50
- ),
51
- ...props,
52
- children: [
53
- children,
54
- showCloseButton && /* @__PURE__ */ jsxs(
55
- Dialog.Close,
56
- {
57
- "data-slot": "sheet-close",
58
- render: /* @__PURE__ */ jsx(
59
- Button,
60
- {
61
- variant: "ghost",
62
- className: "absolute top-3 right-3",
63
- size: "icon-sm"
64
- }
65
- ),
66
- children: [
67
- /* @__PURE__ */ jsx(
68
- XIcon,
69
- {}
70
- ),
71
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
72
- ]
73
- }
74
- )
75
- ]
76
- }
77
- )
78
- ] });
79
- }
80
- function SheetHeader({ className, ...props }) {
81
- return /* @__PURE__ */ jsx(
82
- "div",
83
- {
84
- "data-slot": "sheet-header",
85
- className: cn("flex flex-col gap-0.5 p-4", className),
86
- ...props
87
- }
88
- );
89
- }
90
- function SheetFooter({ className, ...props }) {
91
- return /* @__PURE__ */ jsx(
92
- "div",
93
- {
94
- "data-slot": "sheet-footer",
95
- className: cn("mt-auto flex flex-col gap-2 p-4", className),
96
- ...props
97
- }
98
- );
99
- }
100
- function SheetTitle({ className, ...props }) {
101
- return /* @__PURE__ */ jsx(
102
- Dialog.Title,
103
- {
104
- "data-slot": "sheet-title",
105
- className: cn(
106
- "font-heading text-base font-medium text-foreground",
107
- className
108
- ),
109
- ...props
110
- }
111
- );
112
- }
113
- function SheetDescription({
114
- className,
115
- ...props
116
- }) {
117
- return /* @__PURE__ */ jsx(
118
- Dialog.Description,
119
- {
120
- "data-slot": "sheet-description",
121
- className: cn("text-sm text-muted-foreground", className),
122
- ...props
123
- }
124
- );
125
- }
126
-
127
- export { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger };
2
+ export { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from '../chunk-3YKVH4Y7.js';
3
+ import '../chunk-I4WDVYHX.js';
4
+ import '../chunk-77QBZC7J.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-CtBC5-TW.js';
4
+ import { D as Dictionary } from './types-B8MopM4b.js';
5
5
  import 'zod';
6
6
  import './types.js';
7
7
 
package/dist/ui-config.js CHANGED
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- export { OvrConfigProvider, ThemeProvider, useCopy, useFormatters, useOvrConfig, useTheme } from './chunk-E2D7QT6N.js';
3
- import './chunk-B634JHKZ.js';
2
+ export { OvrConfigProvider, ThemeProvider, useCopy, useFormatters, useOvrConfig, useTheme } from './chunk-TJSNVTVB.js';
3
+ import './chunk-BI4EGLPG.js';
@@ -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-CtBC5-TW.js';
3
+ import { D as Dictionary, C as CopyOverrides } from './types-B8MopM4b.js';
4
4
  import 'zod';
5
5
  import './types.js';
6
6
 
package/dist/ui-server.js CHANGED
@@ -1,5 +1,5 @@
1
- import { mergeCopy } from './chunk-5YYR37CF.js';
2
- import { createFormatters } from './chunk-B634JHKZ.js';
1
+ import { mergeCopy } from './chunk-DJMUW5T2.js';
2
+ import { createFormatters } from './chunk-BI4EGLPG.js';
3
3
  import 'server-only';
4
4
 
5
5
  var current = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gelabs/ovr",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
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-types": "0.0.0",
162
161
  "@gelabs/ovr-config": "0.0.0",
163
- "@gelabs/ovr-data": "0.0.0",
164
- "@gelabs/ovr-ui": "0.0.0",
165
162
  "@gelabs/ovr-offline": "0.0.0",
166
163
  "@gelabs/ovr-core": "0.0.0",
167
- "@gelabs/ovr-auth": "0.0.0",
168
- "@gelabs/ovr-runtime": "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
+ "@gelabs/ovr-runtime": "0.0.0",
168
+ "@gelabs/ovr-auth": "0.0.0"
169
169
  },
170
170
  "scripts": {
171
171
  "build": "tsup && node scripts/copy-assets.mjs",
@@ -0,0 +1,3 @@
1
+ -- AlterEnum
2
+ -- GE-013 RBAC: add the SUPER_ADMIN tier (manages accounts) above ADMIN/ENFORCER.
3
+ ALTER TYPE "UserRole" ADD VALUE 'SUPER_ADMIN';
@@ -0,0 +1,4 @@
1
+ -- AlterTable
2
+ -- GE-011: record the apprehending enforcer account (+ snapshot name) on a ticket.
3
+ ALTER TABLE "Ticket" ADD COLUMN "apprehendingEnforcerId" TEXT;
4
+ ALTER TABLE "Ticket" ADD COLUMN "apprehendingEnforcerName" TEXT;
@@ -0,0 +1,30 @@
1
+ -- GE-013 (custom roles): roles + permissions become editable DATA.
2
+
3
+ -- CreateTable
4
+ CREATE TABLE "Role" (
5
+ "name" TEXT NOT NULL,
6
+ "label" TEXT NOT NULL,
7
+ "isSystem" BOOLEAN NOT NULL DEFAULT false,
8
+ "permissions" TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[],
9
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
10
+ "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
11
+ CONSTRAINT "Role_pkey" PRIMARY KEY ("name")
12
+ );
13
+
14
+ -- Seed the system roles up-front (they must exist before the FK below, and so
15
+ -- existing User.role values 'ENFORCER'/'ADMIN'/'SUPER_ADMIN' satisfy it).
16
+ INSERT INTO "Role" ("name", "label", "isSystem", "permissions", "updatedAt") VALUES
17
+ ('SUPER_ADMIN', 'Super Admin', true, ARRAY['dashboard:view','tickets:view','tickets:create','accounts:manage','roles:manage'], CURRENT_TIMESTAMP),
18
+ ('ADMIN', 'Administrator', true, ARRAY['dashboard:view','tickets:view','tickets:create'], CURRENT_TIMESTAMP),
19
+ ('ENFORCER', 'Enforcer', true, ARRAY['tickets:view','tickets:create'], CURRENT_TIMESTAMP);
20
+
21
+ -- Convert User.role from the UserRole enum to a TEXT foreign key into Role.name.
22
+ ALTER TABLE "User" ALTER COLUMN "role" DROP DEFAULT;
23
+ ALTER TABLE "User" ALTER COLUMN "role" TYPE TEXT USING "role"::text;
24
+ ALTER TABLE "User" ALTER COLUMN "role" SET DEFAULT 'ENFORCER';
25
+
26
+ -- AddForeignKey
27
+ ALTER TABLE "User" ADD CONSTRAINT "User_role_fkey" FOREIGN KEY ("role") REFERENCES "Role"("name") ON DELETE RESTRICT ON UPDATE CASCADE;
28
+
29
+ -- DropEnum (no longer referenced)
30
+ DROP TYPE "UserRole";
@@ -0,0 +1,18 @@
1
+ -- CreateTable
2
+ -- GE-022: append-only audit trail of account actions.
3
+ CREATE TABLE "ActivityLog" (
4
+ "id" TEXT NOT NULL,
5
+ "actorId" TEXT,
6
+ "actorUsername" TEXT,
7
+ "action" TEXT NOT NULL,
8
+ "summary" TEXT NOT NULL,
9
+ "targetType" TEXT,
10
+ "targetId" TEXT,
11
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
12
+ CONSTRAINT "ActivityLog_pkey" PRIMARY KEY ("id")
13
+ );
14
+
15
+ -- CreateIndex
16
+ CREATE INDEX "ActivityLog_action_idx" ON "ActivityLog"("action");
17
+ CREATE INDEX "ActivityLog_actorId_idx" ON "ActivityLog"("actorId");
18
+ CREATE INDEX "ActivityLog_createdAt_idx" ON "ActivityLog"("createdAt");
@@ -0,0 +1,5 @@
1
+ -- GE-031 (violation catalog management): soft-delete + edit tracking.
2
+ -- `active` lets admins archive a violation (hidden from issuance) while keeping
3
+ -- it resolvable for already-issued tickets. Existing rows default to active.
4
+ ALTER TABLE "ViolationCatalog" ADD COLUMN "active" BOOLEAN NOT NULL DEFAULT true;
5
+ ALTER TABLE "ViolationCatalog" ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
@@ -42,11 +42,6 @@ enum PaymentStatus {
42
42
  CONTESTED
43
43
  }
44
44
 
45
- enum UserRole {
46
- ENFORCER
47
- ADMIN
48
- }
49
-
50
45
  model Officer {
51
46
  id String @id // slug, e.g. "off-novelo"
52
47
  name String // "NOVELO, RAYMUNDO V."
@@ -66,8 +61,10 @@ model ViolationCatalog {
66
61
  category ViolationCategory
67
62
  basicFine Decimal @db.Decimal(12, 2)
68
63
  legalText String?
64
+ active Boolean @default(true) // GE-031: false = archived (hidden from issuance)
69
65
 
70
66
  createdAt DateTime @default(now())
67
+ updatedAt DateTime @default(now()) @updatedAt
71
68
  }
72
69
 
73
70
  model Ticket {
@@ -94,6 +91,12 @@ model Ticket {
94
91
  remarks String?
95
92
  issuedBy String?
96
93
 
94
+ // GE-011: the enforcer ACCOUNT who apprehended (+ snapshot name for display).
95
+ // Soft reference to User.id — intentionally NOT a hard FK so the attribution
96
+ // survives if the account is later renamed or removed.
97
+ apprehendingEnforcerId String?
98
+ apprehendingEnforcerName String?
99
+
97
100
  officerId String
98
101
  officer Officer @relation(fields: [officerId], references: [id])
99
102
 
@@ -141,12 +144,30 @@ model Payment {
141
144
  paidAt DateTime
142
145
  }
143
146
 
147
+ // A role + its permission set (GE-013, custom roles). Permission keys come from
148
+ // the SDK catalog (@gelabs/ovr-types PERMISSION_CATALOG); the mapping is data.
149
+ model Role {
150
+ name String @id // "SUPER_ADMIN" / "ENFORCER" / custom slug e.g. "cashier"
151
+ label String // display name shown in the UI
152
+ isSystem Boolean @default(false) // system roles can't be renamed or deleted
153
+ permissions String[] // granted Permission keys
154
+
155
+ users User[]
156
+
157
+ createdAt DateTime @default(now())
158
+ updatedAt DateTime @updatedAt
159
+ }
160
+
144
161
  model User {
145
- id String @id @default(cuid())
146
- username String @unique
162
+ id String @id @default(cuid())
163
+ username String @unique
147
164
  passwordHash String
148
- role UserRole @default(ENFORCER)
149
- active Boolean @default(true)
165
+
166
+ // Role is DATA now (see model Role): a string FK so custom roles are allowed.
167
+ role String @default("ENFORCER")
168
+ roleRef Role @relation(fields: [role], references: [name])
169
+
170
+ active Boolean @default(true)
150
171
 
151
172
  // Links a login to an enforcer (so issued tickets can attribute the officer).
152
173
  officerId String? @unique
@@ -154,3 +175,21 @@ model User {
154
175
 
155
176
  createdAt DateTime @default(now())
156
177
  }
178
+
179
+ // Audit trail (GE-022): who did what, when. Append-only. Actor is a SOFT
180
+ // reference (snapshot username) so entries survive account deletion.
181
+ model ActivityLog {
182
+ id String @id @default(cuid())
183
+ actorId String?
184
+ actorUsername String?
185
+ action String // e.g. "auth.login", "account.create", "role.update"
186
+ summary String // human-readable one-liner
187
+ targetType String? // "account" | "role" | "ticket" | …
188
+ targetId String?
189
+
190
+ createdAt DateTime @default(now())
191
+
192
+ @@index([action])
193
+ @@index([actorId])
194
+ @@index([createdAt])
195
+ }