feat: disposition modal, persistent top bar, pagination, QA fixes

- DispositionModal: single modal for all call endings. Dismissable (agent can resume call).
  Agent clicks End → modal → select reason → hangup + dispose. Caller disconnects → same modal.
- One call screen: CallWidget stripped to ringing notification + auto-redirect to Call Desk.
- Persistent top bar in AppShell: agent status toggle + network indicator on all pages.
- Network indicator always visible (Connected/Unstable/No connection).
- Pagination: Untitled UI PaginationCardDefault on Call History + Appointments (20/page).
- Pinned table headers/footers: sticky column headers, scrollable body, pinned pagination.
  Applied to Call Desk worklist, Call History, Appointments, Call Recordings, Missed Calls.
- "Patient" → "Caller" column label in Call History.
- Offline → Ready toggle enabled.
- Profile status dot reflects Ozonetel state.
- NavAccountCard: popover placement top, View Profile + Account Settings restored.
- WIP pages for /profile and /account-settings.
- Enquiry form PHONE_INQUIRY → PHONE enum fix.
- Force Ready / View Profile / Account Settings removed then restored properly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 20:29:54 +05:30
parent daa2fbb0c2
commit e6b2208077
21 changed files with 645 additions and 816 deletions

View File

@@ -2,12 +2,11 @@ import type { FC, HTMLAttributes } from "react";
import { useCallback, useEffect, useRef } from "react";
import type { Placement } from "@react-types/overlays";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faUser, faGear, faArrowRightFromBracket, faPhoneVolume, faSort } from "@fortawesome/pro-duotone-svg-icons";
import { faArrowRightFromBracket, faSort, faUser, faGear } from "@fortawesome/pro-duotone-svg-icons";
const IconUser: FC<{ className?: string }> = ({ className }) => <FontAwesomeIcon icon={faUser} className={className} />;
const IconSettings: FC<{ className?: string }> = ({ className }) => <FontAwesomeIcon icon={faGear} className={className} />;
const IconLogout: FC<{ className?: string }> = ({ className }) => <FontAwesomeIcon icon={faArrowRightFromBracket} className={className} />;
const IconForceReady: FC<{ className?: string }> = ({ className }) => <FontAwesomeIcon icon={faPhoneVolume} className={className} />;
import { useFocusManager } from "react-aria";
import type { DialogProps as AriaDialogProps } from "react-aria-components";
import { Button as AriaButton, Dialog as AriaDialog, DialogTrigger as AriaDialogTrigger, Popover as AriaPopover } from "react-aria-components";
@@ -32,9 +31,10 @@ type NavAccountType = {
export const NavAccountMenu = ({
className,
onSignOut,
onForceReady,
onViewProfile,
onAccountSettings,
...dialogProps
}: AriaDialogProps & { className?: string; accounts?: NavAccountType[]; selectedAccountId?: string; onSignOut?: () => void; onForceReady?: () => void }) => {
}: AriaDialogProps & { className?: string; accounts?: NavAccountType[]; selectedAccountId?: string; onSignOut?: () => void; onViewProfile?: () => void; onAccountSettings?: () => void }) => {
const focusManager = useFocusManager();
const dialogRef = useRef<HTMLDivElement>(null);
@@ -75,12 +75,10 @@ export const NavAccountMenu = ({
<>
<div className="rounded-xl bg-primary ring-1 ring-secondary">
<div className="flex flex-col gap-0.5 py-1.5">
<NavAccountCardMenuItem label="View profile" icon={IconUser} shortcut="⌘K->P" />
<NavAccountCardMenuItem label="Account settings" icon={IconSettings} shortcut="⌘S" />
<NavAccountCardMenuItem label="Force Ready" icon={IconForceReady} onClick={() => { close(); onForceReady?.(); }} />
<NavAccountCardMenuItem label="View profile" icon={IconUser} onClick={() => { close(); onViewProfile?.(); }} />
<NavAccountCardMenuItem label="Account settings" icon={IconSettings} onClick={() => { close(); onAccountSettings?.(); }} />
</div>
</div>
<div className="pt-1 pb-1.5">
<NavAccountCardMenuItem label="Sign out" icon={IconLogout} shortcut="⌥⇧Q" onClick={() => { close(); onSignOut?.(); }} />
</div>
@@ -126,13 +124,15 @@ export const NavAccountCard = ({
selectedAccountId,
items = [],
onSignOut,
onForceReady,
onViewProfile,
onAccountSettings,
}: {
popoverPlacement?: Placement;
selectedAccountId?: string;
items?: NavAccountType[];
onSignOut?: () => void;
onForceReady?: () => void;
onViewProfile?: () => void;
onAccountSettings?: () => void;
}) => {
const triggerRef = useRef<HTMLDivElement>(null);
const isDesktop = useBreakpoint("lg");
@@ -173,7 +173,7 @@ export const NavAccountCard = ({
)
}
>
<NavAccountMenu selectedAccountId={selectedAccountId} accounts={items} onSignOut={onSignOut} onForceReady={onForceReady} />
<NavAccountMenu selectedAccountId={selectedAccountId} accounts={items} onSignOut={onSignOut} onViewProfile={onViewProfile} onAccountSettings={onAccountSettings} />
</AriaPopover>
</AriaDialogTrigger>
</div>