'use client' import { useMemo } from 'react' import { format, subDays, startOfDay, isSameDay } from 'date-fns' interface Symptom { id: string type: string severity: number recordedAt: string durationMinutes?: number triggers?: string medicationTaken?: string } interface SymptomTrendChartProps { symptoms: Symptom[] days?: number selectedType?: string | null } const SYMPTOM_COLORS: Record = { FATIGUE: '#8b5cf6', NAUSEA: '#f59e0b', PAIN: '#ef4444', APPETITE: '#10b981', SLEEP: '#3b82f6', MOOD: '#ec4899', CUSTOM: '#6b7280', } const SYMPTOM_EMOJIS: Record = { FATIGUE: '😴', NAUSEA: '🤢', PAIN: '😣', APPETITE: '🍽️', SLEEP: '😴', MOOD: '😔', CUSTOM: '📝', } export function SymptomTrendChart({ symptoms, days = 7, selectedType }: SymptomTrendChartProps) { // Generate date range const today = startOfDay(new Date()) const dates = useMemo(() => Array.from({ length: days }, (_, i) => subDays(today, days - 1 - i)), [days, today] ) // Group symptoms by type and date const dataByTypeAndDate = useMemo(() => { const result: Record> = {} symptoms.forEach(s => { if (selectedType && s.type !== selectedType) return const dateKey = format(new Date(s.recordedAt), 'yyyy-MM-dd') if (!result[s.type]) result[s.type] = {} if (!result[s.type][dateKey]) { result[s.type][dateKey] = { avgSeverity: 0, count: 0 } } result[s.type][dateKey].avgSeverity += s.severity result[s.type][dateKey].count++ }) // Calculate averages Object.keys(result).forEach(type => { Object.keys(result[type]).forEach(date => { const data = result[type][date] data.avgSeverity = data.avgSeverity / data.count }) }) return result }, [symptoms, selectedType]) // Get unique types const types = selectedType ? [selectedType] : Object.keys(dataByTypeAndDate) if (symptoms.length === 0) { return (
No symptom data to display
) } return (
{/* Chart Area */}
{/* Grid lines */}
{[5, 4, 3, 2, 1].map(level => (
{level}
))}
{/* Bars */}
{dates.map((date, i) => { const dateKey = format(date, 'yyyy-MM-dd') const dayData: Record = {} types.forEach(type => { if (dataByTypeAndDate[type]?.[dateKey]) { dayData[type] = dataByTypeAndDate[type][dateKey].avgSeverity } }) const hasData = Object.keys(dayData).length > 0 return (
{hasData ? ( types.map(type => { const severity = dayData[type] if (!severity) return null const height = (severity / 5) * 100 return (
) }) ) : (
)}
) })}
{/* Date labels */}
{dates.map((date, i) => (
{format(date, days > 14 ? 'd' : 'EEE')}
))}
{/* Legend */} {!selectedType && types.length > 0 && (
{types.map(type => (
{SYMPTOM_EMOJIS[type]} {type.charAt(0) + type.slice(1).toLowerCase()}
))}
)}
) }