← back to Goodquestion

src/components/historical/TrajectoryCharts.tsx

144 lines

'use client'

import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
import {
  LineChart,
  Line,
  AreaChart,
  Area,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  Legend,
  ResponsiveContainer,
} from 'recharts'
import type { AreaTrajectory } from '@/types/swot'

interface TrajectoryChartsProps {
  trajectories: AreaTrajectory[]
}

export function TrajectoryCharts({ trajectories }: TrajectoryChartsProps) {
  const getTrendColor = (trend: 'increasing' | 'decreasing' | 'stable') => {
    switch (trend) {
      case 'increasing':
        return '#22c55e' // green
      case 'decreasing':
        return '#ef4444' // red
      case 'stable':
        return '#3b82f6' // blue
    }
  }

  const formatMetricName = (metric: string) => {
    return metric
      .split('-')
      .map(word => word.charAt(0).toUpperCase() + word.slice(1))
      .join(' ')
  }

  const formatValue = (value: number, metric: string) => {
    if (metric.includes('population') || metric.includes('employment')) {
      return value.toLocaleString()
    }
    if (metric.includes('rate') || metric.includes('percentage')) {
      return `${value}%`
    }
    if (metric.includes('income') || metric.includes('revenue')) {
      return `$${value.toLocaleString()}`
    }
    return value.toLocaleString()
  }

  return (
    <div className="space-y-6">
      {trajectories.map((trajectory, index) => {
        const color = getTrendColor(trajectory.trend)
        const hasForecast = trajectory.forecast && trajectory.forecast.length > 0

        // Combine historical and forecast data
        const chartData = [
          ...trajectory.data.map(d => ({
            year: d.year,
            value: d.value,
            type: 'Historical',
          })),
          ...(hasForecast
            ? trajectory.forecast!.map(f => ({
                year: f.year,
                value: f.value,
                type: 'Forecast',
                confidence: f.confidence,
              }))
            : []),
        ]

        return (
          <Card key={index}>
            <CardHeader>
              <CardTitle>{formatMetricName(trajectory.metric)}</CardTitle>
              <CardDescription>
                Trend: <strong className={`text-${trajectory.trend === 'increasing' ? 'green' : trajectory.trend === 'decreasing' ? 'red' : 'blue'}-600`}>
                  {trajectory.trend.charAt(0).toUpperCase() + trajectory.trend.slice(1)}
                </strong>
                {hasForecast && ' • Includes forecast data'}
              </CardDescription>
            </CardHeader>
            <CardContent>
              <ResponsiveContainer width="100%" height={300}>
                {hasForecast ? (
                  <AreaChart data={chartData}>
                    <CartesianGrid strokeDasharray="3 3" />
                    <XAxis dataKey="year" />
                    <YAxis
                      tickFormatter={(value) => formatValue(value, trajectory.metric)}
                    />
                    <Tooltip
                      formatter={(value: any, name: string) => [
                        formatValue(value, trajectory.metric),
                        name,
                      ]}
                    />
                    <Legend />
                    <Area
                      type="monotone"
                      dataKey="value"
                      stroke={color}
                      fill={color}
                      fillOpacity={0.3}
                      name={formatMetricName(trajectory.metric)}
                    />
                  </AreaChart>
                ) : (
                  <LineChart data={chartData}>
                    <CartesianGrid strokeDasharray="3 3" />
                    <XAxis dataKey="year" />
                    <YAxis
                      tickFormatter={(value) => formatValue(value, trajectory.metric)}
                    />
                    <Tooltip
                      formatter={(value: any) => [
                        formatValue(value, trajectory.metric),
                        formatMetricName(trajectory.metric),
                      ]}
                    />
                    <Line
                      type="monotone"
                      dataKey="value"
                      stroke={color}
                      strokeWidth={2}
                      dot={{ fill: color, r: 4 }}
                      activeDot={{ r: 6 }}
                    />
                  </LineChart>
                )}
              </ResponsiveContainer>
            </CardContent>
          </Card>
        )
      })}
    </div>
  )
}