diff --git a/src/components/call-desk/appointment-form.tsx b/src/components/call-desk/appointment-form.tsx index 9427c32..9c95d2a 100644 --- a/src/components/call-desk/appointment-form.tsx +++ b/src/components/call-desk/appointment-form.tsx @@ -283,23 +283,13 @@ export const AppointmentForm = ({ const trimmedName = patientName.trim(); const nameChanged = isNameEditable && trimmedName.length > 0 && trimmedName !== initialLeadName; - // Update patient name ONLY if the agent explicitly renamed. - // This guard is the fix for the long-standing bug where the - // form silently overwrote existing patients' names with - // whatever happened to be in the input. - if (nameChanged && patientId) { - await apiClient.graphql( - `mutation UpdatePatient($id: UUID!, $data: PatientUpdateInput!) { - updatePatient(id: $id, data: $data) { id } - }`, - { - id: patientId, - data: { - fullName: { firstName: trimmedName.split(' ')[0], lastName: trimmedName.split(' ').slice(1).join(' ') || '' }, - }, - }, - ).catch((err: unknown) => console.warn('Failed to update patient name:', err)); - } + // DO NOT update the shared Patient entity when name changes + // during appointment creation. The Patient record is shared + // across all appointments — modifying it here would + // retroactively change the name on all past appointments. + // The patient name for THIS appointment is stored on the + // Appointment entity itself (via doctorName/department). + // Bug #527: removed updatePatient() call. // Update lead status/lastContacted on every appointment book // (those are genuinely about this appointment), but only diff --git a/src/pages/call-history.tsx b/src/pages/call-history.tsx index f48a449..3af72d3 100644 --- a/src/pages/call-history.tsx +++ b/src/pages/call-history.tsx @@ -16,7 +16,6 @@ import { Badge } from '@/components/base/badges/badges'; import { Button } from '@/components/base/buttons/button'; import { Input } from '@/components/base/input/input'; import { Select } from '@/components/base/select/select'; -import { TopBar } from '@/components/layout/top-bar'; import { ClickToCallButton } from '@/components/call-desk/click-to-call-button'; import { formatShortDate, formatPhone } from '@/lib/format'; import { computeSlaStatus } from '@/lib/scoring'; @@ -174,8 +173,6 @@ export const CallHistoryPage = () => { return (
- -
{ }, []); const logout = useCallback(async () => { + // Block logout during active call + const { isOutboundPending, disconnectSip } = await import('@/state/sip-manager'); + const activeUcid = localStorage.getItem('helix_active_ucid'); + if (isOutboundPending() || activeUcid) { + const confirmed = window.confirm( + 'You have an active call. Logging out will disconnect the call. Are you sure?', + ); + if (!confirmed) return; + } + // Disconnect SIP before logout try { - const { disconnectSip } = await import('@/state/sip-manager'); - disconnectSip(); + disconnectSip(true); } catch {} // Notify sidecar to unlock Redis session + Ozonetel logout — await before clearing tokens diff --git a/src/providers/sip-provider.tsx b/src/providers/sip-provider.tsx index eb1d874..f2923e9 100644 --- a/src/providers/sip-provider.tsx +++ b/src/providers/sip-provider.tsx @@ -156,6 +156,22 @@ export const useSip = () => { // Ozonetel outbound dial — single path for all outbound calls const dialOutbound = useCallback(async (phoneNumber: string): Promise => { + // Block outbound calls when agent is on Break or Training + const agentCfg = localStorage.getItem('helix_agent_config'); + if (agentCfg) { + const { useAgentState: _ } = await import('@/hooks/use-agent-state'); + // Read state from the SSE endpoint directly (can't use hook here) + const agentId = JSON.parse(agentCfg).ozonetelAgentId; + try { + const stateRes = await fetch(`/api/supervisor/agent-state?agentId=${agentId}`); + const stateData = await stateRes.json(); + if (stateData.state === 'break' || stateData.state === 'training') { + const { notify } = await import('@/lib/toast'); + notify.info('Status: ' + stateData.state, 'Change status to Ready before placing calls'); + return; + } + } catch {} + } console.log(`[DIAL] Outbound dial started: phone=${phoneNumber}`); setCallState('ringing-out'); setCallerNumber(phoneNumber);