import { Card } from './Card'; import { BarChart, Bar, LineChart, Line, AreaChart, Area, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; export interface ChartRow { dimension: string; value: number; series?: string; } export interface ChartConfig { chart_uid: string; key: string; rows: ChartRow[]; } export interface AnalyticsChartProps { data?: unknown[]; gridCols?: number; } export function AnalyticsChart({ data, gridCols }: AnalyticsChartProps) { if (!data || !Array.isArray(data) || data.length === 0) return null; const charts = data as ChartConfig[]; const colors = ['#3B82F6', '#10B981', '#F59E0B', '#8B5CF6', '#EC4899', '#14B8A6']; const gridClass = gridCols === 1 ? "grid grid-cols-1 gap-6 w-full" : gridCols === 2 ? "grid grid-cols-1 lg:grid-cols-2 gap-6 w-full" : "grid grid-cols-1 lg:grid-cols-3 gap-6 w-full"; return (
{charts.map((chart, idx) => { const title = (chart.key || `Chart ${idx + 1}`) .replace(/_/g, ' ') .replace(/\b\w/g, c => c.toUpperCase()); const hasSeries = chart.rows?.some(r => r.series); let finalData: any[] = []; let seriesKeys: string[] = []; if (hasSeries) { const grouped = new Map(); const sKeys = new Set(); chart.rows?.forEach(r => { const dim = String(r.dimension || '').trim() || 'Unknown'; const s = String(r.series || '').trim() || 'Unknown'; sKeys.add(s); if (!grouped.has(dim)) { grouped.set(dim, { dimension: dim }); } const entry = grouped.get(dim); entry[s] = Number(r.value || 0); }); finalData = Array.from(grouped.values()); seriesKeys = Array.from(sKeys).sort(); // Sort series keys for consistency } else { finalData = (chart.rows || []).map(r => ({ ...r, dimension: String(r.dimension || '').trim() || 'Unknown', value: Number(r.value || 0) })); seriesKeys = ['value']; } if (finalData.length === 0) return null; const lowerKey = String(chart.key || '').toLowerCase(); let chartType = idx % 3; // 0 = Bar, 1 = Line, 2 = Area if (lowerKey.includes('status')) { chartType = 3; // Pie } else if (lowerKey.includes('route')) { chartType = 4; // Donut } else if (lowerKey.includes('brand') || lowerKey.includes('product')) { chartType = 5; // Table } else if (lowerKey.includes('monthly') || lowerKey.includes('yearly')) { chartType = 0; // Bar } // Determine if it should span full width const isFullWidth = (gridCols === 1) || (!gridCols && charts.length <= 2) || hasSeries || lowerKey.includes('monthly') || lowerKey.includes('yearly') || finalData.length > 8; const fullSpanClass = gridCols === 2 ? 'lg:col-span-2' : 'lg:col-span-3'; // Calculate a dynamic width if there's a lot of data to allow horizontal scrolling const minChartWidth = chartType === 0 || chartType === 1 || chartType === 2 ? Math.max(100, finalData.length * (hasSeries ? seriesKeys.length * 15 + 40 : 60)) : 100; const renderChartContent = () => { return ( <> {hasSeries && } {seriesKeys.map((key, i) => { const color = colors[i % colors.length]; if (chartType === 1) { return ( ); } else if (chartType === 2) { return ( ); } else { const barFill = i === 0 ? `url(#barGradient-${idx}-0)` : (i === 1 ? `url(#barGradient-${idx}-1)` : color); return ( ); } })} ); }; return (
100 ? 'overflow-x-auto scrollbar-slim' : ''}`}> {chartType === 5 ? (
{seriesKeys.map(k => ( ))} {finalData.filter(row => seriesKeys.some(k => row[k] > 0)).map((row, rIdx) => ( {seriesKeys.map(k => ( ))} ))}
Dimension{hasSeries ? k : 'Value'}
{row.dimension}{row[k]}
) : (
100 ? `${minChartWidth}px` : '100%', height: '100%' }}> {chartType === 3 || chartType === 4 ? ( {finalData.map((_, index) => ( ))} ) : chartType === 1 ? ( {renderChartContent()} ) : chartType === 2 ? ( {renderChartContent()} ) : ( {renderChartContent()} )}
)}
); })}
); }