The appointment-edit form opened with clinic/time blank even for
well-formed appointments because the pipeline never carried clinicId
end-to-end. Four-layer audit + fix:
1. APPOINTMENTS_QUERY now fetches clinicId + clinic { id clinicName }
+ doctor.fullName (was only doctor.id).
2. transformAppointments populates real clinicId + clinicName from the
relation instead of faking clinicName=department.
3. Appointment type gets clinicId: string | null.
4. context-panel passes clinicId through to AppointmentForm's
existingAppointment prop; form initial-states clinic from it.
Also on edit: if the saved timeSlot isn't in the fresh slot list
(past-slot filter, schedule change, clinic mismatch) we inject it as
"HH:MM (current)" so the dropdown displays the existing value instead
of looking cleared.
Historical appointments with clinicId=null on the platform still fall
through to the auto-select-from-slot logic; a maint backfill for those
is a separate task.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
The Agent Performance table on the team dashboard was bucketing by raw
call.agentName — the field that holds Ozonetel's transfer-chain string
("RamaiahAdmin -> GlobalHealthX") and collides for distinct AgentIDs
that share a Full Name. Result: 7 rows for 3 real agents.
Now buckets by call.agent.id when the CDR enrichment has populated it,
falls back to legacy agentName grouping otherwise. Calls without any
agent info are dropped from the agent rollup (instead of being
collapsed under "Unknown").
Pulls agent { id name ozonetelAgentId } + transferredTo + transferType
on CALLS_QUERY.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add CallDirection, CallStatus, CallDisposition, Call types to entities.ts
- Add IntegrationStatus, AuthStatus, IngestionPlatform, LeadIngestionSource types
- Add aiSummary and aiSuggestedAction fields to Lead type
- Create src/mocks/calls.ts with 15 INBOUND COMPLETED calls across 3 agents
- Create src/mocks/ingestion-sources.ts with 6 integration sources (ACTIVE/WARNING/ERROR)
- Update mockLeads with AI summaries on ~20 leads (new, contacted, spam cohorts)
- Expose calls, ingestionSources, and addCall() in DataContext
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>