From 31479029e3a87421608f30c02b6121bf3e10551e Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:41:51 -0400 Subject: [PATCH] Add time tracking to dispatch workflow - timeSince utility: relative time display (2h ago, 3d ago) - timeBetween utility: duration between two timestamps - waitTimeColor utility: green (<4h), yellow (4-24h), red (>24h) - Dispatch detail modal shows accepted time with duration - Awaiting acceptance shows elapsed time with color coding - Dispatches table shows Wait column with color-coded time for Sent dispatches --- .../workorders/view/WorkOrderViewPage.css | 10 ++++- .../workorders/view/WorkOrderViewPage.js | 8 ++-- src/utils/timeSince.js | 38 +++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 src/utils/timeSince.js diff --git a/src/pages/workorders/view/WorkOrderViewPage.css b/src/pages/workorders/view/WorkOrderViewPage.css index 9671f2f3..49afdccf 100644 --- a/src/pages/workorders/view/WorkOrderViewPage.css +++ b/src/pages/workorders/view/WorkOrderViewPage.css @@ -735,11 +735,19 @@ } .dispatchWaiting { - color: #ffc107; font-weight: 500; font-size: 13px; } +.dispatchWait-green { color: #28a745; } +.dispatchWait-yellow { color: #ffc107; } +.dispatchWait-red { color: #dc3545; } + +.dispatchWaitDot { + font-size: 12px; + font-weight: 600; +} + .dispatchChecklist { display: flex; flex-direction: column; diff --git a/src/pages/workorders/view/WorkOrderViewPage.js b/src/pages/workorders/view/WorkOrderViewPage.js index 3eede848..e3da056e 100644 --- a/src/pages/workorders/view/WorkOrderViewPage.js +++ b/src/pages/workorders/view/WorkOrderViewPage.js @@ -4,6 +4,7 @@ import { useParams, useNavigate } from "react-router"; import { toast } from "react-toastify"; import { getWorkOrderById, addComment, changeWorkOrderStatus, fetchUsers, changeWorkOrderAssignment, fetchVendorsDropdown, dispatchToVendor, getDispatchById, updateDispatch, addDispatchComment, fetchTaskTemplates, updateChecklistItem, addChecklistItem } from "../api"; import { getCurrentUser } from "../../../services/authService"; +import { timeSince, timeBetween, waitTimeColor } from "../../../utils/timeSince"; import "./WorkOrderViewPage.css"; function AssignDropdown({ value, onAssign }) { @@ -314,9 +315,9 @@ function DispatchDetailModal({ dispatchId, onClose, onUpdated }) {
| Dispatch # | Vendor | NTE | Status | Date | |
|---|---|---|---|---|---|
| Dispatch # | Vendor | NTE | Status | Date | Wait | {d.nteAmount != null ? `$${parseFloat(d.nteAmount).toFixed(2)}` : "—"} | {d.status} | {d.dispatchedAt ? formatDateTime(d.dispatchedAt) : "—"} | +{d.status === "Sent" ? {timeSince(d.dispatchedAt)} : "—"} | ))} diff --git a/src/utils/timeSince.js b/src/utils/timeSince.js new file mode 100644 index 00000000..72e5d2ce --- /dev/null +++ b/src/utils/timeSince.js @@ -0,0 +1,38 @@ +export function timeSince(dateString) { + if (!dateString) return ""; + const d = new Date(dateString.endsWith("Z") ? dateString : dateString + "Z"); + if (isNaN(d)) return ""; + const now = new Date(); + const diffMs = now - d; + const mins = Math.floor(diffMs / 60000); + if (mins < 1) return "just now"; + if (mins < 60) return `${mins}m ago`; + const hours = Math.floor(mins / 60); + if (hours < 24) return `${hours}h ago`; + const days = Math.floor(hours / 24); + if (days < 7) return `${days}d ago`; + return `${Math.floor(days / 7)}w ago`; +} + +export function timeBetween(startStr, endStr) { + if (!startStr || !endStr) return ""; + const start = new Date(startStr.endsWith("Z") ? startStr : startStr + "Z"); + const end = new Date(endStr.endsWith("Z") ? endStr : endStr + "Z"); + if (isNaN(start) || isNaN(end)) return ""; + const diffMs = end - start; + const mins = Math.floor(diffMs / 60000); + if (mins < 60) return `${mins}m`; + const hours = Math.floor(mins / 60); + if (hours < 24) return `${hours}h`; + const days = Math.floor(hours / 24); + return `${days}d`; +} + +export function waitTimeColor(dateString) { + if (!dateString) return ""; + const d = new Date(dateString.endsWith("Z") ? dateString : dateString + "Z"); + const hours = (new Date() - d) / 3600000; + if (hours < 4) return "green"; + if (hours < 24) return "yellow"; + return "red"; +}