@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,199 @@
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
+ MailConfigWidgetData,
15
+ } from '@/types/widget-data';
16
+ import { CheckCircle2, Mail, Send, Server } from 'lucide-react';
17
+ import { useTranslations } from 'next-intl';
18
+ import { WidgetWrapper } from '../widget-wrapper';
19
+
20
+ const defaultMailConfigData: MailConfigWidgetData = {
21
+ status: {
22
+ isConfigured: false,
23
+ selectedProvider: null,
24
+ configuredProvider: null,
25
+ },
26
+ sender: {
27
+ from: null,
28
+ },
29
+ metrics: {
30
+ templateCount: 0,
31
+ sentCount: 0,
32
+ sentLast30Days: 0,
33
+ },
34
+ providers: [],
35
+ };
36
+
37
+ interface MailConfigProps {
38
+ widget?: { name?: string };
39
+ onRemove?: () => void;
40
+ }
41
+
42
+ const iconByProvider: Record<string, React.ElementType> = {
43
+ SMTP: Server,
44
+ GMAIL: Mail,
45
+ SES: Send,
46
+ };
47
+
48
+ export default function MailConfig({ widget, onRemove }: MailConfigProps) {
49
+ const t = useTranslations('core.DashboardPage.mailConfig');
50
+
51
+ const { data, isLoading, isError, isAccessDenied } = useWidgetData<
52
+ DashboardCoreConfigOverviewData,
53
+ MailConfigWidgetData
54
+ >({
55
+ endpoint: '/dashboard-core/config/overview',
56
+ queryKey: 'dashboard-core-config-overview',
57
+ select: (d) => d.mailConfig,
58
+ });
59
+
60
+ const mailData = data ?? defaultMailConfigData;
61
+
62
+ return (
63
+ <WidgetWrapper
64
+ isLoading={isLoading}
65
+ isError={isError}
66
+ isAccessDenied={isAccessDenied}
67
+ widgetName={widget?.name ?? t('title')}
68
+ onRemove={onRemove}
69
+ >
70
+ <Card className="flex h-full min-h-0 flex-col overflow-hidden">
71
+ <CardHeader className="shrink-0">
72
+ <div className="flex items-center justify-between gap-3">
73
+ <div className="flex items-center gap-3">
74
+ <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-blue-50">
75
+ <Mail className="h-5 w-5 text-blue-600" />
76
+ </div>
77
+ <div>
78
+ <CardTitle className="text-base">{t('title')}</CardTitle>
79
+ <CardDescription>{t('description')}</CardDescription>
80
+ </div>
81
+ </div>
82
+ <Badge
83
+ variant="secondary"
84
+ className={
85
+ mailData.status.isConfigured
86
+ ? 'bg-emerald-50 text-emerald-700'
87
+ : 'bg-amber-50 text-amber-700'
88
+ }
89
+ >
90
+ {mailData.status.isConfigured ? t('configured') : t('pending')}
91
+ </Badge>
92
+ </div>
93
+ </CardHeader>
94
+ <CardContent className="flex min-h-0 flex-1 flex-col gap-4 overflow-hidden pt-0">
95
+ <div className="grid grid-cols-3 gap-2">
96
+ <div className="rounded-lg border bg-muted/30 p-3 text-center">
97
+ <p className="text-[11px] text-muted-foreground">
98
+ {t('templates')}
99
+ </p>
100
+ <p className="mt-1 text-lg font-semibold">
101
+ {mailData.metrics.templateCount}
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">
106
+ {t('sentTotal')}
107
+ </p>
108
+ <p className="mt-1 text-lg font-semibold">
109
+ {mailData.metrics.sentCount}
110
+ </p>
111
+ </div>
112
+ <div className="rounded-lg border bg-muted/30 p-3 text-center">
113
+ <p className="text-[11px] text-muted-foreground">
114
+ {t('sent30Days')}
115
+ </p>
116
+ <p className="mt-1 text-lg font-semibold">
117
+ {mailData.metrics.sentLast30Days}
118
+ </p>
119
+ </div>
120
+ </div>
121
+
122
+ <div className="rounded-lg border p-3">
123
+ <p className="mb-2 text-xs text-muted-foreground">{t('sender')}</p>
124
+ <p className="truncate text-sm font-medium">
125
+ {mailData.sender.from || t('notSet')}
126
+ </p>
127
+ </div>
128
+
129
+ <div className="min-h-0 flex-1 rounded-lg border p-3">
130
+ <div className="mb-2 flex items-center justify-between">
131
+ <p className="text-xs text-muted-foreground">{t('providers')}</p>
132
+ <Badge variant="outline" className="text-[10px]">
133
+ {t('selectedProvider', {
134
+ provider: mailData.status.selectedProvider || t('none'),
135
+ })}
136
+ </Badge>
137
+ </div>
138
+ <div className="space-y-2">
139
+ {mailData.providers.length > 0 ? (
140
+ mailData.providers.map((provider) => {
141
+ const Icon = iconByProvider[provider.id] ?? Mail;
142
+ const statusClass = provider.configured
143
+ ? 'bg-emerald-50 text-emerald-700'
144
+ : 'bg-muted text-muted-foreground';
145
+
146
+ return (
147
+ <div
148
+ key={provider.id}
149
+ className="flex items-center justify-between rounded-lg border p-2"
150
+ >
151
+ <div className="flex min-w-0 items-center gap-2">
152
+ <div className="flex h-7 w-7 items-center justify-center rounded-md bg-muted/60">
153
+ <Icon className="h-3.5 w-3.5" />
154
+ </div>
155
+ <div className="min-w-0">
156
+ <p className="truncate text-sm font-medium">
157
+ {provider.label}
158
+ </p>
159
+ <p className="truncate text-[11px] text-muted-foreground">
160
+ {provider.missingKeys.length > 0
161
+ ? t('missingKeys', {
162
+ count: provider.missingKeys.length,
163
+ })
164
+ : t('allKeysPresent')}
165
+ </p>
166
+ </div>
167
+ </div>
168
+ <div className="flex items-center gap-1.5">
169
+ {provider.selected && (
170
+ <Badge variant="outline" className="text-[10px]">
171
+ {t('selected')}
172
+ </Badge>
173
+ )}
174
+ <Badge variant="secondary" className={statusClass}>
175
+ {provider.configured ? (
176
+ <>
177
+ <CheckCircle2 className="mr-1 h-3 w-3" />
178
+ {t('configured')}
179
+ </>
180
+ ) : (
181
+ t('pending')
182
+ )}
183
+ </Badge>
184
+ </div>
185
+ </div>
186
+ );
187
+ })
188
+ ) : (
189
+ <p className="text-xs text-muted-foreground">
190
+ {t('noProviders')}
191
+ </p>
192
+ )}
193
+ </div>
194
+ </div>
195
+ </CardContent>
196
+ </Card>
197
+ </WidgetWrapper>
198
+ );
199
+ }
@@ -0,0 +1,58 @@
1
+ import { useWidgetData } from '@/hooks/use-widget-data';
2
+ import { Mail } from 'lucide-react';
3
+ import { useTranslations } from 'next-intl';
4
+ import StatCard from '../stats';
5
+ import { WidgetWrapper } from '../widget-wrapper';
6
+
7
+ interface MailSentProps {
8
+ widget?: any;
9
+ onRemove?: () => void;
10
+ }
11
+
12
+ interface MailStatsData {
13
+ cards?: {
14
+ emailsSent?: {
15
+ value: number;
16
+ change: number | null;
17
+ };
18
+ };
19
+ }
20
+
21
+ export default function MailSent({ widget, onRemove }: MailSentProps) {
22
+ const t = useTranslations('core.Dashboard');
23
+
24
+ const { data, isLoading, isAccessDenied, isError } =
25
+ useWidgetData<MailStatsData>({
26
+ endpoint: '/dashboard-core/stats/overview/mails',
27
+ queryKey: 'dashboard-stats-mails',
28
+ });
29
+
30
+ const value = data?.cards?.emailsSent?.value?.toLocaleString('pt-BR') || '0';
31
+ const change = data?.cards?.emailsSent?.change;
32
+ const changeType =
33
+ change !== null && change !== undefined && change >= 0 ? 'up' : 'down';
34
+
35
+ return (
36
+ <WidgetWrapper
37
+ isLoading={isLoading}
38
+ isAccessDenied={isAccessDenied}
39
+ isError={isError}
40
+ widgetName={widget?.name || t('emailsSent')}
41
+ onRemove={onRemove}
42
+ >
43
+ <StatCard
44
+ title={t('emailsSent')}
45
+ value={value}
46
+ change={
47
+ change !== null && change !== undefined
48
+ ? `${change > 0 ? '+' : ''}${change}%`
49
+ : undefined
50
+ }
51
+ changeType={changeType}
52
+ icon={<Mail className="h-6 w-6 text-amber-500" />}
53
+ iconBg="bg-amber-500/10"
54
+ delay={150}
55
+ />
56
+ </WidgetWrapper>
57
+ );
58
+ }
@@ -0,0 +1,149 @@
1
+ 'use client';
2
+
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ CardDescription,
7
+ CardHeader,
8
+ CardTitle,
9
+ } from '@/components/ui/card';
10
+ import { useWidgetData } from '@/hooks/use-widget-data';
11
+ import { IconGripVertical } from '@tabler/icons-react';
12
+ import { useTranslations } from 'next-intl';
13
+ import {
14
+ Bar,
15
+ BarChart,
16
+ CartesianGrid,
17
+ ResponsiveContainer,
18
+ Tooltip,
19
+ XAxis,
20
+ YAxis,
21
+ } from 'recharts';
22
+ import { WidgetWrapper } from '../widget-wrapper';
23
+
24
+ function CustomTooltip({
25
+ active,
26
+ payload,
27
+ label,
28
+ }: {
29
+ active?: boolean;
30
+ payload?: Array<{ value: number; dataKey: string }>;
31
+ label?: string;
32
+ }) {
33
+ const t = useTranslations('core.Dashboard');
34
+ if (!active || !payload?.length) return null;
35
+
36
+ return (
37
+ <div className="rounded-lg border bg-card px-3 py-2 shadow-xl">
38
+ <p className="mb-1 text-xs font-medium text-card-foreground">{label}</p>
39
+ {payload.map((entry) => (
40
+ <p key={entry.dataKey} className="text-xs text-muted-foreground">
41
+ <span
42
+ className="mr-1.5 inline-block h-2 w-2 rounded-full"
43
+ style={{ backgroundColor: '#3b82f6' }}
44
+ />
45
+ {t('sent')}: {entry.value.toLocaleString('pt-BR')}
46
+ </p>
47
+ ))}
48
+ </div>
49
+ );
50
+ }
51
+
52
+ interface EmailStatsChartProps {
53
+ widget?: any;
54
+ onRemove?: () => void;
55
+ }
56
+
57
+ interface MailStatsData {
58
+ charts?: {
59
+ emailsPerWeek?: Array<{
60
+ day: string;
61
+ sent: number;
62
+ }>;
63
+ };
64
+ }
65
+
66
+ export default function EmailStatsChart({
67
+ widget,
68
+ onRemove,
69
+ }: EmailStatsChartProps) {
70
+ const t = useTranslations('core.Dashboard');
71
+
72
+ const { data, isLoading, isAccessDenied, isError } =
73
+ useWidgetData<MailStatsData>({
74
+ endpoint: '/dashboard-core/stats/overview/mails',
75
+ queryKey: 'dashboard-stats-mails',
76
+ });
77
+
78
+ const chartData = data?.charts?.emailsPerWeek || [];
79
+
80
+ return (
81
+ <WidgetWrapper
82
+ isLoading={isLoading}
83
+ isAccessDenied={isAccessDenied}
84
+ isError={isError}
85
+ widgetName={widget?.name || t('emailSendingTitle')}
86
+ onRemove={onRemove}
87
+ >
88
+ <Card className="h-full flex flex-col group">
89
+ <div
90
+ className="drag-handle absolute top-3 left-4 z-10"
91
+ style={{ cursor: 'grab' }}
92
+ >
93
+ <IconGripVertical className="text-muted-foreground/50 size-4 shrink-0" />
94
+ </div>
95
+ <CardHeader className="pb-2 pt-4 pl-10">
96
+ <CardTitle className="text-base font-semibold">
97
+ {t('emailSendingTitle')}
98
+ </CardTitle>
99
+ <CardDescription>{t('emailSendingDescription')}</CardDescription>
100
+ </CardHeader>
101
+ <CardContent className="flex-1 pt-0">
102
+ <div className="h-[280px] w-full">
103
+ <ResponsiveContainer width="100%" height="100%">
104
+ <BarChart
105
+ data={chartData}
106
+ margin={{ top: 5, right: 10, left: -20, bottom: 0 }}
107
+ >
108
+ <CartesianGrid
109
+ strokeDasharray="3 3"
110
+ stroke="currentColor"
111
+ opacity={0.1}
112
+ />
113
+ <XAxis
114
+ dataKey="day"
115
+ tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 12 }}
116
+ axisLine={false}
117
+ tickLine={false}
118
+ />
119
+ <YAxis
120
+ tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 12 }}
121
+ axisLine={false}
122
+ tickLine={false}
123
+ />
124
+ <Tooltip content={<CustomTooltip />} />
125
+ <Bar
126
+ dataKey="sent"
127
+ fill="#3b82f6"
128
+ radius={[4, 4, 0, 0]}
129
+ animationDuration={1200}
130
+ />
131
+ </BarChart>
132
+ </ResponsiveContainer>
133
+ </div>
134
+ <div className="mt-3 flex items-center justify-center">
135
+ <div className="flex items-center gap-2">
136
+ <div
137
+ className="h-2.5 w-2.5 rounded-full"
138
+ style={{ backgroundColor: '#3b82f6' }}
139
+ />
140
+ <span className="text-xs text-muted-foreground">
141
+ {t('emailsSent')}
142
+ </span>
143
+ </div>
144
+ </div>
145
+ </CardContent>
146
+ </Card>
147
+ </WidgetWrapper>
148
+ );
149
+ }
@@ -0,0 +1,58 @@
1
+ import { useWidgetData } from '@/hooks/use-widget-data';
2
+ import { LayoutList } from 'lucide-react';
3
+ import { useTranslations } from 'next-intl';
4
+ import StatCard from '../stats';
5
+ import { WidgetWrapper } from '../widget-wrapper';
6
+
7
+ interface MenusCardProps {
8
+ widget?: any;
9
+ onRemove?: () => void;
10
+ }
11
+
12
+ interface SystemStatsData {
13
+ cards?: {
14
+ menus?: {
15
+ value: number;
16
+ change: number | null;
17
+ };
18
+ };
19
+ }
20
+
21
+ export default function MenusCard({ widget, onRemove }: MenusCardProps) {
22
+ const t = useTranslations('core.Dashboard');
23
+
24
+ const { data, isLoading, isAccessDenied, isError } =
25
+ useWidgetData<SystemStatsData>({
26
+ endpoint: '/dashboard-core/stats/overview/system',
27
+ queryKey: 'dashboard-stats-system',
28
+ });
29
+
30
+ const value = data?.cards?.menus?.value?.toLocaleString('pt-BR') || '0';
31
+ const change = data?.cards?.menus?.change;
32
+ const changeType =
33
+ change !== null && change !== undefined && change >= 0 ? 'up' : 'down';
34
+
35
+ return (
36
+ <WidgetWrapper
37
+ isLoading={isLoading}
38
+ isAccessDenied={isAccessDenied}
39
+ isError={isError}
40
+ widgetName={widget?.name || t('menus')}
41
+ onRemove={onRemove}
42
+ >
43
+ <StatCard
44
+ title={t('menus')}
45
+ value={value}
46
+ change={
47
+ change !== null && change !== undefined
48
+ ? `${change > 0 ? '+' : ''}${change}%`
49
+ : undefined
50
+ }
51
+ changeType={changeType}
52
+ icon={<LayoutList className="h-6 w-6 text-green-500" />}
53
+ iconBg="bg-green-500/10"
54
+ delay={50}
55
+ />
56
+ </WidgetWrapper>
57
+ );
58
+ }
@@ -0,0 +1,175 @@
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
+ OAuthConfigWidgetData,
15
+ } from '@/types/widget-data';
16
+ import { CheckCircle2, KeyRound, XCircle } from 'lucide-react';
17
+ import { useTranslations } from 'next-intl';
18
+ import { WidgetWrapper } from '../widget-wrapper';
19
+
20
+ const defaultOAuthConfigData: OAuthConfigWidgetData = {
21
+ status: {
22
+ isConfigured: false,
23
+ enabledProviderCount: 0,
24
+ configuredProviderCount: 0,
25
+ connectedAccountCount: 0,
26
+ },
27
+ providers: [],
28
+ };
29
+
30
+ interface OAuthConfigProps {
31
+ widget?: { name?: string };
32
+ onRemove?: () => void;
33
+ }
34
+
35
+ export default function OAuthConfig({ widget, onRemove }: OAuthConfigProps) {
36
+ const t = useTranslations('core.DashboardPage.oauthConfig');
37
+
38
+ const { data, isLoading, isError, isAccessDenied } = useWidgetData<
39
+ DashboardCoreConfigOverviewData,
40
+ OAuthConfigWidgetData
41
+ >({
42
+ endpoint: '/dashboard-core/config/overview',
43
+ queryKey: 'dashboard-core-config-overview',
44
+ select: (d) => d.oauthConfig,
45
+ });
46
+
47
+ const oauthData = data ?? defaultOAuthConfigData;
48
+
49
+ return (
50
+ <WidgetWrapper
51
+ isLoading={isLoading}
52
+ isError={isError}
53
+ isAccessDenied={isAccessDenied}
54
+ widgetName={widget?.name ?? t('title')}
55
+ onRemove={onRemove}
56
+ >
57
+ <Card className="flex h-full min-h-0 flex-col overflow-hidden">
58
+ <CardHeader className="shrink-0">
59
+ <div className="flex items-center justify-between gap-3">
60
+ <div className="flex items-center gap-3">
61
+ <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-amber-50">
62
+ <KeyRound className="h-5 w-5 text-amber-600" />
63
+ </div>
64
+ <div>
65
+ <CardTitle className="text-base">{t('title')}</CardTitle>
66
+ <CardDescription>{t('description')}</CardDescription>
67
+ </div>
68
+ </div>
69
+ <Badge
70
+ variant="secondary"
71
+ className={
72
+ oauthData.status.isConfigured
73
+ ? 'bg-emerald-50 text-emerald-700'
74
+ : 'bg-amber-50 text-amber-700'
75
+ }
76
+ >
77
+ {oauthData.status.isConfigured ? t('configured') : t('pending')}
78
+ </Badge>
79
+ </div>
80
+ </CardHeader>
81
+ <CardContent className="flex min-h-0 flex-1 flex-col gap-4 overflow-hidden pt-0">
82
+ <div className="grid grid-cols-3 gap-2">
83
+ <div className="rounded-lg border bg-muted/30 p-3 text-center">
84
+ <p className="text-[11px] text-muted-foreground">
85
+ {t('enabled')}
86
+ </p>
87
+ <p className="mt-1 text-lg font-semibold">
88
+ {oauthData.status.enabledProviderCount}
89
+ </p>
90
+ </div>
91
+ <div className="rounded-lg border bg-muted/30 p-3 text-center">
92
+ <p className="text-[11px] text-muted-foreground">
93
+ {t('configuredProviders')}
94
+ </p>
95
+ <p className="mt-1 text-lg font-semibold">
96
+ {oauthData.status.configuredProviderCount}
97
+ </p>
98
+ </div>
99
+ <div className="rounded-lg border bg-muted/30 p-3 text-center">
100
+ <p className="text-[11px] text-muted-foreground">
101
+ {t('connectedAccounts')}
102
+ </p>
103
+ <p className="mt-1 text-lg font-semibold">
104
+ {oauthData.status.connectedAccountCount}
105
+ </p>
106
+ </div>
107
+ </div>
108
+
109
+ <div className="min-h-0 flex-1 space-y-2 overflow-auto">
110
+ {oauthData.providers.length > 0 ? (
111
+ oauthData.providers.map((provider) => (
112
+ <div key={provider.id} className="rounded-lg border p-3">
113
+ <div className="flex items-center justify-between gap-2">
114
+ <p className="text-sm font-medium">{provider.label}</p>
115
+ <div className="flex items-center gap-1.5">
116
+ <Badge
117
+ variant="secondary"
118
+ className={
119
+ provider.enabled
120
+ ? 'bg-emerald-50 text-emerald-700'
121
+ : 'bg-muted text-muted-foreground'
122
+ }
123
+ >
124
+ {provider.enabled ? (
125
+ <>
126
+ <CheckCircle2 className="mr-1 h-3 w-3" />
127
+ {t('enabled')}
128
+ </>
129
+ ) : (
130
+ <>
131
+ <XCircle className="mr-1 h-3 w-3" />
132
+ {t('disabled')}
133
+ </>
134
+ )}
135
+ </Badge>
136
+ <Badge
137
+ variant="outline"
138
+ className={
139
+ provider.configured
140
+ ? 'border-emerald-200 text-emerald-700'
141
+ : 'text-muted-foreground'
142
+ }
143
+ >
144
+ {provider.configured ? t('configured') : t('pending')}
145
+ </Badge>
146
+ </div>
147
+ </div>
148
+ <div className="mt-2 flex flex-wrap gap-3 text-[11px] text-muted-foreground">
149
+ <span>
150
+ {t('scopesCount', { count: provider.scopesCount })}
151
+ </span>
152
+ <span>
153
+ {t('connectedUsers', { count: provider.connectedUsers })}
154
+ </span>
155
+ <span>
156
+ {provider.missingKeys.length > 0
157
+ ? t('missingKeys', {
158
+ count: provider.missingKeys.length,
159
+ })
160
+ : t('allKeysPresent')}
161
+ </span>
162
+ </div>
163
+ </div>
164
+ ))
165
+ ) : (
166
+ <p className="text-xs text-muted-foreground">
167
+ {t('noProviders')}
168
+ </p>
169
+ )}
170
+ </div>
171
+ </CardContent>
172
+ </Card>
173
+ </WidgetWrapper>
174
+ );
175
+ }