@hed-hog/core 0.0.215 → 0.0.216
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +5 -5
- package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +1 -1
- package/hedhog/frontend/app/dashboard/components/add-widget-selector-dialog.tsx.ejs +312 -0
- package/hedhog/frontend/app/dashboard/components/dashboard-grid.tsx.ejs +54 -0
- package/hedhog/frontend/app/dashboard/components/draggable-grid.tsx.ejs +132 -0
- package/hedhog/frontend/app/dashboard/components/dynamic-widget.tsx.ejs +88 -0
- package/hedhog/frontend/app/dashboard/components/index.ts.ejs +6 -0
- package/hedhog/frontend/app/dashboard/components/stats.tsx.ejs +93 -0
- package/hedhog/frontend/app/dashboard/components/widget-wrapper.tsx.ejs +150 -0
- package/hedhog/frontend/app/dashboard/components/widgets/account-security.tsx.ejs +184 -0
- package/hedhog/frontend/app/dashboard/components/widgets/active-users-card.tsx.ejs +58 -0
- package/hedhog/frontend/app/dashboard/components/widgets/activity-timeline.tsx.ejs +219 -0
- package/hedhog/frontend/app/dashboard/components/widgets/email-notifications.tsx.ejs +191 -0
- package/hedhog/frontend/app/dashboard/components/widgets/locale-config.tsx.ejs +309 -0
- package/hedhog/frontend/app/dashboard/components/widgets/login-history-chart.tsx.ejs +111 -0
- package/hedhog/frontend/app/dashboard/components/widgets/mail-config.tsx.ejs +445 -0
- package/hedhog/frontend/app/dashboard/components/widgets/mail-sent-card.tsx.ejs +58 -0
- package/hedhog/frontend/app/dashboard/components/widgets/mail-sent-chart.tsx.ejs +149 -0
- package/hedhog/frontend/app/dashboard/components/widgets/oauth-config.tsx.ejs +296 -0
- package/hedhog/frontend/app/dashboard/components/widgets/permissions-card.tsx.ejs +61 -0
- package/hedhog/frontend/app/dashboard/components/widgets/permissions-chart.tsx.ejs +152 -0
- package/hedhog/frontend/app/dashboard/components/widgets/profile-card.tsx.ejs +186 -0
- package/hedhog/frontend/app/dashboard/components/widgets/session-activity-chart.tsx.ejs +183 -0
- package/hedhog/frontend/app/dashboard/components/widgets/sessions-today-card.tsx.ejs +62 -0
- package/hedhog/frontend/app/dashboard/components/widgets/stat-access-level.tsx.ejs +57 -0
- package/hedhog/frontend/app/dashboard/components/widgets/stat-actions-today.tsx.ejs +57 -0
- package/hedhog/frontend/app/dashboard/components/widgets/stat-consecutive-days.tsx.ejs +57 -0
- package/hedhog/frontend/app/dashboard/components/widgets/stat-online-time.tsx.ejs +57 -0
- package/hedhog/frontend/app/dashboard/components/widgets/storage-config.tsx.ejs +340 -0
- package/hedhog/frontend/app/dashboard/components/widgets/theme-config.tsx.ejs +275 -0
- package/hedhog/frontend/app/dashboard/components/widgets/user-growth-chart.tsx.ejs +210 -0
- package/hedhog/frontend/app/dashboard/components/widgets/user-roles.tsx.ejs +130 -0
- package/hedhog/frontend/app/dashboard/components/widgets/user-sessions.tsx.ejs +233 -0
- package/hedhog/frontend/messages/en.json +143 -1
- package/hedhog/frontend/messages/pt.json +143 -1
- package/package.json +3 -3
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Badge } from '@/components/ui/badge';
|
|
4
|
+
import {
|
|
5
|
+
Card,
|
|
6
|
+
CardContent,
|
|
7
|
+
CardDescription,
|
|
8
|
+
CardHeader,
|
|
9
|
+
CardTitle,
|
|
10
|
+
} from '@/components/ui/card';
|
|
11
|
+
import { ScrollArea } from '@/components/ui/scroll-area';
|
|
12
|
+
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
13
|
+
import type { ActivityEvent, AllWidgetsData } from '@/types/widget-data';
|
|
14
|
+
import {
|
|
15
|
+
FileEdit,
|
|
16
|
+
LogIn,
|
|
17
|
+
LogOut,
|
|
18
|
+
Mail,
|
|
19
|
+
Settings,
|
|
20
|
+
ShieldAlert,
|
|
21
|
+
UserCheck,
|
|
22
|
+
} from 'lucide-react';
|
|
23
|
+
import { useTranslations } from 'next-intl';
|
|
24
|
+
import { WidgetWrapper } from '../widget-wrapper';
|
|
25
|
+
|
|
26
|
+
const typeIconMap: Record<string, React.ElementType> = {
|
|
27
|
+
login: LogIn,
|
|
28
|
+
logout: LogOut,
|
|
29
|
+
security: ShieldAlert,
|
|
30
|
+
settings: Settings,
|
|
31
|
+
edit: FileEdit,
|
|
32
|
+
permission: UserCheck,
|
|
33
|
+
email: Mail,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const typeColorMap: Record<string, { color: string; bg: string }> = {
|
|
37
|
+
login: {
|
|
38
|
+
color: 'text-blue-600 dark:text-blue-400',
|
|
39
|
+
bg: 'bg-blue-50 dark:bg-blue-950/40',
|
|
40
|
+
},
|
|
41
|
+
logout: { color: 'text-muted-foreground', bg: 'bg-muted' },
|
|
42
|
+
security: {
|
|
43
|
+
color: 'text-amber-600 dark:text-amber-400',
|
|
44
|
+
bg: 'bg-amber-50 dark:bg-amber-950/40',
|
|
45
|
+
},
|
|
46
|
+
settings: { color: 'text-foreground', bg: 'bg-muted' },
|
|
47
|
+
edit: {
|
|
48
|
+
color: 'text-indigo-600 dark:text-indigo-400',
|
|
49
|
+
bg: 'bg-indigo-50 dark:bg-indigo-950/40',
|
|
50
|
+
},
|
|
51
|
+
permission: {
|
|
52
|
+
color: 'text-emerald-600 dark:text-emerald-400',
|
|
53
|
+
bg: 'bg-emerald-50 dark:bg-emerald-950/40',
|
|
54
|
+
},
|
|
55
|
+
email: {
|
|
56
|
+
color: 'text-rose-600 dark:text-rose-400',
|
|
57
|
+
bg: 'bg-rose-50 dark:bg-rose-950/40',
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function detectType(action: string): string {
|
|
62
|
+
const a = action.toLowerCase();
|
|
63
|
+
if (a.includes('login') || a.includes('entrou') || a.includes('acesso'))
|
|
64
|
+
return 'login';
|
|
65
|
+
if (a.includes('logout') || a.includes('saiu') || a.includes('encerr'))
|
|
66
|
+
return 'logout';
|
|
67
|
+
if (
|
|
68
|
+
a.includes('senha') ||
|
|
69
|
+
a.includes('2fa') ||
|
|
70
|
+
a.includes('mfa') ||
|
|
71
|
+
a.includes('segur')
|
|
72
|
+
)
|
|
73
|
+
return 'security';
|
|
74
|
+
if (a.includes('config') || a.includes('idioma') || a.includes('preferên'))
|
|
75
|
+
return 'settings';
|
|
76
|
+
if (
|
|
77
|
+
a.includes('edit') ||
|
|
78
|
+
a.includes('atualiz') ||
|
|
79
|
+
a.includes('alter') ||
|
|
80
|
+
a.includes('perfil')
|
|
81
|
+
)
|
|
82
|
+
return 'edit';
|
|
83
|
+
if (a.includes('permiss') || a.includes('acesso') || a.includes('role'))
|
|
84
|
+
return 'permission';
|
|
85
|
+
if (a.includes('email') || a.includes('e-mail') || a.includes('notif'))
|
|
86
|
+
return 'email';
|
|
87
|
+
return 'settings';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function formatDate(
|
|
91
|
+
dateStr: string,
|
|
92
|
+
tToday: string,
|
|
93
|
+
tYesterday: string
|
|
94
|
+
): string {
|
|
95
|
+
const date = new Date(dateStr);
|
|
96
|
+
const now = new Date();
|
|
97
|
+
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
98
|
+
const yesterday = new Date(today);
|
|
99
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
100
|
+
const eventDay = new Date(
|
|
101
|
+
date.getFullYear(),
|
|
102
|
+
date.getMonth(),
|
|
103
|
+
date.getDate()
|
|
104
|
+
);
|
|
105
|
+
if (eventDay.getTime() === today.getTime()) return tToday;
|
|
106
|
+
if (eventDay.getTime() === yesterday.getTime()) return tYesterday;
|
|
107
|
+
return date.toLocaleDateString(undefined, { day: '2-digit', month: 'short' });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function formatTime(dateStr: string): string {
|
|
111
|
+
return new Date(dateStr).toLocaleTimeString('pt-BR', {
|
|
112
|
+
hour: '2-digit',
|
|
113
|
+
minute: '2-digit',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function TimelineContent({ events }: { events: ActivityEvent[] }) {
|
|
118
|
+
const t = useTranslations('core.DashboardPage.activityTimeline');
|
|
119
|
+
let lastDate = '';
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<Card className="flex h-full flex-col">
|
|
123
|
+
<CardHeader className="shrink-0 pb-3">
|
|
124
|
+
<div className="flex items-center justify-between">
|
|
125
|
+
<div>
|
|
126
|
+
<CardTitle className="text-base font-semibold">
|
|
127
|
+
{t('title')}
|
|
128
|
+
</CardTitle>
|
|
129
|
+
<CardDescription>{t('description')}</CardDescription>
|
|
130
|
+
</div>
|
|
131
|
+
<Badge variant="secondary">
|
|
132
|
+
{t('events', { count: events.length })}
|
|
133
|
+
</Badge>
|
|
134
|
+
</div>
|
|
135
|
+
</CardHeader>
|
|
136
|
+
<CardContent className="flex min-h-0 flex-1 flex-col overflow-hidden pt-0">
|
|
137
|
+
<ScrollArea className="h-full pr-3">
|
|
138
|
+
<div className="relative flex flex-col pb-2">
|
|
139
|
+
<div className="absolute bottom-0 left-[15px] top-0 w-px bg-border/60" />
|
|
140
|
+
{events.map((event, index) => {
|
|
141
|
+
const type = detectType(event.action);
|
|
142
|
+
const config =
|
|
143
|
+
typeColorMap[type] ??
|
|
144
|
+
(typeColorMap.settings as { color: string; bg: string });
|
|
145
|
+
const Icon = (typeIconMap[type] ?? Settings) as React.ElementType;
|
|
146
|
+
const dateLabel = formatDate(
|
|
147
|
+
event.created_at,
|
|
148
|
+
t('today'),
|
|
149
|
+
t('yesterday')
|
|
150
|
+
);
|
|
151
|
+
const showDate = dateLabel !== lastDate;
|
|
152
|
+
lastDate = dateLabel;
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<div key={event.id}>
|
|
156
|
+
{showDate && (
|
|
157
|
+
<div className="relative z-10 mb-1 mt-4 first:mt-0">
|
|
158
|
+
<span className="ml-11 inline-block rounded-md border border-border bg-muted px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">
|
|
159
|
+
{dateLabel}
|
|
160
|
+
</span>
|
|
161
|
+
</div>
|
|
162
|
+
)}
|
|
163
|
+
<div className="group relative flex items-start gap-3 py-1.5">
|
|
164
|
+
<div
|
|
165
|
+
className={`relative z-10 mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ${config.bg}`}
|
|
166
|
+
>
|
|
167
|
+
<Icon className={`h-3.5 w-3.5 ${config.color}`} />
|
|
168
|
+
</div>
|
|
169
|
+
<div className="flex min-w-0 flex-1 flex-col gap-0.5 rounded-lg px-2 py-1.5 transition-colors group-hover:bg-muted/40">
|
|
170
|
+
<div className="flex items-center justify-between gap-2">
|
|
171
|
+
<span className="text-sm font-medium leading-snug text-foreground">
|
|
172
|
+
{event.action}
|
|
173
|
+
</span>
|
|
174
|
+
<span className="shrink-0 text-[11px] tabular-nums text-muted-foreground">
|
|
175
|
+
{formatTime(event.created_at)}
|
|
176
|
+
</span>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
182
|
+
})}
|
|
183
|
+
</div>
|
|
184
|
+
</ScrollArea>
|
|
185
|
+
</CardContent>
|
|
186
|
+
</Card>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
interface ActivityTimelineProps {
|
|
191
|
+
widget?: { name?: string };
|
|
192
|
+
onRemove?: () => void;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export default function ActivityTimeline({
|
|
196
|
+
widget,
|
|
197
|
+
onRemove,
|
|
198
|
+
}: ActivityTimelineProps) {
|
|
199
|
+
const { data, isLoading, isError, isAccessDenied } = useWidgetData<
|
|
200
|
+
AllWidgetsData,
|
|
201
|
+
ActivityEvent[]
|
|
202
|
+
>({
|
|
203
|
+
endpoint: '/dashboard-core/widgets/me',
|
|
204
|
+
queryKey: 'widget-me',
|
|
205
|
+
select: (d) => d.activityTimeline,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
return (
|
|
209
|
+
<WidgetWrapper
|
|
210
|
+
isLoading={isLoading}
|
|
211
|
+
isError={isError}
|
|
212
|
+
isAccessDenied={isAccessDenied}
|
|
213
|
+
widgetName={widget?.name ?? 'activity-timeline'}
|
|
214
|
+
onRemove={onRemove}
|
|
215
|
+
>
|
|
216
|
+
{data && <TimelineContent events={data} />}
|
|
217
|
+
</WidgetWrapper>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
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 { Mail, MailCheck, MailWarning, MailX } from 'lucide-react';
|
|
16
|
+
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts';
|
|
17
|
+
import { WidgetWrapper } from '../widget-wrapper';
|
|
18
|
+
|
|
19
|
+
const data = [
|
|
20
|
+
{ date: '01 Fev', recebidos: 5, lidos: 4 },
|
|
21
|
+
{ date: '03 Fev', recebidos: 3, lidos: 2 },
|
|
22
|
+
{ date: '05 Fev', recebidos: 8, lidos: 6 },
|
|
23
|
+
{ date: '07 Fev', recebidos: 4, lidos: 4 },
|
|
24
|
+
{ date: '09 Fev', recebidos: 6, lidos: 3 },
|
|
25
|
+
{ date: '11 Fev', recebidos: 2, lidos: 2 },
|
|
26
|
+
{ date: '13 Fev', recebidos: 7, lidos: 5 },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const chartConfig = {
|
|
30
|
+
recebidos: {
|
|
31
|
+
label: 'Recebidos',
|
|
32
|
+
color: 'hsl(221, 83%, 53%)',
|
|
33
|
+
},
|
|
34
|
+
lidos: {
|
|
35
|
+
label: 'Lidos',
|
|
36
|
+
color: 'hsl(160, 84%, 39%)',
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const emailStats = [
|
|
41
|
+
{
|
|
42
|
+
label: 'Recebidos',
|
|
43
|
+
value: '35',
|
|
44
|
+
icon: Mail,
|
|
45
|
+
color: 'text-blue-600 dark:text-blue-400',
|
|
46
|
+
bg: 'bg-blue-50 dark:bg-blue-950/40',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
label: 'Lidos',
|
|
50
|
+
value: '26',
|
|
51
|
+
icon: MailCheck,
|
|
52
|
+
color: 'text-emerald-600 dark:text-emerald-400',
|
|
53
|
+
bg: 'bg-emerald-50 dark:bg-emerald-950/40',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
label: 'Nao lidos',
|
|
57
|
+
value: '9',
|
|
58
|
+
icon: MailWarning,
|
|
59
|
+
color: 'text-amber-600 dark:text-amber-400',
|
|
60
|
+
bg: 'bg-amber-50 dark:bg-amber-950/40',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
label: 'Com erro',
|
|
64
|
+
value: '2',
|
|
65
|
+
icon: MailX,
|
|
66
|
+
color: 'text-red-600 dark:text-red-400',
|
|
67
|
+
bg: 'bg-red-50 dark:bg-red-950/40',
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
interface EmailNotificationsProps {
|
|
72
|
+
widget?: { name?: string };
|
|
73
|
+
onRemove?: () => void;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default function EmailNotifications({
|
|
77
|
+
widget,
|
|
78
|
+
onRemove,
|
|
79
|
+
}: EmailNotificationsProps) {
|
|
80
|
+
return (
|
|
81
|
+
<WidgetWrapper
|
|
82
|
+
isLoading={false}
|
|
83
|
+
isError={false}
|
|
84
|
+
isAccessDenied={false}
|
|
85
|
+
widgetName={widget?.name ?? 'email-notifications'}
|
|
86
|
+
onRemove={onRemove}
|
|
87
|
+
>
|
|
88
|
+
<Card className="flex h-full flex-col">
|
|
89
|
+
<CardHeader className="shrink-0 pb-2">
|
|
90
|
+
<div className="flex items-center gap-2">
|
|
91
|
+
<Mail className="h-5 w-5 text-rose-600 dark:text-rose-400" />
|
|
92
|
+
<div>
|
|
93
|
+
<CardTitle className="text-base font-semibold">
|
|
94
|
+
Notificacoes por E-mail
|
|
95
|
+
</CardTitle>
|
|
96
|
+
<CardDescription>
|
|
97
|
+
E-mails do sistema nos ultimos 14 dias
|
|
98
|
+
</CardDescription>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</CardHeader>
|
|
102
|
+
<CardContent className="flex-1 overflow-auto pt-0">
|
|
103
|
+
<div className="mb-4 grid grid-cols-4 gap-2">
|
|
104
|
+
{emailStats.map((stat) => {
|
|
105
|
+
const Icon = stat.icon;
|
|
106
|
+
return (
|
|
107
|
+
<div
|
|
108
|
+
key={stat.label}
|
|
109
|
+
className="flex flex-col items-center gap-1 rounded-lg border p-2.5 transition-colors hover:bg-muted/30"
|
|
110
|
+
>
|
|
111
|
+
<div
|
|
112
|
+
className={`flex h-7 w-7 items-center justify-center rounded-md ${stat.bg}`}
|
|
113
|
+
>
|
|
114
|
+
<Icon className={`h-3.5 w-3.5 ${stat.color}`} />
|
|
115
|
+
</div>
|
|
116
|
+
<span className="text-lg font-bold text-foreground">
|
|
117
|
+
{stat.value}
|
|
118
|
+
</span>
|
|
119
|
+
<span className="text-[10px] text-muted-foreground">
|
|
120
|
+
{stat.label}
|
|
121
|
+
</span>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
})}
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<ChartContainer config={chartConfig} className="h-[180px] w-full">
|
|
128
|
+
<AreaChart data={data}>
|
|
129
|
+
<CartesianGrid vertical={false} strokeDasharray="3 3" />
|
|
130
|
+
<XAxis
|
|
131
|
+
dataKey="date"
|
|
132
|
+
tickLine={false}
|
|
133
|
+
axisLine={false}
|
|
134
|
+
fontSize={11}
|
|
135
|
+
tickMargin={8}
|
|
136
|
+
/>
|
|
137
|
+
<YAxis
|
|
138
|
+
tickLine={false}
|
|
139
|
+
axisLine={false}
|
|
140
|
+
fontSize={11}
|
|
141
|
+
tickMargin={4}
|
|
142
|
+
allowDecimals={false}
|
|
143
|
+
/>
|
|
144
|
+
<ChartTooltip content={<ChartTooltipContent />} />
|
|
145
|
+
<defs>
|
|
146
|
+
<linearGradient id="fillRecebidos" x1="0" y1="0" x2="0" y2="1">
|
|
147
|
+
<stop
|
|
148
|
+
offset="5%"
|
|
149
|
+
stopColor="hsl(221, 83%, 53%)"
|
|
150
|
+
stopOpacity={0.2}
|
|
151
|
+
/>
|
|
152
|
+
<stop
|
|
153
|
+
offset="95%"
|
|
154
|
+
stopColor="hsl(221, 83%, 53%)"
|
|
155
|
+
stopOpacity={0}
|
|
156
|
+
/>
|
|
157
|
+
</linearGradient>
|
|
158
|
+
<linearGradient id="fillLidos" x1="0" y1="0" x2="0" y2="1">
|
|
159
|
+
<stop
|
|
160
|
+
offset="5%"
|
|
161
|
+
stopColor="hsl(160, 84%, 39%)"
|
|
162
|
+
stopOpacity={0.2}
|
|
163
|
+
/>
|
|
164
|
+
<stop
|
|
165
|
+
offset="95%"
|
|
166
|
+
stopColor="hsl(160, 84%, 39%)"
|
|
167
|
+
stopOpacity={0}
|
|
168
|
+
/>
|
|
169
|
+
</linearGradient>
|
|
170
|
+
</defs>
|
|
171
|
+
<Area
|
|
172
|
+
type="monotone"
|
|
173
|
+
dataKey="recebidos"
|
|
174
|
+
stroke="hsl(221, 83%, 53%)"
|
|
175
|
+
fill="url(#fillRecebidos)"
|
|
176
|
+
strokeWidth={2}
|
|
177
|
+
/>
|
|
178
|
+
<Area
|
|
179
|
+
type="monotone"
|
|
180
|
+
dataKey="lidos"
|
|
181
|
+
stroke="hsl(160, 84%, 39%)"
|
|
182
|
+
fill="url(#fillLidos)"
|
|
183
|
+
strokeWidth={2}
|
|
184
|
+
/>
|
|
185
|
+
</AreaChart>
|
|
186
|
+
</ChartContainer>
|
|
187
|
+
</CardContent>
|
|
188
|
+
</Card>
|
|
189
|
+
</WidgetWrapper>
|
|
190
|
+
);
|
|
191
|
+
}
|