updates on the changes on warning and lat and long fixed to make it good
This commit is contained in:
@@ -32,7 +32,22 @@ import {
|
||||
getAdminTenants,
|
||||
getTenantLocations
|
||||
} from '@/api/doormile/endpoints';
|
||||
import { calculateDrivingRoute, calculateTotalCharge, getLastRouteDurationMin } from '@/lib/distance';
|
||||
// calculateDrivingDistance was used by the deadhead-leg effect below without
|
||||
// ever being imported — a ReferenceError on every customer-pickup order that
|
||||
// had a pinned collection address, thrown synchronously inside the effect so
|
||||
// the `.catch()` on that promise chain could never see it. Neither the build
|
||||
// nor the lint config catches an unbound identifier in a .jsx file, which is
|
||||
// why it survived. Found while auditing the coordinate changes; unrelated to
|
||||
// them.
|
||||
//
|
||||
// getLastRouteDurationMin is gone from this list: it was imported and never
|
||||
// called, which the project's own lint reports as an error. Dropped while
|
||||
// rewriting the statement rather than left behind in it.
|
||||
import {
|
||||
calculateDrivingDistance,
|
||||
calculateDrivingRoute,
|
||||
calculateTotalCharge
|
||||
} from '@/lib/distance';
|
||||
import { saveRecentAddress } from '@/lib/geocodingService';
|
||||
import { useHubs } from '@/lib/doormileHooks';
|
||||
import {
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
normalizeHeader,
|
||||
requiredSheetColumns
|
||||
} from '@/lib/bulkOrderColumns';
|
||||
import { coord, hasCoords } from '@/lib/coords';
|
||||
import { calculateDrivingDistance, calculateTotalCharge } from '@/lib/distance';
|
||||
import { useHubs } from '@/lib/doormileHooks';
|
||||
import { PICKUP_SOURCE, buildAnchors } from '@/lib/orderFlow';
|
||||
@@ -465,8 +466,20 @@ export default function MultipleOrders() {
|
||||
});
|
||||
});
|
||||
|
||||
const latitude = place.geometry.location.lat();
|
||||
const longitude = place.geometry.location.lng();
|
||||
// Read the place's own fields first and fall back to the Google-shaped
|
||||
// accessors, matching how line 343 already does it. Reading the accessor
|
||||
// alone was the entry point for the 0,0 defect: geocodingService used to
|
||||
// return 0 from `geometry.location.lat()` for a suggestion with no
|
||||
// coordinates, this assignment stored that 0 verbatim, and the pre-submit
|
||||
// guard's `== null` test could not see it.
|
||||
const latitude = coord(
|
||||
place?.latitude ?? place?.geometry?.location?.lat?.(),
|
||||
'lat'
|
||||
);
|
||||
const longitude = coord(
|
||||
place?.longitude ?? place?.geometry?.location?.lng?.(),
|
||||
'lng'
|
||||
);
|
||||
const address = place.formatted_address || '';
|
||||
|
||||
setDropCust((prev) =>
|
||||
@@ -477,6 +490,20 @@ export default function MultipleOrders() {
|
||||
)
|
||||
);
|
||||
|
||||
// No pin, no quote. Pricing an unpinned row is what produced the wrong
|
||||
// charges: the distance came back from a fallback measurement to 0,0 and
|
||||
// the row carried it as `totalcharge`, which the backend then honours as
|
||||
// `finalprice`. Clearing the charge leaves the row visibly incomplete, and
|
||||
// the submit guard below refuses it.
|
||||
if (latitude === null || longitude === null) {
|
||||
setDropCust((prev) =>
|
||||
prev.map((c) =>
|
||||
c._rowkey === rowkey ? { ...c, distance: null, totalcharge: null } : c
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { roundedDistance, totalcharge } = await calculateDistance({ latitude, longitude });
|
||||
setDropCust((prev) =>
|
||||
@@ -532,7 +559,17 @@ export default function MultipleOrders() {
|
||||
return;
|
||||
}
|
||||
|
||||
const incomplete = dropCust.find((c) => c.latitude == null || c.longitude == null || !c.address);
|
||||
// Checked with hasCoords, not `== null`.
|
||||
//
|
||||
// `== null` matches null and undefined only, so a row carrying latitude 0
|
||||
// — which is what a suggestion with no coordinates used to produce —
|
||||
// passed this guard and was submitted. It then priced either as an
|
||||
// 11,000 km run or, with no charge quoted, at base rate with no distance
|
||||
// component. hasCoords also rejects '' and unparseable sheet cells, which
|
||||
// reach here from an uploaded file.
|
||||
const incomplete = dropCust.find(
|
||||
(c) => !hasCoords(c.latitude, c.longitude) || !c.address
|
||||
);
|
||||
if (incomplete) {
|
||||
OpenToast(
|
||||
`Please search and complete address for ${incomplete.firstname || 'one of the drops'}`,
|
||||
@@ -542,6 +579,31 @@ export default function MultipleOrders() {
|
||||
return;
|
||||
}
|
||||
|
||||
// The collection end, which was never checked here at all. CreateOrder
|
||||
// gained this check already; the bulk form did not, so a hand-typed
|
||||
// pickup that failed to geocode submitted every row in the file against a
|
||||
// pickup the backend has to rescue from the hub record.
|
||||
//
|
||||
// Checked per row through rowPickup, not once against the shared pickup:
|
||||
// a row that resolved its own sender address collects from THAT, and
|
||||
// buildBulkBookingPayload reads the same `row.__pickup || sharedPickup`.
|
||||
// Validating only the shared one would leave a per-row collection point
|
||||
// unchecked, which is the half of the fan-out that varies.
|
||||
const unpinnedPickup = dropCust.find((c) => {
|
||||
const origin = rowPickup(c);
|
||||
return !hasCoords(origin?.latitude, origin?.longitude);
|
||||
});
|
||||
if (unpinnedPickup) {
|
||||
OpenToast(
|
||||
rowPickup(unpinnedPickup) === pickCust
|
||||
? 'The collection address has no coordinates — pick it from the suggestions or drop a map pin'
|
||||
: `The sender address for ${unpinnedPickup.firstname || 'one of the drops'} has no coordinates`,
|
||||
'warning',
|
||||
4000
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const deliverytime = dayjs(`${startDate} ${selectedSlotTime}`, 'YYYY-MM-DD HH:mm').format(
|
||||
'YYYY-MM-DD HH:mm:ss'
|
||||
);
|
||||
@@ -1048,7 +1110,14 @@ export default function MultipleOrders() {
|
||||
</thead>
|
||||
<tbody className="divide-y divide-slate-100 bg-white">
|
||||
{dropCust.map((row, idx) => {
|
||||
const needsAddress = row.latitude == null || row.longitude == null || !row.address;
|
||||
// Same rule as the submit guard, deliberately. When this
|
||||
// used `== null` and the guard used hasCoords, a row
|
||||
// carrying latitude 0 rendered as complete and was then
|
||||
// refused on dispatch — an error with nothing on screen
|
||||
// pointing at the row that caused it. Both ends ask the
|
||||
// same question now, so an unusable row always shows its
|
||||
// address search.
|
||||
const needsAddress = !hasCoords(row.latitude, row.longitude) || !row.address;
|
||||
return (
|
||||
<tr key={row._rowkey || idx} className="hover:bg-slate-50/70 transition-colors">
|
||||
<td className="py-3 pl-4 pr-2 text-slate-600 font-mono text-xs font-bold">{idx + 1}</td>
|
||||
|
||||
Reference in New Issue
Block a user