mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 10:23:27 +00:00
- 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>
200 lines
8.8 KiB
TypeScript
200 lines
8.8 KiB
TypeScript
import type { FC } from "react";
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
import { faArrowLeft, faArrowRight } from "@fortawesome/pro-duotone-svg-icons";
|
|
import { Button } from "@/components/base/buttons/button";
|
|
|
|
const ArrowLeft: FC<{ className?: string }> = ({ className }) => <FontAwesomeIcon icon={faArrowLeft} className={className} />;
|
|
const ArrowRight: FC<{ className?: string }> = ({ className }) => <FontAwesomeIcon icon={faArrowRight} className={className} />;
|
|
import { useBreakpoint } from "@/hooks/use-breakpoint";
|
|
import { cx } from "@/utils/cx";
|
|
import type { PaginationRootProps } from "./pagination-base";
|
|
import { Pagination } from "./pagination-base";
|
|
|
|
interface PaginationProps extends Partial<Omit<PaginationRootProps, "children">> {
|
|
/** Whether the pagination buttons are rounded. */
|
|
rounded?: boolean;
|
|
}
|
|
|
|
const PaginationItem = ({ value, rounded, isCurrent }: { value: number; rounded?: boolean; isCurrent: boolean }) => {
|
|
return (
|
|
<Pagination.Item
|
|
value={value}
|
|
isCurrent={isCurrent}
|
|
className={({ isSelected }) =>
|
|
cx(
|
|
"flex size-9 cursor-pointer items-center justify-center p-3 text-sm font-medium text-quaternary outline-focus-ring transition duration-100 ease-linear hover:bg-primary_hover hover:text-secondary focus-visible:z-10 focus-visible:bg-primary_hover focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
rounded ? "rounded-full" : "rounded-lg",
|
|
isSelected && "bg-primary_hover text-secondary",
|
|
)
|
|
}
|
|
>
|
|
{value}
|
|
</Pagination.Item>
|
|
);
|
|
};
|
|
|
|
export const PaginationPageDefault = ({ rounded, page = 1, total = 10, className, ...props }: PaginationProps) => {
|
|
const isDesktop = useBreakpoint("md");
|
|
|
|
return (
|
|
<Pagination.Root
|
|
{...props}
|
|
page={page}
|
|
total={total}
|
|
className={cx("flex w-full items-center justify-between gap-3 border-t border-secondary pt-4 md:pt-5", className)}
|
|
>
|
|
<div className="hidden flex-1 justify-start md:flex">
|
|
<Pagination.PrevTrigger asChild>
|
|
<Button iconLeading={ArrowLeft} color="link-gray" size="sm">
|
|
{isDesktop ? "Previous" : undefined}
|
|
</Button>
|
|
</Pagination.PrevTrigger>
|
|
</div>
|
|
|
|
<Pagination.PrevTrigger asChild className="md:hidden">
|
|
<Button iconLeading={ArrowLeft} color="secondary" size="sm">
|
|
{isDesktop ? "Previous" : undefined}
|
|
</Button>
|
|
</Pagination.PrevTrigger>
|
|
|
|
<Pagination.Context>
|
|
{({ pages, currentPage, total }) => (
|
|
<>
|
|
<div className="hidden justify-center gap-0.5 md:flex">
|
|
{pages.map((page, index) =>
|
|
page.type === "page" ? (
|
|
<PaginationItem key={index} rounded={rounded} {...page} />
|
|
) : (
|
|
<Pagination.Ellipsis key={index} className="flex size-9 shrink-0 items-center justify-center text-tertiary">
|
|
…
|
|
</Pagination.Ellipsis>
|
|
),
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex justify-center text-sm whitespace-pre text-fg-secondary md:hidden">
|
|
Page <span className="font-medium">{currentPage}</span> of <span className="font-medium">{total}</span>
|
|
</div>
|
|
</>
|
|
)}
|
|
</Pagination.Context>
|
|
|
|
<div className="hidden flex-1 justify-end md:flex">
|
|
<Pagination.NextTrigger asChild>
|
|
<Button iconTrailing={ArrowRight} color="link-gray" size="sm">
|
|
{isDesktop ? "Next" : undefined}
|
|
</Button>
|
|
</Pagination.NextTrigger>
|
|
</div>
|
|
<Pagination.NextTrigger asChild className="md:hidden">
|
|
<Button iconTrailing={ArrowRight} color="secondary" size="sm">
|
|
{isDesktop ? "Next" : undefined}
|
|
</Button>
|
|
</Pagination.NextTrigger>
|
|
</Pagination.Root>
|
|
);
|
|
};
|
|
|
|
export const PaginationPageMinimalCenter = ({ rounded, page = 1, total = 10, className, ...props }: PaginationProps) => {
|
|
const isDesktop = useBreakpoint("md");
|
|
|
|
return (
|
|
<Pagination.Root
|
|
{...props}
|
|
page={page}
|
|
total={total}
|
|
className={cx("flex w-full items-center justify-between gap-3 border-t border-secondary pt-4 md:pt-5", className)}
|
|
>
|
|
<div className="flex flex-1 justify-start">
|
|
<Pagination.PrevTrigger asChild>
|
|
<Button iconLeading={ArrowLeft} color="secondary" size="sm">
|
|
{isDesktop ? "Previous" : undefined}
|
|
</Button>
|
|
</Pagination.PrevTrigger>
|
|
</div>
|
|
|
|
<Pagination.Context>
|
|
{({ pages, currentPage, total }) => (
|
|
<>
|
|
<div className="hidden justify-center gap-0.5 md:flex">
|
|
{pages.map((page, index) =>
|
|
page.type === "page" ? (
|
|
<PaginationItem key={index} rounded={rounded} {...page} />
|
|
) : (
|
|
<Pagination.Ellipsis key={index} className="flex size-9 shrink-0 items-center justify-center text-tertiary">
|
|
…
|
|
</Pagination.Ellipsis>
|
|
),
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex justify-center text-sm whitespace-pre text-fg-secondary md:hidden">
|
|
Page <span className="font-medium">{currentPage}</span> of <span className="font-medium">{total}</span>
|
|
</div>
|
|
</>
|
|
)}
|
|
</Pagination.Context>
|
|
|
|
<div className="flex flex-1 justify-end">
|
|
<Pagination.NextTrigger asChild>
|
|
<Button iconTrailing={ArrowRight} color="secondary" size="sm">
|
|
{isDesktop ? "Next" : undefined}
|
|
</Button>
|
|
</Pagination.NextTrigger>
|
|
</div>
|
|
</Pagination.Root>
|
|
);
|
|
};
|
|
|
|
export const PaginationCardDefault = ({ rounded, page = 1, total = 10, ...props }: PaginationProps) => {
|
|
const isDesktop = useBreakpoint("md");
|
|
|
|
return (
|
|
<Pagination.Root
|
|
{...props}
|
|
page={page}
|
|
total={total}
|
|
className="flex w-full items-center justify-between gap-3 border-t border-secondary px-4 py-3 md:px-6 md:pt-3 md:pb-4"
|
|
>
|
|
<div className="flex flex-1 justify-start">
|
|
<Pagination.PrevTrigger asChild>
|
|
<Button iconLeading={ArrowLeft} color="secondary" size="sm">
|
|
{isDesktop ? "Previous" : undefined}
|
|
</Button>
|
|
</Pagination.PrevTrigger>
|
|
</div>
|
|
|
|
<Pagination.Context>
|
|
{({ pages, currentPage, total }) => (
|
|
<>
|
|
<div className="hidden justify-center gap-0.5 md:flex">
|
|
{pages.map((page, index) =>
|
|
page.type === "page" ? (
|
|
<PaginationItem key={index} rounded={rounded} {...page} />
|
|
) : (
|
|
<Pagination.Ellipsis key={index} className="flex size-9 shrink-0 items-center justify-center text-tertiary">
|
|
…
|
|
</Pagination.Ellipsis>
|
|
),
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex justify-center text-sm whitespace-pre text-fg-secondary md:hidden">
|
|
Page <span className="font-medium">{currentPage}</span> of <span className="font-medium">{total}</span>
|
|
</div>
|
|
</>
|
|
)}
|
|
</Pagination.Context>
|
|
|
|
<div className="flex flex-1 justify-end">
|
|
<Pagination.NextTrigger asChild>
|
|
<Button iconTrailing={ArrowRight} color="secondary" size="sm">
|
|
{isDesktop ? "Next" : undefined}
|
|
</Button>
|
|
</Pagination.NextTrigger>
|
|
</div>
|
|
</Pagination.Root>
|
|
);
|
|
};
|
|
|