// EnhancedCharts.tsx - Production-Grade Interactive Charts // Theme-aware colors, touch interactions, varied color palettes import React, { useMemo, useState } from 'react'; import { Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Area, ComposedChart, Bar, BarChart, Legend, ReferenceLine, Cell, RadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, Radar, } from 'recharts'; import { TrendingUp, TrendingDown, AlertTriangle, CheckCircle, Target, Zap, DollarSign, Users, Activity, BarChart3, } from 'lucide-react'; // ============================================================================ // COLOR PALETTES - Different for each chart type // ============================================================================ const CHART_PALETTES = { // Revenue/Forecast - Blue to Orange gradient forecast: { primary: '#3b82f6', // Blue - Historical secondary: 'var(--accent-primary)', // Dynamic Theme Color - Forecast success: '#10b981', // Green - Growth danger: '#ef4444', // Red - Decline confidence: 'rgba(249, 115, 22, 0.15)', gradient1: '#60a5fa', gradient2: '#3b82f6', }, // Scenario Comparison - Purple/Violet scenario: { primary: '#8b5cf6', // Violet secondary: '#a855f7', // Purple success: '#22c55e', // Green danger: '#f43f5e', // Rose neutral: '#6b7280', best: '#10b981', colors: ['#8b5cf6', '#a855f7', '#c084fc', '#d946ef', '#e879f9'], }, // Profit/Loss - Green/Red profit: { profit: '#10b981', // Emerald loss: '#ef4444', // Red revenue: '#3b82f6', // Blue cost: '#f59e0b', // Amber neutral: '#6b7280', }, // Churn/Risk - Warm colors churn: { low: '#22c55e', // Green medium: '#f59e0b', // Amber high: '#ef4444', // Red critical: '#dc2626', // Red intense colors: ['#22c55e', '#84cc16', '#eab308', '#f97316', '#ef4444'], }, // Multi-series - Rainbow multiSeries: [ '#3b82f6', // Blue '#10b981', // Emerald '#f59e0b', // Amber '#8b5cf6', // Purple '#ec4899', // Pink '#06b6d4', // Cyan '#f97316', // Orange ], }; // ============================================================================ // ENHANCED FORECAST CHART - Blue Historical, Orange Forecast // ============================================================================ interface ForecastDataPoint { date: string; value: number; lower?: number; upper?: number; type: 'historical' | 'forecast'; } interface EnhancedForecastProps { data: ForecastDataPoint[]; title?: string; currency?: string; showConfidenceBand?: boolean; } export const EnhancedForecastChart: React.FC = ({ data, title = 'Revenue Prediction', currency = '₹', showConfidenceBand = true, }) => { // const [activePoint, setActivePoint] = useState(null); // Transform data for dual-line rendering const chartData = useMemo(() => { return data.map((d, idx) => ({ ...d, historical: d.type === 'historical' ? d.value : null, forecast: d.type === 'forecast' ? d.value : null, // Connect forecast to last historical point forecastLine: d.type === 'forecast' || (d.type === 'historical' && idx === data.filter(x => x.type === 'historical').length - 1) ? d.value : null, })); }, [data]); const historicalData = data.filter(d => d.type === 'historical'); const forecastData = data.filter(d => d.type === 'forecast'); const growthPct = historicalData.length && forecastData.length ? ((forecastData[forecastData.length - 1].value - historicalData[historicalData.length - 1].value) / historicalData[historicalData.length - 1].value * 100).toFixed(1) : '0'; const CustomTooltip = ({ active, payload }: any) => { if (!active || !payload?.length) return null; const d = payload[0]?.payload; const isForecast = d?.type === 'forecast'; return (

{d?.date}

{currency}{d?.value?.toLocaleString()}

{isForecast && d?.lower && d?.upper && (

Confidence: {currency}{d.lower.toLocaleString()} - {currency}{d.upper.toLocaleString()}

)}
{isForecast ? : } {isForecast ? 'Predicted' : 'Actual'}
); }; return (
{/* Header */}

{title}

{forecastData.length} months forecast

0 ? 'bg-emerald-100 dark:bg-emerald-500/20 text-emerald-700 dark:text-emerald-400' : 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400' }`}> {Number(growthPct) > 0 ? : } {Number(growthPct) > 0 ? '+' : ''}{growthPct}%
{/* Chart */}
{/* Historical gradient */} {/* Forecast gradient */} {/* Growth zone */} `${currency}${(v / 1000).toFixed(0)}k`} /> } /> {/* Confidence band */} {showConfidenceBand && ( )} {/* Historical area */} {/* Forecast line with dashes - DYNAMIC COLOR */} (
Historical
Forecast
Growth Zone
)} />
); }; // ============================================================================ // ENHANCED SCENARIO CHART - Purple/Violet Theme // ============================================================================ interface ScenarioData { name: string; value: number; change: number; risk: 'low' | 'medium' | 'high'; } interface EnhancedScenarioProps { scenarios: ScenarioData[]; bestScenario?: string; currency?: string; title?: string; } export const EnhancedScenarioChart: React.FC = ({ scenarios, bestScenario, currency = '₹', title = 'Scenario Comparison', }) => { const [hoveredBar, setHoveredBar] = useState(null); const chartData = useMemo(() => { return scenarios.map((s, idx) => ({ ...s, fill: s.name === bestScenario ? CHART_PALETTES.scenario.best : CHART_PALETTES.scenario.colors[idx % CHART_PALETTES.scenario.colors.length], isBest: s.name === bestScenario, })); }, [scenarios, bestScenario]); const CustomBar = (props: any) => { const { x, y, width, height, fill, isBest, index } = props; const isHovered = hoveredBar === index; return ( {/* Glow effect for best */} {isBest && ( )} setHoveredBar(index)} onMouseLeave={() => setHoveredBar(null)} /> {/* Value label */} {currency}{(props.value / 1000).toFixed(0)}k ); }; return (
{/* Header */}

