feat: update analitycs
This commit is contained in:
181
components/analytics/analytics-chart.tsx
Normal file
181
components/analytics/analytics-chart.tsx
Normal file
@@ -0,0 +1,181 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { CartesianGrid, Line, LineChart, XAxis, Bar, BarChart } from "recharts";
|
||||
import { CardContent } from "@/components/ui/card";
|
||||
import {
|
||||
ChartConfig,
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
ChartLegend,
|
||||
ChartLegendContent,
|
||||
} from "@/components/ui/chart";
|
||||
import { formatCurrency, formatNumber } from "@/lib/utils/format";
|
||||
import type { SpendingDataPoint, AnalyticsMetric } from "@/lib/types/api";
|
||||
|
||||
interface AnalyticsChartProps {
|
||||
data: SpendingDataPoint[];
|
||||
metrics: AnalyticsMetric[];
|
||||
chartType: "line" | "bar";
|
||||
showDataLabels?: boolean;
|
||||
}
|
||||
|
||||
const METRIC_LABELS: Record<AnalyticsMetric, string> = {
|
||||
cost: "Расходы",
|
||||
subscriptions: "Подписки",
|
||||
views: "Просмотры",
|
||||
cpf: "CPF",
|
||||
cpm: "CPM",
|
||||
};
|
||||
|
||||
export const AnalyticsChart: React.FC<AnalyticsChartProps> = ({
|
||||
data,
|
||||
metrics,
|
||||
chartType,
|
||||
showDataLabels = false,
|
||||
}) => {
|
||||
// Создаем конфигурацию для chart
|
||||
const chartConfig: ChartConfig = metrics.reduce((acc, metric, index) => {
|
||||
acc[metric] = {
|
||||
label: METRIC_LABELS[metric],
|
||||
color: `var(--chart-${index + 1})`,
|
||||
};
|
||||
return acc;
|
||||
}, {} as ChartConfig);
|
||||
|
||||
const formatValue = (value: number | null, metric: AnalyticsMetric) => {
|
||||
if (value === null) return "—";
|
||||
if (metric === "cost" || metric === "cpf" || metric === "cpm") {
|
||||
return formatCurrency(value);
|
||||
}
|
||||
return formatNumber(value);
|
||||
};
|
||||
|
||||
if (chartType === "bar") {
|
||||
return (
|
||||
<CardContent className="px-2 sm:p-6">
|
||||
<ChartContainer
|
||||
config={chartConfig}
|
||||
className="aspect-auto h-[350px] w-full"
|
||||
>
|
||||
<BarChart
|
||||
accessibilityLayer
|
||||
data={data}
|
||||
margin={{
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: showDataLabels ? 20 : 5,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="period"
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickMargin={8}
|
||||
minTickGap={32}
|
||||
/>
|
||||
<ChartTooltip
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(value) => `Период: ${value}`}
|
||||
formatter={(value, name) => [
|
||||
formatValue(
|
||||
value as number,
|
||||
name as AnalyticsMetric
|
||||
),
|
||||
chartConfig[name as AnalyticsMetric]?.label || name,
|
||||
]}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<ChartLegend content={<ChartLegendContent />} />
|
||||
{metrics.map((metric) => (
|
||||
<Bar
|
||||
key={metric}
|
||||
dataKey={metric}
|
||||
fill={chartConfig[metric]?.color}
|
||||
radius={4}
|
||||
label={
|
||||
showDataLabels
|
||||
? {
|
||||
position: "top",
|
||||
formatter: (value: number) =>
|
||||
formatValue(value, metric),
|
||||
fontSize: 10,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<CardContent className="px-2 sm:p-6">
|
||||
<ChartContainer
|
||||
config={chartConfig}
|
||||
className="aspect-auto h-[350px] w-full"
|
||||
>
|
||||
<LineChart
|
||||
accessibilityLayer
|
||||
data={data}
|
||||
margin={{
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: showDataLabels ? 20 : 5,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="period"
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickMargin={8}
|
||||
minTickGap={32}
|
||||
/>
|
||||
<ChartTooltip
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(value) => `Период: ${value}`}
|
||||
formatter={(value, name) => [
|
||||
formatValue(
|
||||
value as number,
|
||||
name as AnalyticsMetric
|
||||
),
|
||||
chartConfig[name as AnalyticsMetric]?.label || name,
|
||||
]}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<ChartLegend content={<ChartLegendContent />} />
|
||||
{metrics.map((metric) => (
|
||||
<Line
|
||||
key={metric}
|
||||
dataKey={metric}
|
||||
type="monotone"
|
||||
stroke={chartConfig[metric]?.color}
|
||||
strokeWidth={2}
|
||||
dot={showDataLabels}
|
||||
label={
|
||||
showDataLabels
|
||||
? {
|
||||
position: "top",
|
||||
formatter: (value: number) =>
|
||||
formatValue(value, metric),
|
||||
fontSize: 10,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user