feat: QA fixes — Patient 360 rewrite, token refresh, call flow, UI polish

- Patient 360 page queries Patient entity with appointments, calls, leads
- Patients added to CC agent sidebar navigation
- Auto token refresh on 401 (deduplicated concurrent refreshes)
- Call desk: callDismissed flag prevents SIP race on worklist return
- Missed calls skip disposition when never answered
- Callbacks tab renamed to Leads tab
- Branch column header on missed calls tab
- F0rty2.ai link on login footer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-23 11:52:33 +05:30
parent 88fc743928
commit 727a0728ee
7 changed files with 312 additions and 100 deletions

View File

@@ -50,6 +50,8 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
const [enquiryOpen, setEnquiryOpen] = useState(false);
// Capture direction at mount — survives through disposition stage
const callDirectionRef = useRef(callState === 'ringing-out' ? 'OUTBOUND' : 'INBOUND');
// Track if the call was ever answered (reached 'active' state)
const wasAnsweredRef = useRef(callState === 'active');
const firstName = lead?.contactName?.firstName ?? '';
const lastName = lead?.contactName?.lastName ?? '';
@@ -174,6 +176,20 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
);
}
// Skip disposition for unanswered calls (ringing-in → ended without ever reaching active)
if (!wasAnsweredRef.current && postCallStage === null && (callState === 'ended' || callState === 'failed')) {
return (
<div className="rounded-xl border border-secondary bg-primary p-4 text-center">
<FontAwesomeIcon icon={faPhoneHangup} className="size-6 text-fg-quaternary mb-2" />
<p className="text-sm font-semibold text-primary">Missed Call</p>
<p className="text-xs text-tertiary mt-1">{phoneDisplay} not answered</p>
<Button size="sm" color="secondary" className="mt-3" onClick={handleReset}>
Back to Worklist
</Button>
</div>
);
}
// Post-call flow takes priority over active state (handles race between hangup + SIP ended event)
if (postCallStage !== null || callState === 'ended' || callState === 'failed') {
// Done state
@@ -235,6 +251,7 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
// Active call
if (callState === 'active') {
wasAnsweredRef.current = true;
return (
<div className="rounded-xl border border-brand bg-primary p-4">
<div className="flex items-center justify-between">