diff --git a/client/src/components/trans-routes/RouteEdit.js b/client/src/components/trans-routes/RouteEdit.js index eca1975..00dac77 100644 --- a/client/src/components/trans-routes/RouteEdit.js +++ b/client/src/components/trans-routes/RouteEdit.js @@ -120,6 +120,37 @@ const RouteEdit = () => { return true; }; + const normalizeAddressText = (value) => { + return (value || '') + .toString() + .toLowerCase() + .replace(/\([^)]*\)/g, ' ') + .replace(/[^a-z0-9]/g, ' ') + .replace(/\s+/g, ' ') + .trim(); + }; + + const formatStructuredAddress = (line1, line2, city, state, zipCode, note) => { + const cityState = [city, state].filter(Boolean).join(', '); + const mainAddress = [line1, line2, cityState, zipCode] + .filter((item) => item && String(item).trim() !== '') + .join(' ') + .trim(); + const addressNote = (note || '').trim(); + if (!mainAddress) return ''; + return addressNote ? `${mainAddress} (${addressNote})` : mainAddress; + }; + + const getStructuredAddresses = (customerProfile) => { + if (!customerProfile) return []; + return [ + formatStructuredAddress(customerProfile.address_line_1, customerProfile.address_line_2, customerProfile.city, customerProfile.state, customerProfile.zip_code, customerProfile.address_note), + formatStructuredAddress(customerProfile.address2_line_1, customerProfile.address2_line_2, customerProfile.city2, customerProfile.state2, customerProfile.zip_code2, customerProfile.address2_note), + formatStructuredAddress(customerProfile.address3_line_1, customerProfile.address3_line_2, customerProfile.city3, customerProfile.state3, customerProfile.zip_code3, customerProfile.address3_note), + formatStructuredAddress(customerProfile.address4_line_1, customerProfile.address4_line_2, customerProfile.city4, customerProfile.state4, customerProfile.zip_code4, customerProfile.address4_note) + ].filter((addr) => (addr || '').trim() !== ''); + }; + const updateCurrentRoute = () => { try { if (!validateRoute()) { @@ -129,7 +160,29 @@ const RouteEdit = () => { const filteredCustomerList = (newCustomerList || []).filter( (customer) => customer?.customer_route_status !== PERSONAL_ROUTE_STATUS.SCHEDULED_ABSENT ); - let data = Object.assign({}, currentRoute, {name: routeName, driver: newDriver, vehicle: newVehicle, type: newRouteType, route_customer_list: filteredCustomerList}); + const existingRouteCustomers = currentRoute?.route_customer_list || []; + const existingByCustomerId = new Map(existingRouteCustomers.map((c) => [c?.customer_id, c])); + const customerProfileById = new Map((allCustomers || []).map((c) => [c?.id, c])); + const stabilizedCustomerList = filteredCustomerList.map((customerItem) => { + const existingCustomer = existingByCustomerId.get(customerItem?.customer_id); + if (!existingCustomer?.customer_address) return customerItem; + + const customerProfile = customerProfileById.get(customerItem?.customer_id); + const structuredAddresses = getStructuredAddresses(customerProfile); + if (structuredAddresses.length === 0) return customerItem; + + const structuredAddressSet = new Set(structuredAddresses.map(normalizeAddressText).filter(Boolean)); + const existingAddressNormalized = normalizeAddressText(existingCustomer.customer_address); + if (!existingAddressNormalized) return customerItem; + + // Keep the route's current address if it no longer exists in DB structured addresses. + if (!structuredAddressSet.has(existingAddressNormalized)) { + return Object.assign({}, customerItem, { customer_address: existingCustomer.customer_address }); + } + return customerItem; + }); + + let data = Object.assign({}, currentRoute, {name: routeName, driver: newDriver, vehicle: newVehicle, type: newRouteType, route_customer_list: stabilizedCustomerList}); if (estimatedStartTime && estimatedStartTime !== '') { data = Object.assign({}, data, {estimated_start_time: combineDateAndTime(currentRoute.schedule_date, estimatedStartTime)}) } diff --git a/client/src/components/trans-routes/RoutesDashboard.js b/client/src/components/trans-routes/RoutesDashboard.js index cef455c..257c2c9 100644 --- a/client/src/components/trans-routes/RoutesDashboard.js +++ b/client/src/components/trans-routes/RoutesDashboard.js @@ -148,6 +148,13 @@ const RoutesDashboard = () => { return `${routeNames.slice(0, -1).join(', ')}, and ${routeNames[routeNames.length - 1]}`; }; + const formatRouteAddressList = (routes = []) => { + const parts = (routes || []).map((route) => `Route ${route.routeName}(address: ${route.customerAddress || 'N/A'})`); + if (parts.length <= 1) return parts[0] || ''; + if (parts.length === 2) return `${parts[0]}, ${parts[1]}`; + return `${parts.slice(0, -1).join(', ')}, and ${parts[parts.length - 1]}`; + }; + const getCustomerTypeLabel = (type) => CUSTOMER_TYPE_TEXT[type] || type || 'N/A'; const getCustomerKey = (customer) => { return customer?.customer_id || customer?.id || normalizeName(customer?.customer_name || customer?.name); @@ -201,26 +208,17 @@ const RoutesDashboard = () => { }); const issues = []; - const seenPairs = new Set(); byCustomer.forEach((records) => { - if (records.length < 2) return; - for (let i = 0; i < records.length; i += 1) { - for (let j = i + 1; j < records.length; j += 1) { - const first = records[i]; - const second = records[j]; - if (first.routeId === second.routeId) continue; - const pairKey = [first.customerKey, first.routeId, second.routeId].sort().join('|'); - if (seenPairs.has(pairKey)) continue; - seenPairs.add(pairKey); - issues.push({ - customerName: first.customerName || second.customerName, - customerAddressA: first.customerAddress || '', - customerAddressB: second.customerAddress || '', - routeA: first.routeName, - routeB: second.routeName - }); - } - } + const uniqueRoutes = Array.from( + new Map( + records.map((item) => [item.routeId, { routeId: item.routeId, routeName: item.routeName, customerAddress: item.customerAddress || '' }]) + ).values() + ); + if (uniqueRoutes.length < 2) return; + issues.push({ + customerName: records[0]?.customerName || 'Unknown', + routes: uniqueRoutes + }); }); return issues; }; @@ -1982,7 +1980,7 @@ const RoutesDashboard = () => {
Inbound Issues
{checkRoutesResult.inbound.map((issue, idx) => (
- both {issue.routeA} and {issue.routeB} route has {issue.customerName}, {issue.customerName}'s address on {issue.routeA} is {issue.customerAddressA || 'N/A'}, on {issue.routeB} is {issue.customerAddressB || 'N/A'} + {issue.customerName} appears on multiple routes: {formatRouteAddressList(issue.routes)}
))} @@ -1992,7 +1990,7 @@ const RoutesDashboard = () => {
Outbound Issues
{checkRoutesResult.outbound.map((issue, idx) => (
- both {issue.routeA} and {issue.routeB} route has {issue.customerName}, {issue.customerName}'s address on {issue.routeA} is {issue.customerAddressA || 'N/A'}, on {issue.routeB} is {issue.customerAddressB || 'N/A'} + {issue.customerName} appears on multiple routes: {formatRouteAddressList(issue.routes)}
))}