mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
#533: Remove redundant Call History top header (duplicate TopBar) #531: Block logout during active call (confirm dialog + UCID check) #529: Block outbound calls when agent is on Break/Training #527: Remove updatePatient during appointment creation (was mutating shared Patient entity, affecting all past appointments) #547: SLA rules seeded via API (config issue, not code) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 (
|
||||
<div className="flex flex-1 flex-col overflow-hidden">
|
||||
<TopBar title="Call History" subtitle={`${filteredCalls.length} total calls`} />
|
||||
|
||||
<div className="flex flex-1 flex-col overflow-hidden p-7">
|
||||
<TableCard.Root size="md" className="flex-1 min-h-0">
|
||||
<TableCard.Header
|
||||
|
||||
@@ -96,10 +96,19 @@ export const AuthProvider = ({ children }: AuthProviderProps) => {
|
||||
}, []);
|
||||
|
||||
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
|
||||
|
||||
@@ -156,6 +156,22 @@ export const useSip = () => {
|
||||
|
||||
// Ozonetel outbound dial — single path for all outbound calls
|
||||
const dialOutbound = useCallback(async (phoneNumber: string): Promise<void> => {
|
||||
// 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);
|
||||
|
||||
Reference in New Issue
Block a user