diff --git a/client/src/components/trans-routes/RouteCustomerEditor.js b/client/src/components/trans-routes/RouteCustomerEditor.js index bef5d4e..262dff9 100644 --- a/client/src/components/trans-routes/RouteCustomerEditor.js +++ b/client/src/components/trans-routes/RouteCustomerEditor.js @@ -328,7 +328,7 @@ const RouteCustomerEditor = ({currentRoute, setNewCustomerList = (a) => {}, view customer_avatar: customer.avatar, customer_type: customer.type, customer_pickup_status: customer.pickup_status, - customer_note: customer.note, + customer_note: customer.notes_for_driver || '', customer_special_needs: customer.notes_for_driver || '', customer_phone: customer.phone || customer.mobile_phone || customer.home_phone, customer_route_status: PERSONAL_ROUTE_STATUS.NO_STATUS, @@ -353,7 +353,7 @@ const RouteCustomerEditor = ({currentRoute, setNewCustomerList = (a) => {}, view customer_group_address: newGroupAddress, customer_type: customer.type, customer_pickup_status: customer.pickup_status, - customer_note: customer.note, + customer_note: customer.notes_for_driver || '', customer_special_needs: customer.notes_for_driver || '', customer_phone: customer.phone || customer.mobile_phone || customer.home_phone, customer_route_status: PERSONAL_ROUTE_STATUS.NO_STATUS, @@ -462,7 +462,7 @@ const RouteCustomerEditor = ({currentRoute, setNewCustomerList = (a) => {}, view customer_avatar: customerData.avatar, customer_type: customerData.type, customer_pickup_status: customerData.pickup_status, - customer_note: customerData.note, + customer_note: customerData.notes_for_driver || '', customer_special_needs: customerData.notes_for_driver || '', customer_phone: customerData.phone || customerData.mobile_phone || customerData.home_phone, customer_route_status: PERSONAL_ROUTE_STATUS.NO_STATUS, diff --git a/client/src/components/trans-routes/RoutesDashboard.js b/client/src/components/trans-routes/RoutesDashboard.js index 0382058..1c4e64b 100644 --- a/client/src/components/trans-routes/RoutesDashboard.js +++ b/client/src/components/trans-routes/RoutesDashboard.js @@ -86,9 +86,10 @@ const RoutesDashboard = () => { const [scheduleImportProgress, setScheduleImportProgress] = useState(0); const [scheduleImportLabel, setScheduleImportLabel] = useState(''); const [showCheckRoutesModal, setShowCheckRoutesModal] = useState(false); - const [checkRoutesResult, setCheckRoutesResult] = useState({ inbound: [], outbound: [], attendance: [], addressMismatch: [], customerTypeMismatch: [], customerSpecialNeedsMismatch: [], dischargedOnRoute: [] }); + const [checkRoutesResult, setCheckRoutesResult] = useState({ inbound: [], outbound: [], attendance: [], addressMismatch: [], customerTypeMismatch: [], customerSpecialNeedsMismatch: [], customerNoteMismatch: [], dischargedOnRoute: [] }); const [customerTypeFixing, setCustomerTypeFixing] = useState({}); const [customerSpecialNeedsFixing, setCustomerSpecialNeedsFixing] = useState({}); + const [customerNoteFixing, setCustomerNoteFixing] = useState({}); const scheduleImportProgressTimerRef = useRef(null); @@ -459,6 +460,40 @@ const RoutesDashboard = () => { })); }; + const buildCustomerNoteMismatchIssues = (routes = []) => { + const customerProfileById = new Map((customers || []).map((customer) => [customer.id, customer])); + const mismatchMap = new Map(); + (routes || []).forEach((route) => { + (route?.route_customer_list || []).forEach((customerInRoute) => { + const customerId = customerInRoute?.customer_id; + if (!customerId) return; + const customerProfile = customerProfileById.get(customerId); + if (!customerProfile) return; + + const routeNote = `${customerInRoute?.customer_note || ''}`.trim(); + const dbNoteToDriver = `${customerProfile?.notes_for_driver || ''}`.trim(); + if (routeNote === dbNoteToDriver) return; + + const existing = mismatchMap.get(customerId) || { + customerId, + customerName: customerInRoute?.customer_name || customerProfile?.name || 'Unknown', + dbNoteToDriver, + mismatchedRoutes: [] + }; + existing.mismatchedRoutes.push({ + routeId: route?.id, + routeName: route?.name || 'Unnamed Route', + routeNote: routeNote || '' + }); + mismatchMap.set(customerId, existing); + }); + }); + return Array.from(mismatchMap.values()).map((item) => ({ + ...item, + mismatchedRoutes: item.mismatchedRoutes.filter((route, idx, arr) => arr.findIndex((r) => r.routeId === route.routeId) === idx) + })); + }; + const syncCustomerTypeForMismatch = async (issue) => { if (!issue?.customerId || !issue?.dbType || !issue?.mismatchedRoutes?.length) return; setCustomerTypeFixing((prev) => Object.assign({}, prev, { [issue.customerId]: true })); @@ -515,12 +550,41 @@ const RoutesDashboard = () => { } }; + const syncCustomerNoteForMismatch = async (issue) => { + if (!issue?.customerId || !issue?.mismatchedRoutes?.length) return; + setCustomerNoteFixing((prev) => Object.assign({}, prev, { [issue.customerId]: true })); + try { + const routeMap = new Map([...(tmrInboundRoutes || []), ...(tmrOutboundRoutes || [])].map((route) => [route.id, route])); + const updatePromises = issue.mismatchedRoutes.map((routeMeta) => { + const route = routeMap.get(routeMeta.routeId); + if (!route) return Promise.resolve(); + const nextCustomerList = (route.route_customer_list || []).map((customer) => { + if (customer?.customer_id !== issue.customerId) return customer; + return Object.assign({}, customer, { customer_note: issue.dbNoteToDriver || '' }); + }); + return TransRoutesService.updateRoute(route.id, Object.assign({}, route, { route_customer_list: nextCustomerList })); + }); + await Promise.all(updatePromises); + setSuccessMessage(`Synced route note for ${issue.customerName}.`); + setTimeout(() => setSuccessMessage(undefined), 5000); + dispatch(fetchAllTomorrowRoutes({dateText: moment(dateSelected).format('MM/DD/YYYY')})); + await runCheckRoutes(); + } catch (error) { + console.error('Error syncing customer note mismatch:', error); + setErrorMessage(`Failed to sync route note for ${issue.customerName}.`); + setTimeout(() => setErrorMessage(undefined), 5000); + } finally { + setCustomerNoteFixing((prev) => Object.assign({}, prev, { [issue.customerId]: false })); + } + }; + const runCheckRoutes = async () => { const inboundIssues = buildRouteConflictsByDirection(tmrInboundRoutes || []); const outboundIssues = buildRouteConflictsByDirection(tmrOutboundRoutes || []); const addressMismatchIssues = buildAddressMismatchIssues([...(tmrInboundRoutes || []), ...(tmrOutboundRoutes || [])]); const customerTypeMismatchIssues = buildCustomerTypeMismatchIssues([...(tmrInboundRoutes || []), ...(tmrOutboundRoutes || [])]); const customerSpecialNeedsMismatchIssues = buildCustomerSpecialNeedsMismatchIssues([...(tmrInboundRoutes || []), ...(tmrOutboundRoutes || [])]); + const customerNoteMismatchIssues = buildCustomerNoteMismatchIssues([...(tmrInboundRoutes || []), ...(tmrOutboundRoutes || [])]); const dischargedOnRouteIssues = buildDischargedCustomerRouteIssues([...(tmrInboundRoutes || []), ...(tmrOutboundRoutes || [])]); let attendanceIssues = []; try { @@ -528,7 +592,7 @@ const RoutesDashboard = () => { } catch (error) { console.error('Error checking attendance notes against routes:', error); } - setCheckRoutesResult({ inbound: inboundIssues, outbound: outboundIssues, attendance: attendanceIssues, addressMismatch: addressMismatchIssues, customerTypeMismatch: customerTypeMismatchIssues, customerSpecialNeedsMismatch: customerSpecialNeedsMismatchIssues, dischargedOnRoute: dischargedOnRouteIssues }); + setCheckRoutesResult({ inbound: inboundIssues, outbound: outboundIssues, attendance: attendanceIssues, addressMismatch: addressMismatchIssues, customerTypeMismatch: customerTypeMismatchIssues, customerSpecialNeedsMismatch: customerSpecialNeedsMismatchIssues, customerNoteMismatch: customerNoteMismatchIssues, dischargedOnRoute: dischargedOnRouteIssues }); setShowCheckRoutesModal(true); }; @@ -2050,7 +2114,7 @@ const RoutesDashboard = () => { Check Routes Result - {(checkRoutesResult.inbound.length === 0 && checkRoutesResult.outbound.length === 0 && checkRoutesResult.attendance.length === 0 && checkRoutesResult.addressMismatch.length === 0 && checkRoutesResult.customerTypeMismatch.length === 0 && checkRoutesResult.customerSpecialNeedsMismatch.length === 0 && checkRoutesResult.dischargedOnRoute.length === 0) ? ( + {(checkRoutesResult.inbound.length === 0 && checkRoutesResult.outbound.length === 0 && checkRoutesResult.attendance.length === 0 && checkRoutesResult.addressMismatch.length === 0 && checkRoutesResult.customerTypeMismatch.length === 0 && checkRoutesResult.customerSpecialNeedsMismatch.length === 0 && checkRoutesResult.customerNoteMismatch.length === 0 && checkRoutesResult.dischargedOnRoute.length === 0) ? (
No issue found. @@ -2121,18 +2185,54 @@ const RoutesDashboard = () => {
Note to Driver Mismatch Issues
{checkRoutesResult.customerSpecialNeedsMismatch.map((issue, idx) => ( -
+
- Customer {issue.customerName}'s note to driver is mismatched on route {joinRouteNames(issue.mismatchedRoutes.map((route) => route.routeName))}. Latest note in system is {issue.dbNoteToDriver || 'empty'}. + Customer {issue.customerName}'s note to driver is mismatched on route {joinRouteNames(issue.mismatchedRoutes.map((route) => route.routeName))}. +
+
+ Latest note in system: +
+ {issue.dbNoteToDriver || 'empty'} +
+
+
+ +
+
+ ))} +
+ )} + {checkRoutesResult.customerNoteMismatch.length > 0 && ( +
+
Route Note Mismatch Issues
+ {checkRoutesResult.customerNoteMismatch.map((issue, idx) => ( +
+
+ Customer {issue.customerName}'s route note is mismatched on route {joinRouteNames(issue.mismatchedRoutes.map((route) => route.routeName))}. +
+
+ Latest note in system: +
+ {issue.dbNoteToDriver || 'empty'} +
+
+
+
-
))}