mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 10:23:27 +00:00
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:
@@ -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 (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user