@hed-hog/core 0.0.279 → 0.0.286

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 (35) hide show
  1. package/dist/auth/auth.controller.d.ts +3 -3
  2. package/dist/auth/auth.service.d.ts +8 -8
  3. package/dist/file/file.controller.d.ts +2 -2
  4. package/dist/file/file.service.d.ts +4 -4
  5. package/dist/role/guards/role.guard.d.ts.map +1 -1
  6. package/dist/role/guards/role.guard.js +1 -1
  7. package/dist/role/guards/role.guard.js.map +1 -1
  8. package/dist/session/session.controller.d.ts +1 -1
  9. package/dist/session/session.service.d.ts +3 -3
  10. package/dist/setting/setting.controller.d.ts +3 -0
  11. package/dist/setting/setting.controller.d.ts.map +1 -1
  12. package/dist/setting/setting.controller.js +10 -0
  13. package/dist/setting/setting.controller.js.map +1 -1
  14. package/dist/setting/setting.service.d.ts +2 -1
  15. package/dist/setting/setting.service.d.ts.map +1 -1
  16. package/dist/setting/setting.service.js +51 -12
  17. package/dist/setting/setting.service.js.map +1 -1
  18. package/dist/user/user.controller.d.ts +2 -2
  19. package/dist/user/user.service.d.ts +6 -6
  20. package/hedhog/data/route.yaml +8 -0
  21. package/hedhog/frontend/app/ai_agent/page.tsx.ejs +72 -65
  22. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +1 -92
  23. package/hedhog/frontend/app/dashboard/page.tsx.ejs +2 -2
  24. package/hedhog/frontend/app/mail/log/page.tsx.ejs +37 -42
  25. package/hedhog/frontend/app/mail/template/page.tsx.ejs +176 -126
  26. package/hedhog/frontend/app/menu/page.tsx.ejs +45 -39
  27. package/hedhog/frontend/app/preferences/page.tsx.ejs +34 -121
  28. package/hedhog/frontend/app/roles/page.tsx.ejs +45 -46
  29. package/hedhog/frontend/app/users/page.tsx.ejs +71 -68
  30. package/hedhog/frontend/messages/en.json +7 -0
  31. package/hedhog/frontend/messages/pt.json +7 -0
  32. package/package.json +2 -2
  33. package/src/role/guards/role.guard.ts +9 -8
  34. package/src/setting/setting.controller.ts +21 -16
  35. package/src/setting/setting.service.ts +63 -17
