@hed-hog/core 0.0.215 → 0.0.216

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 (36) hide show
  1. package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +5 -5
  2. package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +1 -1
  3. package/hedhog/frontend/app/dashboard/components/add-widget-selector-dialog.tsx.ejs +312 -0
  4. package/hedhog/frontend/app/dashboard/components/dashboard-grid.tsx.ejs +54 -0
  5. package/hedhog/frontend/app/dashboard/components/draggable-grid.tsx.ejs +132 -0
  6. package/hedhog/frontend/app/dashboard/components/dynamic-widget.tsx.ejs +88 -0
  7. package/hedhog/frontend/app/dashboard/components/index.ts.ejs +6 -0
  8. package/hedhog/frontend/app/dashboard/components/stats.tsx.ejs +93 -0
  9. package/hedhog/frontend/app/dashboard/components/widget-wrapper.tsx.ejs +150 -0
  10. package/hedhog/frontend/app/dashboard/components/widgets/account-security.tsx.ejs +184 -0
  11. package/hedhog/frontend/app/dashboard/components/widgets/active-users-card.tsx.ejs +58 -0
  12. package/hedhog/frontend/app/dashboard/components/widgets/activity-timeline.tsx.ejs +219 -0
  13. package/hedhog/frontend/app/dashboard/components/widgets/email-notifications.tsx.ejs +191 -0
  14. package/hedhog/frontend/app/dashboard/components/widgets/locale-config.tsx.ejs +309 -0
  15. package/hedhog/frontend/app/dashboard/components/widgets/login-history-chart.tsx.ejs +111 -0
  16. package/hedhog/frontend/app/dashboard/components/widgets/mail-config.tsx.ejs +445 -0
  17. package/hedhog/frontend/app/dashboard/components/widgets/mail-sent-card.tsx.ejs +58 -0
  18. package/hedhog/frontend/app/dashboard/components/widgets/mail-sent-chart.tsx.ejs +149 -0
  19. package/hedhog/frontend/app/dashboard/components/widgets/oauth-config.tsx.ejs +296 -0
  20. package/hedhog/frontend/app/dashboard/components/widgets/permissions-card.tsx.ejs +61 -0
  21. package/hedhog/frontend/app/dashboard/components/widgets/permissions-chart.tsx.ejs +152 -0
  22. package/hedhog/frontend/app/dashboard/components/widgets/profile-card.tsx.ejs +186 -0
  23. package/hedhog/frontend/app/dashboard/components/widgets/session-activity-chart.tsx.ejs +183 -0
  24. package/hedhog/frontend/app/dashboard/components/widgets/sessions-today-card.tsx.ejs +62 -0
  25. package/hedhog/frontend/app/dashboard/components/widgets/stat-access-level.tsx.ejs +57 -0
  26. package/hedhog/frontend/app/dashboard/components/widgets/stat-actions-today.tsx.ejs +57 -0
  27. package/hedhog/frontend/app/dashboard/components/widgets/stat-consecutive-days.tsx.ejs +57 -0
  28. package/hedhog/frontend/app/dashboard/components/widgets/stat-online-time.tsx.ejs +57 -0
  29. package/hedhog/frontend/app/dashboard/components/widgets/storage-config.tsx.ejs +340 -0
  30. package/hedhog/frontend/app/dashboard/components/widgets/theme-config.tsx.ejs +275 -0
  31. package/hedhog/frontend/app/dashboard/components/widgets/user-growth-chart.tsx.ejs +210 -0
  32. package/hedhog/frontend/app/dashboard/components/widgets/user-roles.tsx.ejs +130 -0
  33. package/hedhog/frontend/app/dashboard/components/widgets/user-sessions.tsx.ejs +233 -0
  34. package/hedhog/frontend/messages/en.json +143 -1
  35. package/hedhog/frontend/messages/pt.json +143 -1
  36. package/package.json +3 -3
