shoc-frontend-new/src/app/(protected)/dashboard/_components/dashboard-scope-picker.tsx

119 lines
3.6 KiB
TypeScript
Raw Normal View History

import { useMemo } from "react";
import { Popover, Skeleton } from "@mui/material";
import { ChevronDown, Users } from "lucide-react";
import type { WorkOrderUser } from "@/domain/work-orders/types/work-order";
import { CheckboxMenuItem } from "@/components/ui/checkbox-menu-item";
import { MenuAnchorButton } from "@/components/ui/menu-anchor-button";
import { useMenuAnchor } from "@/hooks/use-menu-anchor";
import type { DashboardScope } from "./dashboard-scope";
type DashboardScopePickerProps = {
scope: DashboardScope;
onChange: (scope: DashboardScope) => void;
users: WorkOrderUser[];
usersLoading?: boolean;
currentUserId?: string | number;
};
export function DashboardScopePicker({
scope,
onChange,
users,
usersLoading = false,
currentUserId,
}: DashboardScopePickerProps) {
const { anchorEl, open, setAnchor, close } = useMenuAnchor();
const meId = currentUserId != null && currentUserId !== "" ? String(currentUserId) : null;
const dispatchers = useMemo(
() => [...users].sort((a, b) => a.name.localeCompare(b.name)),
[users],
);
const label = useMemo(() => {
if (scope.mode === "all") return "All dispatchers";
if (scope.mode === "mine") return "My WOs";
return dispatchers.find((user) => String(user.id) === scope.id)?.name ?? "Dispatcher";
}, [scope, dispatchers]);
const select = (next: DashboardScope) => {
onChange(next);
close();
};
if (usersLoading && users.length === 0) {
return (
<Skeleton
variant="rounded"
width={140}
height={18}
animation="wave"
aria-label="Loading dispatchers"
/>
);
}
return (
<>
<MenuAnchorButton
onAnchor={setAnchor}
open={open}
className="flex w-auto shrink-0 items-center gap-1.5 whitespace-nowrap transition-colors"
style={{ fontSize: 13, fontWeight: 500, color: "var(--muted-foreground)" }}
aria-haspopup="listbox"
>
<Users size={13} aria-hidden style={{ color: "var(--muted-foreground)" }} />
{label}
<ChevronDown size={13} aria-hidden style={{ color: "var(--muted-foreground)" }} />
</MenuAnchorButton>
<Popover
open={open}
anchorEl={anchorEl}
onClose={close}
anchorOrigin={{ vertical: "bottom", horizontal: "left" }}
transformOrigin={{ vertical: "top", horizontal: "left" }}
slotProps={{
paper: {
className: "mt-1 w-[220px] rounded-lg border border-border p-1.5 shadow-md",
},
}}
>
<CheckboxMenuItem
checked={scope.mode === "all"}
label="All dispatchers"
onClick={() => select({ mode: "all" })}
/>
{meId != null && (
<CheckboxMenuItem
checked={scope.mode === "mine"}
label="My WOs only"
labelClassName="font-medium text-primary"
className="mb-1 pb-2"
style={{ borderBottom: "1px solid var(--color-border)" }}
onClick={() => select({ mode: "mine" })}
/>
)}
{dispatchers.map((user) => {
const id = String(user.id);
return (
<CheckboxMenuItem
key={id}
checked={scope.mode === "individual" && scope.id === id}
label={user.name}
right={
meId === id ? (
<span className="text-[10px] text-muted-foreground">me</span>
) : undefined
}
onClick={() => select({ mode: "individual", id })}
/>
);
})}
</Popover>
</>
);
}