mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-05-18 20:08:19 +00:00
- 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>
89 lines
3.9 KiB
TypeScript
89 lines
3.9 KiB
TypeScript
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>
|
|
);
|
|
};
|