@@ -0,0 +1,309 @@
1
+ 'use client';
2
+
3
+ import { Badge } from '@/components/ui/badge';
4
+ import { Button } from '@/components/ui/button';
5
+ import {
6
+ Card,
7
+ CardContent,
8
+ CardDescription,
9
+ CardHeader,
10
+ CardTitle,
11
+ } 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
+ ];
42
+
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',
73
+ },
74
+ ];
75
+
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);
83
+
84
+ const enabledLanguages = languages.filter((l) => l.enabled);
85
+
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
+ }
97
+
98
+ 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" />
105
+ </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>
125
+ </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
+ ))}
155
+ </div>
156
+ </div>
157
+
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>
186
+ </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
+
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>
207
+ </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>
222
+ </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>
232
+ </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
+ </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>
308
+ );
309
+ }
@@ -0,0 +1,111 @@
1
+ 'use client';
2
+
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ CardDescription,
7
+ CardHeader,
8
+ CardTitle,
9
+ } from '@/components/ui/card';
10
+ import {
11
+ ChartContainer,
12
+ ChartTooltip,
13
+ ChartTooltipContent,
14
+ } from '@/components/ui/chart';
15
+ import { useWidgetData } from '@/hooks/use-widget-data';
16
+ import type { AllWidgetsData, LoginDay } from '@/types/widget-data';
17
+ import { LogIn } from 'lucide-react';
18
+ import { useTranslations } from 'next-intl';
19
+ import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from 'recharts';
20
+ import { WidgetWrapper } from '../widget-wrapper';
21
+
22
+ function LoginChart({ data }: { data: LoginDay[] }) {
23
+ const t = useTranslations('core.DashboardPage.loginHistory');
24
+
25
+ const chartConfig = {
26
+ logins: { label: t('logins'), color: 'hsl(221, 83%, 53%)' },
27
+ failed: { label: t('failed'), color: 'hsl(0, 84%, 60%)' },
28
+ };
29
+
30
+ return (
31
+ <Card className="flex h-full flex-col">
32
+ <CardHeader className="shrink-0 pb-2">
33
+ <div className="flex items-center gap-2">
34
+ <LogIn className="h-5 w-5 text-blue-600" />
35
+ <div>
36
+ <CardTitle className="text-base font-semibold">
37
+ {t('title')}
38
+ </CardTitle>
39
+ <CardDescription>{t('description')}</CardDescription>
40
+ </div>
41
+ </div>
42
+ </CardHeader>
43
+ <CardContent className="flex flex-1 flex-col pt-0">
44
+ <ChartContainer
45
+ config={chartConfig}
46
+ className="h-full min-h-[120px] w-full flex-1"
47
+ >
48
+ <BarChart data={data as any} barGap={2}>
49
+ <CartesianGrid vertical={false} strokeDasharray="3 3" />
50
+ <XAxis
51
+ dataKey="day"
52
+ tickLine={false}
53
+ axisLine={false}
54
+ fontSize={12}
55
+ tickMargin={8}
56
+ />
57
+ <YAxis
58
+ tickLine={false}
59
+ axisLine={false}
60
+ fontSize={12}
61
+ tickMargin={4}
62
+ allowDecimals={false}
63
+ />
64
+ <ChartTooltip content={<ChartTooltipContent />} />
65
+ <Bar
66
+ dataKey="logins"
67
+ fill="hsl(221, 83%, 53%)"
68
+ radius={[4, 4, 0, 0]}
69
+ />
70
+ <Bar
71
+ dataKey="failed"
72
+ fill="hsl(0, 84%, 60%)"
73
+ radius={[4, 4, 0, 0]}
74
+ />
75
+ </BarChart>
76
+ </ChartContainer>
77
+ </CardContent>
78
+ </Card>
79
+ );
80
+ }
81
+
82
+ interface LoginHistoryChartProps {
83
+ widget?: { name?: string };
84
+ onRemove?: () => void;
85
+ }
86
+
87
+ export default function LoginHistoryChart({
88
+ widget,
89
+ onRemove,
90
+ }: LoginHistoryChartProps) {
91
+ const { data, isLoading, isError, isAccessDenied } = useWidgetData<
92
+ AllWidgetsData,
93
+ LoginDay[]
94
+ >({
95
+ endpoint: '/dashboard-core/widgets/me',
96
+ queryKey: 'widget-me',
97
+ select: (d) => d.loginHistory,
98
+ });
99
+
100
+ return (
101
+ <WidgetWrapper
102
+ isLoading={isLoading}
103
+ isError={isError}
104
+ isAccessDenied={isAccessDenied}
105
+ widgetName={widget?.name ?? 'login-history-chart'}
106
+ onRemove={onRemove}
107
+ >
108
+ {data && <LoginChart data={data} />}
109
+ </WidgetWrapper>
110
+ );
111
+ }