@@ -24,6 +24,7 @@ export default function PreferencesPage() {
24
24
  const {
25
25
  currentTheme,
26
26
  setCurrentTheme,
27
+ refreshUserSettings,
27
28
  request,
28
29
  getSettingValue,
29
30
  setSettingValue,
@@ -32,115 +33,7 @@ export default function PreferencesPage() {
32
33
  } = useApp();
33
34
  const t = useTranslations('core.PreferencesPage');
34
35
 
35
- const applyThemeSettings = async (
36
- themeMode?: 'light' | 'dark' | 'system'
37
- ) => {
38
- try {
39
- const response: any = await request({
40
- url: '/setting/initial',
41
- method: 'GET',
42
- });
43
-
44
- const newSettings = response.data?.setting || {};
45
- localStorage.setItem('settings', JSON.stringify(newSettings));
46
-
47
- const root = document.documentElement;
48
- const effectiveTheme = themeMode || currentTheme || 'system';
49
- let resolvedTheme: 'light' | 'dark' = 'light';
50
-
51
- if (effectiveTheme === 'system') {
52
- const prefersDark = window.matchMedia(
53
- '(prefers-color-scheme: dark)'
54
- ).matches;
55
- resolvedTheme = prefersDark ? 'dark' : 'light';
56
- } else {
57
- resolvedTheme = effectiveTheme as 'light' | 'dark';
58
- }
59
-
60
- root.classList.remove('light', 'dark');
61
- root.classList.add(resolvedTheme);
62
-
63
- const existingStyle = document.getElementById('theme-custom-styles');
64
- if (existingStyle) {
65
- existingStyle.remove();
66
- }
67
-
68
- const styleTag = document.createElement('style');
69
- styleTag.id = 'theme-custom-styles';
70
- let cssRules = '';
71
-
72
- const addRule = (varName: string, settingKey: string) => {
73
- const hexColor = newSettings[settingKey];
74
- if (
75
- hexColor &&
76
- typeof hexColor === 'string' &&
77
- hexColor.startsWith('#')
78
- ) {
79
- cssRules += ` ${varName}: ${hexColor} !important;\n`;
80
- }
81
- };
82
-
83
- if (resolvedTheme === 'light') {
84
- cssRules += '@supports (color: lab(0% 0 0)) {\n';
85
- cssRules += ' html.light, .light, :root.light {\n';
86
- addRule('--primary', 'theme-primary-light');
87
- addRule('--bprogress-color', 'theme-primary-light');
88
- addRule('--primary-foreground', 'theme-primary-foreground-light');
89
- addRule('--secondary', 'theme-secondary-light');
90
- addRule('--secondary-foreground', 'theme-secondary-foreground-light');
91
- addRule('--accent', 'theme-accent-light');
92
- addRule('--accent-foreground', 'theme-accent-foreground-light');
93
- addRule('--muted', 'theme-muted-light');
94
- addRule('--muted-foreground', 'theme-muted-foreground-light');
95
- addRule('--background', 'theme-background-light');
96
- addRule('--foreground', 'theme-background-foreground-light');
97
- addRule('--card', 'theme-card-light');
98
- addRule('--card-foreground', 'theme-card-foreground-light');
99
- } else {
100
- cssRules += '@supports (color: lab(0% 0 0)) {\n';
101
- cssRules += ' html.dark, .dark, :root.dark {\n';
102
- addRule('--primary', 'theme-primary-dark');
103
- addRule('--bprogress-color', 'theme-primary-dark');
104
- addRule('--primary-foreground', 'theme-primary-foreground-dark');
105
- addRule('--secondary', 'theme-secondary-dark');
106
- addRule('--secondary-foreground', 'theme-secondary-foreground-dark');
107
- addRule('--accent', 'theme-accent-dark');
108
- addRule('--accent-foreground', 'theme-accent-foreground-dark');
109
- addRule('--muted', 'theme-muted-dark');
110
- addRule('--muted-foreground', 'theme-muted-foreground-dark');
111
- addRule('--background', 'theme-background-dark');
112
- addRule('--foreground', 'theme-background-foreground-dark');
113
- addRule('--card', 'theme-card-dark');
114
- addRule('--card-foreground', 'theme-card-foreground-dark');
115
- }
116
-
117
- if (newSettings['theme-radius']) {
118
- cssRules += ` --radius: ${newSettings['theme-radius']}rem !important;\n`;
119
- }
120
- if (newSettings['theme-text-size']) {
121
- cssRules += ` font-size: ${newSettings['theme-text-size']}rem !important;\n`;
122
- }
123
-
124
- cssRules += ' }\n';
125
- cssRules += '}\n';
126
-
127
- if (newSettings['theme-font']) {
128
- cssRules += `:root {\n`;
129
- cssRules += ` --font-sans: ${newSettings['theme-font']} !important;\n`;
130
- cssRules += `}\n`;
131
- cssRules += `html {\n`;
132
- cssRules += ` font-family: ${newSettings['theme-font']} !important;\n`;
133
- cssRules += `}\n`;
134
- }
135
-
136
- styleTag.textContent = cssRules;
137
- document.head.appendChild(styleTag);
138
- } catch (error) {
139
- console.error('Error applying theme settings:', error);
140
- }
141
- };
142
-
143
- // Busca as settings do grupo de localization
36
+ // Buspnpm grupo de localization
144
37
  const { data: localizationSettings, isLoading } = useQuery<
145
38
  PaginatedResult<Setting>
146
39
  >({
@@ -182,21 +75,41 @@ export default function PreferencesPage() {
182
75
  });
183
76
 
184
77
  const handleThemeChange = async (value: 'light' | 'dark' | 'system') => {
78
+ const previousTheme = currentTheme;
185
79
  setCurrentTheme(value);
186
- await request({
187
- url: '/profile/preferences',
188
- method: 'PUT',
189
- data: { theme: value },
190
- });
191
- await applyThemeSettings(value);
80
+
81
+ try {
82
+ await request({
83
+ url: '/profile/preferences',
84
+ method: 'PUT',
85
+ data: { theme: value },
86
+ });
87
+ await refreshUserSettings();
88
+ } catch (error) {
89
+ setCurrentTheme(previousTheme);
90
+ await refreshUserSettings();
91
+ showToastHandler(
92
+ 'error',
93
+ t('themeUpdateError') || 'Failed to update theme'
94
+ );
95
+ }
192
96
  };
193
97
 
194
- const handleLanguageChange = (code: string) => {
195
- request({
196
- url: '/profile/preferences',
197
- method: 'PUT',
198
- data: { language: code },
199
- });
98
+ const handleLanguageChange = async (code: string) => {
99
+ try {
100
+ await request({
101
+ url: '/profile/preferences',
102
+ method: 'PUT',
103
+ data: { language: code },
104
+ });
105
+ await refreshUserSettings();
106
+ } catch (error) {
107
+ showToastHandler(
108
+ 'error',
109
+ t('languageUpdateError') || 'Failed to update language'
110
+ );
111
+ throw error;
112
+ }
200
113
  };
201
114
 
202
115
  const handleDateFormatChange = async (value: string) => {
@@ -1,12 +1,24 @@
1
1
  'use client';
2
2
 
3
3
  import {
4
+ EmptyState,
5
+ Page,
4
6
  PageHeader,
5
7
  PaginationFooter,
6
8
  SearchBar,
7
9
  StatsCards,
8
10
  } from '@/components/entity-list';
9
11
  import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
12
+ import {
13
+ AlertDialog,
14
+ AlertDialogAction,
15
+ AlertDialogCancel,
16
+ AlertDialogContent,
17
+ AlertDialogDescription,
18
+ AlertDialogFooter,
19
+ AlertDialogHeader,
20
+ AlertDialogTitle,
21
+ } from '@/components/ui/alert-dialog';
10
22
  import { Button } from '@/components/ui/button';
11
23
  import {
12
24
  Card,
@@ -15,13 +27,6 @@ import {
15
27
  CardHeader,
16
28
  CardTitle,
17
29
  } from '@/components/ui/card';
18
- import {
19
- Dialog,
20
- DialogContent,
21
- DialogDescription,
22
- DialogHeader,
23
- DialogTitle,
24
- } from '@/components/ui/dialog';
25
30
  import {
26
31
  Form,
27
32
  FormControl,
@@ -367,7 +372,7 @@ export default function RolePage() {
367
372
  };
368
373
 
369
374
  return (
370
- <div className="flex flex-col h-screen px-4">
375
+ <Page>
371
376
  <PageHeader
372
377
  breadcrumbs={[{ label: 'Home', href: '/' }, { label: t('roles') }]}
373
378
  actions={[
@@ -423,7 +428,13 @@ export default function RolePage() {
423
428
 
424
429
  {!isLoading &&
425
430
  (!rolesResponse?.data || rolesResponse.data.length === 0) ? (
426
- <p className="text-sm text-muted-foreground">{t('noRolesFound')}</p>
431
+ <EmptyState
432
+ icon={<ShieldCheck className="h-12 w-12" />}
433
+ title={t('noRolesFound')}
434
+ description={t('description')}
435
+ actionLabel={t('buttonAddRole')}
436
+ onAction={() => setIsDialogOpen(true)}
437
+ />
427
438
  ) : (
428
439
  <div className="grid gap-4 grid-cols-1 lg:grid-cols-2 xl:grid-cols-3">
429
440
  {(rolesResponse?.data as (Role & { role_id: number })[])?.map(
@@ -504,19 +515,18 @@ export default function RolePage() {
504
515
  />
505
516
  </div>
506
517
 
507
- <Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
508
- <DialogContent className="sm:max-w-lg">
509
- <DialogHeader>
510
- <DialogTitle>{t('dialogAddRoleTitle')}</DialogTitle>
511
- <DialogDescription>
518
+ <Sheet open={isDialogOpen} onOpenChange={setIsDialogOpen}>
519
+ <SheetContent className="w-full sm:max-w-lg overflow-y-auto gap-0">
520
+ <SheetHeader>
521
+ <SheetTitle>{t('dialogAddRoleTitle')}</SheetTitle>
522
+ <SheetDescription>
512
523
  {t('dialogAddRoleDescription')}
513
- </DialogDescription>
514
- </DialogHeader>
515
- <div className="w-full border-t pt-1 mt-1" />
524
+ </SheetDescription>
525
+ </SheetHeader>
516
526
  <Form {...form}>
517
527
  <form
518
528
  onSubmit={form.handleSubmit(onSubmit)}
519
- className="space-y-4"
529
+ className="space-y-4 px-4 pt-2"
520
530
  >
521
531
  <FormField
522
532
  control={form.control}
@@ -586,8 +596,8 @@ export default function RolePage() {
586
596
  </Button>
587
597
  </form>
588
598
  </Form>
589
- </DialogContent>
590
- </Dialog>
599
+ </SheetContent>
600
+ </Sheet>
591
601
 
592
602
  {editingRole && (
593
603
  <Sheet open={!!editingRole} onOpenChange={() => setEditingRole(null)}>
@@ -783,34 +793,23 @@ export default function RolePage() {
783
793
  </Sheet>
784
794
  )}
785
795
 
786
- <Dialog open={openDeleteModal} onOpenChange={setOpenDeleteModal}>
787
- <DialogContent className="sm:max-w-lg">
788
- <DialogHeader>
789
- <DialogTitle>{t('dialogDeleteRoleTitle')}</DialogTitle>
790
- <DialogDescription>
796
+ <AlertDialog open={openDeleteModal} onOpenChange={setOpenDeleteModal}>
797
+ <AlertDialogContent>
798
+ <AlertDialogHeader>
799
+ <AlertDialogTitle>{t('dialogDeleteRoleTitle')}</AlertDialogTitle>
800
+ <AlertDialogDescription>
791
801
  {t('dialogDeleteRoleDescription')}
792
- </DialogDescription>
793
- </DialogHeader>
794
- <hr className="mt-4" />
795
- <div className="flex justify-end">
796
- <Button
797
- type="button"
798
- className="px-4 w-28 h-12 py-2 bg-gray-300 text-black hover:bg-gray-300 hover:text-black rounded-sm mr-2 text-md"
799
- onClick={() => setOpenDeleteModal(false)}
800
- >
801
- {t('deleteRoleCancel')}
802
- </Button>
803
- <Button
804
- onClick={onDelete}
805
- variant="destructive"
806
- className="px-4 w-32 h-12 py-2 text-white hover:text-white rounded-sm text-md cursor-pointer"
807
- >
802
+ </AlertDialogDescription>
803
+ </AlertDialogHeader>
804
+ <AlertDialogFooter>
805
+ <AlertDialogCancel>{t('deleteRoleCancel')}</AlertDialogCancel>
806
+ <AlertDialogAction onClick={onDelete}>
808
807
  {t('deleteRoleConfirm')}
809
- </Button>
810
- </div>
811
- </DialogContent>
812
- </Dialog>
808
+ </AlertDialogAction>
809
+ </AlertDialogFooter>
810
+ </AlertDialogContent>
811
+ </AlertDialog>
813
812
  </div>
814
- </div>
813
+ </Page>
815
814
  );
816
815
  }
@@ -1,6 +1,8 @@
1
1
  'use client';
2
2
 
3
3
  import {
4
+ EmptyState,
5
+ Page,
4
6
  PageHeader,
5
7
  PaginationFooter,
6
8
  SearchBar,
@@ -25,13 +27,6 @@ import {
25
27
  CardHeader,
26
28
  CardTitle,
27
29
  } from '@/components/ui/card';
28
- import {
29
- Dialog,
30
- DialogContent,
31
- DialogDescription,
32
- DialogHeader,
33
- DialogTitle,
34
- } from '@/components/ui/dialog';
35
30
  import {
36
31
  Form,
37
32
  FormControl,
@@ -220,16 +215,22 @@ export default function UserPage() {
220
215
  const chars: string[] = [];
221
216
 
222
217
  groups.forEach((group, index) => {
223
- chars.push(group[randomValues[index] % group.length]);
218
+ const randomValue = randomValues[index] ?? 0;
219
+ chars.push(group.charAt(randomValue % group.length));
224
220
  });
225
221
 
226
222
  for (let i = groups.length; i < randomValues.length; i++) {
227
- chars.push(allChars[randomValues[i] % allChars.length]);
223
+ const randomValue = randomValues[i] ?? 0;
224
+ chars.push(allChars.charAt(randomValue % allChars.length));
228
225
  }
229
226
 
230
227
  for (let i = chars.length - 1; i > 0; i--) {
231
- const j = randomValues[i] % (i + 1);
232
- [chars[i], chars[j]] = [chars[j], chars[i]];
228
+ const randomValue = randomValues[i] ?? 0;
229
+ const j = randomValue % (i + 1);
230
+ const currentChar = chars[i]!;
231
+ const swapChar = chars[j]!;
232
+ chars[i] = swapChar;
233
+ chars[j] = currentChar;
233
234
  }
234
235
 
235
236
  return chars.slice(0, length).join('');
@@ -422,7 +423,7 @@ export default function UserPage() {
422
423
  ];
423
424
 
424
425
  return (
425
- <div className="flex flex-col h-screen px-4">
426
+ <Page>
426
427
  <PageHeader
427
428
  breadcrumbs={[{ label: 'Home', href: '/' }, { label: t('users') }]}
428
429
  actions={[
@@ -487,10 +488,9 @@ export default function UserPage() {
487
488
  { label: t('filterOptionBlocked'), value: 'blocked' },
488
489
  ],
489
490
  }}
490
- className="mt-4"
491
491
  />
492
492
 
493
- <div className="flex-1 pt-4">
493
+ <div className="flex-1 ">
494
494
  {isLoading && (
495
495
  <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
496
496
  {Array.from({ length: 3 }).map((_, i) => (
@@ -522,7 +522,13 @@ export default function UserPage() {
522
522
  )}
523
523
 
524
524
  {(paginate?.data?.length || 0) === 0 ? (
525
- <p className="text-sm text-muted-foreground">{t('noUsersFound')}</p>
525
+ <EmptyState
526
+ icon={<Users className="h-12 w-12" />}
527
+ title={t('noUsersFound')}
528
+ description={t('description')}
529
+ actionLabel={t('buttonAddUser')}
530
+ onAction={() => setIsDialogOpen(true)}
531
+ />
526
532
  ) : (
527
533
  <div className="grid gap-4 grid-cols-1 lg:grid-cols-2 xl:grid-cols-3">
528
534
  {paginate?.data?.map((user: User) => (
@@ -1157,36 +1163,29 @@ export default function UserPage() {
1157
1163
  </Button>
1158
1164
  </div>
1159
1165
 
1160
- <Dialog
1166
+ <AlertDialog
1161
1167
  open={openDeleteModal}
1162
1168
  onOpenChange={setOpenDeleteModal}
1163
1169
  >
1164
- <DialogContent className="sm:max-w-lg">
1165
- <DialogHeader>
1166
- <DialogTitle>{t('dialogDeleteUserTitle')}</DialogTitle>
1167
- <DialogDescription>
1170
+ <AlertDialogContent>
1171
+ <AlertDialogHeader>
1172
+ <AlertDialogTitle>
1173
+ {t('dialogDeleteUserTitle')}
1174
+ </AlertDialogTitle>
1175
+ <AlertDialogDescription>
1168
1176
  {t('dialogDeleteUserDescription')}
1169
- </DialogDescription>
1170
- </DialogHeader>
1171
- <hr className="mt-4" />
1172
- <div className="flex justify-end">
1173
- <Button
1174
- type="button"
1175
- className="px-4 w-28 h-12 py-2 bg-gray-300 text-black hover:bg-gray-300 hover:text-black rounded-sm mr-2 text-md"
1176
- onClick={() => setOpenDeleteModal(false)}
1177
- >
1177
+ </AlertDialogDescription>
1178
+ </AlertDialogHeader>
1179
+ <AlertDialogFooter>
1180
+ <AlertDialogCancel>
1178
1181
  {t('deleteUserCancel')}
1179
- </Button>
1180
- <Button
1181
- onClick={onDelete}
1182
- variant="destructive"
1183
- className="px-4 w-32 h-12 py-2 text-white hover:text-white rounded-sm text-md cursor-pointer"
1184
- >
1182
+ </AlertDialogCancel>
1183
+ <AlertDialogAction onClick={onDelete}>
1185
1184
  {t('deleteUserConfirm')}
1186
- </Button>
1187
- </div>
1188
- </DialogContent>
1189
- </Dialog>
1185
+ </AlertDialogAction>
1186
+ </AlertDialogFooter>
1187
+ </AlertDialogContent>
1188
+ </AlertDialog>
1190
1189
  </TabsContent>
1191
1190
 
1192
1191
  <TabsContent value="edit" className="space-y-4 mt-4 p-4 pt-0">
@@ -1232,27 +1231,29 @@ export default function UserPage() {
1232
1231
  value="credentials"
1233
1232
  className="space-y-4 mt-4 p-4 pt-0"
1234
1233
  >
1235
- <Card className="border-amber-200 bg-amber-50/50">
1236
- <CardHeader className="pb-2">
1237
- <CardTitle className="text-sm">
1234
+ <div className="space-y-3 rounded-lg border p-4">
1235
+ <div>
1236
+ <h4 className="text-sm font-semibold">
1238
1237
  {t('passwordResetTitle')}
1239
- </CardTitle>
1240
- <CardDescription>
1238
+ </h4>
1239
+ <p className="text-xs text-muted-foreground mt-1">
1241
1240
  {t('passwordResetDescription')}
1242
- </CardDescription>
1243
- </CardHeader>
1244
- <CardContent className="flex flex-col gap-3">
1245
- <div className="text-xs text-muted-foreground">
1246
- {t('passwordResetNotice')}
1247
- </div>
1248
- <div>
1249
- <Button type="button" onClick={openResetPasswordDialog}>
1250
- <RefreshCcw className="h-4 w-4 mr-2" />
1251
- {t('buttonResetPassword')}
1252
- </Button>
1253
- </div>
1254
- </CardContent>
1255
- </Card>
1241
+ </p>
1242
+ </div>
1243
+ <p className="text-xs text-muted-foreground">
1244
+ {t('passwordResetNotice')}
1245
+ </p>
1246
+ <div className="flex flex-col gap-2">
1247
+ <Button
1248
+ type="button"
1249
+ onClick={openResetPasswordDialog}
1250
+ className="w-full sm:w-fit"
1251
+ >
1252
+ <RefreshCcw className="h-4 w-4 mr-2" />
1253
+ {t('buttonResetPassword')}
1254
+ </Button>
1255
+ </div>
1256
+ </div>
1256
1257
 
1257
1258
  <div className="space-y-3">
1258
1259
  <h4 className="text-sm font-medium">
@@ -1422,7 +1423,7 @@ export default function UserPage() {
1422
1423
  </AlertDialogContent>
1423
1424
  </AlertDialog>
1424
1425
 
1425
- <Dialog
1426
+ <AlertDialog
1426
1427
  open={isResetResultDialogOpen}
1427
1428
  onOpenChange={(open) => {
1428
1429
  setIsResetResultDialogOpen(open);
@@ -1432,13 +1433,15 @@ export default function UserPage() {
1432
1433
  }
1433
1434
  }}
1434
1435
  >
1435
- <DialogContent className="sm:max-w-lg">
1436
- <DialogHeader>
1437
- <DialogTitle>{t('passwordResultTitle')}</DialogTitle>
1438
- <DialogDescription>
1436
+ <AlertDialogContent>
1437
+ <AlertDialogHeader>
1438
+ <AlertDialogTitle>
1439
+ {t('passwordResultTitle')}
1440
+ </AlertDialogTitle>
1441
+ <AlertDialogDescription>
1439
1442
  {t('passwordResultDescription')}
1440
- </DialogDescription>
1441
- </DialogHeader>
1443
+ </AlertDialogDescription>
1444
+ </AlertDialogHeader>
1442
1445
 
1443
1446
  <div className="space-y-3">
1444
1447
  <div className="relative">
@@ -1484,8 +1487,8 @@ export default function UserPage() {
1484
1487
  </Button>
1485
1488
  </div>
1486
1489
  </div>
1487
- </DialogContent>
1488
- </Dialog>
1490
+ </AlertDialogContent>
1491
+ </AlertDialog>
1489
1492
  </TabsContent>
1490
1493
 
1491
1494
  <TabsContent
@@ -1573,6 +1576,6 @@ export default function UserPage() {
1573
1576
  </Sheet>
1574
1577
  )}
1575
1578
  </div>
1576
- </div>
1579
+ </Page>
1577
1580
  );
1578
1581
  }
@@ -104,6 +104,8 @@
104
104
  "localization": "Localization",
105
105
  "language": "Language",
106
106
  "setPreferredLanguage": "Set your preferred language",
107
+ "themeUpdateError": "Failed to update theme",
108
+ "languageUpdateError": "Failed to update language",
107
109
  "dateFormat": "Date Format",
108
110
  "dateAndTimeFormat": "Date and Time Format",
109
111
  "setPreferredDateFormat": "Set your preferred date format",
@@ -329,6 +331,9 @@
329
331
  "newTemplate": "New Template",
330
332
  "title": "Email Templates",
331
333
  "description": "Manage your email templates",
334
+ "searchPlaceholder": "Search templates by slug or subject...",
335
+ "noTemplatesFound": "No templates found",
336
+ "noTemplatesHint": "Create your first template to start sending emails.",
332
337
  "tableSlug": "Slug",
333
338
  "tableSubject": "Subject",
334
339
  "tableVariables": "Variables",
@@ -849,6 +854,8 @@
849
854
  "noLogsFound": "No email logs found",
850
855
  "adjustSearch": "Try adjusting your search terms",
851
856
  "noEmailsSent": "No emails have been sent yet",
857
+ "clearSearch": "Clear search",
858
+ "refreshList": "Refresh list",
852
859
  "viewDetails": "View Details",
853
860
  "emailDetails": "Email Details",
854
861
  "detailsDescription": "Complete information about the sent email",
@@ -104,6 +104,8 @@
104
104
  "localization": "Localização",
105
105
  "language": "Idioma",
106
106
  "setPreferredLanguage": "Defina seu idioma preferido",
107
+ "themeUpdateError": "Falha ao atualizar o tema",
108
+ "languageUpdateError": "Falha ao atualizar o idioma",
107
109
  "dateFormat": "Formato de Data",
108
110
  "dateAndTimeFormat": "Formato de Data e Hora",
109
111
  "setPreferredDateFormat": "Defina seu formato de data preferido",
@@ -329,6 +331,9 @@
329
331
  "newTemplate": "Novo Template",
330
332
  "title": "Templates de E-mail",
331
333
  "description": "Gerencie seus templates de e-mail",
334
+ "searchPlaceholder": "Buscar templates por slug ou assunto...",
335
+ "noTemplatesFound": "Nenhum template encontrado",
336
+ "noTemplatesHint": "Crie o primeiro template para começar a enviar e-mails.",
332
337
  "tableSlug": "Slug",
333
338
  "tableSubject": "Assunto",
334
339
  "tableVariables": "Variáveis",
@@ -852,6 +857,8 @@
852
857
  "noLogsFound": "Nenhum log de e-mail encontrado",
853
858
  "adjustSearch": "Tente ajustar seus termos de busca",
854
859
  "noEmailsSent": "Nenhum e-mail foi enviado ainda",
860
+ "clearSearch": "Limpar busca",
861
+ "refreshList": "Atualizar lista",
855
862
  "viewDetails": "Ver Detalhes",
856
863
  "emailDetails": "Detalhes do E-mail",
857
864
  "detailsDescription": "Informações completas sobre o e-mail enviado",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/core",
3
- "version": "0.0.279",
3
+ "version": "0.0.286",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -32,9 +32,9 @@
32
32
  "uuid": "^11.1.0",
33
33
  "@hed-hog/api-pagination": "0.0.6",
34
34
  "@hed-hog/api-types": "0.0.1",
35
+ "@hed-hog/api-prisma": "0.0.5",
35
36
  "@hed-hog/api-locale": "0.0.13",
36
37
  "@hed-hog/api-mail": "0.0.8",
37
- "@hed-hog/api-prisma": "0.0.5",
38
38
  "@hed-hog/api": "0.0.4"
39
39
  },
40
40
  "exports": {
@@ -2,13 +2,14 @@ import { IS_PUBLIC_KEY, WITH_ROLE } from '@hed-hog/api';
2
2
  import { getLocaleText } from '@hed-hog/api-locale';
3
3
  import { PrismaService } from '@hed-hog/api-prisma';
4
4
  import {
5
- CanActivate,
6
- ExecutionContext,
7
- forwardRef,
8
- Inject,
9
- Injectable,
10
- RequestMethod,
11
- UnauthorizedException,
5
+ CanActivate,
6
+ ExecutionContext,
7
+ ForbiddenException,
8
+ forwardRef,
9
+ Inject,
10
+ Injectable,
11
+ RequestMethod,
12
+ UnauthorizedException,
12
13
  } from '@nestjs/common';
13
14
  import { METHOD_METADATA } from '@nestjs/common/constants';
14
15
  import { Reflector } from '@nestjs/core';
@@ -130,7 +131,7 @@ export class RoleGuard implements CanActivate {
130
131
  .replace('{{method}}', httpMethod)
131
132
  .replace('{{path}}', fullPath);
132
133
 
133
- throw new UnauthorizedException(message);
134
+ throw new ForbiddenException(message);
134
135
  }
135
136
 
136
137
  const hasPendingPasswordReset = await this.prisma.user_credential.findFirst({