mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 08:03:13 +00:00
- Toolbar shows "X of Y" when status or assignee filter is active - Pagination bar totalCount reflects filtered row count - Extracted filter logic into filteredRows variable for reuse
144 lines
4.8 KiB
JavaScript
144 lines
4.8 KiB
JavaScript
import { useState, useEffect } from "react";
|
|
import { useNavigate } from "react-router";
|
|
import { toast } from "react-toastify";
|
|
import usePaginatedList from "../../../hooks/usePaginatedList";
|
|
import { fetchWorkOrdersPaged } from "./api";
|
|
import { fetchUsers } from "../api";
|
|
import Table from "./Table";
|
|
import DeleteModal from "../../../components/DeleteModal";
|
|
import "./styles.css";
|
|
|
|
export default function WorkOrdersList() {
|
|
const navigate = useNavigate();
|
|
const {
|
|
rows, search, setSearch, page, setPage, pageSize, setPageSize,
|
|
totalCount, loading, err, sortBy, setSortBy, sortDir, setSortDir
|
|
} = usePaginatedList(fetchWorkOrdersPaged);
|
|
|
|
const [deleteModal, setDeleteModal] = useState({
|
|
isOpen: false,
|
|
item: null,
|
|
loading: false
|
|
});
|
|
|
|
const totalPages = Math.max(1, Math.ceil(totalCount / pageSize));
|
|
|
|
const handleDeleteClick = (item) => {
|
|
setDeleteModal({ isOpen: true, item, loading: false });
|
|
};
|
|
|
|
const handleDeleteConfirm = async () => {
|
|
setDeleteModal((prev) => ({ ...prev, loading: true }));
|
|
try {
|
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
toast.success("Work Order deleted successfully!");
|
|
setDeleteModal({ isOpen: false, item: null, loading: false });
|
|
} catch {
|
|
toast.error("Failed to delete work order");
|
|
setDeleteModal((prev) => ({ ...prev, loading: false }));
|
|
}
|
|
};
|
|
|
|
const [statusFilter, setStatusFilter] = useState("");
|
|
const [assigneeFilter, setAssigneeFilter] = useState("");
|
|
const [users, setUsers] = useState([]);
|
|
const statuses = ["Open", "In Progress", "On Hold", "Done", "Cancelled"];
|
|
|
|
useEffect(() => {
|
|
fetchUsers().then(setUsers).catch(() => {});
|
|
}, []);
|
|
|
|
const filteredRows = rows.filter((r) => {
|
|
if (statusFilter && r.status !== statusFilter) return false;
|
|
if (assigneeFilter === "__unassigned" && r.assignedTo) return false;
|
|
if (assigneeFilter && assigneeFilter !== "__unassigned" && r.assignedTo !== assigneeFilter) return false;
|
|
return true;
|
|
});
|
|
|
|
const hasFilter = statusFilter || assigneeFilter;
|
|
|
|
return (
|
|
<>
|
|
<section className="listPage">
|
|
<div className="woListToolbar">
|
|
<div className="woListToolbarLeft">
|
|
<h2 className="woListTitle">Work Orders</h2>
|
|
<span className="woListCount">
|
|
{hasFilter ? `${filteredRows.length} of ${totalCount}` : `${totalCount} total`}
|
|
</span>
|
|
</div>
|
|
<div className="woListToolbarRight">
|
|
<input
|
|
className="woSearchInput"
|
|
value={search}
|
|
onChange={(e) => { setSearch(e.target.value); setPage(1); }}
|
|
placeholder="Search..."
|
|
/>
|
|
<button className="woNewBtn" onClick={() => navigate("/workorders/new")}>
|
|
+ New Work Order
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="woFilterBar">
|
|
<button
|
|
className={`woFilterChip ${statusFilter === "" ? "active" : ""}`}
|
|
onClick={() => setStatusFilter("")}
|
|
>
|
|
All
|
|
</button>
|
|
{statuses.map((s) => (
|
|
<button
|
|
key={s}
|
|
className={`woFilterChip ${statusFilter === s ? "active" : ""}`}
|
|
onClick={() => setStatusFilter(statusFilter === s ? "" : s)}
|
|
>
|
|
{s}
|
|
</button>
|
|
))}
|
|
<span className="woFilterDivider" />
|
|
<select
|
|
className="woFilterSelect"
|
|
value={assigneeFilter}
|
|
onChange={(e) => setAssigneeFilter(e.target.value)}
|
|
>
|
|
<option value="">All Assignees</option>
|
|
<option value="__unassigned">Unassigned</option>
|
|
{users.map((u) => (
|
|
<option key={u.id} value={u.name}>{u.name}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
|
|
<Table
|
|
loading={loading}
|
|
error={err}
|
|
rows={filteredRows}
|
|
onEdit={(item) => navigate(`/workorders/${item.id}`)}
|
|
onDelete={handleDeleteClick}
|
|
page={page}
|
|
setPage={setPage}
|
|
pageSize={pageSize}
|
|
setPageSize={setPageSize}
|
|
totalCount={hasFilter ? filteredRows.length : totalCount}
|
|
totalPages={totalPages}
|
|
sortBy={sortBy}
|
|
setSortBy={setSortBy}
|
|
sortDir={sortDir}
|
|
setSortDir={setSortDir}
|
|
/>
|
|
|
|
<DeleteModal
|
|
isOpen={deleteModal.isOpen}
|
|
onClose={() =>
|
|
setDeleteModal({ isOpen: false, item: null, loading: false })
|
|
}
|
|
onConfirm={handleDeleteConfirm}
|
|
title="Delete Work Order"
|
|
message={`Are you sure you want to delete "${deleteModal.item?.title}"? This action cannot be undone.`}
|
|
loading={deleteModal.loading}
|
|
/>
|
|
</section>
|
|
</>
|
|
);
|
|
}
|