fix: disposition returns straight to worklist — no intermediate screens

Disposition is the last step. After submission, handleReset() clears
all state and returns to worklist immediately. Removed the "Call Completed"
card, post-disposition appointment form, and "Skip" button.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 09:55:37 +05:30
parent 938f2a84d8
commit 1df40f14ff

View File

@@ -2,7 +2,7 @@ import { useState, useRef } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faPhone, faPhoneHangup, faMicrophone, faMicrophoneSlash,
faPause, faPlay, faCalendarPlus, faCheckCircle,
faPause, faPlay, faCalendarPlus,
faPhoneArrowRight, faRecordVinyl, faClipboardQuestion,
} from '@fortawesome/pro-duotone-svg-icons';
import { Button } from '@/components/base/buttons/button';
@@ -42,7 +42,6 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
const setCallerNumber = useSetAtom(sipCallerNumberAtom);
const setCallUcid = useSetAtom(sipCallUcidAtom);
const [postCallStage, setPostCallStage] = useState<PostCallStage | null>(null);
const [savedDisposition, setSavedDisposition] = useState<CallDisposition | null>(null);
const [appointmentOpen, setAppointmentOpen] = useState(false);
const [appointmentBookedDuringCall, setAppointmentBookedDuringCall] = useState(false);
const [transferOpen, setTransferOpen] = useState(false);
@@ -60,7 +59,6 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
const phoneDisplay = phone ? formatPhone(phone) : callerPhone || 'Unknown';
const handleDisposition = async (disposition: CallDisposition, notes: string) => {
setSavedDisposition(disposition);
// Submit disposition to sidecar — handles Ozonetel ACW release
if (callUcid) {
@@ -76,12 +74,8 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
}).catch((err) => console.warn('Disposition failed:', err));
}
if (disposition === 'APPOINTMENT_BOOKED') {
setPostCallStage('appointment');
setAppointmentOpen(true);
} else if (disposition === 'FOLLOW_UP_SCHEDULED') {
setPostCallStage('follow-up');
// Create follow-up
// Side effects per disposition type
if (disposition === 'FOLLOW_UP_SCHEDULED') {
try {
await apiClient.graphql(`mutation($data: FollowUpCreateInput!) { createFollowUp(data: $data) { id } }`, {
data: {
@@ -97,27 +91,23 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
} catch {
notify.info('Follow-up', 'Could not auto-create follow-up');
}
setPostCallStage('done');
} else {
notify.success('Call Logged', `Disposition: ${disposition.replace(/_/g, ' ').toLowerCase()}`);
setPostCallStage('done');
}
// Disposition is the last step — return to worklist immediately
notify.success('Call Logged', `Disposition: ${disposition.replace(/_/g, ' ').toLowerCase()}`);
handleReset();
};
const handleAppointmentSaved = () => {
setAppointmentOpen(false);
notify.success('Appointment Booked', 'Payment link will be sent to the patient');
// If booked during active call, don't skip to 'done' — wait for disposition after call ends
if (callState === 'active') {
setAppointmentBookedDuringCall(true);
} else {
setPostCallStage('done');
}
};
const handleReset = () => {
setPostCallStage(null);
setSavedDisposition(null);
setCallState('idle');
setCallerNumber(null);
setCallUcid(null);
@@ -192,50 +182,6 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
// Post-call flow takes priority over active state (handles race between hangup + SIP ended event)
if (postCallStage !== null || callState === 'ended' || callState === 'failed') {
// Done state
if (postCallStage === 'done') {
return (
<div className="rounded-xl border border-success bg-success-primary p-4 text-center">
<FontAwesomeIcon icon={faCheckCircle} className="size-8 text-fg-success-primary mb-2" />
<p className="text-sm font-semibold text-success-primary">Call Completed</p>
<p className="text-xs text-tertiary mt-1">
{savedDisposition ? savedDisposition.replace(/_/g, ' ').toLowerCase() : 'logged'}
</p>
<Button size="sm" color="secondary" className="mt-3" onClick={handleReset}>
Back to Worklist
</Button>
</div>
);
}
// Appointment booking after disposition — auto-return when form closes
if (postCallStage === 'appointment') {
return (
<>
<div className="rounded-xl border border-brand bg-brand-primary p-4 text-center">
<FontAwesomeIcon icon={faCalendarPlus} className="size-6 text-fg-brand-primary mb-2" />
<p className="text-sm font-semibold text-brand-secondary">Booking Appointment</p>
<p className="text-xs text-tertiary mt-1">for {fullName || phoneDisplay}</p>
<Button size="sm" color="secondary" className="mt-2" onClick={() => setPostCallStage('done')}>
Skip & Return to Worklist
</Button>
</div>
<AppointmentForm
isOpen={appointmentOpen}
onOpenChange={(open) => {
setAppointmentOpen(open);
if (!open) setPostCallStage('done');
}}
callerNumber={callerPhone}
leadName={fullName || null}
leadId={lead?.id ?? null}
patientId={(lead as any)?.patientId ?? null}
onSaved={handleAppointmentSaved}
/>
</>
);
}
// Disposition form + enquiry access
return (
<>