@hed-hog/core 0.0.297 → 0.0.299

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 (183) 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/dashboard.controller.d.ts +3 -0
  4. package/dist/dashboard/dashboard/dashboard.controller.d.ts.map +1 -1
  5. package/dist/dashboard/dashboard/dashboard.service.d.ts +3 -0
  6. package/dist/dashboard/dashboard/dashboard.service.d.ts.map +1 -1
  7. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +12 -0
  8. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts.map +1 -1
  9. package/dist/dashboard/dashboard-component/dashboard-component.controller.js +22 -0
  10. package/dist/dashboard/dashboard-component/dashboard-component.controller.js.map +1 -1
  11. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +15 -0
  12. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts.map +1 -1
  13. package/dist/dashboard/dashboard-component/dashboard-component.service.js +110 -3
  14. package/dist/dashboard/dashboard-component/dashboard-component.service.js.map +1 -1
  15. package/dist/dashboard/dashboard-component/dto/create.dto.d.ts +1 -0
  16. package/dist/dashboard/dashboard-component/dto/create.dto.d.ts.map +1 -1
  17. package/dist/dashboard/dashboard-component/dto/create.dto.js +5 -0
  18. package/dist/dashboard/dashboard-component/dto/create.dto.js.map +1 -1
  19. package/dist/dashboard/dashboard-component/dto/update.dto.d.ts +1 -0
  20. package/dist/dashboard/dashboard-component/dto/update.dto.d.ts.map +1 -1
  21. package/dist/dashboard/dashboard-component/dto/update.dto.js +5 -0
  22. package/dist/dashboard/dashboard-component/dto/update.dto.js.map +1 -1
  23. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +1 -0
  24. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts.map +1 -1
  25. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +1 -0
  26. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts.map +1 -1
  27. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +21 -1
  28. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
  29. package/dist/dashboard/dashboard-core/dashboard-core.controller.js +9 -0
  30. package/dist/dashboard/dashboard-core/dashboard-core.controller.js.map +1 -1
  31. package/dist/dashboard/dashboard-core/dashboard-core.module.d.ts.map +1 -1
  32. package/dist/dashboard/dashboard-core/dashboard-core.module.js +6 -1
  33. package/dist/dashboard/dashboard-core/dashboard-core.module.js.map +1 -1
  34. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +180 -2
  35. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
  36. package/dist/dashboard/dashboard-core/dashboard-core.service.js +619 -9
  37. package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
  38. package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +1 -0
  39. package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts.map +1 -1
  40. package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +1 -0
  41. package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts.map +1 -1
  42. package/dist/file/file.controller.d.ts.map +1 -1
  43. package/dist/file/file.controller.js +16 -0
  44. package/dist/file/file.controller.js.map +1 -1
  45. package/dist/file/file.service.d.ts +7 -1
  46. package/dist/file/file.service.d.ts.map +1 -1
  47. package/dist/file/file.service.js +38 -1
  48. package/dist/file/file.service.js.map +1 -1
  49. package/dist/file/provider/s3.provider.d.ts +1 -0
  50. package/dist/file/provider/s3.provider.d.ts.map +1 -1
  51. package/dist/file/provider/s3.provider.js +38 -29
  52. package/dist/file/provider/s3.provider.js.map +1 -1
  53. package/dist/oauth/oauth.service.d.ts.map +1 -1
  54. package/dist/oauth/oauth.service.js +2 -1
  55. package/dist/oauth/oauth.service.js.map +1 -1
  56. package/dist/user/constants/user.constants.d.ts +1 -0
  57. package/dist/user/constants/user.constants.d.ts.map +1 -1
  58. package/dist/user/constants/user.constants.js +2 -1
  59. package/dist/user/constants/user.constants.js.map +1 -1
  60. package/dist/user/user.controller.d.ts +10 -10
  61. package/dist/user/user.service.d.ts +30 -30
  62. package/dist/user/user.service.d.ts.map +1 -1
  63. package/dist/user/user.service.js +2 -1
  64. package/dist/user/user.service.js.map +1 -1
  65. package/hedhog/data/dashboard_item.yaml +10 -10
  66. package/hedhog/data/route.yaml +20 -0
  67. package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +212 -34
  68. package/hedhog/frontend/app/dashboard/[slug]/types.ts.ejs +3 -0
  69. package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +136 -23
  70. package/hedhog/frontend/app/dashboard/components/add-widget-selector-dialog.tsx.ejs +266 -85
  71. package/hedhog/frontend/app/dashboard/components/widgets/core..gitkeep.ejs +11 -0
  72. package/hedhog/frontend/app/dashboard/components/widgets/core.account-security.tsx.ejs +192 -0
  73. package/hedhog/frontend/app/dashboard/components/widgets/core.email-notifications.tsx.ejs +226 -0
  74. package/hedhog/frontend/app/dashboard/components/widgets/core.locale-config.tsx.ejs +168 -0
  75. package/hedhog/frontend/app/dashboard/components/widgets/core.mail-config.tsx.ejs +199 -0
  76. package/hedhog/frontend/app/dashboard/components/widgets/core.oauth-config.tsx.ejs +175 -0
  77. package/hedhog/frontend/app/dashboard/components/widgets/core.profile-card.tsx.ejs +186 -0
  78. package/hedhog/frontend/app/dashboard/components/widgets/core.storage-config.tsx.ejs +196 -0
  79. package/hedhog/frontend/app/dashboard/components/widgets/core.theme-config.tsx.ejs +213 -0
  80. package/hedhog/frontend/app/dashboard/components/widgets/core.user-roles.tsx.ejs +132 -0
  81. package/hedhog/frontend/app/dashboard/components/widgets/core.user-sessions.tsx.ejs +236 -0
  82. package/hedhog/frontend/app/dashboard/components/widgets/finance.alerts.tsx.ejs +108 -0
  83. package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-balance-kpi.tsx.ejs +66 -0
  84. package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-flow-chart.tsx.ejs +122 -0
  85. package/hedhog/frontend/app/dashboard/components/widgets/finance.default-kpi.tsx.ejs +63 -0
  86. package/hedhog/frontend/app/dashboard/components/widgets/finance.payable-30d-kpi.tsx.ejs +73 -0
  87. package/hedhog/frontend/app/dashboard/components/widgets/finance.receivable-30d-kpi.tsx.ejs +73 -0
  88. package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-payable.tsx.ejs +123 -0
  89. package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-receivable.tsx.ejs +118 -0
  90. package/hedhog/frontend/messages/en.json +93 -0
  91. package/hedhog/frontend/messages/pt.json +93 -0
  92. package/hedhog/frontend/public/dashboard-previews/.gitkeep +12 -0
  93. package/hedhog/frontend/public/dashboard-previews/account-security.png +0 -0
  94. package/hedhog/frontend/public/dashboard-previews/active-users-card.png +0 -0
  95. package/hedhog/frontend/public/dashboard-previews/activity-timeline.png +0 -0
  96. package/hedhog/frontend/public/dashboard-previews/cash-balance-kpi.png +0 -0
  97. package/hedhog/frontend/public/dashboard-previews/cash-flow-chart.png +0 -0
  98. package/hedhog/frontend/public/dashboard-previews/default-kpi.png +0 -0
  99. package/hedhog/frontend/public/dashboard-previews/email-notifications.png +0 -0
  100. package/hedhog/frontend/public/dashboard-previews/financial-alerts.png +0 -0
  101. package/hedhog/frontend/public/dashboard-previews/login-history-chart.png +0 -0
  102. package/hedhog/frontend/public/dashboard-previews/mail-sent-card.png +0 -0
  103. package/hedhog/frontend/public/dashboard-previews/mail-sent-chart.png +0 -0
  104. package/hedhog/frontend/public/dashboard-previews/menus-card.png +0 -0
  105. package/hedhog/frontend/public/dashboard-previews/payable-30d-kpi.png +0 -0
  106. package/hedhog/frontend/public/dashboard-previews/permissions-card.png +0 -0
  107. package/hedhog/frontend/public/dashboard-previews/permissions-chart.png +0 -0
  108. package/hedhog/frontend/public/dashboard-previews/profile-card.png +0 -0
  109. package/hedhog/frontend/public/dashboard-previews/receivable-30d-kpi.png +0 -0
  110. package/hedhog/frontend/public/dashboard-previews/routes-card.png +0 -0
  111. package/hedhog/frontend/public/dashboard-previews/session-activity-chart.png +0 -0
  112. package/hedhog/frontend/public/dashboard-previews/sessions-today-card.png +0 -0
  113. package/hedhog/frontend/public/dashboard-previews/stat-access-level.png +0 -0
  114. package/hedhog/frontend/public/dashboard-previews/stat-actions-today.png +0 -0
  115. package/hedhog/frontend/public/dashboard-previews/stat-consecutive-days.png +0 -0
  116. package/hedhog/frontend/public/dashboard-previews/stat-online-time.png +0 -0
  117. package/hedhog/frontend/public/dashboard-previews/upcoming-payable.png +0 -0
  118. package/hedhog/frontend/public/dashboard-previews/upcoming-receivable.png +0 -0
  119. package/hedhog/frontend/public/dashboard-previews/user-growth-chart.png +0 -0
  120. package/hedhog/frontend/public/dashboard-previews/user-roles.png +0 -0
  121. package/hedhog/frontend/{app/dashboard/components/widgets → widgets}/account-security.tsx.ejs +33 -29
  122. package/hedhog/frontend/widgets/active-users-card.tsx.ejs +58 -0
  123. package/hedhog/frontend/widgets/activity-timeline.tsx.ejs +223 -0
  124. package/hedhog/frontend/{app/dashboard/components/widgets → widgets}/email-notifications.tsx.ejs +85 -61
  125. package/hedhog/frontend/widgets/locale-config.tsx.ejs +168 -0
  126. package/hedhog/frontend/widgets/login-history-chart.tsx.ejs +115 -0
  127. package/hedhog/frontend/widgets/mail-config.tsx.ejs +199 -0
  128. package/hedhog/frontend/widgets/mail-sent-card.tsx.ejs +58 -0
  129. package/hedhog/frontend/widgets/mail-sent-chart.tsx.ejs +149 -0
  130. package/hedhog/frontend/widgets/menus-card.tsx.ejs +58 -0
  131. package/hedhog/frontend/widgets/oauth-config.tsx.ejs +175 -0
  132. package/hedhog/frontend/widgets/permissions-card.tsx.ejs +61 -0
  133. package/hedhog/frontend/widgets/permissions-chart.tsx.ejs +156 -0
  134. package/hedhog/frontend/{app/dashboard/components/widgets → widgets}/profile-card.tsx.ejs +3 -3
  135. package/hedhog/frontend/widgets/routes-card.tsx.ejs +58 -0
  136. package/hedhog/frontend/widgets/session-activity-chart.tsx.ejs +183 -0
  137. package/hedhog/frontend/widgets/sessions-today-card.tsx.ejs +62 -0
  138. package/hedhog/frontend/widgets/stat-access-level.tsx.ejs +57 -0
  139. package/hedhog/frontend/widgets/stat-actions-today.tsx.ejs +57 -0
  140. package/hedhog/frontend/widgets/stat-consecutive-days.tsx.ejs +57 -0
  141. package/hedhog/frontend/widgets/stat-online-time.tsx.ejs +57 -0
  142. package/hedhog/frontend/widgets/storage-config.tsx.ejs +196 -0
  143. package/hedhog/frontend/widgets/theme-config.tsx.ejs +213 -0
  144. package/hedhog/frontend/widgets/user-growth-chart.tsx.ejs +210 -0
  145. package/hedhog/frontend/{app/dashboard/components/widgets → widgets}/user-roles.tsx.ejs +12 -14
  146. package/hedhog/frontend/{app/dashboard/components/widgets → widgets}/user-sessions.tsx.ejs +1 -1
  147. package/hedhog/table/dashboard_component.yaml +7 -0
  148. package/hedhog/table/mail_sent_user.yaml +75 -0
  149. package/package.json +4 -4
  150. package/src/dashboard/dashboard-component/dashboard-component.controller.ts +36 -12
  151. package/src/dashboard/dashboard-component/dashboard-component.service.ts +150 -3
  152. package/src/dashboard/dashboard-component/dto/create.dto.ts +4 -0
  153. package/src/dashboard/dashboard-component/dto/update.dto.ts +4 -0
  154. package/src/dashboard/dashboard-core/dashboard-core.controller.ts +5 -0
  155. package/src/dashboard/dashboard-core/dashboard-core.module.ts +6 -1
  156. package/src/dashboard/dashboard-core/dashboard-core.service.ts +874 -8
  157. package/src/file/file.controller.ts +37 -13
  158. package/src/file/file.service.ts +47 -5
  159. package/src/file/provider/s3.provider.ts +39 -29
  160. package/src/oauth/oauth.service.ts +8 -7
  161. package/src/user/constants/user.constants.ts +1 -0
  162. package/src/user/user.service.ts +2 -1
  163. package/hedhog/frontend/app/dashboard/components/widgets/locale-config.tsx.ejs +0 -309
  164. package/hedhog/frontend/app/dashboard/components/widgets/mail-config.tsx.ejs +0 -445
  165. package/hedhog/frontend/app/dashboard/components/widgets/oauth-config.tsx.ejs +0 -296
  166. package/hedhog/frontend/app/dashboard/components/widgets/storage-config.tsx.ejs +0 -340
  167. package/hedhog/frontend/app/dashboard/components/widgets/theme-config.tsx.ejs +0 -275
  168. /package/hedhog/frontend/app/dashboard/components/widgets/{active-users-card.tsx.ejs → core.active-users-card.tsx.ejs} +0 -0
  169. /package/hedhog/frontend/app/dashboard/components/widgets/{activity-timeline.tsx.ejs → core.activity-timeline.tsx.ejs} +0 -0
  170. /package/hedhog/frontend/app/dashboard/components/widgets/{login-history-chart.tsx.ejs → core.login-history-chart.tsx.ejs} +0 -0
  171. /package/hedhog/frontend/app/dashboard/components/widgets/{mail-sent-card.tsx.ejs → core.mail-sent-card.tsx.ejs} +0 -0
  172. /package/hedhog/frontend/app/dashboard/components/widgets/{mail-sent-chart.tsx.ejs → core.mail-sent-chart.tsx.ejs} +0 -0
  173. /package/hedhog/frontend/app/dashboard/components/widgets/{menus-card.tsx.ejs → core.menus-card.tsx.ejs} +0 -0
  174. /package/hedhog/frontend/app/dashboard/components/widgets/{permissions-card.tsx.ejs → core.permissions-card.tsx.ejs} +0 -0
  175. /package/hedhog/frontend/app/dashboard/components/widgets/{permissions-chart.tsx.ejs → core.permissions-chart.tsx.ejs} +0 -0
  176. /package/hedhog/frontend/app/dashboard/components/widgets/{routes-card.tsx.ejs → core.routes-card.tsx.ejs} +0 -0
  177. /package/hedhog/frontend/app/dashboard/components/widgets/{session-activity-chart.tsx.ejs → core.session-activity-chart.tsx.ejs} +0 -0
  178. /package/hedhog/frontend/app/dashboard/components/widgets/{sessions-today-card.tsx.ejs → core.sessions-today-card.tsx.ejs} +0 -0
  179. /package/hedhog/frontend/app/dashboard/components/widgets/{stat-access-level.tsx.ejs → core.stat-access-level.tsx.ejs} +0 -0
  180. /package/hedhog/frontend/app/dashboard/components/widgets/{stat-actions-today.tsx.ejs → core.stat-actions-today.tsx.ejs} +0 -0
  181. /package/hedhog/frontend/app/dashboard/components/widgets/{stat-consecutive-days.tsx.ejs → core.stat-consecutive-days.tsx.ejs} +0 -0
  182. /package/hedhog/frontend/app/dashboard/components/widgets/{stat-online-time.tsx.ejs → core.stat-online-time.tsx.ejs} +0 -0
  183. /package/hedhog/frontend/app/dashboard/components/widgets/{user-growth-chart.tsx.ejs → core.user-growth-chart.tsx.ejs} +0 -0
