mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-03 01:03:21 +00:00
Keep SH-116 CompDocDialog wiring and completedDate board contract. Drop slide-over ownership (SH-112) so it stays in PR #32.
176 lines
7.2 KiB
TypeScript
176 lines
7.2 KiB
TypeScript
import { useMemo, useState } from "react";
|
|
import { Box } from "@mui/material";
|
|
import { useNavigate } from "react-router";
|
|
import { PageHeader } from "@/components/ui/page-header";
|
|
import { CompDocDialog } from "@/app/(protected)/workorders/_components/comp-doc/comp-doc-dialog";
|
|
import { MediaUploadModal } from "@/app/(protected)/workorders/_components/media/media-upload-modal";
|
|
import { WorkOrdersAdvancedSearchSheet } from "@/app/(protected)/workorders/_components/list/advanced-search/work-orders-advanced-search-sheet";
|
|
import { WorkOrdersAdvancedFiltersBanner } from "@/app/(protected)/workorders/_components/list/work-orders-advanced-filters-banner";
|
|
import { WorkOrdersFilterBar } from "@/app/(protected)/workorders/_components/list/filter-bar/work-orders-filter-bar";
|
|
import { WorkOrdersListHeader } from "@/app/(protected)/workorders/_components/list/work-orders-list-header";
|
|
import { WoTable } from "@/app/(protected)/workorders/_components/list/table/wo-table";
|
|
import { NewWoWizard } from "@/app/(protected)/workorders/_components/wizard/new-wo-wizard";
|
|
import { useWorkOrdersListFilters } from "@/app/(protected)/workorders/_hooks/use-work-orders-list-filters";
|
|
import { useWorkOrdersTableData } from "@/app/(protected)/workorders/_hooks/use-work-orders-table-data";
|
|
import { useDropdownOptionsByCategory } from "@/domain/settings/dropdown-options/use-cases/use-dropdown-options-by-category";
|
|
import {
|
|
useWorkOrderLocations,
|
|
useWorkOrderVendors,
|
|
} from "@/domain/work-orders/use-cases/use-work-order-detail";
|
|
import { useWorkOrderUsers } from "@/domain/work-orders/use-cases/use-work-orders-list";
|
|
import { isWoTableMockEnabled } from "@/domain/work-orders/mocks/is-wo-table-mock-enabled";
|
|
import { getMockPmTypes } from "@/domain/work-orders/mocks/wo-table-mock-data";
|
|
import type { CompDocData } from "@/domain/work-orders/types/completion-doc";
|
|
import { EMPTY_MEDIA, type MediaFile } from "@/domain/work-orders/types/work-order-media";
|
|
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
|
|
import { useWorkOrderTableMutations } from "@/domain/work-orders/use-cases/use-work-order-table-mutations";
|
|
import { useAuthContext } from "@/providers/auth-context";
|
|
|
|
export default function WorkOrdersListPage() {
|
|
const navigate = useNavigate();
|
|
const { user } = useAuthContext();
|
|
const [wizardOpen, setWizardOpen] = useState(false);
|
|
const [docRow, setDocRow] = useState<WorkOrderTableRow | null>(null);
|
|
const [mediaRow, setMediaRow] = useState<WorkOrderTableRow | null>(null);
|
|
const [completionDocs, setCompletionDocs] = useState<Record<string, CompDocData>>({});
|
|
const [mediaFiles, setMediaFiles] = useState<Record<string, MediaFile[]>>({});
|
|
const filters = useWorkOrdersListFilters(user?.id);
|
|
const tableData = useWorkOrdersTableData(filters);
|
|
const { patchField } = useWorkOrderTableMutations(tableData.patchRow);
|
|
|
|
const { data: users = [] } = useWorkOrderUsers();
|
|
const { data: locations = [] } = useWorkOrderLocations();
|
|
const { data: vendors = [] } = useWorkOrderVendors();
|
|
const { data: problemOptions = [] } = useDropdownOptionsByCategory("Problem");
|
|
|
|
const pmTypes = useMemo(
|
|
() =>
|
|
isWoTableMockEnabled()
|
|
? getMockPmTypes()
|
|
: problemOptions.map((option) => option.value).filter(Boolean),
|
|
[problemOptions],
|
|
);
|
|
|
|
const vendorTechs = useMemo(
|
|
() => [...new Set(vendors.map((vendor) => vendor.companyName).filter(Boolean))],
|
|
[vendors],
|
|
);
|
|
|
|
const totalCount = tableData.totalCount;
|
|
const scopeTotalCount = tableData.scopeTotalCount;
|
|
|
|
const activeDocRow = useMemo(() => {
|
|
if (!docRow) return null;
|
|
return tableData.rows.find((row) => row.id === docRow.id) ?? docRow;
|
|
}, [docRow, tableData.rows]);
|
|
|
|
const activeMediaRow = useMemo(() => {
|
|
if (!mediaRow) return null;
|
|
return tableData.rows.find((row) => row.id === mediaRow.id) ?? mediaRow;
|
|
}, [mediaRow, tableData.rows]);
|
|
|
|
return (
|
|
<Box className="flex h-full flex-col overflow-hidden p-2.5">
|
|
<PageHeader
|
|
surface
|
|
eyebrow="OPERATIONS"
|
|
title="Work Orders"
|
|
actions={
|
|
<WorkOrdersListHeader
|
|
search={filters.search}
|
|
onSearchChange={filters.handleSearchChange}
|
|
onOpenAdvancedFilters={() => filters.setAdvOpen(true)}
|
|
onNewWorkOrder={() => setWizardOpen(true)}
|
|
activeFilterCount={filters.activeFilterCount}
|
|
isFetching={tableData.isFetching && !tableData.isLoading}
|
|
/>
|
|
}
|
|
/>
|
|
|
|
<WorkOrdersFilterBar
|
|
weekMonday={filters.weekMonday}
|
|
onWeekChange={filters.setWeekMonday}
|
|
dispatcherIds={filters.dispatcherIds}
|
|
onDispatcherChange={filters.setDispatcherIds}
|
|
typeFilter={filters.typeFilter}
|
|
onTypeChange={filters.setTypeFilter}
|
|
users={users}
|
|
currentUserId={user?.id}
|
|
filteredCount={totalCount}
|
|
scopeTotalCount={scopeTotalCount}
|
|
/>
|
|
|
|
{filters.advApplied != null && (
|
|
<WorkOrdersAdvancedFiltersBanner
|
|
applied={filters.advApplied}
|
|
totalCount={totalCount}
|
|
sites={locations}
|
|
users={users}
|
|
onClearChip={filters.clearAdvancedFilterChip}
|
|
onClearAll={filters.clearAdvancedFilters}
|
|
/>
|
|
)}
|
|
|
|
<WoTable
|
|
tableData={tableData}
|
|
users={users}
|
|
sites={locations}
|
|
vendors={vendors}
|
|
pmTypes={pmTypes}
|
|
onOpenSlideOver={(row, edit) => {
|
|
tableData.setSelectedId(row.id);
|
|
navigate(edit ? `/workorders/edit/${row.id}` : `/workorders/${row.id}`);
|
|
}}
|
|
onOpenCompDoc={setDocRow}
|
|
onOpenMedia={setMediaRow}
|
|
onClearSearch={() => filters.handleSearchChange("")}
|
|
onOpenAdvancedFilters={() => filters.setAdvOpen(true)}
|
|
/>
|
|
|
|
<WorkOrdersAdvancedSearchSheet
|
|
open={filters.advOpen}
|
|
onOpenChange={filters.setAdvOpen}
|
|
initial={filters.advInitial}
|
|
onApply={filters.applyAdvancedFilters}
|
|
onClearAll={filters.clearAdvancedFilters}
|
|
sites={locations}
|
|
users={users}
|
|
pmTypes={pmTypes}
|
|
vendorTechs={vendorTechs}
|
|
/>
|
|
|
|
<NewWoWizard open={wizardOpen} onOpenChange={setWizardOpen} users={users} />
|
|
|
|
{activeDocRow != null && (
|
|
<CompDocDialog
|
|
row={activeDocRow}
|
|
open={!!activeDocRow}
|
|
onOpenChange={(open) => {
|
|
if (!open) setDocRow(null);
|
|
}}
|
|
data={completionDocs[String(activeDocRow.id)]}
|
|
onSave={(data, status) => {
|
|
setCompletionDocs((prev) => ({ ...prev, [String(activeDocRow.id)]: data }));
|
|
patchField(activeDocRow.id, { docStatus: status });
|
|
}}
|
|
onDateCompletedChange={(date) => patchField(activeDocRow.id, { completedDate: date })}
|
|
/>
|
|
)}
|
|
|
|
{activeMediaRow != null && (
|
|
<MediaUploadModal
|
|
row={activeMediaRow}
|
|
open={!!activeMediaRow}
|
|
onOpenChange={(open) => {
|
|
if (!open) setMediaRow(null);
|
|
}}
|
|
uploads={mediaFiles[String(activeMediaRow.id)] ?? EMPTY_MEDIA}
|
|
onChange={(files) => {
|
|
setMediaFiles((prev) => ({ ...prev, [String(activeMediaRow.id)]: files }));
|
|
patchField(activeMediaRow.id, { mediaCount: files.length });
|
|
}}
|
|
/>
|
|
)}
|
|
</Box>
|
|
);
|
|
}
|