Files
helix-engage/src/components/call-desk/ai-summary-card.tsx
saridsa2 b3ba840dec 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>
2026-04-17 11:22:22 +05:30

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)} &middot; {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)} &middot; {caller.lastAppointment.status}
</span>
</div>
)}
</div>
</div>
);
};