@hed-hog/core 0.0.297 → 0.0.298

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 (60) hide show
  1. package/dist/auth/auth.controller.d.ts +10 -10
  2. package/dist/auth/auth.service.d.ts +10 -10
  3. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +14 -0
  4. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
  5. package/dist/dashboard/dashboard-core/dashboard-core.controller.js +9 -0
  6. package/dist/dashboard/dashboard-core/dashboard-core.controller.js.map +1 -1
  7. package/dist/dashboard/dashboard-core/dashboard-core.module.d.ts.map +1 -1
  8. package/dist/dashboard/dashboard-core/dashboard-core.module.js +6 -1
  9. package/dist/dashboard/dashboard-core/dashboard-core.module.js.map +1 -1
  10. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +173 -1
  11. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
  12. package/dist/dashboard/dashboard-core/dashboard-core.service.js +531 -5
  13. package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
  14. package/dist/file/file.controller.d.ts.map +1 -1
  15. package/dist/file/file.controller.js +16 -0
  16. package/dist/file/file.controller.js.map +1 -1
  17. package/dist/file/file.service.d.ts +7 -1
  18. package/dist/file/file.service.d.ts.map +1 -1
  19. package/dist/file/file.service.js +38 -1
  20. package/dist/file/file.service.js.map +1 -1
  21. package/dist/file/provider/s3.provider.d.ts +1 -0
  22. package/dist/file/provider/s3.provider.d.ts.map +1 -1
  23. package/dist/file/provider/s3.provider.js +38 -29
  24. package/dist/file/provider/s3.provider.js.map +1 -1
  25. package/dist/oauth/oauth.service.d.ts.map +1 -1
  26. package/dist/oauth/oauth.service.js +2 -1
  27. package/dist/oauth/oauth.service.js.map +1 -1
  28. package/dist/user/constants/user.constants.d.ts +1 -0
  29. package/dist/user/constants/user.constants.d.ts.map +1 -1
  30. package/dist/user/constants/user.constants.js +2 -1
  31. package/dist/user/constants/user.constants.js.map +1 -1
  32. package/dist/user/user.controller.d.ts +10 -10
  33. package/dist/user/user.service.d.ts +30 -30
  34. package/dist/user/user.service.d.ts.map +1 -1
  35. package/dist/user/user.service.js +2 -1
  36. package/dist/user/user.service.js.map +1 -1
  37. package/hedhog/data/dashboard_item.yaml +11 -11
  38. package/hedhog/data/route.yaml +8 -0
  39. package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +76 -15
  40. package/hedhog/frontend/app/dashboard/components/widgets/email-notifications.tsx.ejs +85 -61
  41. package/hedhog/frontend/app/dashboard/components/widgets/locale-config.tsx.ejs +139 -280
  42. package/hedhog/frontend/app/dashboard/components/widgets/mail-config.tsx.ejs +161 -407
  43. package/hedhog/frontend/app/dashboard/components/widgets/oauth-config.tsx.ejs +150 -271
  44. package/hedhog/frontend/app/dashboard/components/widgets/profile-card.tsx.ejs +3 -3
  45. package/hedhog/frontend/app/dashboard/components/widgets/storage-config.tsx.ejs +161 -305
  46. package/hedhog/frontend/app/dashboard/components/widgets/theme-config.tsx.ejs +184 -246
  47. package/hedhog/frontend/app/dashboard/components/widgets/user-roles.tsx.ejs +12 -14
  48. package/hedhog/frontend/messages/en.json +90 -0
  49. package/hedhog/frontend/messages/pt.json +90 -0
  50. package/hedhog/table/mail_sent_user.yaml +75 -0
  51. package/package.json +5 -5
  52. package/src/dashboard/dashboard-core/dashboard-core.controller.ts +5 -0
  53. package/src/dashboard/dashboard-core/dashboard-core.module.ts +6 -1
  54. package/src/dashboard/dashboard-core/dashboard-core.service.ts +766 -3
  55. package/src/file/file.controller.ts +37 -13
  56. package/src/file/file.service.ts +47 -5
  57. package/src/file/provider/s3.provider.ts +39 -29
  58. package/src/oauth/oauth.service.ts +8 -7
  59. package/src/user/constants/user.constants.ts +1 -0
  60. package/src/user/user.service.ts +2 -1
