This commit is contained in:
@@ -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)})
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
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: first.customerName || second.customerName,
|
||||
customerAddressA: first.customerAddress || '',
|
||||
customerAddressB: second.customerAddress || '',
|
||||
routeA: first.routeName,
|
||||
routeB: second.routeName
|
||||
customerName: records[0]?.customerName || 'Unknown',
|
||||
routes: uniqueRoutes
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return issues;
|
||||
};
|
||||
@@ -1982,7 +1980,7 @@ const RoutesDashboard = () => {
|
||||
<div className="fw-bold mb-2">Inbound Issues</div>
|
||||
{checkRoutesResult.inbound.map((issue, idx) => (
|
||||
<div key={`inbound-issue-${idx}`} className="mb-2">
|
||||
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)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -1992,7 +1990,7 @@ const RoutesDashboard = () => {
|
||||
<div className="fw-bold mb-2">Outbound Issues</div>
|
||||
{checkRoutesResult.outbound.map((issue, idx) => (
|
||||
<div key={`outbound-issue-${idx}`} className="mb-2">
|
||||
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)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user