@@ -0,0 +1,223 @@
1
+ 'use client';
2
+
3
+ import { Badge } from '@/components/ui/badge';
4
+ import {
5
+ Card,
6
+ CardContent,
7
+ CardDescription,
8
+ CardHeader,
9
+ CardTitle,
10
+ } from '@/components/ui/card';
11
+ import { ScrollArea } from '@/components/ui/scroll-area';
12
+ import { useWidgetData } from '@/hooks/use-widget-data';
13
+ import type { ActivityEvent, AllWidgetsData } from '@/types/widget-data';
14
+ import {
15
+ FileEdit,
16
+ LogIn,
17
+ LogOut,
18
+ Mail,
19
+ Settings,
20
+ ShieldAlert,
21
+ UserCheck,
22
+ } from 'lucide-react';
23
+ import { useTranslations } from 'next-intl';
24
+ import { WidgetWrapper } from '../widget-wrapper';
25
+
26
+ const typeIconMap: Record<string, React.ElementType> = {
27
+ login: LogIn,
28
+ logout: LogOut,
29
+ security: ShieldAlert,
30
+ settings: Settings,
31
+ edit: FileEdit,
32
+ permission: UserCheck,
33
+ email: Mail,
34
+ };
35
+
36
+ const typeColorMap: Record<string, { color: string; bg: string }> = {
37
+ login: {
38
+ color: 'text-blue-600 dark:text-blue-400',
39
+ bg: 'bg-blue-50 dark:bg-blue-950/40',
40
+ },
41
+ logout: { color: 'text-muted-foreground', bg: 'bg-muted' },
42
+ security: {
43
+ color: 'text-amber-600 dark:text-amber-400',
44
+ bg: 'bg-amber-50 dark:bg-amber-950/40',
45
+ },
46
+ settings: { color: 'text-foreground', bg: 'bg-muted' },
47
+ edit: {
48
+ color: 'text-indigo-600 dark:text-indigo-400',
49
+ bg: 'bg-indigo-50 dark:bg-indigo-950/40',
50
+ },
51
+ permission: {
52
+ color: 'text-emerald-600 dark:text-emerald-400',
53
+ bg: 'bg-emerald-50 dark:bg-emerald-950/40',
54
+ },
55
+ email: {
56
+ color: 'text-rose-600 dark:text-rose-400',
57
+ bg: 'bg-rose-50 dark:bg-rose-950/40',
58
+ },
59
+ };
60
+
61
+ function detectType(action: string): string {
62
+ const a = action.toLowerCase();
63
+ if (a.includes('login') || a.includes('entrou') || a.includes('acesso'))
64
+ return 'login';
65
+ if (a.includes('logout') || a.includes('saiu') || a.includes('encerr'))
66
+ return 'logout';
67
+ if (
68
+ a.includes('senha') ||
69
+ a.includes('2fa') ||
70
+ a.includes('mfa') ||
71
+ a.includes('segur')
72
+ )
73
+ return 'security';
74
+ if (a.includes('config') || a.includes('idioma') || a.includes('preferên'))
75
+ return 'settings';
76
+ if (
77
+ a.includes('edit') ||
78
+ a.includes('atualiz') ||
79
+ a.includes('alter') ||
80
+ a.includes('perfil')
81
+ )
82
+ return 'edit';
83
+ if (a.includes('permiss') || a.includes('acesso') || a.includes('role'))
84
+ return 'permission';
85
+ if (a.includes('email') || a.includes('e-mail') || a.includes('notif'))
86
+ return 'email';
87
+ return 'settings';
88
+ }
89
+
90
+ function formatDate(
91
+ dateStr: string,
92
+ tToday: string,
93
+ tYesterday: string
94
+ ): string {
95
+ const date = new Date(dateStr);
96
+ const now = new Date();
97
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
98
+ const yesterday = new Date(today);
99
+ yesterday.setDate(yesterday.getDate() - 1);
100
+ const eventDay = new Date(
101
+ date.getFullYear(),
102
+ date.getMonth(),
103
+ date.getDate()
104
+ );
105
+ if (eventDay.getTime() === today.getTime()) return tToday;
106
+ if (eventDay.getTime() === yesterday.getTime()) return tYesterday;
107
+ return date.toLocaleDateString(undefined, { day: '2-digit', month: 'short' });
108
+ }
109
+
110
+ function formatTime(dateStr: string): string {
111
+ return new Date(dateStr).toLocaleTimeString('pt-BR', {
112
+ hour: '2-digit',
113
+ minute: '2-digit',
114
+ });
115
+ }
116
+
117
+ function TimelineContent({ events }: { events: ActivityEvent[] }) {
118
+ const t = useTranslations('core.DashboardPage.activityTimeline');
119
+ let lastDate = '';
120
+
121
+ return (
122
+ <Card className="flex h-full min-h-0 flex-col overflow-hidden">
123
+ <CardHeader className="shrink-0 pb-3">
124
+ <div className="flex items-center justify-between">
125
+ <div>
126
+ <CardTitle className="text-sm font-semibold sm:text-base">
127
+ {t('title')}
128
+ </CardTitle>
129
+ <CardDescription className="text-xs sm:text-sm">
130
+ {t('description')}
131
+ </CardDescription>
132
+ </div>
133
+ <Badge variant="secondary" className="text-[10px] sm:text-xs">
134
+ {t('events', { count: events.length })}
135
+ </Badge>
136
+ </div>
137
+ </CardHeader>
138
+ <CardContent className="flex min-h-0 flex-1 flex-col overflow-hidden pt-0">
139
+ <ScrollArea className="h-full pr-2 sm:pr-3">
140
+ <div className="relative flex flex-col pb-2">
141
+ <div className="absolute bottom-0 left-[13px] top-0 w-px bg-border/60 sm:left-[15px]" />
142
+ {events.map((event, index) => {
143
+ const type = detectType(event.action);
144
+ const config =
145
+ typeColorMap[type] ??
146
+ (typeColorMap.settings as { color: string; bg: string });
147
+ const Icon = (typeIconMap[type] ?? Settings) as React.ElementType;
148
+ const dateLabel = formatDate(
149
+ event.created_at,
150
+ t('today'),
151
+ t('yesterday')
152
+ );
153
+ const showDate = dateLabel !== lastDate;
154
+ lastDate = dateLabel;
155
+
156
+ return (
157
+ <div key={event.id}>
158
+ {showDate && (
159
+ <div className="relative z-10 mb-1 mt-4 first:mt-0">
160
+ <span className="ml-9 inline-block rounded-md border border-border bg-muted px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground sm:ml-11 sm:px-2 sm:text-[11px]">
161
+ {dateLabel}
162
+ </span>
163
+ </div>
164
+ )}
165
+ <div className="group relative flex items-start gap-3 py-1.5">
166
+ <div
167
+ className={`relative z-10 mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-lg sm:h-8 sm:w-8 ${config.bg}`}
168
+ >
169
+ <Icon
170
+ className={`h-3 w-3 sm:h-3.5 sm:w-3.5 ${config.color}`}
171
+ />
172
+ </div>
173
+ <div className="flex min-w-0 flex-1 flex-col gap-0.5 rounded-lg px-1.5 py-1.5 transition-colors group-hover:bg-muted/40 sm:px-2">
174
+ <div className="flex items-center justify-between gap-2">
175
+ <span className="min-w-0 wrap-break-word text-xs font-medium leading-snug text-foreground sm:text-sm">
176
+ {event.action}
177
+ </span>
178
+ <span className="shrink-0 text-[10px] tabular-nums text-muted-foreground sm:text-[11px]">
179
+ {formatTime(event.created_at)}
180
+ </span>
181
+ </div>
182
+ </div>
183
+ </div>
184
+ </div>
185
+ );
186
+ })}
187
+ </div>
188
+ </ScrollArea>
189
+ </CardContent>
190
+ </Card>
191
+ );
192
+ }
193
+
194
+ interface ActivityTimelineProps {
195
+ widget?: { name?: string };
196
+ onRemove?: () => void;
197
+ }
198
+
199
+ export default function ActivityTimeline({
200
+ widget,
201
+ onRemove,
202
+ }: ActivityTimelineProps) {
203
+ const { data, isLoading, isError, isAccessDenied } = useWidgetData<
204
+ AllWidgetsData,
205
+ ActivityEvent[]
206
+ >({
207
+ endpoint: '/dashboard-core/widgets/me',
208
+ queryKey: 'widget-me',
209
+ select: (d) => d.activityTimeline,
210
+ });
211
+
212
+ return (
213
+ <WidgetWrapper
214
+ isLoading={isLoading}
215
+ isError={isError}
216
+ isAccessDenied={isAccessDenied}
217
+ widgetName={widget?.name ?? 'activity-timeline'}
218
+ onRemove={onRemove}
219
+ >
220
+ {data && <TimelineContent events={data} />}
221
+ </WidgetWrapper>
222
+ );
223
+ }
@@ -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"
@@ -0,0 +1,168 @@
1
+ 'use client';
2
+
3
+ import { Badge } from '@/components/ui/badge';
4
+ import {
5
+ Card,
6
+ CardContent,
7
+ CardDescription,
8
+ CardHeader,
9
+ CardTitle,
10
+ } from '@/components/ui/card';
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';
19
+
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,
30
+ },
31
+ locales: [],
32
+ };
33
+
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');
41
+
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
+ });
50
+
51
+ const localeData = data ?? defaultLocaleConfigData;
52
+ const enabledLocales = localeData.locales.filter((locale) => locale.enabled);
53
+
54
+ return (
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>
73
+ </div>
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>
84
+ </div>
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>
110
+ </div>
111
+
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>
140
+ </div>
141
+
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>
146
+ </div>
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}
154
+ </span>
155
+ </Badge>
156
+ ))
157
+ ) : (
158
+ <span className="text-xs text-muted-foreground">
159
+ {t('noneEnabled')}
160
+ </span>
161
+ )}
162
+ </div>
163
+ </div>
164
+ </CardContent>
165
+ </Card>
166
+ </WidgetWrapper>
167
+ );
168
+ }
@@ -0,0 +1,115 @@
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 min-h-0 flex-col overflow-hidden">
32
+ <CardHeader className="shrink-0 pb-2">
33
+ <div className="flex items-center gap-2">
34
+ <LogIn className="h-4 w-4 text-blue-600 sm:h-5 sm:w-5" />
35
+ <div>
36
+ <CardTitle className="text-sm font-semibold sm:text-base">
37
+ {t('title')}
38
+ </CardTitle>
39
+ <CardDescription className="text-xs sm:text-sm">
40
+ {t('description')}
41
+ </CardDescription>
42
+ </div>
43
+ </div>
44
+ </CardHeader>
45
+ <CardContent className="flex min-h-0 flex-1 flex-col overflow-hidden pt-0">
46
+ <ChartContainer
47
+ config={chartConfig}
48
+ className="h-full min-h-[140px] w-full flex-1 overflow-hidden sm:min-h-40"
49
+ >
50
+ <BarChart data={data as any} barGap={2}>
51
+ <CartesianGrid vertical={false} strokeDasharray="3 3" />
52
+ <XAxis
53
+ dataKey="day"
54
+ tickLine={false}
55
+ axisLine={false}
56
+ fontSize={10}
57
+ tickMargin={4}
58
+ minTickGap={20}
59
+ interval="preserveStartEnd"
60
+ />
61
+ <YAxis
62
+ tickLine={false}
63
+ axisLine={false}
64
+ fontSize={10}
65
+ tickMargin={4}
66
+ allowDecimals={false}
67
+ />
68
+ <ChartTooltip content={<ChartTooltipContent />} />
69
+ <Bar
70
+ dataKey="logins"
71
+ fill="hsl(221, 83%, 53%)"
72
+ radius={[4, 4, 0, 0]}
73
+ />
74
+ <Bar
75
+ dataKey="failed"
76
+ fill="hsl(0, 84%, 60%)"
77
+ radius={[4, 4, 0, 0]}
78
+ />
79
+ </BarChart>
80
+ </ChartContainer>
81
+ </CardContent>
82
+ </Card>
83
+ );
84
+ }
85
+
86
+ interface LoginHistoryChartProps {
87
+ widget?: { name?: string };
88
+ onRemove?: () => void;
89
+ }
90
+
91
+ export default function LoginHistoryChart({
92
+ widget,
93
+ onRemove,
94
+ }: LoginHistoryChartProps) {
95
+ const { data, isLoading, isError, isAccessDenied } = useWidgetData<
96
+ AllWidgetsData,
97
+ LoginDay[]
98
+ >({
99
+ endpoint: '/dashboard-core/widgets/me',
100
+ queryKey: 'widget-me',
101
+ select: (d) => d.loginHistory,
102
+ });
103
+
104
+ return (
105
+ <WidgetWrapper
106
+ isLoading={isLoading}
107
+ isError={isError}
108
+ isAccessDenied={isAccessDenied}
109
+ widgetName={widget?.name ?? 'login-history-chart'}
110
+ onRemove={onRemove}
111
+ >
112
+ {data && <LoginChart data={data} />}
113
+ </WidgetWrapper>
114
+ );
115
+ }