Files
monitoring-app/src/frontend/components/DashboardCharts.tsx
2026-04-16 11:47:19 +08:00

143 lines
4.5 KiB
TypeScript

import { BarChart, LineChart } from '@mantine/charts'
import {
Badge,
Box,
Group,
Paper,
Stack,
Text,
ThemeIcon,
useMantineTheme
} from '@mantine/core'
import { TbArrowUpRight, TbChartBar, TbTimeline } from 'react-icons/tb'
interface ChartProps {
data?: any[]
isLoading?: boolean
}
export function VillageActivityLineChart({ data = [], isLoading }: ChartProps) {
const theme = useMantineTheme()
return (
<Paper withBorder p="xl" radius="2xl" className="glass h-full">
<Stack gap="md" h="100%">
<Group justify="space-between">
<Group gap="sm">
<ThemeIcon variant="light" size="lg" radius="md" color="blue">
<TbTimeline size={20} />
</ThemeIcon>
<Box>
<Text fw={700} size="sm">DAILY ACTIVITY - ALL VILLAGES</Text>
<Text size="xs" c="dimmed">Trend over the last 7 days</Text>
</Box>
</Group>
{
isLoading && (
<Badge variant="light" color="blue" size="sm" rightSection={<TbArrowUpRight size={12} />}>
...
</Badge>
)
}
</Group>
<Box h={300} mt="lg">
<LineChart
h={300}
data={data}
dataKey="date"
series={[{ name: 'logs', color: '#2563EB' }]}
curveType="monotone"
tickLine="none"
gridAxis="x"
withTooltip
tooltipAnimationDuration={200}
tooltipProps={{
allowEscapeViewBox: { x: true, y: false },
}}
styles={{
root: {
'.recharts-line-curve': {
strokeWidth: 3,
filter: 'drop-shadow(0 4px 8px rgba(37, 99, 235, 0.3))'
}
}
}}
/>
</Box>
</Stack>
</Paper>
)
}
export function VillageComparisonBarChart({ data = [], isLoading }: ChartProps) {
const theme = useMantineTheme()
return (
<Paper withBorder p="xl" radius="2xl" className="glass h-full">
<Stack gap="md" h="100%">
<Group justify="space-between">
<Group gap="sm">
<ThemeIcon variant="light" size="lg" radius="md" color="brand-purple">
<TbChartBar size={20} />
</ThemeIcon>
<Box>
<Text fw={700} size="sm">USAGE COMPARISON BETWEEN VILLAGES</Text>
<Text size="xs" c="dimmed">Most active village deployments</Text>
</Box>
</Group>
</Group>
<Box h={300} mt="lg">
<BarChart
h={300}
data={data}
dataKey="village"
series={[{ name: 'activity', color: 'blue.6' }]} // Menggunakan warna dari theme
withTooltip
barProps={{
radius: [8, 8, 0, 0],
fill: 'url(#barGradient)', // Menggunakan gradient yang Anda buat
}}
tooltipProps={{
cursor: { fill: '#373A40', opacity: 0.4 },
allowEscapeViewBox: { x: false, y: false },
content: ({ active, payload }) => {
if (active && payload && payload.length) {
return (
<div style={{
backgroundColor: '#1A1B1E',
padding: '8px 12px',
borderRadius: '6px',
border: '1px solid #373A40',
boxShadow: '0 4px 12px rgba(0,0,0,0.5)',
pointerEvents: 'none', // Sangat penting agar tidak mengganggu hover
whiteSpace: 'nowrap' // Mencegah teks turun ke bawah
}}>
<div style={{ fontSize: '12px', fontWeight: 600, color: '#fff', marginBottom: '4px' }}>
{payload[0].payload.village}
</div>
<div style={{ fontSize: '11px', color: '#2563EB' }}>
Activity: <span style={{ fontWeight: 700 }}>{payload[0].value}</span>
</div>
</div>
);
}
return null;
},
}}
>
<defs>
<linearGradient id="barGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#2563EB" stopOpacity={1} />
<stop offset="100%" stopColor="#7C3AED" stopOpacity={0.8} />
</linearGradient>
</defs>
</BarChart>
</Box>
</Stack>
</Paper>
)
}