mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-05-18 20:08:19 +00:00
feat: AI coaching panel — summary card, suggestions, structured responses
- ai-summary-card.tsx: Zone 1 — patient profile (name, badges, AI summary, source/campaign, appointment pills) - ai-suggestions.tsx: Zone 2 — collapsible suggestion pills with expand, script display, "Tell me more" action - ai-chat-panel.tsx: rewritten — orchestrates 3 zones, parses structured JSON from AI responses, progressive suggestion updates - context-panel.tsx: removed P360 tab toggle and all legacy sections, single coaching surface with callerSummary prop Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
88
src/components/call-desk/ai-summary-card.tsx
Normal file
88
src/components/call-desk/ai-summary-card.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faUser, faCalendarCheck, faPhone } from '@fortawesome/pro-duotone-svg-icons';
|
||||
import { Badge } from '@/components/base/badges/badges';
|
||||
|
||||
export type CallerSummary = {
|
||||
name: string;
|
||||
phone: string;
|
||||
isNew: boolean;
|
||||
aiSummary?: string | null;
|
||||
leadSource?: string | null;
|
||||
utmCampaign?: string | null;
|
||||
nextAppointment?: { scheduledAt: string; doctorName: string; department: string } | null;
|
||||
lastAppointment?: { scheduledAt: string; status: string; department: string } | null;
|
||||
};
|
||||
|
||||
interface AiSummaryCardProps {
|
||||
caller: CallerSummary | null;
|
||||
}
|
||||
|
||||
const formatDate = (dateStr: string): string => {
|
||||
const d = new Date(dateStr);
|
||||
return d.toLocaleDateString('en-IN', { day: 'numeric', month: 'short' });
|
||||
};
|
||||
|
||||
export const AiSummaryCard = ({ caller }: AiSummaryCardProps) => {
|
||||
if (!caller) {
|
||||
return (
|
||||
<div className="rounded-xl border border-secondary bg-secondary_alt p-3">
|
||||
<p className="text-xs text-quaternary text-center">Select a patient or receive a call</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-xl border border-secondary bg-secondary_alt p-3 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex size-8 shrink-0 items-center justify-center rounded-full bg-brand-primary">
|
||||
<FontAwesomeIcon icon={faUser} className="size-3 text-fg-brand-primary" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="text-sm font-semibold text-primary truncate">{caller.name || caller.phone}</span>
|
||||
<Badge size="sm" color={caller.isNew ? 'brand' : 'success'} type="pill-color">
|
||||
{caller.isNew ? 'New' : 'Returning'}
|
||||
</Badge>
|
||||
</div>
|
||||
{caller.name && (
|
||||
<span className="text-[10px] text-tertiary">{caller.phone}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{caller.aiSummary && (
|
||||
<p className="text-xs text-secondary leading-relaxed line-clamp-2">{caller.aiSummary}</p>
|
||||
)}
|
||||
|
||||
{(caller.leadSource || caller.utmCampaign) && (
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{caller.leadSource && (
|
||||
<Badge size="sm" color="gray" type="pill-color">{caller.leadSource}</Badge>
|
||||
)}
|
||||
{caller.utmCampaign && (
|
||||
<Badge size="sm" color="purple" type="pill-color">{caller.utmCampaign}</Badge>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-2">
|
||||
{caller.nextAppointment && (
|
||||
<div className="flex items-center gap-1.5 rounded-lg bg-success-primary px-2 py-1">
|
||||
<FontAwesomeIcon icon={faCalendarCheck} className="size-2.5 text-fg-success-primary" />
|
||||
<span className="text-[10px] font-medium text-success-primary">
|
||||
{formatDate(caller.nextAppointment.scheduledAt)} · {caller.nextAppointment.doctorName}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{caller.lastAppointment && (
|
||||
<div className="flex items-center gap-1.5 rounded-lg bg-secondary px-2 py-1">
|
||||
<FontAwesomeIcon icon={faPhone} className="size-2.5 text-fg-quaternary" />
|
||||
<span className="text-[10px] text-tertiary">
|
||||
Last: {formatDate(caller.lastAppointment.scheduledAt)} · {caller.lastAppointment.status}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user