Files
pn-new-crm/src/components/dashboard/pipeline-chart.tsx

95 lines
2.5 KiB
TypeScript
Raw Normal View History

'use client';
import { useQuery } from '@tanstack/react-query';
import {
Bar,
BarChart,
CartesianGrid,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts';
import { apiFetch } from '@/lib/api/client';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { CardSkeleton } from '@/components/shared/loading-skeleton';
import { WidgetErrorBoundary } from './widget-error-boundary';
interface PipelineRow {
stage: string;
count: number;
}
const STAGE_LABELS: Record<string, string> = {
open: 'Open',
details_sent: 'Details Sent',
in_communication: 'In Communication',
visited: 'Visited',
signed_eoi_nda: 'Signed EOI/NDA',
deposit_10pct: 'Deposit 10%',
contract: 'Contract',
completed: 'Completed',
};
function PipelineChartInner() {
const { data, isLoading } = useQuery<PipelineRow[]>({
queryKey: ['dashboard', 'pipeline'],
queryFn: () => apiFetch<PipelineRow[]>('/api/v1/dashboard/pipeline'),
staleTime: 60_000,
retry: 2,
});
if (isLoading) {
return <CardSkeleton />;
}
const chartData = (data ?? []).map((row) => ({
stage: STAGE_LABELS[row.stage] ?? row.stage,
count: row.count,
}));
return (
<Card className="h-full">
<CardHeader>
<CardTitle className="text-base">Pipeline Overview</CardTitle>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={260}>
<BarChart data={chartData} margin={{ top: 4, right: 8, left: -16, bottom: 60 }}>
<CartesianGrid strokeDasharray="3 3" className="stroke-border" />
<XAxis
dataKey="stage"
tick={{ fontSize: 11, fill: 'hsl(var(--muted-foreground))' }}
angle={-40}
textAnchor="end"
interval={0}
/>
<YAxis
tick={{ fontSize: 11, fill: 'hsl(var(--muted-foreground))' }}
allowDecimals={false}
/>
<Tooltip
contentStyle={{
background: 'hsl(var(--popover))',
border: '1px solid hsl(var(--border))',
borderRadius: '6px',
fontSize: 12,
}}
/>
<Bar dataKey="count" fill="hsl(var(--chart-1))" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
</CardContent>
</Card>
);
}
export function PipelineChart() {
return (
<WidgetErrorBoundary>
<PipelineChartInner />
</WidgetErrorBoundary>
);
}