From 62bc2f058c3d4edeb117e53ab973fc5b26898c95 Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:28:52 -0400 Subject: [PATCH] Add checklist UI to dispatch workflow - Task List Template picker in dispatch modal - Checklist section in dispatch detail modal with toggleable items - Shows completion count, completed by user name + timestamp - Strikethrough styling on completed items - fetchTaskTemplates, updateChecklistItem, addChecklistItem API functions --- src/pages/workorders/api.js | 13 +++++ .../workorders/view/WorkOrderViewPage.css | 42 ++++++++++++++++ .../workorders/view/WorkOrderViewPage.js | 48 ++++++++++++++++++- 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/pages/workorders/api.js b/src/pages/workorders/api.js index 19128b68..b906bd73 100644 --- a/src/pages/workorders/api.js +++ b/src/pages/workorders/api.js @@ -121,6 +121,19 @@ export const fetchVendorsDropdown = async (trade, siteZip) => { return (await apiGet(`${API_URL}/Vendor/Dropdown${qs ? `?${qs}` : ""}`)) || []; }; +export const fetchTaskTemplates = async () => { + const { get: apiGet } = await import("../../apiUtil"); + return (await apiGet(`${API_URL}/TaskListTemplate`)) || []; +}; + +export const updateChecklistItem = async (id, isCompleted, completedBy) => { + return post(`${API_URL}/WorkOrder/UpdateChecklistItem`, { Id: id, IsCompleted: isCompleted, CompletedBy: completedBy }); +}; + +export const addChecklistItem = async (dispatchId, itemText, workOrderId) => { + return post(`${API_URL}/WorkOrder/AddChecklistItem`, { DispatchId: dispatchId, ItemText: itemText, WorkOrderId: workOrderId }); +}; + export const getDispatchById = async (id) => { const { get: apiGet } = await import("../../apiUtil"); return apiGet(`${API_URL}/WorkOrder/GetDispatch/${id}`); diff --git a/src/pages/workorders/view/WorkOrderViewPage.css b/src/pages/workorders/view/WorkOrderViewPage.css index 8337864c..23c6c31c 100644 --- a/src/pages/workorders/view/WorkOrderViewPage.css +++ b/src/pages/workorders/view/WorkOrderViewPage.css @@ -734,6 +734,48 @@ padding-top: 4px; } +.dispatchChecklist { + display: flex; + flex-direction: column; + gap: 4px; + margin-bottom: 16px; +} + +.dispatchChecklistItem { + display: flex; + align-items: center; + gap: 10px; + padding: 6px 8px; + border-radius: 4px; + font-size: 13px; +} + +.dispatchChecklistItem:hover { + background: #f8f9fa; +} + +.dispatchChecklistItem.completed .dispatchChecklistText { + text-decoration: line-through; + color: #999; +} + +.dispatchChecklistText { + flex: 1; + color: #333; +} + +.dispatchChecklistDone { + font-size: 11px; + color: #28a745; +} + +.dispatchChecklistItem input[type="checkbox"] { + width: 16px; + height: 16px; + flex-shrink: 0; + cursor: pointer; +} + .dispatchThreadContainer { display: flex; flex-direction: column; diff --git a/src/pages/workorders/view/WorkOrderViewPage.js b/src/pages/workorders/view/WorkOrderViewPage.js index 7c64146d..9b567e5d 100644 --- a/src/pages/workorders/view/WorkOrderViewPage.js +++ b/src/pages/workorders/view/WorkOrderViewPage.js @@ -2,7 +2,8 @@ import React, { useState, useEffect, useRef } from "react"; import ReactDOM from "react-dom"; import { useParams, useNavigate } from "react-router"; import { toast } from "react-toastify"; -import { getWorkOrderById, addComment, changeWorkOrderStatus, fetchUsers, changeWorkOrderAssignment, fetchVendorsDropdown, dispatchToVendor, getDispatchById, updateDispatch, addDispatchComment } from "../api"; +import { getWorkOrderById, addComment, changeWorkOrderStatus, fetchUsers, changeWorkOrderAssignment, fetchVendorsDropdown, dispatchToVendor, getDispatchById, updateDispatch, addDispatchComment, fetchTaskTemplates, updateChecklistItem, addChecklistItem } from "../api"; +import { getCurrentUser } from "../../../services/authService"; import "./WorkOrderViewPage.css"; function AssignDropdown({ value, onAssign }) { @@ -329,6 +330,38 @@ function DispatchDetailModal({ dispatchId, onClose, onUpdated }) {