mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
- Appointment/enquiry forms reverted to inline rendering (not modals) - Forms: flat scrollable section with pinned footer, no card wrapper - Appointment form: DatePicker component, date prefilled, removed Returning Patient checkbox - Enquiry form: removed disposition dropdown, lead status defaults to CONTACTED - Transfer dialog: agent picker with live status, doctor list with department, select-then-connect flow - Transfer: removed external number input, moved Cancel/Connect to pinned header row - Button mutual exclusivity: Book Appt / Enquiry / Transfer close each other - Patient name write-back: appointment + enquiry forms update patient fullName after save - Caller cache invalidation: POST /api/caller/invalidate after name update - Follow-up fix (#513): assignedAgent, patientId, date validation in createFollowUp - Patients page: removed status filters + column, added pagination (15/page) - Pending badge removed from call desk header - Table resize handles visible (bg-tertiary pill) - Sim call button: dev-only (import.meta.env.DEV) - CallControlStrip component (reusable, not currently mounted) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
62 lines
3.0 KiB
TypeScript
62 lines
3.0 KiB
TypeScript
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
import {
|
|
faMicrophone, faMicrophoneSlash,
|
|
faPause, faPlay, faPhoneHangup,
|
|
} from '@fortawesome/pro-duotone-svg-icons';
|
|
import { useSip } from '@/providers/sip-provider';
|
|
import { cx } from '@/utils/cx';
|
|
|
|
const formatDuration = (seconds: number): string => {
|
|
const m = Math.floor(seconds / 60).toString().padStart(2, '0');
|
|
const s = (seconds % 60).toString().padStart(2, '0');
|
|
return `${m}:${s}`;
|
|
};
|
|
|
|
export const CallControlStrip = () => {
|
|
const { callState, callDuration, isMuted, isOnHold, toggleMute, toggleHold, hangup } = useSip();
|
|
|
|
if (callState !== 'active' && callState !== 'ringing-out') return null;
|
|
|
|
return (
|
|
<div className="flex items-center justify-between rounded-lg bg-success-secondary px-3 py-2">
|
|
<div className="flex items-center gap-2">
|
|
<span className="relative flex size-2">
|
|
<span className="absolute inline-flex size-full animate-ping rounded-full bg-success-solid opacity-75" />
|
|
<span className="relative inline-flex size-2 rounded-full bg-success-solid" />
|
|
</span>
|
|
<span className="text-xs font-semibold text-success-primary">Live Call</span>
|
|
<span className="text-xs font-bold tabular-nums text-success-primary">{formatDuration(callDuration)}</span>
|
|
</div>
|
|
<div className="flex items-center gap-1">
|
|
<button
|
|
onClick={toggleMute}
|
|
title={isMuted ? 'Unmute' : 'Mute'}
|
|
className={cx(
|
|
'flex size-7 items-center justify-center rounded-md transition duration-100 ease-linear',
|
|
isMuted ? 'bg-error-solid text-white' : 'bg-primary text-fg-quaternary hover:text-fg-secondary',
|
|
)}
|
|
>
|
|
<FontAwesomeIcon icon={isMuted ? faMicrophoneSlash : faMicrophone} className="size-3" />
|
|
</button>
|
|
<button
|
|
onClick={toggleHold}
|
|
title={isOnHold ? 'Resume' : 'Hold'}
|
|
className={cx(
|
|
'flex size-7 items-center justify-center rounded-md transition duration-100 ease-linear',
|
|
isOnHold ? 'bg-warning-solid text-white' : 'bg-primary text-fg-quaternary hover:text-fg-secondary',
|
|
)}
|
|
>
|
|
<FontAwesomeIcon icon={isOnHold ? faPlay : faPause} className="size-3" />
|
|
</button>
|
|
<button
|
|
onClick={hangup}
|
|
title="End Call"
|
|
className="flex size-7 items-center justify-center rounded-md bg-error-solid text-white hover:bg-error-solid_hover transition duration-100 ease-linear"
|
|
>
|
|
<FontAwesomeIcon icon={faPhoneHangup} className="size-3" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|