Files
helix-engage/src/components/call-desk/call-log.tsx
saridsa2 d3cbf4d2bb fix: P2 defect batch + context-panel edit takeover
Layout (P1-adjacent):
- context-panel switches to an edit-only layout when editingAppointment
  is set. Previously AppointmentForm rendered inline BELOW the AI panel,
  crushing the AI area into a ~2-line strip that made the returning-
  patient summary + quick actions unusable. Edit view gets full height
  with a "Back to context" button.

P2s:
- Remove Attempted sub-tab from Missed Calls worklist (Pending only).
- Add CALL_DROPPED disposition option + propagate through every
  per-disposition Record<CallDisposition,...> map (incoming-call-card,
  call-log, call-history, agent-detail, patient-360).
- Block SLA-gaming on unanswered calls: Book Appt / Enquiry / Transfer
  buttons on active-call-card are disabled until the call reaches the
  answered state (wasAnsweredRef). The disposition filter was already
  in place; this closes the upstream entry.
- Data labels on performance charts: my-performance bar chart shows
  value on top of each bar; donut shows {d}% slice labels; team-
  performance day trend line shows per-point values.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:48:39 +05:30

86 lines
4.0 KiB
TypeScript

import type { FC } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faArrowRight } from '@fortawesome/pro-duotone-svg-icons';
import { Badge } from '@/components/base/badges/badges';
import { Button } from '@/components/base/buttons/button';
const ArrowRight: FC<{ className?: string }> = ({ className }) => <FontAwesomeIcon icon={faArrowRight} className={className} />;
import { formatShortDate } from '@/lib/format';
import type { Call, CallDisposition } from '@/types/entities';
interface CallLogProps {
calls: Call[];
}
const dispositionConfig: Record<CallDisposition, { label: string; color: 'success' | 'brand' | 'blue-light' | 'warning' | 'gray' | 'error' }> = {
APPOINTMENT_BOOKED: { label: 'Booked', color: 'success' },
APPOINTMENT_RESCHEDULED: { label: 'Rescheduled', color: 'warning' },
APPOINTMENT_CANCELLED: { label: 'Cancelled', color: 'error' },
FOLLOW_UP_SCHEDULED: { label: 'Follow-up', color: 'brand' },
INFO_PROVIDED: { label: 'Info', color: 'blue-light' },
NO_ANSWER: { label: 'No Answer', color: 'warning' },
WRONG_NUMBER: { label: 'Wrong #', color: 'gray' },
NOT_INTERESTED: { label: 'Not Interested', color: 'error' },
CALLBACK_REQUESTED: { label: 'Callback', color: 'brand' },
CALL_DROPPED: { label: 'Call Dropped', color: 'gray' },
};
const formatDuration = (seconds: number | null): string => {
if (seconds === null || seconds === 0) return '0 min';
const minutes = Math.round(seconds / 60);
return `${minutes} min`;
};
export const CallLog = ({ calls }: CallLogProps) => {
return (
<div className="rounded-2xl border border-secondary bg-primary">
<div className="flex items-center justify-between border-b border-secondary px-5 py-4">
<div className="flex items-center gap-2">
<span className="text-sm font-bold text-primary">Today's Calls</span>
<Badge size="sm" color="gray">{calls.length}</Badge>
</div>
</div>
{calls.length > 0 ? (
<div className="divide-y divide-secondary">
{calls.map((call) => {
const config = call.disposition !== null
? dispositionConfig[call.disposition]
: null;
return (
<div
key={call.id}
className="flex items-center gap-3 px-5 py-3"
>
<span className="w-20 shrink-0 text-xs text-quaternary">
{call.startedAt !== null ? formatShortDate(call.startedAt) : ''}
</span>
<span className="min-w-0 flex-1 truncate text-sm font-medium text-primary">
{call.leadName ?? call.callerNumber?.[0]?.number ?? 'Unknown'}
</span>
{config !== null && (
<Badge size="sm" color={config.color}>{config.label}</Badge>
)}
<span className="w-12 shrink-0 text-right text-xs text-quaternary">
{formatDuration(call.durationSeconds)}
</span>
</div>
);
})}
</div>
) : (
<div className="flex items-center justify-center py-8">
<p className="text-sm text-quaternary">No calls handled today</p>
</div>
)}
<div className="border-t border-secondary px-5 py-3">
<Button href="/call-history" color="link-color" size="sm" iconTrailing={ArrowRight}>
View Full History
</Button>
</div>
</div>
);
};