@hed-hog/core 0.0.298 → 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 (139) hide show
  1. package/dist/dashboard/dashboard/dashboard.controller.d.ts +3 -0
  2. package/dist/dashboard/dashboard/dashboard.controller.d.ts.map +1 -1
  3. package/dist/dashboard/dashboard/dashboard.service.d.ts +3 -0
  4. package/dist/dashboard/dashboard/dashboard.service.d.ts.map +1 -1
  5. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +12 -0
  6. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts.map +1 -1
  7. package/dist/dashboard/dashboard-component/dashboard-component.controller.js +22 -0
  8. package/dist/dashboard/dashboard-component/dashboard-component.controller.js.map +1 -1
  9. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +15 -0
  10. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts.map +1 -1
  11. package/dist/dashboard/dashboard-component/dashboard-component.service.js +110 -3
  12. package/dist/dashboard/dashboard-component/dashboard-component.service.js.map +1 -1
  13. package/dist/dashboard/dashboard-component/dto/create.dto.d.ts +1 -0
  14. package/dist/dashboard/dashboard-component/dto/create.dto.d.ts.map +1 -1
  15. package/dist/dashboard/dashboard-component/dto/create.dto.js +5 -0
  16. package/dist/dashboard/dashboard-component/dto/create.dto.js.map +1 -1
  17. package/dist/dashboard/dashboard-component/dto/update.dto.d.ts +1 -0
  18. package/dist/dashboard/dashboard-component/dto/update.dto.d.ts.map +1 -1
  19. package/dist/dashboard/dashboard-component/dto/update.dto.js +5 -0
  20. package/dist/dashboard/dashboard-component/dto/update.dto.js.map +1 -1
  21. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +1 -0
  22. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts.map +1 -1
  23. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +1 -0
  24. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts.map +1 -1
  25. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +7 -1
  26. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
  27. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +7 -1
  28. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
  29. package/dist/dashboard/dashboard-core/dashboard-core.service.js +88 -4
  30. package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
  31. package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +1 -0
  32. package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts.map +1 -1
  33. package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +1 -0
  34. package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts.map +1 -1
  35. package/hedhog/data/dashboard_item.yaml +1 -1
  36. package/hedhog/data/route.yaml +12 -0
  37. package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +141 -24
  38. package/hedhog/frontend/app/dashboard/[slug]/types.ts.ejs +3 -0
  39. package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +136 -23
  40. package/hedhog/frontend/app/dashboard/components/add-widget-selector-dialog.tsx.ejs +266 -85
  41. package/hedhog/frontend/app/dashboard/components/widgets/core..gitkeep.ejs +11 -0
  42. package/hedhog/frontend/app/dashboard/components/widgets/core.account-security.tsx.ejs +192 -0
  43. package/hedhog/frontend/app/dashboard/components/widgets/core.user-sessions.tsx.ejs +236 -0
  44. package/hedhog/frontend/app/dashboard/components/widgets/finance.alerts.tsx.ejs +108 -0
  45. package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-balance-kpi.tsx.ejs +66 -0
  46. package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-flow-chart.tsx.ejs +122 -0
  47. package/hedhog/frontend/app/dashboard/components/widgets/finance.default-kpi.tsx.ejs +63 -0
  48. package/hedhog/frontend/app/dashboard/components/widgets/finance.payable-30d-kpi.tsx.ejs +73 -0
  49. package/hedhog/frontend/app/dashboard/components/widgets/finance.receivable-30d-kpi.tsx.ejs +73 -0
  50. package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-payable.tsx.ejs +123 -0
  51. package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-receivable.tsx.ejs +118 -0
  52. package/hedhog/frontend/messages/en.json +3 -0
  53. package/hedhog/frontend/messages/pt.json +3 -0
  54. package/hedhog/frontend/public/dashboard-previews/.gitkeep +12 -0
  55. package/hedhog/frontend/public/dashboard-previews/account-security.png +0 -0
  56. package/hedhog/frontend/public/dashboard-previews/active-users-card.png +0 -0
  57. package/hedhog/frontend/public/dashboard-previews/activity-timeline.png +0 -0
  58. package/hedhog/frontend/public/dashboard-previews/cash-balance-kpi.png +0 -0
  59. package/hedhog/frontend/public/dashboard-previews/cash-flow-chart.png +0 -0
  60. package/hedhog/frontend/public/dashboard-previews/default-kpi.png +0 -0
  61. package/hedhog/frontend/public/dashboard-previews/email-notifications.png +0 -0
  62. package/hedhog/frontend/public/dashboard-previews/financial-alerts.png +0 -0
  63. package/hedhog/frontend/public/dashboard-previews/login-history-chart.png +0 -0
  64. package/hedhog/frontend/public/dashboard-previews/mail-sent-card.png +0 -0
  65. package/hedhog/frontend/public/dashboard-previews/mail-sent-chart.png +0 -0
  66. package/hedhog/frontend/public/dashboard-previews/menus-card.png +0 -0
  67. package/hedhog/frontend/public/dashboard-previews/payable-30d-kpi.png +0 -0
  68. package/hedhog/frontend/public/dashboard-previews/permissions-card.png +0 -0
  69. package/hedhog/frontend/public/dashboard-previews/permissions-chart.png +0 -0
  70. package/hedhog/frontend/public/dashboard-previews/profile-card.png +0 -0
  71. package/hedhog/frontend/public/dashboard-previews/receivable-30d-kpi.png +0 -0
  72. package/hedhog/frontend/public/dashboard-previews/routes-card.png +0 -0
  73. package/hedhog/frontend/public/dashboard-previews/session-activity-chart.png +0 -0
  74. package/hedhog/frontend/public/dashboard-previews/sessions-today-card.png +0 -0
  75. package/hedhog/frontend/public/dashboard-previews/stat-access-level.png +0 -0
  76. package/hedhog/frontend/public/dashboard-previews/stat-actions-today.png +0 -0
  77. package/hedhog/frontend/public/dashboard-previews/stat-consecutive-days.png +0 -0
  78. package/hedhog/frontend/public/dashboard-previews/stat-online-time.png +0 -0
  79. package/hedhog/frontend/public/dashboard-previews/upcoming-payable.png +0 -0
  80. package/hedhog/frontend/public/dashboard-previews/upcoming-receivable.png +0 -0
  81. package/hedhog/frontend/public/dashboard-previews/user-growth-chart.png +0 -0
  82. package/hedhog/frontend/public/dashboard-previews/user-roles.png +0 -0
  83. package/hedhog/frontend/{app/dashboard/components/widgets → widgets}/account-security.tsx.ejs +33 -29
  84. package/hedhog/frontend/widgets/active-users-card.tsx.ejs +58 -0
  85. package/hedhog/frontend/widgets/activity-timeline.tsx.ejs +223 -0
  86. package/hedhog/frontend/widgets/email-notifications.tsx.ejs +226 -0
  87. package/hedhog/frontend/widgets/locale-config.tsx.ejs +168 -0
  88. package/hedhog/frontend/widgets/login-history-chart.tsx.ejs +115 -0
  89. package/hedhog/frontend/widgets/mail-config.tsx.ejs +199 -0
  90. package/hedhog/frontend/widgets/mail-sent-card.tsx.ejs +58 -0
  91. package/hedhog/frontend/widgets/mail-sent-chart.tsx.ejs +149 -0
  92. package/hedhog/frontend/widgets/menus-card.tsx.ejs +58 -0
  93. package/hedhog/frontend/widgets/oauth-config.tsx.ejs +175 -0
  94. package/hedhog/frontend/widgets/permissions-card.tsx.ejs +61 -0
  95. package/hedhog/frontend/widgets/permissions-chart.tsx.ejs +156 -0
  96. package/hedhog/frontend/widgets/profile-card.tsx.ejs +186 -0
  97. package/hedhog/frontend/widgets/routes-card.tsx.ejs +58 -0
  98. package/hedhog/frontend/widgets/session-activity-chart.tsx.ejs +183 -0
  99. package/hedhog/frontend/widgets/sessions-today-card.tsx.ejs +62 -0
  100. package/hedhog/frontend/widgets/stat-access-level.tsx.ejs +57 -0
  101. package/hedhog/frontend/widgets/stat-actions-today.tsx.ejs +57 -0
  102. package/hedhog/frontend/widgets/stat-consecutive-days.tsx.ejs +57 -0
  103. package/hedhog/frontend/widgets/stat-online-time.tsx.ejs +57 -0
  104. package/hedhog/frontend/widgets/storage-config.tsx.ejs +196 -0
  105. package/hedhog/frontend/widgets/theme-config.tsx.ejs +213 -0
  106. package/hedhog/frontend/widgets/user-growth-chart.tsx.ejs +210 -0
  107. package/hedhog/frontend/widgets/user-roles.tsx.ejs +132 -0
  108. package/hedhog/frontend/{app/dashboard/components/widgets → widgets}/user-sessions.tsx.ejs +1 -1
  109. package/hedhog/table/dashboard_component.yaml +7 -0
  110. package/package.json +4 -4
  111. package/src/dashboard/dashboard-component/dashboard-component.controller.ts +36 -12
  112. package/src/dashboard/dashboard-component/dashboard-component.service.ts +150 -3
  113. package/src/dashboard/dashboard-component/dto/create.dto.ts +4 -0
  114. package/src/dashboard/dashboard-component/dto/update.dto.ts +4 -0
  115. package/src/dashboard/dashboard-core/dashboard-core.service.ts +108 -5
  116. /package/hedhog/frontend/app/dashboard/components/widgets/{active-users-card.tsx.ejs → core.active-users-card.tsx.ejs} +0 -0
  117. /package/hedhog/frontend/app/dashboard/components/widgets/{activity-timeline.tsx.ejs → core.activity-timeline.tsx.ejs} +0 -0
  118. /package/hedhog/frontend/app/dashboard/components/widgets/{email-notifications.tsx.ejs → core.email-notifications.tsx.ejs} +0 -0
  119. /package/hedhog/frontend/app/dashboard/components/widgets/{locale-config.tsx.ejs → core.locale-config.tsx.ejs} +0 -0
  120. /package/hedhog/frontend/app/dashboard/components/widgets/{login-history-chart.tsx.ejs → core.login-history-chart.tsx.ejs} +0 -0
  121. /package/hedhog/frontend/app/dashboard/components/widgets/{mail-config.tsx.ejs → core.mail-config.tsx.ejs} +0 -0
  122. /package/hedhog/frontend/app/dashboard/components/widgets/{mail-sent-card.tsx.ejs → core.mail-sent-card.tsx.ejs} +0 -0
  123. /package/hedhog/frontend/app/dashboard/components/widgets/{mail-sent-chart.tsx.ejs → core.mail-sent-chart.tsx.ejs} +0 -0
  124. /package/hedhog/frontend/app/dashboard/components/widgets/{menus-card.tsx.ejs → core.menus-card.tsx.ejs} +0 -0
  125. /package/hedhog/frontend/app/dashboard/components/widgets/{oauth-config.tsx.ejs → core.oauth-config.tsx.ejs} +0 -0
  126. /package/hedhog/frontend/app/dashboard/components/widgets/{permissions-card.tsx.ejs → core.permissions-card.tsx.ejs} +0 -0
  127. /package/hedhog/frontend/app/dashboard/components/widgets/{permissions-chart.tsx.ejs → core.permissions-chart.tsx.ejs} +0 -0
  128. /package/hedhog/frontend/app/dashboard/components/widgets/{profile-card.tsx.ejs → core.profile-card.tsx.ejs} +0 -0
  129. /package/hedhog/frontend/app/dashboard/components/widgets/{routes-card.tsx.ejs → core.routes-card.tsx.ejs} +0 -0
  130. /package/hedhog/frontend/app/dashboard/components/widgets/{session-activity-chart.tsx.ejs → core.session-activity-chart.tsx.ejs} +0 -0
  131. /package/hedhog/frontend/app/dashboard/components/widgets/{sessions-today-card.tsx.ejs → core.sessions-today-card.tsx.ejs} +0 -0
  132. /package/hedhog/frontend/app/dashboard/components/widgets/{stat-access-level.tsx.ejs → core.stat-access-level.tsx.ejs} +0 -0
  133. /package/hedhog/frontend/app/dashboard/components/widgets/{stat-actions-today.tsx.ejs → core.stat-actions-today.tsx.ejs} +0 -0
  134. /package/hedhog/frontend/app/dashboard/components/widgets/{stat-consecutive-days.tsx.ejs → core.stat-consecutive-days.tsx.ejs} +0 -0
  135. /package/hedhog/frontend/app/dashboard/components/widgets/{stat-online-time.tsx.ejs → core.stat-online-time.tsx.ejs} +0 -0
  136. /package/hedhog/frontend/app/dashboard/components/widgets/{storage-config.tsx.ejs → core.storage-config.tsx.ejs} +0 -0
  137. /package/hedhog/frontend/app/dashboard/components/widgets/{theme-config.tsx.ejs → core.theme-config.tsx.ejs} +0 -0
  138. /package/hedhog/frontend/app/dashboard/components/widgets/{user-growth-chart.tsx.ejs → core.user-growth-chart.tsx.ejs} +0 -0
  139. /package/hedhog/frontend/app/dashboard/components/widgets/{user-roles.tsx.ejs → core.user-roles.tsx.ejs} +0 -0
@@ -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
+ }
@@ -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
+ }