@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,61 @@
1
+ import { useWidgetData } from '@/hooks/use-widget-data';
2
+ import { Shield } from 'lucide-react';
3
+ import { useTranslations } from 'next-intl';
4
+ import StatCard from '../stats';
5
+ import { WidgetWrapper } from '../widget-wrapper';
6
+
7
+ interface PermissionsCardProps {
8
+ widget?: any;
9
+ onRemove?: () => void;
10
+ }
11
+
12
+ interface UserStatsData {
13
+ cards?: {
14
+ roles?: {
15
+ value: number;
16
+ change: number | null;
17
+ };
18
+ };
19
+ }
20
+
21
+ export default function PermissionsCard({
22
+ widget,
23
+ onRemove,
24
+ }: PermissionsCardProps) {
25
+ const t = useTranslations('core.Dashboard');
26
+
27
+ const { data, isLoading, isAccessDenied, isError } =
28
+ useWidgetData<UserStatsData>({
29
+ endpoint: '/dashboard-core/stats/overview/users',
30
+ queryKey: 'dashboard-stats-users',
31
+ });
32
+
33
+ const value = data?.cards?.roles?.value?.toLocaleString('pt-BR') || '0';
34
+ const change = data?.cards?.roles?.change;
35
+ const changeType =
36
+ change !== null && change !== undefined && change >= 0 ? 'up' : 'down';
37
+
38
+ return (
39
+ <WidgetWrapper
40
+ isLoading={isLoading}
41
+ isAccessDenied={isAccessDenied}
42
+ isError={isError}
43
+ widgetName={widget?.name || t('permissions')}
44
+ onRemove={onRemove}
45
+ >
46
+ <StatCard
47
+ title={t('permissions')}
48
+ value={value}
49
+ change={
50
+ change !== null && change !== undefined
51
+ ? `${change > 0 ? '+' : ''}${change}%`
52
+ : undefined
53
+ }
54
+ changeType={changeType}
55
+ icon={<Shield className="h-6 w-6 text-rose-500" />}
56
+ iconBg="bg-rose-500/10"
57
+ delay={200}
58
+ />
59
+ </WidgetWrapper>
60
+ );
61
+ }
@@ -0,0 +1,156 @@
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 { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from 'recharts';
14
+ import { WidgetWrapper } from '../widget-wrapper';
15
+
16
+ function CustomTooltip({
17
+ active,
18
+ payload,
19
+ }: {
20
+ active?: boolean;
21
+ payload?: Array<{ name: string; value: number; payload: { color: string } }>;
22
+ }) {
23
+ const t = useTranslations('core.Dashboard');
24
+ if (!active || !payload?.length) return null;
25
+
26
+ const entry = payload[0];
27
+ return (
28
+ <div className="rounded-lg border bg-card px-3 py-2 shadow-xl">
29
+ <p className="text-xs text-muted-foreground">
30
+ <span
31
+ className="mr-1.5 inline-block h-2 w-2 rounded-full"
32
+ style={{ backgroundColor: entry?.payload.color }}
33
+ />
34
+ {entry?.name}: {entry?.value} {t('permissionsLowercase')}
35
+ </p>
36
+ </div>
37
+ );
38
+ }
39
+
40
+ interface PermissionsChartProps {
41
+ widget?: {
42
+ name?: string;
43
+ } | null;
44
+ onRemove?: () => void;
45
+ }
46
+
47
+ interface PermissionDistributionItem {
48
+ name: string;
49
+ value: number;
50
+ color: string;
51
+ }
52
+
53
+ interface UserStatsData {
54
+ charts?: {
55
+ permissionDistribution?: PermissionDistributionItem[];
56
+ };
57
+ }
58
+
59
+ export default function PermissionsChart({
60
+ widget,
61
+ onRemove,
62
+ }: PermissionsChartProps) {
63
+ const t = useTranslations('core.Dashboard');
64
+
65
+ const {
66
+ data: statsData,
67
+ isLoading,
68
+ isAccessDenied,
69
+ isError,
70
+ } = useWidgetData<UserStatsData>({
71
+ endpoint: '/dashboard-core/stats/overview/users',
72
+ queryKey: 'dashboard-stats-users',
73
+ });
74
+
75
+ const data = statsData?.charts?.permissionDistribution || [];
76
+ const total = data.reduce((sum, item) => sum + item.value, 0);
77
+
78
+ return (
79
+ <WidgetWrapper
80
+ isLoading={isLoading}
81
+ isAccessDenied={isAccessDenied}
82
+ isError={isError}
83
+ widgetName={widget?.name || t('permissionsDistributionTitle')}
84
+ onRemove={onRemove}
85
+ >
86
+ <Card className="h-full flex flex-col group">
87
+ <div
88
+ className="drag-handle absolute top-3 left-4 z-10"
89
+ style={{ cursor: 'grab' }}
90
+ >
91
+ <IconGripVertical className="text-muted-foreground/50 size-4 shrink-0" />
92
+ </div>
93
+ <CardHeader className="pb-2 pt-4 pl-10">
94
+ <CardTitle className="text-base font-semibold">
95
+ {t('permissionsDistributionTitle')}
96
+ </CardTitle>
97
+ <CardDescription>
98
+ {t('permissionsDistributionDescription')}
99
+ </CardDescription>
100
+ </CardHeader>
101
+ <CardContent className="flex-1 pt-0">
102
+ <div className="flex h-full items-center justify-between gap-4 overflow-hidden">
103
+ <div className="relative h-[280px] w-[280px] shrink-0">
104
+ <ResponsiveContainer width="100%" height="100%">
105
+ <PieChart>
106
+ <Pie
107
+ data={data}
108
+ cx="50%"
109
+ cy="50%"
110
+ innerRadius={70}
111
+ outerRadius={110}
112
+ paddingAngle={4}
113
+ dataKey="value"
114
+ animationDuration={1200}
115
+ strokeWidth={0}
116
+ >
117
+ {data.map((entry, index: number) => (
118
+ <Cell key={`cell-${index}`} fill={entry.color} />
119
+ ))}
120
+ </Pie>
121
+ <Tooltip content={<CustomTooltip />} />
122
+ </PieChart>
123
+ </ResponsiveContainer>
124
+ <div className="absolute inset-0 flex flex-col items-center justify-center">
125
+ <span className="text-2xl font-bold text-foreground">
126
+ {total}
127
+ </span>
128
+ <span className="text-[10px] text-muted-foreground">
129
+ {t('total')}
130
+ </span>
131
+ </div>
132
+ </div>
133
+ <div className="grid max-h-[280px] min-w-0 flex-1 grid-cols-2 content-start gap-x-4 gap-y-2 overflow-y-auto pr-2">
134
+ {data.map((item) => (
135
+ <div key={item.name} className="flex min-w-0 items-start gap-2.5">
136
+ <div
137
+ className="mt-1 h-2.5 w-2.5 shrink-0 rounded-sm"
138
+ style={{ backgroundColor: item.color }}
139
+ />
140
+ <div className="flex min-w-0 flex-col">
141
+ <span className="break-words text-xs font-medium leading-tight text-foreground">
142
+ {item.name}
143
+ </span>
144
+ <span className="text-[11px] text-muted-foreground">
145
+ {item.value} ({total ? Math.round((item.value / total) * 100) : 0}%)
146
+ </span>
147
+ </div>
148
+ </div>
149
+ ))}
150
+ </div>
151
+ </div>
152
+ </CardContent>
153
+ </Card>
154
+ </WidgetWrapper>
155
+ );
156
+ }
@@ -39,8 +39,8 @@ function ProfileContent({ profile }: { profile: ProfileData }) {
39
39
 
40
40
  return (
41
41
  <Card className="relative flex h-full flex-col overflow-hidden">
42
- <div className="absolute inset-x-0 top-0 h-24 bg-linear-to-br from-muted to-muted/50" />
43
- <CardContent className="relative flex flex-col flex-1 overflow-hidden pt-6 pb-10">
42
+ <div className="absolute inset-x-0 top-0 h-28 bg-linear-to-br from-muted to-muted/50" />
43
+ <CardContent className="relative flex flex-1 flex-col overflow-hidden pt-7 pb-12">
44
44
  <div className="flex flex-col items-center gap-4 sm:flex-row sm:items-end">
45
45
  <div className="relative">
46
46
  <Avatar className="h-20 w-20 border-4 border-card shadow-md">
@@ -84,7 +84,7 @@ function ProfileContent({ profile }: { profile: ProfileData }) {
84
84
  </Button>
85
85
  </div>
86
86
 
87
- <Separator className="my-5" />
87
+ <Separator className="my-6" />
88
88
 
89
89
  <div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
90
90
  <div className="flex items-center gap-2.5 rounded-lg p-2 transition-colors hover:bg-muted/50">
@@ -0,0 +1,58 @@
1
+ import { useWidgetData } from '@/hooks/use-widget-data';
2
+ import { Route } from 'lucide-react';
3
+ import { useTranslations } from 'next-intl';
4
+ import StatCard from '../stats';
5
+ import { WidgetWrapper } from '../widget-wrapper';
6
+
7
+ interface RoutesCardProps {
8
+ widget?: any;
9
+ onRemove?: () => void;
10
+ }
11
+
12
+ interface SystemStatsData {
13
+ cards?: {
14
+ routes?: {
15
+ value: number;
16
+ change: number | null;
17
+ };
18
+ };
19
+ }
20
+
21
+ export default function RoutesCard({ widget, onRemove }: RoutesCardProps) {
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?.routes?.value?.toLocaleString('pt-BR') || '0';
31
+ const change = data?.cards?.routes?.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('routes')}
41
+ onRemove={onRemove}
42
+ >
43
+ <StatCard
44
+ title={t('routes')}
45
+ value={value}
46
+ change={
47
+ change !== null && change !== undefined
48
+ ? `${change > 0 ? '+' : ''}${change}%`
49
+ : undefined
50
+ }
51
+ changeType={changeType}
52
+ icon={<Route className="h-6 w-6 text-orange-500" />}
53
+ iconBg="bg-orange-500/10"
54
+ delay={50}
55
+ />
56
+ </WidgetWrapper>
57
+ );
58
+ }
@@ -0,0 +1,183 @@
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
+ CartesianGrid,
15
+ Line,
16
+ LineChart,
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={{
44
+ backgroundColor:
45
+ entry.dataKey === 'active' ? '#10b981' : '#f59e0b',
46
+ }}
47
+ />
48
+ {entry.dataKey === 'active' ? t('active') : t('expired')}:{' '}
49
+ {entry.value}
50
+ </p>
51
+ ))}
52
+ </div>
53
+ );
54
+ }
55
+
56
+ interface SessionActivityChartProps {
57
+ widget?: any;
58
+ onRemove?: () => void;
59
+ }
60
+
61
+ interface UserStatsData {
62
+ charts?: {
63
+ sessionActivity?: Array<{
64
+ hour: string;
65
+ active: number;
66
+ expired: number;
67
+ }>;
68
+ };
69
+ }
70
+
71
+ export default function SessionActivityChart({
72
+ widget,
73
+ onRemove,
74
+ }: SessionActivityChartProps) {
75
+ const t = useTranslations('core.Dashboard');
76
+
77
+ const {
78
+ data: statsData,
79
+ isLoading,
80
+ isAccessDenied,
81
+ isError,
82
+ } = useWidgetData<UserStatsData>({
83
+ endpoint: '/dashboard-core/stats/overview/users',
84
+ queryKey: 'dashboard-stats-users',
85
+ });
86
+
87
+ const data = statsData?.charts?.sessionActivity || [];
88
+
89
+ return (
90
+ <WidgetWrapper
91
+ isLoading={isLoading}
92
+ isAccessDenied={isAccessDenied}
93
+ isError={isError}
94
+ widgetName={widget?.name || t('sessionActivityTitle')}
95
+ onRemove={onRemove}
96
+ >
97
+ <Card className="h-full flex flex-col group">
98
+ <div
99
+ className="drag-handle absolute top-3 left-4 z-10"
100
+ style={{ cursor: 'grab' }}
101
+ >
102
+ <IconGripVertical className="text-muted-foreground/50 size-4 shrink-0" />
103
+ </div>
104
+ <CardHeader className="flex flex-row items-center justify-between pb-2 pt-4">
105
+ <div className="pl-6">
106
+ <CardTitle className="text-base font-semibold">
107
+ {t('sessionActivityTitle')}
108
+ </CardTitle>
109
+ <CardDescription>{t('sessionActivityDescription')}</CardDescription>
110
+ </div>
111
+ </CardHeader>
112
+ <CardContent className="flex-1 pt-0">
113
+ <div className="h-[200px] w-full">
114
+ <ResponsiveContainer width="100%" height="100%">
115
+ <LineChart
116
+ data={data}
117
+ margin={{ top: 5, right: 10, left: -20, bottom: 0 }}
118
+ >
119
+ <CartesianGrid
120
+ strokeDasharray="3 3"
121
+ stroke="currentColor"
122
+ opacity={0.1}
123
+ />
124
+ <XAxis
125
+ dataKey="hour"
126
+ tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 11 }}
127
+ axisLine={false}
128
+ tickLine={false}
129
+ />
130
+ <YAxis
131
+ tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 11 }}
132
+ axisLine={false}
133
+ tickLine={false}
134
+ />
135
+ <Tooltip content={<CustomTooltip />} />
136
+ <Line
137
+ type="monotone"
138
+ dataKey="active"
139
+ stroke="#10b981"
140
+ strokeWidth={3}
141
+ dot={false}
142
+ activeDot={{ r: 5, fill: '#10b981' }}
143
+ animationDuration={1500}
144
+ />
145
+ <Line
146
+ type="monotone"
147
+ dataKey="expired"
148
+ stroke="#f59e0b"
149
+ strokeWidth={2.5}
150
+ dot={false}
151
+ strokeDasharray="5 5"
152
+ activeDot={{ r: 4, fill: '#f59e0b' }}
153
+ animationDuration={1500}
154
+ animationBegin={300}
155
+ />
156
+ </LineChart>
157
+ </ResponsiveContainer>
158
+ </div>
159
+ <div className="mt-2 flex items-center justify-center gap-6">
160
+ <div className="flex items-center gap-2">
161
+ <div
162
+ className="h-0.5 w-4 rounded-full"
163
+ style={{ backgroundColor: '#10b981' }}
164
+ />
165
+ <span className="text-xs text-muted-foreground">
166
+ {t('active')}
167
+ </span>
168
+ </div>
169
+ <div className="flex items-center gap-2">
170
+ <div
171
+ className="h-0.5 w-4 rounded-full"
172
+ style={{ backgroundColor: '#f59e0b' }}
173
+ />
174
+ <span className="text-xs text-muted-foreground">
175
+ {t('expired')}
176
+ </span>
177
+ </div>
178
+ </div>
179
+ </CardContent>
180
+ </Card>
181
+ </WidgetWrapper>
182
+ );
183
+ }
@@ -0,0 +1,62 @@
1
+ import { useWidgetData } from '@/hooks/use-widget-data';
2
+ import { Activity } from 'lucide-react';
3
+ import { useTranslations } from 'next-intl';
4
+ import StatCard from '../stats';
5
+ import { WidgetWrapper } from '../widget-wrapper';
6
+
7
+ interface SessionsTodayProps {
8
+ widget?: any;
9
+ onRemove?: () => void;
10
+ }
11
+
12
+ interface UserStatsData {
13
+ cards?: {
14
+ sessionsToday?: {
15
+ value: number;
16
+ change: number | null;
17
+ };
18
+ };
19
+ }
20
+
21
+ export default function SessionsToday({
22
+ widget,
23
+ onRemove,
24
+ }: SessionsTodayProps) {
25
+ const t = useTranslations('core.Dashboard');
26
+
27
+ const { data, isLoading, isAccessDenied, isError } =
28
+ useWidgetData<UserStatsData>({
29
+ endpoint: '/dashboard-core/stats/overview/users',
30
+ queryKey: 'dashboard-stats-users',
31
+ });
32
+
33
+ const value =
34
+ data?.cards?.sessionsToday?.value?.toLocaleString('pt-BR') || '0';
35
+ const change = data?.cards?.sessionsToday?.change;
36
+ const changeType =
37
+ change !== null && change !== undefined && change >= 0 ? 'up' : 'down';
38
+
39
+ return (
40
+ <WidgetWrapper
41
+ isLoading={isLoading}
42
+ isAccessDenied={isAccessDenied}
43
+ isError={isError}
44
+ widgetName={widget?.name || t('sessionsToday')}
45
+ onRemove={onRemove}
46
+ >
47
+ <StatCard
48
+ title={t('sessionsToday')}
49
+ value={value}
50
+ change={
51
+ change !== null && change !== undefined
52
+ ? `${change > 0 ? '+' : ''}${change}%`
53
+ : undefined
54
+ }
55
+ changeType={changeType}
56
+ icon={<Activity className="h-6 w-6 text-emerald-500" />}
57
+ iconBg="bg-emerald-500/10"
58
+ delay={100}
59
+ />
60
+ </WidgetWrapper>
61
+ );
62
+ }
@@ -0,0 +1,57 @@
1
+ 'use client';
2
+
3
+ import { Card, CardContent } from '@/components/ui/card';
4
+ import { useWidgetData } from '@/hooks/use-widget-data';
5
+ import type { AllWidgetsData } from '@/types/widget-data';
6
+ import { Zap } from 'lucide-react';
7
+ import { useTranslations } from 'next-intl';
8
+ import { WidgetWrapper } from '../widget-wrapper';
9
+
10
+ interface StatAccessLevelProps {
11
+ widget?: { name?: string };
12
+ onRemove?: () => void;
13
+ }
14
+
15
+ export default function StatAccessLevel({
16
+ widget,
17
+ onRemove,
18
+ }: StatAccessLevelProps) {
19
+ const t = useTranslations('core.DashboardPage.quickStats');
20
+ const { data, isLoading, isError, isAccessDenied } = useWidgetData<
21
+ AllWidgetsData,
22
+ number
23
+ >({
24
+ endpoint: '/dashboard-core/widgets/me',
25
+ queryKey: 'widget-me',
26
+ select: (d) => d.quickStats.securityLevel,
27
+ });
28
+
29
+ return (
30
+ <WidgetWrapper
31
+ isLoading={isLoading}
32
+ isError={isError}
33
+ isAccessDenied={isAccessDenied}
34
+ widgetName={widget?.name ?? 'stat-access-level'}
35
+ onRemove={onRemove}
36
+ >
37
+ <Card className="h-full overflow-hidden transition-all duration-300 hover:shadow-md">
38
+ <CardContent className="flex h-full items-center gap-2.5 p-2.5 sm:gap-3 sm:p-3 md:gap-4 md:p-4">
39
+ <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-xl bg-amber-50 dark:bg-amber-950/40 sm:h-9 sm:w-9 md:h-11 md:w-11">
40
+ <Zap className="h-3.5 w-3.5 text-amber-600 dark:text-amber-400 sm:h-4 sm:w-4 md:h-5 md:w-5" />
41
+ </div>
42
+ <div className="flex min-w-0 flex-col">
43
+ <span className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground sm:text-[11px]">
44
+ {t('accessLevel')}
45
+ </span>
46
+ <span className="truncate text-base font-bold tracking-tight text-foreground sm:text-lg md:text-2xl">
47
+ {data ? t('accessLevelValue', { level: data }) : '—'}
48
+ </span>
49
+ <span className="truncate text-[10px] text-muted-foreground sm:text-[11px]">
50
+ {t('accessLevelSubtitle')}
51
+ </span>
52
+ </div>
53
+ </CardContent>
54
+ </Card>
55
+ </WidgetWrapper>
56
+ );
57
+ }
@@ -0,0 +1,57 @@
1
+ 'use client';
2
+
3
+ import { Card, CardContent } from '@/components/ui/card';
4
+ import { useWidgetData } from '@/hooks/use-widget-data';
5
+ import type { AllWidgetsData } from '@/types/widget-data';
6
+ import { MousePointerClick } from 'lucide-react';
7
+ import { useTranslations } from 'next-intl';
8
+ import { WidgetWrapper } from '../widget-wrapper';
9
+
10
+ interface StatActionsTodayProps {
11
+ widget?: { name?: string };
12
+ onRemove?: () => void;
13
+ }
14
+
15
+ export default function StatActionsToday({
16
+ widget,
17
+ onRemove,
18
+ }: StatActionsTodayProps) {
19
+ const t = useTranslations('core.DashboardPage.quickStats');
20
+ const { data, isLoading, isError, isAccessDenied } = useWidgetData<
21
+ AllWidgetsData,
22
+ number
23
+ >({
24
+ endpoint: '/dashboard-core/widgets/me',
25
+ queryKey: 'widget-me',
26
+ select: (d) => d.quickStats.actionsToday,
27
+ });
28
+
29
+ return (
30
+ <WidgetWrapper
31
+ isLoading={isLoading}
32
+ isError={isError}
33
+ isAccessDenied={isAccessDenied}
34
+ widgetName={widget?.name ?? 'stat-actions-today'}
35
+ onRemove={onRemove}
36
+ >
37
+ <Card className="h-full overflow-hidden transition-all duration-300 hover:shadow-md">
38
+ <CardContent className="flex h-full items-center gap-2.5 p-2.5 sm:gap-3 sm:p-3 md:gap-4 md:p-4">
39
+ <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-xl bg-indigo-50 dark:bg-indigo-950/40 sm:h-9 sm:w-9 md:h-11 md:w-11">
40
+ <MousePointerClick className="h-3.5 w-3.5 text-indigo-600 dark:text-indigo-400 sm:h-4 sm:w-4 md:h-5 md:w-5" />
41
+ </div>
42
+ <div className="flex min-w-0 flex-col">
43
+ <span className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground sm:text-[11px]">
44
+ {t('actionsToday')}
45
+ </span>
46
+ <span className="truncate text-lg font-bold tracking-tight text-foreground sm:text-xl md:text-2xl">
47
+ {data ?? '—'}
48
+ </span>
49
+ <span className="truncate text-[10px] text-muted-foreground sm:text-[11px]">
50
+ {t('actionsTodaySubtitle')}
51
+ </span>
52
+ </div>
53
+ </CardContent>
54
+ </Card>
55
+ </WidgetWrapper>
56
+ );
57
+ }