Files
loyaly_cutomerweb/src/features/commerce/components/SalesTrendChart.tsx
2026-09-28 16:35:34 +05:30

98 lines
3.2 KiB
TypeScript

'use client';
import {useId} from 'react';
import {Area, AreaChart, CartesianGrid, Tooltip, XAxis, YAxis} from 'recharts';
import {Card} from '@astryxdesign/core/Card';
import {VStack} from '@astryxdesign/core/Layout';
import {Text} from '@astryxdesign/core/Text';
import {ChartFrame, AXIS_TICK} from '@/shared/components/charts/ChartFrame';
import {CHART} from '@/shared/components/charts/palette';
import {useChartMotion} from '@/shared/components/charts/useChartMotion';
import {formatCount, formatInr, formatInrCompact} from '@/shared/utils/format';
import type {TrendPoint} from '@/features/commerce/services/salesAnalysis';
/**
* Daily sales across the selected period — compact, one area in brand warm
* (sales are money, and money is warm on this console).
*
* Its own small chart rather than AreaChartView because the tooltip needs two
* units at once — rupees for sales, a plain count for purchases — and the
* shared tooltip formats every series with the one `yFormat`.
*/
export function SalesTrendChart({
data,
height = 180,
}: {
data: TrendPoint[];
height?: number;
}) {
const uid = useId().replace(/:/g, '');
const motion = useChartMotion(true);
return (
<ChartFrame height={height}>
<AreaChart data={data} margin={{top: 8, right: 8, bottom: 0, left: 0}}>
<defs>
<linearGradient id={`sales-${uid}`} x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor={CHART.brand.warm} stopOpacity={0.35} />
<stop offset="100%" stopColor={CHART.brand.warm} stopOpacity={0.02} />
</linearGradient>
</defs>
<CartesianGrid stroke={CHART.grid} strokeDasharray="3 3" vertical={false} />
<XAxis
dataKey="label"
tick={AXIS_TICK}
tickLine={false}
axisLine={false}
minTickGap={24}
/>
<YAxis
tick={AXIS_TICK}
tickLine={false}
axisLine={false}
width={48}
tickCount={4}
tickFormatter={(v: number) => formatInrCompact(v)}
/>
<Tooltip
cursor={{stroke: CHART.axisLine}}
content={({active, payload}) => {
const p = active ? (payload?.[0]?.payload as TrendPoint | undefined) : undefined;
if (!p) return null;
return (
<Card elevation="high" padding={3}>
<VStack gap={1}>
<Text size="sm" color="secondary">
{p.label}
</Text>
<Text size="sm" weight="semibold">
Sales {formatInr(p.sales)}
</Text>
<Text size="sm">Purchases {formatCount(p.purchases)}</Text>
</VStack>
</Card>
);
}}
/>
<Area
type="monotone"
dataKey="sales"
name="Sales"
stroke={CHART.brand.warm}
strokeWidth={2.5}
fill={`url(#sales-${uid})`}
fillOpacity={1}
dot={false}
activeDot={{
r: 4,
stroke: CHART.brand.warm,
strokeWidth: 2,
fill: 'var(--color-background-surface)',
}}
{...motion}
/>
</AreaChart>
</ChartFrame>
);
}