feat: creats frontend for the project

This commit is contained in:
vakabunga
2026-03-02 00:33:09 +03:00
parent 4d67636633
commit cd56e2bf9d
37 changed files with 3762 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
} from 'recharts';
import type { TimeseriesItem } from '@family-budget/shared';
interface Props {
data: TimeseriesItem[];
}
const rubFormatter = new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB',
maximumFractionDigits: 0,
});
export function TimeseriesChart({ data }: Props) {
if (data.length === 0) {
return <div className="chart-empty">Нет данных за период</div>;
}
const chartData = data.map((item) => ({
period: item.periodStart,
Расходы: Math.abs(item.expenseAmount) / 100,
Доходы: item.incomeAmount / 100,
}));
return (
<ResponsiveContainer width="100%" height={300}>
<BarChart data={chartData}>
<CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" />
<XAxis
dataKey="period"
tickFormatter={(v: string) => {
const d = new Date(v);
return `${d.getDate()}.${String(d.getMonth() + 1).padStart(2, '0')}`;
}}
fontSize={12}
stroke="#64748b"
/>
<YAxis
tickFormatter={(v: number) =>
v >= 1000 ? `${(v / 1000).toFixed(0)}к` : String(v)
}
fontSize={12}
stroke="#64748b"
/>
<Tooltip
formatter={(value: number) => rubFormatter.format(value)}
/>
<Legend />
<Bar
dataKey="Расходы"
fill="#ef4444"
radius={[4, 4, 0, 0]}
/>
<Bar
dataKey="Доходы"
fill="#10b981"
radius={[4, 4, 0, 0]}
/>
</BarChart>
</ResponsiveContainer>
);
}