fix
All checks were successful
Build And Deploy Main / build-and-deploy (push) Successful in 33s

This commit is contained in:
2026-03-10 16:47:22 -04:00
parent 137b137312
commit 1d0fb112f6
2 changed files with 116 additions and 16 deletions

View File

@@ -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,

View File

@@ -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 = () => {
<Modal.Title>Check Routes Result</Modal.Title>
</Modal.Header>
<Modal.Body>
{(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) ? (
<div className="text-success d-flex align-items-center">
<Check size={18} className="me-2"></Check>
<span>No issue found.</span>
@@ -2121,18 +2185,54 @@ const RoutesDashboard = () => {
<div className="mt-3">
<div className="fw-bold mb-2">Note to Driver Mismatch Issues</div>
{checkRoutesResult.customerSpecialNeedsMismatch.map((issue, idx) => (
<div key={`customer-special-needs-mismatch-issue-${idx}`} className="mb-2 d-flex align-items-center justify-content-between" style={{ gap: '12px' }}>
<div key={`customer-special-needs-mismatch-issue-${idx}`} className="mb-2" style={{ whiteSpace: 'normal', overflowWrap: 'anywhere' }}>
<div>
Customer {issue.customerName}&apos;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}&apos;s note to driver is mismatched on route {joinRouteNames(issue.mismatchedRoutes.map((route) => route.routeName))}.
</div>
<div className="mt-1">
Latest note in system:
<div style={{ whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' }}>
{issue.dbNoteToDriver || 'empty'}
</div>
</div>
<div className="mt-2">
<Button
variant="outline-primary"
size="sm"
disabled={!!customerSpecialNeedsFixing[issue.customerId]}
onClick={() => syncCustomerSpecialNeedsForMismatch(issue)}
>
{customerSpecialNeedsFixing[issue.customerId] ? 'Fixing...' : 'Fix'}
</Button>
</div>
</div>
))}
</div>
)}
{checkRoutesResult.customerNoteMismatch.length > 0 && (
<div className="mt-3">
<div className="fw-bold mb-2">Route Note Mismatch Issues</div>
{checkRoutesResult.customerNoteMismatch.map((issue, idx) => (
<div key={`customer-note-mismatch-issue-${idx}`} className="mb-2" style={{ whiteSpace: 'normal', overflowWrap: 'anywhere' }}>
<div>
Customer {issue.customerName}&apos;s route note is mismatched on route {joinRouteNames(issue.mismatchedRoutes.map((route) => route.routeName))}.
</div>
<div className="mt-1">
Latest note in system:
<div style={{ whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' }}>
{issue.dbNoteToDriver || 'empty'}
</div>
</div>
<div className="mt-2">
<Button
variant="outline-primary"
size="sm"
disabled={!!customerNoteFixing[issue.customerId]}
onClick={() => syncCustomerNoteForMismatch(issue)}
>
{customerNoteFixing[issue.customerId] ? 'Fixing...' : 'Fix'}
</Button>
</div>
<Button
variant="outline-primary"
size="sm"
disabled={!!customerSpecialNeedsFixing[issue.customerId]}
onClick={() => syncCustomerSpecialNeedsForMismatch(issue)}
>
{customerSpecialNeedsFixing[issue.customerId] ? 'Fixing...' : 'Fix'}
</Button>
</div>
))}
</div>