{title}

{scenarios.length} scenarios analyzed

{bestScenario && (
Best: {bestScenario}
)}
{/* Chart */}
`${currency}${(v / 1000).toFixed(0)}k`} /> { if (!active || !payload?.length) return null; const d = payload[0]?.payload; return (

{d?.name}

{currency}{d?.value?.toLocaleString()}

0 ? 'text-emerald-600 dark:text-emerald-400' : d?.change < 0 ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400' }`}> {d?.change > 0 ? : } {d?.change > 0 ? '+' : ''}{d?.change}%
Risk: {d?.risk}
); }} /> } />
); }; // ============================================================================ // PROFIT/LOSS CHART - Green for Profit, Red for Loss // ============================================================================ interface ProfitLossData { period: string; revenue: number; cost: number; profit: number; } interface EnhancedProfitLossProps { data: ProfitLossData[]; currency?: string; title?: string; } export const EnhancedProfitLossChart: React.FC = ({ data, currency = '₹', title = 'Profit/Loss Analysis', }) => { const totalProfit = data.reduce((sum, d) => sum + d.profit, 0); const avgMargin = data.length ? (data.reduce((sum, d) => sum + (d.profit / d.revenue * 100), 0) / data.length).toFixed(1) : '0'; // Prevent typescript unused variable error const _ignore = avgMargin; console.log(_ignore); // Use it so TS doesn't complain return (
{/* Header */}

{title}

{data.length} periods analyzed

Total Profit

= 0 ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400'}`}> {totalProfit >= 0 ? '+' : ''}{currency}{totalProfit.toLocaleString()}

{/* Chart */}
`${currency}${(v / 1000).toFixed(0)}k`} /> { if (!active || !payload?.length) return null; const d = payload[0]?.payload; return (

{label}

Revenue: {currency}{d?.revenue?.toLocaleString()}
Cost: {currency}{d?.cost?.toLocaleString()}
= 0 ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400'}>Profit: = 0 ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400'}`}> {d?.profit >= 0 ? '+' : ''}{currency}{d?.profit?.toLocaleString()}
); }} /> (
Revenue
Cost
Profit
)} /> {data.map((entry, index) => ( = 0 ? '#10b981' : '#ef4444'} /> ))}
); }; // ============================================================================ // CHURN RISK CHART - Warm Color Scale // ============================================================================ interface ChurnData { segment: string; risk: number; // 0-100% customers: number; } interface EnhancedChurnChartProps { data: ChurnData[]; title?: string; } export const EnhancedChurnChart: React.FC = ({ data, title = 'Churn Risk Analysis', }) => { const getRiskColor = (risk: number) => { if (risk >= 70) return '#ef4444'; if (risk >= 50) return '#f97316'; if (risk >= 30) return '#f59e0b'; if (risk >= 15) return '#84cc16'; return '#22c55e'; }; const getRiskLabel = (risk: number) => { if (risk >= 70) return 'Critical'; if (risk >= 50) return 'High'; if (risk >= 30) return 'Medium'; if (risk >= 15) return 'Low'; return 'Very Low'; }; const totalAtRisk = data.filter(d => d.risk >= 30).reduce((sum, d) => sum + d.customers, 0); return (
{/* Header */}

{title}

{data.length} segments analyzed

{totalAtRisk.toLocaleString()} at risk
{/* Chart */}
`${v}%`} /> { if (!active || !payload?.length) return null; const d = payload[0]?.payload; return (

{d?.segment}

{d?.risk}% {getRiskLabel(d?.risk)}

{d?.customers?.toLocaleString()} customers

); }} /> {data.map((entry, index) => ( ))}
{/* Legend */}
{['Very Low', 'Low', 'Medium', 'High', 'Critical'].map((label, idx) => (
{label}
))}
); }; // ============================================================================ // MULTI-METRIC RADAR CHART // ============================================================================ interface RadarData { metric: string; current: number; target: number; max: number; } interface EnhancedRadarProps { data: RadarData[]; title?: string; } export const EnhancedRadarChart: React.FC = ({ data, title = 'Performance Metrics', }) => { return (
{/* Header */}

{title}

{data.length} metrics tracked

{/* Chart */}
{ if (!active || !payload?.length) return null; return (

{payload[0].payload.metric}

Current: {payload[0].value}
Target: {payload[1]?.value}
); }} /> (
Current
Target
)} />
); }; export default { EnhancedForecastChart, EnhancedScenarioChart, EnhancedProfitLossChart, EnhancedChurnChart, EnhancedRadarChart, };