import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { Lightbulb, ArrowRight, CheckCircle2 } from 'lucide-react';
import { coachingApi } from '../../api/coachingApi';
import type { CoachingInsight, CoachingSeverity } from '../../types';
const SEVERITY_ORDER: Record<CoachingSeverity, number> = { high: 0, medium: 1, low: 2 };
const severityBadgeStyles: Record<CoachingSeverity, string> = {
high: 'bg-red-100 text-red-700',
medium: 'bg-amber-100 text-amber-700',
low: 'bg-emerald-100 text-emerald-700',
};
interface NextMoveWidgetProps {
/** Where "View all" links to. Defaults to the admin coaching page. */
coachingPath?: string;
}
/**
* Compact "Next Move" card for dashboards — shows the single highest-priority
* coaching insight with a link to the full Smart Coaching page.
* Renders nothing while loading or on error to avoid dashboard jank.
*/
export function NextMoveWidget({ coachingPath = '/admin/coaching' }: NextMoveWidgetProps) {
const [insight, setInsight] = useState<CoachingInsight | null>(null);
const [state, setState] = useState<'loading' | 'ready' | 'clear' | 'error'>('loading');
useEffect(() => {
let cancelled = false;
coachingApi
.getInsights()
.then((res) => {
if (cancelled) return;
const top = res.insights
.filter((i) => !i.dismissed)
.sort((a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity])[0];
if (top) {
setInsight(top);
setState('ready');
} else {
setState('clear');
}
})
.catch(() => {
if (!cancelled) setState('error');
});
return () => {
cancelled = true;
};
}, []);
if (state === 'loading' || state === 'error') return null;
if (state === 'clear') {
return (
<div className="rounded-xl border border-surface-200 bg-white p-5">
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-emerald-100 text-emerald-600">
<CheckCircle2 className="h-5 w-5" />
</div>
<div className="min-w-0 flex-1">
<p className="text-xs font-bold uppercase tracking-wider text-surface-400">Next Move</p>
<p className="text-sm font-medium text-surface-700">All clear — no coaching recommendations right now.</p>
</div>
<Link to={coachingPath} className="shrink-0 text-sm font-medium text-brand-600 hover:text-brand-700">
View all
</Link>
</div>
</div>
);
}
return (
<div className="rounded-xl border border-brand-200 bg-gradient-to-r from-brand-50 to-white p-5">
<div className="flex items-start gap-3">
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-brand-100 text-brand-600">
<Lightbulb className="h-5 w-5" />
</div>
<div className="min-w-0 flex-1">
<div className="flex flex-wrap items-center gap-2">
<p className="text-xs font-bold uppercase tracking-wider text-brand-600">Next Move</p>
{insight && (
<span className={`rounded-full px-2 py-0.5 text-xs font-semibold uppercase ${severityBadgeStyles[insight.severity]}`}>
{insight.severity}
</span>
)}
</div>
<h3 className="mt-1 truncate text-sm font-semibold text-surface-900">{insight?.title}</h3>
<p className="mt-1 line-clamp-2 text-sm text-surface-600">{insight?.narrative}</p>
</div>
<Link
to={coachingPath}
className="inline-flex shrink-0 items-center gap-1 text-sm font-semibold text-brand-600 hover:text-brand-700"
>
View all <ArrowRight className="h-3.5 w-3.5" />
</Link>
</div>
</div>
);
}