import React, { useState } from 'react'; import { Link } from 'react-router-dom'; import InfoTooltip from './InfoTooltip'; export type ScoreAction = | { kind: 'link'; label: string; to: string; primary?: boolean; } | { kind: 'button'; label: string; onClick: () => Promise | void; busyLabel?: string; primary?: boolean; }; export interface ScoreRow { label: string; tag?: string; score: number; delta?: number; context?: string; tooltip?: string; action: ScoreAction; } interface ScoreBreakdownProps { rows: ScoreRow[]; } interface BandTheme { bar: string; numberText: string; deltaBg: string; deltaText: string; } const bandTheme = (score: number): BandTheme => { if (score >= 80) return { bar: 'bg-emerald-500', numberText: 'text-emerald-600', deltaBg: 'bg-emerald-50', deltaText: 'text-emerald-700', }; if (score >= 65) return { bar: 'bg-lime-500', numberText: 'text-lime-600', deltaBg: 'bg-emerald-50', deltaText: 'text-emerald-700', }; if (score >= 50) return { bar: 'bg-amber-400', numberText: 'text-amber-600', deltaBg: 'bg-emerald-50', deltaText: 'text-emerald-700', }; if (score >= 35) return { bar: 'bg-orange-500', numberText: 'text-orange-600', deltaBg: 'bg-emerald-50', deltaText: 'text-emerald-700', }; return { bar: 'bg-red-500', numberText: 'text-red-600', deltaBg: 'bg-red-50', deltaText: 'text-red-600', }; }; export function ScoreBreakdown({ rows }: ScoreBreakdownProps) { return (
{rows.map(row => ( ))}
); } function ScoreBreakdownRow({ row }: { row: ScoreRow }) { const theme: BandTheme = bandTheme(row.score); const clamped: number = Math.max(0, Math.min(100, Math.round(row.score))); const deltaPositive: boolean = (row.delta ?? 0) >= 0; return (
{row.label} {row.tag && ( {row.tag} )} {row.tooltip && }
{clamped} /100 {typeof row.delta === 'number' && row.delta !== 0 && ( {deltaPositive ? '↑' : '↓'} {Math.abs(row.delta)} )}

{row.context ?? ' '}

); } function ScoreActionButton({ action }: { action: ScoreAction }) { const [busy, setBusy] = useState(false); const className: string = 'shrink-0 cursor-pointer text-xs font-semibold text-[#B7007C] hover:text-[#900063] transition-colors'; if (action.kind === 'link') { return ( {action.label} → ); } const label: string = busy && action.busyLabel ? action.busyLabel : action.label; const handleClick = async (): Promise => { if (busy) return; setBusy(true); try { await action.onClick(); } finally { setBusy(false); } }; return ( ); }