import { useMemo, useState } from "react"; import { useNavigate } from "react-router"; import EditOutlinedIcon from "@mui/icons-material/EditOutlined"; import VisibilityOutlinedIcon from "@mui/icons-material/VisibilityOutlined"; import { WorkOrderStatusBadge } from "@/components/domain/status-badge"; import { Alert, Box, Button, Chip, CircularProgress, FormControl, IconButton, InputLabel, MenuItem, Paper, Select, Stack, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow, TextField, Tooltip, Typography, } from "@mui/material"; import { useDebounce } from "@/hooks/use-debounce"; import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order"; import { useWorkOrderUsers, useWorkOrdersList, } from "@/domain/work-orders/use-cases/use-work-orders-list"; const STATUS_OPTIONS = ["Open", "In Progress", "On Hold", "Done", "Cancelled"] as const; function formatDateTime(value: string): string { if (!value) { return "—"; } const normalized = value.endsWith("Z") ? value : `${value}Z`; const date = new Date(normalized); if (Number.isNaN(date.getTime())) { return value; } const datePart = date.toLocaleDateString("en-CA"); const timePart = date.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit", hour12: false, }); const tz = date.toLocaleTimeString(undefined, { timeZoneName: "short" }).split(" ").pop(); return `${datePart} ${timePart} ${tz ?? ""}`.trim(); } export default function WorkOrdersListPage() { const navigate = useNavigate(); const [search, setSearch] = useState(""); const [statusFilter, setStatusFilter] = useState(""); const [assigneeFilter, setAssigneeFilter] = useState(""); const [page, setPage] = useState(0); const [pageSize, setPageSize] = useState(12); const [sortBy, setSortBy] = useState(""); const [sortDir, setSortDir] = useState<"asc" | "desc" | "">(""); const debouncedSearch = useDebounce(search, 300); const listParams = useMemo( () => ({ search: debouncedSearch, page: page + 1, pageSize, sortBy, sortDir, status: statusFilter, assignee: assigneeFilter, }), [debouncedSearch, page, pageSize, sortBy, sortDir, statusFilter, assigneeFilter], ); const { data, isLoading, isFetching, error } = useWorkOrdersList(listParams); const { data: users = [] } = useWorkOrderUsers(); const rows = data?.items ?? []; const totalCount = data?.totalCount ?? 0; const handleSort = (column: string) => { if (sortBy === column) { setSortDir((current) => (current === "asc" ? "desc" : current === "desc" ? "" : "asc")); if (sortDir === "desc") { setSortBy(""); } return; } setSortBy(column); setSortDir("asc"); }; const sortIndicator = (column: string) => { if (sortBy !== column) { return ""; } return sortDir === "desc" ? " ↓" : " ↑"; }; const handleStatusFilter = (status: string) => { setStatusFilter((current) => (current === status ? "" : status)); setPage(0); }; return ( Work Orders {totalCount} total {isFetching && !isLoading && } { setSearch(event.target.value); setPage(0); }} placeholder="Search..." className="min-w-[220px]" /> { setStatusFilter(""); setPage(0); }} /> {STATUS_OPTIONS.map((status) => ( handleStatusFilter(status)} /> ))} Assignee {error && ( {error instanceof Error ? error.message : "Failed to load work orders"} )} handleSort("number")} > WO #{sortIndicator("number")} handleSort("title")} > Title{sortIndicator("title")} Location Priority Status Created Assigned To Last Updated Actions {isLoading ? ( ) : rows.length === 0 ? ( No work orders found ) : ( rows.map((row: WorkOrderTableRow) => ( {row.title} {row.location} {row.priority} {formatDateTime(row.scheduledOn)} {row.tech || "Unassigned"} {formatDateTime(row.dueDate)} navigate(`/workorders/${row.id}`)} > navigate(`/workorders/edit/${row.id}`)} > )) )}
setPage(nextPage)} rowsPerPage={pageSize} onRowsPerPageChange={(event) => { setPageSize(Number(event.target.value)); setPage(0); }} rowsPerPageOptions={[12, 24, 48]} />
); }