@@ -12,66 +12,26 @@ import {
12
12
  ChartTooltip,
13
13
  ChartTooltipContent,
14
14
  } from '@/components/ui/chart';
15
+ import { useWidgetData } from '@/hooks/use-widget-data';
16
+ import type {
17
+ AllWidgetsData,
18
+ EmailNotificationsData,
19
+ } from '@/types/widget-data';
15
20
  import { Mail, MailCheck, MailWarning, MailX } from 'lucide-react';
21
+ import { useTranslations } from 'next-intl';
16
22
  import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts';
17
23
  import { WidgetWrapper } from '../widget-wrapper';
18
24
 
19
- const data = [
20
- { date: '01 Fev', recebidos: 5, lidos: 4 },
21
- { date: '03 Fev', recebidos: 3, lidos: 2 },
22
- { date: '05 Fev', recebidos: 8, lidos: 6 },
23
- { date: '07 Fev', recebidos: 4, lidos: 4 },
24
- { date: '09 Fev', recebidos: 6, lidos: 3 },
25
- { date: '11 Fev', recebidos: 2, lidos: 2 },
26
- { date: '13 Fev', recebidos: 7, lidos: 5 },
27
- ];
28
-
29
- const chartConfig = {
30
- recebidos: {
31
- label: 'Recebidos',
32
- color: 'hsl(221, 83%, 53%)',
33
- },
34
- lidos: {
35
- label: 'Lidos',
36
- color: 'hsl(160, 84%, 39%)',
25
+ const defaultEmailNotificationsData: EmailNotificationsData = {
26
+ cards: {
27
+ received: 0,
28
+ read: 0,
29
+ unread: 0,
30
+ error: 0,
37
31
  },
32
+ chart: [],
38
33
  };
39
34
 
40
- const emailStats = [
41
- {
42
- label: 'Recebidos',
43
- shortLabel: 'Rec.',
44
- value: '35',
45
- icon: Mail,
46
- color: 'text-blue-600 dark:text-blue-400',
47
- bg: 'bg-blue-50 dark:bg-blue-950/40',
48
- },
49
- {
50
- label: 'Lidos',
51
- shortLabel: 'Lid.',
52
- value: '26',
53
- icon: MailCheck,
54
- color: 'text-emerald-600 dark:text-emerald-400',
55
- bg: 'bg-emerald-50 dark:bg-emerald-950/40',
56
- },
57
- {
58
- label: 'Nao lidos',
59
- shortLabel: 'N. lid.',
60
- value: '9',
61
- icon: MailWarning,
62
- color: 'text-amber-600 dark:text-amber-400',
63
- bg: 'bg-amber-50 dark:bg-amber-950/40',
64
- },
65
- {
66
- label: 'Com erro',
67
- shortLabel: 'Erro',
68
- value: '2',
69
- icon: MailX,
70
- color: 'text-red-600 dark:text-red-400',
71
- bg: 'bg-red-50 dark:bg-red-950/40',
72
- },
73
- ];
74
-
75
35
  interface EmailNotificationsProps {
76
36
  widget?: { name?: string };
77
37
  onRemove?: () => void;
@@ -81,12 +41,76 @@ export default function EmailNotifications({
81
41
  widget,
82
42
  onRemove,
83
43
  }: EmailNotificationsProps) {
44
+ const t = useTranslations('core.DashboardPage.emailNotifications');
45
+
46
+ const chartConfig = {
47
+ recebidos: {
48
+ label: t('received'),
49
+ color: 'hsl(221, 83%, 53%)',
50
+ },
51
+ lidos: {
52
+ label: t('read'),
53
+ color: 'hsl(160, 84%, 39%)',
54
+ },
55
+ };
56
+
57
+ const { data, isLoading, isError, isAccessDenied } = useWidgetData<
58
+ AllWidgetsData,
59
+ EmailNotificationsData
60
+ >({
61
+ endpoint: '/dashboard-core/widgets/me',
62
+ queryKey: 'widget-me',
63
+ select: (d) => d.emailNotifications,
64
+ });
65
+
66
+ const widgetData = data ?? defaultEmailNotificationsData;
67
+ const chartData = widgetData.chart.map((point) => ({
68
+ date: point.date,
69
+ recebidos: point.received ?? 0,
70
+ lidos: point.read ?? 0,
71
+ }));
72
+
73
+ const emailStats = [
74
+ {
75
+ label: t('received'),
76
+ shortLabel: t('receivedShort'),
77
+ value: widgetData.cards.received ?? 0,
78
+ icon: Mail,
79
+ color: 'text-blue-600 dark:text-blue-400',
80
+ bg: 'bg-blue-50 dark:bg-blue-950/40',
81
+ },
82
+ {
83
+ label: t('read'),
84
+ shortLabel: t('readShort'),
85
+ value: widgetData.cards.read ?? 0,
86
+ icon: MailCheck,
87
+ color: 'text-emerald-600 dark:text-emerald-400',
88
+ bg: 'bg-emerald-50 dark:bg-emerald-950/40',
89
+ },
90
+ {
91
+ label: t('unread'),
92
+ shortLabel: t('unreadShort'),
93
+ value: widgetData.cards.unread ?? 0,
94
+ icon: MailWarning,
95
+ color: 'text-amber-600 dark:text-amber-400',
96
+ bg: 'bg-amber-50 dark:bg-amber-950/40',
97
+ },
98
+ {
99
+ label: t('error'),
100
+ shortLabel: t('errorShort'),
101
+ value: widgetData.cards.error ?? 0,
102
+ icon: MailX,
103
+ color: 'text-red-600 dark:text-red-400',
104
+ bg: 'bg-red-50 dark:bg-red-950/40',
105
+ },
106
+ ];
107
+
84
108
  return (
85
109
  <WidgetWrapper
86
- isLoading={false}
87
- isError={false}
88
- isAccessDenied={false}
89
- widgetName={widget?.name ?? 'email-notifications'}
110
+ isLoading={isLoading}
111
+ isError={isError}
112
+ isAccessDenied={isAccessDenied}
113
+ widgetName={widget?.name ?? t('title')}
90
114
  onRemove={onRemove}
91
115
  >
92
116
  <Card className="flex h-full min-h-0 flex-col overflow-hidden">
@@ -95,10 +119,10 @@ export default function EmailNotifications({
95
119
  <Mail className="h-4 w-4 text-rose-600 dark:text-rose-400 sm:h-5 sm:w-5" />
96
120
  <div>
97
121
  <CardTitle className="text-sm font-semibold sm:text-base">
98
- Notificacoes por E-mail
122
+ {t('title')}
99
123
  </CardTitle>
100
124
  <CardDescription className="text-xs sm:text-sm">
101
- E-mails do sistema nos ultimos 14 dias
125
+ {t('description')}
102
126
  </CardDescription>
103
127
  </div>
104
128
  </div>
@@ -133,9 +157,9 @@ export default function EmailNotifications({
133
157
 
134
158
  <ChartContainer
135
159
  config={chartConfig}
136
- className="min-h-[170px] w-full flex-1 overflow-hidden sm:min-h-[220px]"
160
+ className="min-h-42.5 w-full flex-1 overflow-hidden sm:min-h-55"
137
161
  >
138
- <AreaChart data={data}>
162
+ <AreaChart data={chartData}>
139
163
  <CartesianGrid vertical={false} strokeDasharray="3 3" />
140
164
  <XAxis
141
165
  dataKey="date"
@@ -1,7 +1,6 @@
1
1
  'use client';
2
2
 
3
3
  import { Badge } from '@/components/ui/badge';
4
- import { Button } from '@/components/ui/button';
5
4
  import {
6
5
  Card,
7
6
  CardContent,
@@ -9,301 +8,161 @@ import {
9
8
  CardHeader,
10
9
  CardTitle,
11
10
  } from '@/components/ui/card';
12
- import { Checkbox } from '@/components/ui/checkbox';
13
- import { Label } from '@/components/ui/label';
14
- import {
15
- Select,
16
- SelectContent,
17
- SelectItem,
18
- SelectTrigger,
19
- SelectValue,
20
- } from '@/components/ui/select';
21
- import { Switch } from '@/components/ui/switch';
22
- import { Calendar, CheckCircle2, Clock, Globe, Type } from 'lucide-react';
23
- import { useState } from 'react';
24
-
25
- interface Language {
26
- code: string;
27
- label: string;
28
- flag: string;
29
- enabled: boolean;
30
- }
31
-
32
- const availableLanguages: Language[] = [
33
- { code: 'pt-BR', label: 'Portugues (Brasil)', flag: '🇧🇷', enabled: true },
34
- { code: 'en-US', label: 'Ingles (EUA)', flag: '🇺🇸', enabled: true },
35
- { code: 'es-ES', label: 'Espanhol (Espanha)', flag: '🇪🇸', enabled: false },
36
- { code: 'fr-FR', label: 'Frances (Franca)', flag: '🇫🇷', enabled: false },
37
- { code: 'de-DE', label: 'Alemao (Alemanha)', flag: '🇩🇪', enabled: false },
38
- { code: 'it-IT', label: 'Italiano (Italia)', flag: '🇮🇹', enabled: false },
39
- { code: 'ja-JP', label: 'Japones (Japao)', flag: '🇯🇵', enabled: false },
40
- { code: 'zh-CN', label: 'Chines (Simplificado)', flag: '🇨🇳', enabled: false },
41
- ];
11
+ import { useWidgetData } from '@/hooks/use-widget-data';
12
+ import type {
13
+ DashboardCoreConfigOverviewData,
14
+ LocaleConfigWidgetData,
15
+ } from '@/types/widget-data';
16
+ import { Calendar, Clock, Globe, Languages } from 'lucide-react';
17
+ import { useTranslations } from 'next-intl';
18
+ import { WidgetWrapper } from '../widget-wrapper';
42
19
 
43
- const timezones = [
44
- { value: 'America/Sao_Paulo', label: 'America/Sao_Paulo (GMT-3)' },
45
- { value: 'America/New_York', label: 'America/New_York (GMT-5)' },
46
- { value: 'America/Chicago', label: 'America/Chicago (GMT-6)' },
47
- { value: 'America/Denver', label: 'America/Denver (GMT-7)' },
48
- { value: 'America/Los_Angeles', label: 'America/Los_Angeles (GMT-8)' },
49
- { value: 'Europe/London', label: 'Europe/London (GMT+0)' },
50
- { value: 'Europe/Paris', label: 'Europe/Paris (GMT+1)' },
51
- { value: 'Europe/Berlin', label: 'Europe/Berlin (GMT+1)' },
52
- { value: 'Asia/Tokyo', label: 'Asia/Tokyo (GMT+9)' },
53
- { value: 'Asia/Shanghai', label: 'Asia/Shanghai (GMT+8)' },
54
- { value: 'Australia/Sydney', label: 'Australia/Sydney (GMT+11)' },
55
- ];
56
-
57
- const dateFormats = [
58
- { value: 'DD/MM/YYYY', label: 'DD/MM/YYYY', example: '14/02/2026' },
59
- { value: 'MM/DD/YYYY', label: 'MM/DD/YYYY', example: '02/14/2026' },
60
- { value: 'YYYY-MM-DD', label: 'YYYY-MM-DD', example: '2026-02-14' },
61
- { value: 'DD.MM.YYYY', label: 'DD.MM.YYYY', example: '14.02.2026' },
62
- { value: 'DD-MM-YYYY', label: 'DD-MM-YYYY', example: '14-02-2026' },
63
- ];
64
-
65
- const timeFormats = [
66
- { value: 'HH:mm', label: '24 horas', example: '14:30' },
67
- { value: 'hh:mm A', label: '12 horas', example: '02:30 PM' },
68
- { value: 'HH:mm:ss', label: '24 horas com segundos', example: '14:30:45' },
69
- {
70
- value: 'hh:mm:ss A',
71
- label: '12 horas com segundos',
72
- example: '02:30:45 PM',
20
+ const defaultLocaleConfigData: LocaleConfigWidgetData = {
21
+ status: {
22
+ isConfigured: false,
23
+ enabledLocaleCount: 0,
24
+ disabledLocaleCount: 0,
25
+ },
26
+ settings: {
27
+ dateFormat: null,
28
+ timeFormat: null,
29
+ timezone: null,
73
30
  },
74
- ];
31
+ locales: [],
32
+ };
75
33
 
76
- export default function LocaleConfig() {
77
- const [languages, setLanguages] = useState<Language[]>(availableLanguages);
78
- const [defaultLang, setDefaultLang] = useState('pt-BR');
79
- const [timezone, setTimezone] = useState('America/Sao_Paulo');
80
- const [dateFormat, setDateFormat] = useState('DD/MM/YYYY');
81
- const [timeFormat, setTimeFormat] = useState('HH:mm');
82
- const [autoDetect, setAutoDetect] = useState(true);
34
+ interface LocaleConfigProps {
35
+ widget?: { name?: string };
36
+ onRemove?: () => void;
37
+ }
38
+
39
+ export default function LocaleConfig({ widget, onRemove }: LocaleConfigProps) {
40
+ const t = useTranslations('core.DashboardPage.localeConfig');
83
41
 
84
- const enabledLanguages = languages.filter((l) => l.enabled);
42
+ const { data, isLoading, isError, isAccessDenied } = useWidgetData<
43
+ DashboardCoreConfigOverviewData,
44
+ LocaleConfigWidgetData
45
+ >({
46
+ endpoint: '/dashboard-core/config/overview',
47
+ queryKey: 'dashboard-core-config-overview',
48
+ select: (d) => d.localeConfig,
49
+ });
85
50
 
86
- function toggleLanguage(code: string) {
87
- setLanguages((prev) =>
88
- prev.map((l) => {
89
- if (l.code === code) {
90
- if (l.enabled && l.code === defaultLang) return l;
91
- return { ...l, enabled: !l.enabled };
92
- }
93
- return l;
94
- })
95
- );
96
- }
51
+ const localeData = data ?? defaultLocaleConfigData;
52
+ const enabledLocales = localeData.locales.filter((locale) => locale.enabled);
97
53
 
98
54
  return (
99
- <Card className="h-full">
100
- <CardHeader>
101
- <div className="flex items-center justify-between">
102
- <div className="flex items-center gap-3">
103
- <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-50">
104
- <Globe className="h-5 w-5 text-indigo-600" />
55
+ <WidgetWrapper
56
+ isLoading={isLoading}
57
+ isError={isError}
58
+ isAccessDenied={isAccessDenied}
59
+ widgetName={widget?.name ?? t('title')}
60
+ onRemove={onRemove}
61
+ >
62
+ <Card className="flex h-full min-h-0 flex-col overflow-hidden">
63
+ <CardHeader className="shrink-0">
64
+ <div className="flex items-center justify-between gap-3">
65
+ <div className="flex items-center gap-3">
66
+ <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-50">
67
+ <Globe className="h-5 w-5 text-indigo-600" />
68
+ </div>
69
+ <div>
70
+ <CardTitle className="text-base">{t('title')}</CardTitle>
71
+ <CardDescription>{t('description')}</CardDescription>
72
+ </div>
105
73
  </div>
106
- <div>
107
- <CardTitle className="text-base">Localizacao</CardTitle>
108
- <CardDescription>
109
- Idiomas, fuso horario e formatos regionais
110
- </CardDescription>
111
- </div>
112
- </div>
113
- <Badge variant="secondary" className="bg-indigo-50 text-indigo-700">
114
- {enabledLanguages.length} idioma
115
- {enabledLanguages.length !== 1 ? 's' : ''}
116
- </Badge>
117
- </div>
118
- </CardHeader>
119
- <CardContent className="space-y-6">
120
- {/* Languages */}
121
- <div className="space-y-3">
122
- <div className="flex items-center gap-2">
123
- <Type className="h-4 w-4 text-muted-foreground" />
124
- <Label className="text-sm font-medium">Idiomas habilitados</Label>
74
+ <Badge
75
+ variant="secondary"
76
+ className={
77
+ localeData.status.isConfigured
78
+ ? 'bg-emerald-50 text-emerald-700'
79
+ : 'bg-amber-50 text-amber-700'
80
+ }
81
+ >
82
+ {localeData.status.isConfigured ? t('configured') : t('pending')}
83
+ </Badge>
125
84
  </div>
126
- <div className="grid grid-cols-2 gap-2">
127
- {languages.map((lang) => (
128
- <label
129
- key={lang.code}
130
- className={`flex cursor-pointer items-center gap-3 rounded-lg border p-3 transition-colors ${
131
- lang.enabled
132
- ? 'border-foreground/20 bg-foreground/2'
133
- : 'border-border hover:border-foreground/10'
134
- }`}
135
- >
136
- <Checkbox
137
- checked={lang.enabled}
138
- onCheckedChange={() => toggleLanguage(lang.code)}
139
- disabled={lang.enabled && lang.code === defaultLang}
140
- />
141
- <span className="text-base leading-none">{lang.flag}</span>
142
- <div className="flex flex-1 flex-col">
143
- <span className="text-sm font-medium">{lang.label}</span>
144
- <span className="text-xs text-muted-foreground">
145
- {lang.code}
146
- </span>
147
- </div>
148
- {lang.code === defaultLang && (
149
- <Badge variant="outline" className="text-[10px] h-5">
150
- Padrao
151
- </Badge>
152
- )}
153
- </label>
154
- ))}
85
+ </CardHeader>
86
+ <CardContent className="flex min-h-0 flex-1 flex-col gap-4 overflow-hidden pt-0">
87
+ <div className="grid grid-cols-3 gap-2">
88
+ <div className="rounded-lg border bg-muted/30 p-3 text-center">
89
+ <p className="text-[11px] text-muted-foreground">
90
+ {t('enabled')}
91
+ </p>
92
+ <p className="mt-1 text-lg font-semibold">
93
+ {localeData.status.enabledLocaleCount}
94
+ </p>
95
+ </div>
96
+ <div className="rounded-lg border bg-muted/30 p-3 text-center">
97
+ <p className="text-[11px] text-muted-foreground">
98
+ {t('disabled')}
99
+ </p>
100
+ <p className="mt-1 text-lg font-semibold">
101
+ {localeData.status.disabledLocaleCount}
102
+ </p>
103
+ </div>
104
+ <div className="rounded-lg border bg-muted/30 p-3 text-center">
105
+ <p className="text-[11px] text-muted-foreground">{t('total')}</p>
106
+ <p className="mt-1 text-lg font-semibold">
107
+ {localeData.locales.length}
108
+ </p>
109
+ </div>
155
110
  </div>
156
- </div>
157
111
 
158
- {/* Default Language */}
159
- <div className="space-y-2">
160
- <Label>Idioma padrao</Label>
161
- <Select value={defaultLang} onValueChange={setDefaultLang}>
162
- <SelectTrigger>
163
- <SelectValue />
164
- </SelectTrigger>
165
- <SelectContent>
166
- {enabledLanguages.map((lang) => (
167
- <SelectItem key={lang.code} value={lang.code}>
168
- <span className="flex items-center gap-2">
169
- <span>{lang.flag}</span>
170
- <span>{lang.label}</span>
171
- </span>
172
- </SelectItem>
173
- ))}
174
- </SelectContent>
175
- </Select>
176
- <p className="text-xs text-muted-foreground">
177
- Idioma exibido quando o idioma do usuario nao esta disponivel.
178
- </p>
179
- </div>
180
-
181
- {/* Timezone */}
182
- <div className="space-y-2">
183
- <div className="flex items-center gap-2">
184
- <Clock className="h-4 w-4 text-muted-foreground" />
185
- <Label>Fuso horario do sistema</Label>
112
+ <div className="grid gap-2 sm:grid-cols-3">
113
+ <div className="rounded-lg border p-3">
114
+ <div className="mb-1 flex items-center gap-1.5 text-xs text-muted-foreground">
115
+ <Clock className="h-3.5 w-3.5" />
116
+ {t('timezone')}
117
+ </div>
118
+ <p className="truncate font-mono text-xs">
119
+ {localeData.settings.timezone || t('notSet')}
120
+ </p>
121
+ </div>
122
+ <div className="rounded-lg border p-3">
123
+ <div className="mb-1 flex items-center gap-1.5 text-xs text-muted-foreground">
124
+ <Calendar className="h-3.5 w-3.5" />
125
+ {t('dateFormat')}
126
+ </div>
127
+ <p className="font-mono text-xs">
128
+ {localeData.settings.dateFormat || t('notSet')}
129
+ </p>
130
+ </div>
131
+ <div className="rounded-lg border p-3">
132
+ <div className="mb-1 flex items-center gap-1.5 text-xs text-muted-foreground">
133
+ <Clock className="h-3.5 w-3.5" />
134
+ {t('timeFormat')}
135
+ </div>
136
+ <p className="font-mono text-xs">
137
+ {localeData.settings.timeFormat || t('notSet')}
138
+ </p>
139
+ </div>
186
140
  </div>
187
- <Select value={timezone} onValueChange={setTimezone}>
188
- <SelectTrigger>
189
- <SelectValue />
190
- </SelectTrigger>
191
- <SelectContent>
192
- {timezones.map((tz) => (
193
- <SelectItem key={tz.value} value={tz.value}>
194
- {tz.label}
195
- </SelectItem>
196
- ))}
197
- </SelectContent>
198
- </Select>
199
- </div>
200
141
 
201
- {/* Date & Time Formats */}
202
- <div className="grid gap-4 sm:grid-cols-2">
203
- <div className="space-y-2">
204
- <div className="flex items-center gap-2">
205
- <Calendar className="h-4 w-4 text-muted-foreground" />
206
- <Label>Formato de data</Label>
142
+ <div className="min-h-0 flex-1 rounded-lg border p-3">
143
+ <div className="mb-2 flex items-center gap-2 text-xs text-muted-foreground">
144
+ <Languages className="h-3.5 w-3.5" />
145
+ <span>{t('enabledLocales')}</span>
207
146
  </div>
208
- <Select value={dateFormat} onValueChange={setDateFormat}>
209
- <SelectTrigger>
210
- <SelectValue />
211
- </SelectTrigger>
212
- <SelectContent>
213
- {dateFormats.map((df) => (
214
- <SelectItem key={df.value} value={df.value}>
215
- <span className="flex items-center gap-2">
216
- <span className="font-mono text-xs">{df.value}</span>
217
- <span className="text-muted-foreground">
218
- {'('}
219
- {df.example}
220
- {')'}
221
- </span>
147
+ <div className="flex flex-wrap gap-1.5">
148
+ {enabledLocales.length > 0 ? (
149
+ enabledLocales.map((locale) => (
150
+ <Badge key={locale.id} variant="outline" className="gap-1">
151
+ <span className="font-mono text-[10px]">{locale.code}</span>
152
+ <span className="text-[10px] text-muted-foreground">
153
+ {locale.name}
222
154
  </span>
223
- </SelectItem>
224
- ))}
225
- </SelectContent>
226
- </Select>
227
- </div>
228
- <div className="space-y-2">
229
- <div className="flex items-center gap-2">
230
- <Clock className="h-4 w-4 text-muted-foreground" />
231
- <Label>Formato de hora</Label>
155
+ </Badge>
156
+ ))
157
+ ) : (
158
+ <span className="text-xs text-muted-foreground">
159
+ {t('noneEnabled')}
160
+ </span>
161
+ )}
232
162
  </div>
233
- <Select value={timeFormat} onValueChange={setTimeFormat}>
234
- <SelectTrigger>
235
- <SelectValue />
236
- </SelectTrigger>
237
- <SelectContent>
238
- {timeFormats.map((tf) => (
239
- <SelectItem key={tf.value} value={tf.value}>
240
- <span className="flex items-center gap-2">
241
- <span>{tf.label}</span>
242
- <span className="text-muted-foreground font-mono text-xs">
243
- {'('}
244
- {tf.example}
245
- {')'}
246
- </span>
247
- </span>
248
- </SelectItem>
249
- ))}
250
- </SelectContent>
251
- </Select>
252
- </div>
253
- </div>
254
-
255
- {/* Preview */}
256
- <div className="rounded-lg border bg-muted/50 p-4">
257
- <p className="mb-2 text-xs font-medium text-muted-foreground uppercase tracking-wider">
258
- Pre-visualizacao
259
- </p>
260
- <div className="flex flex-wrap gap-x-6 gap-y-1 text-sm">
261
- <span>
262
- <span className="text-muted-foreground">Data: </span>
263
- <span className="font-medium font-mono">
264
- {dateFormats.find((d) => d.value === dateFormat)?.example}
265
- </span>
266
- </span>
267
- <span>
268
- <span className="text-muted-foreground">Hora: </span>
269
- <span className="font-medium font-mono">
270
- {timeFormats.find((t) => t.value === timeFormat)?.example}
271
- </span>
272
- </span>
273
- <span>
274
- <span className="text-muted-foreground">Fuso: </span>
275
- <span className="font-medium font-mono">
276
- {
277
- timezones
278
- .find((t) => t.value === timezone)
279
- ?.label.split(' ')[0]
280
- }
281
- </span>
282
- </span>
283
- </div>
284
- </div>
285
-
286
- {/* Actions */}
287
- <div className="flex items-center justify-between border-t pt-4">
288
- <div className="flex items-center gap-2">
289
- <Switch
290
- id="auto-detect-lang"
291
- checked={autoDetect}
292
- onCheckedChange={setAutoDetect}
293
- />
294
- <Label
295
- htmlFor="auto-detect-lang"
296
- className="text-sm text-muted-foreground"
297
- >
298
- Detectar idioma do navegador
299
- </Label>
300
163
  </div>
301
- <Button size="sm">
302
- <CheckCircle2 className="mr-1.5 h-3.5 w-3.5" />
303
- Salvar
304
- </Button>
305
- </div>
306
- </CardContent>
307
- </Card>
164
+ </CardContent>
165
+ </Card>
166
+ </WidgetWrapper>
308
167
  );
309
168
  }