@nerdjs/sales-kit 4.0.52 → 4.0.53-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entities/quote/quote.d.ts +2 -1
- package/dist/helpers.d.ts +9 -0
- package/dist/helpers.js +54 -0
- package/dist/helpers.js.map +1 -1
- package/dist/hooks/lep/lepLoadLocation.d.ts +0 -6
- package/dist/hooks/lep/lepLoadLocation.js +207 -177
- package/dist/hooks/lep/lepLoadLocation.js.map +1 -1
- package/dist/hooks/lep/lepShipcons.js +25 -7
- package/dist/hooks/lep/lepShipcons.js.map +1 -1
- package/dist/hooks/lep/nerdMap/nerdMap.js +28 -40
- package/dist/hooks/lep/nerdMap/nerdMap.js.map +1 -1
- package/dist/hooks/locationsForm/locationFormSales/locationFormSales.d.ts +1 -1
- package/dist/hooks/locationsForm/locationFormSales/locationFormSales.js +4 -3
- package/dist/hooks/locationsForm/locationFormSales/locationFormSales.js.map +1 -1
- package/dist/hooks/locationsForm/locationFormSales/locationFormSalesMain.d.ts +0 -5
- package/dist/hooks/locationsForm/locationFormSales/locationFormSalesMain.js +173 -56
- package/dist/hooks/locationsForm/locationFormSales/locationFormSalesMain.js.map +1 -1
- package/dist/hooks/quote/constants.js +2 -2
- package/dist/hooks/quote/constants.js.map +1 -1
- package/dist/hooks/quote/form.js +16 -5
- package/dist/hooks/quote/form.js.map +1 -1
- package/dist/hooks/quote/helpers.d.ts +1 -0
- package/dist/hooks/quote/helpers.js +286 -330
- package/dist/hooks/quote/helpers.js.map +1 -1
- package/dist/hooks/quote/template.js +2 -2
- package/dist/hooks/quote/template.js.map +1 -1
- package/dist/redux/locationV1/locationV1Endpoints.d.ts +12 -12
- package/dist/redux/quote/quoteAction.d.ts +2 -3
- package/dist/redux/quote/quoteAction.js +2 -3
- package/dist/redux/quote/quoteAction.js.map +1 -1
- package/dist/redux/quote/quoteReducer.js +5 -5
- package/dist/redux/quote/quoteReducer.js.map +1 -1
- package/package.json +2 -2
|
@@ -20,6 +20,7 @@ import { LocationForm } from "../locationsForm";
|
|
|
20
20
|
import { FREIGHT_CLASS, LTL, SHIPPERS, TL } from "./constants";
|
|
21
21
|
import { LocationFormSales } from "../locationsForm/locationFormSales/locationFormSales";
|
|
22
22
|
import { unstable_debounce as debounce } from "@mui/utils";
|
|
23
|
+
import { getCacheByPlaceId, useGoogleMapsAutocompleteCache, } from "../../helpers";
|
|
23
24
|
export const getStopsColumnDef = (dispatch, stopKind, rows, customerPortal, onEditLocationClick, errors) => {
|
|
24
25
|
const date = {
|
|
25
26
|
headerName: "Date",
|
|
@@ -47,7 +48,7 @@ export const getStopsColumnDef = (dispatch, stopKind, rows, customerPortal, onEd
|
|
|
47
48
|
editable: false,
|
|
48
49
|
width: 40,
|
|
49
50
|
valueGetter: (_v, row) => {
|
|
50
|
-
return rows.findIndex((r) => r.
|
|
51
|
+
return rows.findIndex((r) => r.id === row.id) + 1;
|
|
51
52
|
},
|
|
52
53
|
renderCell: (p) => (_jsx(Avatar, { size: "sm", variant: "soft", children: p.value })),
|
|
53
54
|
},
|
|
@@ -77,25 +78,36 @@ export const getStopsColumnDef = (dispatch, stopKind, rows, customerPortal, onEd
|
|
|
77
78
|
valueSetter(value, row) {
|
|
78
79
|
if (value && typeof value != "string")
|
|
79
80
|
if (typeof value != "number")
|
|
80
|
-
if (locationEntityTypeGuard(value))
|
|
81
|
+
if (locationEntityTypeGuard(value)) {
|
|
82
|
+
console.warn(value);
|
|
81
83
|
return {
|
|
82
84
|
...row,
|
|
83
85
|
locationId: value.id,
|
|
84
86
|
zip: value.address.zip,
|
|
87
|
+
placeId: undefined,
|
|
85
88
|
};
|
|
86
|
-
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
console.warn(value, "2");
|
|
87
92
|
return {
|
|
88
93
|
...row,
|
|
89
94
|
locationId: value.id,
|
|
90
95
|
zip: value.zip,
|
|
96
|
+
placeId: undefined,
|
|
91
97
|
};
|
|
92
|
-
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
console.warn(value, "HOHO");
|
|
93
101
|
return {
|
|
94
102
|
...row,
|
|
95
103
|
locationId: value,
|
|
104
|
+
placeId: undefined,
|
|
96
105
|
};
|
|
97
|
-
|
|
98
|
-
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
console.warn(value, "HAHA");
|
|
109
|
+
return { ...row, locationId: undefined, placeId: undefined };
|
|
110
|
+
}
|
|
99
111
|
},
|
|
100
112
|
},
|
|
101
113
|
{
|
|
@@ -120,7 +132,7 @@ export const getStopsColumnDef = (dispatch, stopKind, rows, customerPortal, onEd
|
|
|
120
132
|
getActions: (p) => [
|
|
121
133
|
_jsx(GridActionsCellItem, { icon: _jsx("i", { style: { fontSize: 14 }, className: "fa-sharp fa-solid fa-trash" }), label: `Delete`, onClick: (e) => {
|
|
122
134
|
e.stopPropagation();
|
|
123
|
-
dispatch(removeStop(p.row.
|
|
135
|
+
dispatch(removeStop(p.row.id));
|
|
124
136
|
}, color: "inherit" }, "delete"),
|
|
125
137
|
],
|
|
126
138
|
},
|
|
@@ -275,144 +287,153 @@ export const getPalletsColumnDef = (deleteAction, customerPortal, perPalletClass
|
|
|
275
287
|
});
|
|
276
288
|
return ret;
|
|
277
289
|
};
|
|
278
|
-
const ZipCodeRenderCell = ({ value, errors, }) => {
|
|
279
|
-
const
|
|
280
|
-
const
|
|
290
|
+
const ZipCodeRenderCell = ({ value, errors, row, id, }) => {
|
|
291
|
+
const apiRef = useGridApiContext();
|
|
292
|
+
const { getSuggestions } = useGoogleMapsAutocompleteCache();
|
|
281
293
|
useEffect(() => {
|
|
282
|
-
|
|
283
|
-
|
|
294
|
+
let active = true;
|
|
295
|
+
if (!value) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (!row.placeId)
|
|
299
|
+
getSuggestions({
|
|
284
300
|
input: value,
|
|
285
|
-
includedRegionCodes: ["US"],
|
|
286
301
|
includedPrimaryTypes: ["(regions)"],
|
|
302
|
+
includedRegionCodes: ["US"],
|
|
287
303
|
language: "en-US",
|
|
288
304
|
region: "us",
|
|
289
|
-
}).then((
|
|
290
|
-
|
|
305
|
+
}).then((suggestions) => {
|
|
306
|
+
if (!active || !suggestions?.[0])
|
|
307
|
+
return;
|
|
308
|
+
const text = suggestions[0].placePrediction?.text?.text || value;
|
|
309
|
+
apiRef.current.updateRows([
|
|
310
|
+
{
|
|
311
|
+
id: id,
|
|
312
|
+
zip: text,
|
|
313
|
+
placeId: suggestions[0].placePrediction?.placeId || undefined,
|
|
314
|
+
},
|
|
315
|
+
]);
|
|
291
316
|
});
|
|
292
|
-
|
|
317
|
+
return () => {
|
|
318
|
+
active = false;
|
|
319
|
+
};
|
|
293
320
|
}, [value]);
|
|
294
321
|
return (_jsx(Box, { width: "100%", children: value ? (_jsx(Typography, { level: "body-sm", sx: {
|
|
295
322
|
display: "inline",
|
|
296
|
-
opacity:
|
|
297
|
-
color: (theme) => errors
|
|
298
|
-
}, children:
|
|
299
|
-
? googleMapsPredictions[0].placePrediction?.text.text || ""
|
|
300
|
-
: value })) : (_jsxs(_Fragment, { children: [_jsx(Typography, { display: "inline", level: "body-sm", sx: {
|
|
301
|
-
opacity: value || errors ? 1 : 0.5,
|
|
302
|
-
color: (theme) => errors && !value ? theme.palette.danger[500] : undefined,
|
|
303
|
-
}, children: "Enter zip or city, state... " }), _jsx(Typography, { display: "inline", color: "danger", children: "*" })] })) }));
|
|
323
|
+
opacity: errors ? 1 : 0.5,
|
|
324
|
+
color: (theme) => (errors ? theme.palette.danger[500] : undefined),
|
|
325
|
+
}, children: value })) : (_jsxs(_Fragment, { children: [_jsx(Typography, { level: "body-sm", display: "inline", children: "Enter zip or city, state..." }), _jsx(Typography, { display: "inline", color: "danger", children: "*" })] })) }));
|
|
304
326
|
};
|
|
305
|
-
const ZipCodeRenderEditCell = ({
|
|
327
|
+
export const ZipCodeRenderEditCell = ({ id, field, hasFocus, value: initialValue, row, }) => {
|
|
306
328
|
const apiRef = useGridApiContext();
|
|
307
|
-
const [googleMapsPredictions, setGoogleMapsPredictions] = useState([]);
|
|
308
|
-
const fetchAutocompleteSuggestions = google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions;
|
|
309
329
|
const ref = useRef(null);
|
|
330
|
+
const { getSuggestions } = useGoogleMapsAutocompleteCache();
|
|
331
|
+
const [options, setOptions] = useState([]);
|
|
332
|
+
const [inputValue, setInputValue] = useState("");
|
|
310
333
|
const [open, setOpen] = useState(false);
|
|
311
|
-
const [value, setValue] = useState(null);
|
|
312
334
|
useLayoutEffect(() => {
|
|
313
|
-
if (hasFocus)
|
|
335
|
+
if (hasFocus)
|
|
314
336
|
ref.current?.focus();
|
|
315
|
-
}
|
|
316
337
|
}, [hasFocus]);
|
|
317
338
|
useEffect(() => {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
language: "en-US",
|
|
323
|
-
region: "us",
|
|
324
|
-
includedRegionCodes: ["US"],
|
|
325
|
-
}).then(async ({ suggestions }) => {
|
|
326
|
-
const result = suggestions[0];
|
|
327
|
-
if (result) {
|
|
328
|
-
if (result.placePrediction?.text.text) {
|
|
329
|
-
setValue(result.placePrediction?.text.text);
|
|
330
|
-
}
|
|
331
|
-
else
|
|
332
|
-
setValue(_value);
|
|
333
|
-
}
|
|
334
|
-
else
|
|
335
|
-
setValue(_value);
|
|
336
|
-
});
|
|
337
|
-
}, []);
|
|
338
|
-
const handleValueChange = async (_, newValue) => {
|
|
339
|
-
setValue(newValue);
|
|
340
|
-
if (typeof newValue != "string" && newValue != null) {
|
|
341
|
-
if (newValue.placePrediction?.text.text) {
|
|
342
|
-
const _place = newValue.placePrediction.toPlace();
|
|
343
|
-
if (_place) {
|
|
344
|
-
const place = (await _place.fetchFields({ fields: ["addressComponents"] })).place;
|
|
345
|
-
const mainText = place.addressComponents?.[0]?.longText;
|
|
346
|
-
let _value = mainText;
|
|
347
|
-
if (Number.isNaN(Number(mainText)) &&
|
|
348
|
-
place.addressComponents?.[2]?.shortText) {
|
|
349
|
-
_value =
|
|
350
|
-
place.addressComponents?.[0]?.longText +
|
|
351
|
-
", " +
|
|
352
|
-
place.addressComponents?.[2]?.shortText;
|
|
353
|
-
}
|
|
354
|
-
apiRef.current?.setEditCellValue({
|
|
355
|
-
id,
|
|
356
|
-
field,
|
|
357
|
-
value: _value,
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
}
|
|
339
|
+
let active = true;
|
|
340
|
+
if (!initialValue) {
|
|
341
|
+
setInputValue("");
|
|
342
|
+
return;
|
|
361
343
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
value: newValue,
|
|
367
|
-
});
|
|
344
|
+
if (row.placeId) {
|
|
345
|
+
const cached = getCacheByPlaceId(row.placeId);
|
|
346
|
+
setInputValue(cached?.[0]?.placePrediction?.text?.text || initialValue);
|
|
347
|
+
return;
|
|
368
348
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
349
|
+
getSuggestions(initialValue)
|
|
350
|
+
.then((suggestions) => {
|
|
351
|
+
if (!active)
|
|
352
|
+
return;
|
|
353
|
+
const text = suggestions?.[0]?.placePrediction?.text?.text || initialValue;
|
|
354
|
+
setInputValue(text);
|
|
355
|
+
})
|
|
356
|
+
.catch(() => {
|
|
357
|
+
if (active)
|
|
358
|
+
setInputValue(initialValue);
|
|
359
|
+
});
|
|
360
|
+
return () => {
|
|
361
|
+
active = false;
|
|
362
|
+
};
|
|
363
|
+
}, []);
|
|
364
|
+
const loadSuggestions = useMemo(() => debounce(async (val) => {
|
|
365
|
+
if (!val)
|
|
366
|
+
return;
|
|
367
|
+
const results = await getSuggestions({
|
|
368
|
+
input: val,
|
|
369
|
+
includedPrimaryTypes: ["(regions)"],
|
|
370
|
+
includedRegionCodes: ["US"],
|
|
371
|
+
language: "en-US",
|
|
372
|
+
region: "us",
|
|
373
|
+
});
|
|
374
|
+
setOptions(results);
|
|
375
|
+
}, 300), [getSuggestions]);
|
|
376
|
+
const handleChange = async (_, newValue) => {
|
|
377
|
+
if (!newValue) {
|
|
378
|
+
apiRef.current.updateRows([
|
|
379
|
+
{
|
|
380
|
+
id: id,
|
|
381
|
+
zip: "",
|
|
382
|
+
placeId: undefined,
|
|
383
|
+
},
|
|
384
|
+
]);
|
|
385
|
+
return;
|
|
380
386
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
387
|
+
if (typeof newValue === "string") {
|
|
388
|
+
setInputValue(newValue);
|
|
389
|
+
apiRef.current.updateRows([
|
|
390
|
+
{
|
|
391
|
+
id: id,
|
|
392
|
+
zip: newValue,
|
|
393
|
+
placeId: undefined,
|
|
394
|
+
},
|
|
395
|
+
]);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const place = newValue.placePrediction?.toPlace();
|
|
399
|
+
if (!place)
|
|
400
|
+
return;
|
|
401
|
+
const result = await place.fetchFields({
|
|
402
|
+
fields: ["addressComponents"],
|
|
403
|
+
});
|
|
404
|
+
const components = result.place.addressComponents || [];
|
|
405
|
+
const city = components.find((c) => c.types.includes("locality"))?.longText ||
|
|
406
|
+
components.find((c) => c.types.includes("postal_town"))?.longText ||
|
|
407
|
+
components.find((c) => c.types.includes("administrative_area_level_2"))
|
|
408
|
+
?.longText ||
|
|
409
|
+
"";
|
|
410
|
+
const state = components.find((c) => c.types.includes("administrative_area_level_1"))
|
|
411
|
+
?.shortText || "";
|
|
412
|
+
const zip = components.find((c) => c.types.includes("postal_code"))?.longText || "";
|
|
413
|
+
const main = city || zip;
|
|
414
|
+
const finalValue = main && state ? `${main}, ${state}` : main || state || "";
|
|
415
|
+
setInputValue(finalValue);
|
|
416
|
+
apiRef.current.updateRows([
|
|
417
|
+
{
|
|
418
|
+
id: id,
|
|
419
|
+
zip: finalValue,
|
|
420
|
+
placeId: newValue.placePrediction?.placeId || undefined,
|
|
386
421
|
},
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
apiRef.current
|
|
422
|
+
]);
|
|
423
|
+
};
|
|
424
|
+
return (_jsx(Autocomplete, { fullWidth: true, freeSolo: true, open: open, onOpen: () => setOpen(true), onClose: () => setOpen(false), options: options, filterOptions: (x) => x, value: inputValue, getOptionLabel: (option) => typeof option === "string"
|
|
425
|
+
? option
|
|
426
|
+
: option.placePrediction?.text.text || "", onChange: handleChange, onInputChange: (_, v) => {
|
|
427
|
+
if (v === inputValue)
|
|
428
|
+
return;
|
|
429
|
+
setInputValue(v);
|
|
430
|
+
loadSuggestions(v);
|
|
431
|
+
apiRef.current.setEditCellValue({
|
|
397
432
|
id,
|
|
398
433
|
field,
|
|
399
434
|
value: v,
|
|
400
435
|
});
|
|
401
|
-
},
|
|
402
|
-
if (typeof option != "string") {
|
|
403
|
-
return option.placePrediction?.text.text || "";
|
|
404
|
-
}
|
|
405
|
-
else
|
|
406
|
-
return option;
|
|
407
|
-
}, filterOptions: (x) => x, renderInput: (params) => (_jsx(TextField, { tabIndex: 0, ...params, placeholder: "Enter zip or city, state...", autoFocus: apiRef.current?.getRowMode(id) === "edit" ? false : true, inputRef: ref, InputProps: {
|
|
408
|
-
...params.InputProps,
|
|
409
|
-
tabIndex: 0,
|
|
410
|
-
onKeyDown: (e) => {
|
|
411
|
-
if (e.key === "Tab") {
|
|
412
|
-
e.stopPropagation();
|
|
413
|
-
}
|
|
414
|
-
},
|
|
415
|
-
} })), renderOption: (props, c) => (_jsx(LocationOption, { cellInput: true, props: props, c: c }, locationEntityTypeGuard(c) ? c.id : c.placePrediction?.placeId)) }));
|
|
436
|
+
}, renderInput: (params) => (_jsx(TextField, { ...params, inputRef: ref, placeholder: "Enter zip or city, state...", autoFocus: true })) }));
|
|
416
437
|
};
|
|
417
438
|
const NumberEditCell = ({ id, value, field }) => {
|
|
418
439
|
const apiRef = useGridApiContext();
|
|
@@ -672,152 +693,126 @@ export function AccessorialInput({ accessorialIDs: _accessorialIDs, onChange, })
|
|
|
672
693
|
* @returns {ReactElement} The autocomplete
|
|
673
694
|
*/
|
|
674
695
|
export function LocationInputCell(props) {
|
|
675
|
-
const { id,
|
|
696
|
+
const { id, field, hasFocus, onEditLocationClick, customerPortal } = props;
|
|
676
697
|
const apiRef = useGridApiContext();
|
|
677
698
|
const [openDialog, setOpenDialog] = useState(false);
|
|
678
699
|
const [locationInputValue, setLocationInputValue] = useState("");
|
|
700
|
+
const [open, setOpen] = useState(false);
|
|
679
701
|
const [searchExistingLocation, { data: existingLocations }] = useLazySearchExistingLocationQuery();
|
|
680
702
|
const [searchLocation, { data: locationSuggestions }] = useLazySearchLocationQuery();
|
|
681
|
-
const [bounds, setBounds] = useState();
|
|
682
703
|
const [googleMapsPredictions, setGoogleMapsPredictions] = useState([]);
|
|
683
704
|
const fetchAutocompleteSuggestions = google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions;
|
|
684
705
|
const googleMapsGeocoder = new google.maps.Geocoder();
|
|
685
706
|
const [getLocation, { data: location }] = useLazyGetLocationQuery();
|
|
707
|
+
const [bounds, setBounds] = useState();
|
|
686
708
|
const ref = useRef(null);
|
|
687
|
-
const
|
|
709
|
+
const zip = useMemo(() => {
|
|
710
|
+
const z = props.row.zip || props.row.quoteZip || "";
|
|
711
|
+
return [...z.matchAll(/\d/g)].map((m) => m[0]).join("") || z;
|
|
712
|
+
}, [props.row.zip, props.row.quoteZip]);
|
|
688
713
|
useLayoutEffect(() => {
|
|
689
|
-
if (hasFocus)
|
|
714
|
+
if (hasFocus)
|
|
690
715
|
ref.current?.focus();
|
|
691
|
-
}
|
|
692
716
|
}, [hasFocus]);
|
|
693
717
|
useEffect(() => {
|
|
694
|
-
const
|
|
695
|
-
if (
|
|
696
|
-
getLocation(
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
findBounds();
|
|
702
|
-
}
|
|
703
|
-
}, [props.row]);
|
|
704
|
-
const handleValueChange = async (_, newValue) => {
|
|
705
|
-
if (typeof newValue != "string") {
|
|
706
|
-
if (newValue && locationEntityTypeGuard(newValue)) {
|
|
707
|
-
apiRef.current?.setEditCellValue({
|
|
708
|
-
id,
|
|
709
|
-
field,
|
|
710
|
-
value: newValue,
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
|
-
else if (newValue) {
|
|
714
|
-
const place = newValue.placePrediction?.toPlace();
|
|
715
|
-
await place?.fetchFields({
|
|
716
|
-
fields: ["formattedAddress"],
|
|
717
|
-
});
|
|
718
|
-
if (place && place.formattedAddress) {
|
|
719
|
-
try {
|
|
720
|
-
const existingLocations = await searchExistingLocation(place.formattedAddress).unwrap();
|
|
721
|
-
if (existingLocations.length > 0)
|
|
722
|
-
setOpenDialog(true);
|
|
723
|
-
else {
|
|
724
|
-
onEditLocationClick(place, id, field);
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
catch {
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
else {
|
|
733
|
-
apiRef.current?.setEditCellValue({
|
|
734
|
-
id,
|
|
735
|
-
field,
|
|
736
|
-
value: newValue,
|
|
737
|
-
});
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
};
|
|
741
|
-
const findBounds = () => {
|
|
718
|
+
const idNum = Number(props.value);
|
|
719
|
+
if (idNum)
|
|
720
|
+
getLocation(idNum, true);
|
|
721
|
+
}, [props.value]);
|
|
722
|
+
const findBounds = useCallback(() => {
|
|
723
|
+
if (!zip)
|
|
724
|
+
return;
|
|
742
725
|
googleMapsGeocoder.geocode({
|
|
743
|
-
address:
|
|
726
|
+
address: zip,
|
|
744
727
|
componentRestrictions: { country: "US" },
|
|
745
728
|
language: "en-US",
|
|
746
729
|
}, (results, status) => {
|
|
747
|
-
if (status === google.maps.GeocoderStatus.OK && results
|
|
748
|
-
const result = results.find((r) => r.address_components
|
|
749
|
-
|
|
750
|
-
const lat = result.geometry.location.lat();
|
|
751
|
-
const lng = result.geometry.location.lng();
|
|
752
|
-
const center = new google.maps.LatLng(lat, lng);
|
|
730
|
+
if (status === google.maps.GeocoderStatus.OK && results?.length) {
|
|
731
|
+
const result = results.find((r) => r.address_components?.some((a) => a.types.includes("country"))) || results[0];
|
|
732
|
+
const center = new google.maps.LatLng(result.geometry.location.lat(), result.geometry.location.lng());
|
|
753
733
|
const circle = new google.maps.Circle({
|
|
754
|
-
center
|
|
734
|
+
center,
|
|
755
735
|
radius: 10000,
|
|
756
736
|
});
|
|
757
737
|
const bounds = circle.getBounds() || undefined;
|
|
758
738
|
setBounds(bounds);
|
|
759
739
|
}
|
|
760
740
|
});
|
|
761
|
-
};
|
|
762
|
-
|
|
763
|
-
if (
|
|
764
|
-
|
|
765
|
-
input: searchText,
|
|
766
|
-
locationBias: bounds,
|
|
767
|
-
language: "en-US",
|
|
768
|
-
region: "us",
|
|
769
|
-
includedRegionCodes: ["US"],
|
|
770
|
-
});
|
|
771
|
-
setGoogleMapsPredictions(suggestions);
|
|
741
|
+
}, [zip]);
|
|
742
|
+
useEffect(() => {
|
|
743
|
+
if (props.row.zip || props.row.quoteZip) {
|
|
744
|
+
findBounds();
|
|
772
745
|
}
|
|
773
|
-
};
|
|
774
|
-
const
|
|
775
|
-
|
|
776
|
-
|
|
746
|
+
}, [props.row.zip, props.row.quoteZip, findBounds]);
|
|
747
|
+
const getGoogleAddresses = useCallback(async (searchText) => {
|
|
748
|
+
if (!searchText)
|
|
749
|
+
return;
|
|
750
|
+
const { suggestions } = await fetchAutocompleteSuggestions({
|
|
751
|
+
input: searchText,
|
|
752
|
+
locationBias: bounds,
|
|
753
|
+
language: "en-US",
|
|
754
|
+
region: "us",
|
|
755
|
+
includedRegionCodes: ["US"],
|
|
756
|
+
});
|
|
757
|
+
setGoogleMapsPredictions(suggestions || []);
|
|
758
|
+
}, [bounds]);
|
|
759
|
+
const debouncedSearch = useMemo(() => debounce((value) => {
|
|
777
760
|
searchLocation({
|
|
778
|
-
zip
|
|
779
|
-
location:
|
|
761
|
+
zip,
|
|
762
|
+
location: value,
|
|
780
763
|
});
|
|
781
|
-
getGoogleAddresses(
|
|
782
|
-
}, [
|
|
783
|
-
const
|
|
764
|
+
getGoogleAddresses(value);
|
|
765
|
+
}, 400), [zip, bounds, searchLocation, getGoogleAddresses]);
|
|
766
|
+
const handleValueChange = async (_, newValue) => {
|
|
767
|
+
if (!newValue || typeof newValue === "string") {
|
|
768
|
+
apiRef.current?.setEditCellValue({ id, field, value: undefined });
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
if (locationEntityTypeGuard(newValue)) {
|
|
772
|
+
console.warn(newValue);
|
|
773
|
+
apiRef.current?.setEditCellValue({
|
|
774
|
+
id,
|
|
775
|
+
field,
|
|
776
|
+
value: newValue,
|
|
777
|
+
});
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
const place = newValue.placePrediction?.toPlace();
|
|
781
|
+
await place?.fetchFields({ fields: ["formattedAddress"] });
|
|
782
|
+
if (!place?.formattedAddress)
|
|
783
|
+
return;
|
|
784
|
+
try {
|
|
785
|
+
const existing = await searchExistingLocation(place.formattedAddress).unwrap();
|
|
786
|
+
if (existing.length > 0) {
|
|
787
|
+
setOpenDialog(true);
|
|
788
|
+
}
|
|
789
|
+
else {
|
|
790
|
+
onEditLocationClick(place, id, field);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
catch {
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
};
|
|
784
797
|
return (_jsxs(_Fragment, { children: [_jsx(Autocomplete, { fullWidth: true, sx: {
|
|
785
|
-
"& fieldset": {
|
|
786
|
-
borderWidth: "0px !important",
|
|
787
|
-
},
|
|
798
|
+
"& fieldset": { borderWidth: "0px !important" },
|
|
788
799
|
}, options: [
|
|
789
800
|
...(locationSuggestions ?? []),
|
|
790
801
|
...(googleMapsPredictions ?? []),
|
|
791
|
-
], open: open, onClose: () =>
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
},
|
|
799
|
-
if (typeof option != "string") {
|
|
800
|
-
if (locationEntityTypeGuard(option)) {
|
|
801
|
-
return option.name;
|
|
802
|
-
}
|
|
803
|
-
return option.placePrediction?.mainText?.text || "";
|
|
804
|
-
}
|
|
805
|
-
else
|
|
806
|
-
return option;
|
|
807
|
-
}, filterOptions: (x) => x, renderInput: (params) => (_jsx(TextField, { tabIndex: 0, variant: "outlined", ...params, size: "small", placeholder: "Pick a location...", autoFocus: apiRef.current?.getRowMode(id) === "edit" ? false : true, onChange: (e) => {
|
|
808
|
-
debouncedChangeHandler(e);
|
|
809
|
-
}, inputRef: ref, InputProps: {
|
|
810
|
-
...params.InputProps,
|
|
811
|
-
tabIndex: 0,
|
|
812
|
-
} })), renderOption: (props, c) => (_jsx(LocationOption, { cellInput: true, props: props, c: c }, locationEntityTypeGuard(c) ? c.id : c.placePrediction?.placeId)) }), _jsx(ExistingLocations, { updateCell: (value) => {
|
|
802
|
+
], open: open, onOpen: () => setOpen(true), onClose: () => setOpen(false), value: location || "", inputValue: locationInputValue, freeSolo: true, filterOptions: (x) => x, getOptionLabel: (option) => typeof option === "string"
|
|
803
|
+
? option
|
|
804
|
+
: locationEntityTypeGuard(option)
|
|
805
|
+
? option.name
|
|
806
|
+
: option.placePrediction?.mainText?.text || "", onChange: handleValueChange, onInputChange: (_e, v) => {
|
|
807
|
+
setLocationInputValue(v);
|
|
808
|
+
debouncedSearch(v);
|
|
809
|
+
}, renderInput: (params) => (_jsx(TextField, { ...params, size: "small", placeholder: "Pick a location...", inputRef: ref })), renderOption: (props, c) => (_jsx(LocationOption, { cellInput: true, props: props, c: c }, locationEntityTypeGuard(c) ? c.id : c.placePrediction?.placeId)) }), _jsx(ExistingLocations, { updateCell: (value) => {
|
|
813
810
|
apiRef.current?.setEditCellValue({
|
|
814
811
|
id,
|
|
815
812
|
field,
|
|
816
|
-
value
|
|
813
|
+
value,
|
|
817
814
|
});
|
|
818
|
-
}, existingLocations: existingLocations, close: () =>
|
|
819
|
-
setOpenDialog(false);
|
|
820
|
-
}, open: openDialog, openLocationForm: (place) => onEditLocationClick(place, id, field), customerPortal: customerPortal })] }));
|
|
815
|
+
}, existingLocations: existingLocations, close: () => setOpenDialog(false), open: openDialog, openLocationForm: (place) => onEditLocationClick(place, id, field), customerPortal: customerPortal })] }));
|
|
821
816
|
}
|
|
822
817
|
export const LocationInput = ({ zip, locationID, onChange, customerPortal, autoCompleteProps, }) => {
|
|
823
818
|
const [locationFormOpen, setLocationFormOpen] = useState({
|
|
@@ -825,131 +820,92 @@ export const LocationInput = ({ zip, locationID, onChange, customerPortal, autoC
|
|
|
825
820
|
place: undefined,
|
|
826
821
|
});
|
|
827
822
|
const [openDialog, setOpenDialog] = useState(false);
|
|
828
|
-
const [
|
|
829
|
-
const [searchExistingLocation, { data: existingLocations }] = useLazySearchExistingLocationQuery();
|
|
830
|
-
const [searchLocation, { data: locationSuggestions }] = useLazySearchLocationQuery();
|
|
831
|
-
const [bounds, setBounds] = useState();
|
|
823
|
+
const [inputValue, setInputValue] = useState("");
|
|
832
824
|
const [googleMapsPredictions, setGoogleMapsPredictions] = useState([]);
|
|
833
|
-
const fetchAutocompleteSuggestions = google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions;
|
|
834
825
|
const googleMapsGeocoder = new google.maps.Geocoder();
|
|
826
|
+
const [bounds, setBounds] = useState();
|
|
827
|
+
const [searchExistingLocation, { data: existingLocations }] = useLazySearchExistingLocationQuery();
|
|
828
|
+
const [searchLocation, { data: locationSuggestions }] = useLazySearchLocationQuery();
|
|
835
829
|
const [getLocation] = useLazyGetLocationQuery();
|
|
836
830
|
const [location, setLocation] = useState();
|
|
831
|
+
const { getSuggestions } = useGoogleMapsAutocompleteCache();
|
|
837
832
|
useEffect(() => {
|
|
838
833
|
if (locationID) {
|
|
839
834
|
getLocation(locationID, true)
|
|
840
835
|
.unwrap()
|
|
841
|
-
.then(
|
|
836
|
+
.then(setLocation)
|
|
842
837
|
.catch(() => undefined);
|
|
843
838
|
}
|
|
844
|
-
else
|
|
839
|
+
else {
|
|
845
840
|
setLocation(undefined);
|
|
841
|
+
}
|
|
846
842
|
}, [locationID]);
|
|
847
843
|
useEffect(() => {
|
|
848
|
-
if (zip)
|
|
849
|
-
|
|
850
|
-
}
|
|
851
|
-
}, [zip]);
|
|
852
|
-
const handleValueChange = async (_, newValue) => {
|
|
853
|
-
if (typeof newValue != "string")
|
|
854
|
-
if (newValue && locationEntityTypeGuard(newValue)) {
|
|
855
|
-
onChange(newValue);
|
|
856
|
-
}
|
|
857
|
-
else if (newValue) {
|
|
858
|
-
const place = newValue.placePrediction?.toPlace();
|
|
859
|
-
await place?.fetchFields({
|
|
860
|
-
fields: ["formattedAddress"],
|
|
861
|
-
});
|
|
862
|
-
if (place && place.formattedAddress) {
|
|
863
|
-
try {
|
|
864
|
-
const existingLocations = await searchExistingLocation(place?.formattedAddress).unwrap();
|
|
865
|
-
if (existingLocations.length > 0)
|
|
866
|
-
setOpenDialog(true);
|
|
867
|
-
else {
|
|
868
|
-
setLocationFormOpen({ open: true, place: place });
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
catch {
|
|
872
|
-
return;
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
else {
|
|
877
|
-
onChange(newValue);
|
|
878
|
-
}
|
|
879
|
-
};
|
|
880
|
-
const findBounds = () => {
|
|
844
|
+
if (!zip)
|
|
845
|
+
return;
|
|
881
846
|
googleMapsGeocoder.geocode({
|
|
882
847
|
address: zip,
|
|
883
848
|
componentRestrictions: { country: "US" },
|
|
884
|
-
language: "en",
|
|
885
849
|
}, (results, status) => {
|
|
886
|
-
if (status === google.maps.GeocoderStatus.OK && results
|
|
887
|
-
const
|
|
888
|
-
const lat = result.geometry.location.lat();
|
|
889
|
-
const lng = result.geometry.location.lng();
|
|
890
|
-
const center = new google.maps.LatLng(lat, lng);
|
|
850
|
+
if (status === google.maps.GeocoderStatus.OK && results?.[0]) {
|
|
851
|
+
const loc = results[0].geometry.location;
|
|
891
852
|
const circle = new google.maps.Circle({
|
|
892
|
-
center:
|
|
853
|
+
center: loc,
|
|
893
854
|
radius: 10000,
|
|
894
855
|
});
|
|
895
|
-
|
|
896
|
-
setBounds(bounds);
|
|
856
|
+
setBounds(circle.getBounds() || undefined);
|
|
897
857
|
}
|
|
898
858
|
});
|
|
899
|
-
};
|
|
900
|
-
const
|
|
901
|
-
if (
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
859
|
+
}, [zip]);
|
|
860
|
+
const handleValueChange = async (_, newValue) => {
|
|
861
|
+
if (typeof newValue !== "string") {
|
|
862
|
+
if (!newValue) {
|
|
863
|
+
onChange(undefined);
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
if (locationEntityTypeGuard(newValue)) {
|
|
867
|
+
onChange(newValue);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
const place = newValue.placePrediction?.toPlace();
|
|
871
|
+
if (!place)
|
|
872
|
+
return;
|
|
873
|
+
const result = await place.fetchFields({
|
|
874
|
+
fields: ["formattedAddress"],
|
|
908
875
|
});
|
|
909
|
-
|
|
876
|
+
const formatted = result.place.formattedAddress;
|
|
877
|
+
if (!formatted)
|
|
878
|
+
return;
|
|
879
|
+
const existing = await searchExistingLocation(formatted).unwrap();
|
|
880
|
+
if (existing.length > 0) {
|
|
881
|
+
setOpenDialog(true);
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
setLocationFormOpen({ open: true, place });
|
|
910
885
|
}
|
|
911
886
|
};
|
|
912
|
-
const
|
|
913
|
-
searchLocation({ zip
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
return option.placePrediction?.mainText?.text || "";
|
|
935
|
-
}
|
|
936
|
-
else
|
|
937
|
-
return option;
|
|
938
|
-
}, endDecorator: _jsx(IconButton, { sx: {
|
|
939
|
-
display: location ? "inherit" : "none",
|
|
940
|
-
}, size: "small", onClick: () => {
|
|
941
|
-
setLocationFormOpen({ open: true, place: location });
|
|
942
|
-
}, children: _jsx("i", { className: "fa-solid fa-pen-to-square" }) }), renderOption: (props, c) => typeof c !== "string" ? (_jsx(LocationOption, { props: props, c: c, cellInput: false }, locationEntityTypeGuard(c) ? c.id : c.placePrediction?.placeId)) : (c) })] }), customerPortal ? (_jsx(LocationForm, { open: locationFormOpen.open, onClose: () => setLocationFormOpen({ open: false, place: undefined }), place: locationFormOpen.place, onConfirm: (value) => {
|
|
943
|
-
onChange(value);
|
|
944
|
-
} })) : (_jsx(LocationFormSales, { onClose: () => setLocationFormOpen({ open: false, place: undefined }), open: locationFormOpen.open, place: locationFormOpen.place, onCreateLocation: (value) => {
|
|
945
|
-
onChange(value);
|
|
946
|
-
}, onSaveLocation: (value) => {
|
|
947
|
-
onChange(value);
|
|
948
|
-
} })), _jsx(ExistingLocations, { updateCell: (value) => {
|
|
949
|
-
onChange(value);
|
|
950
|
-
}, existingLocations: existingLocations, close: () => {
|
|
951
|
-
setOpenDialog(false);
|
|
952
|
-
}, open: openDialog, openLocationForm: (place, open) => setLocationFormOpen({ open, place }), customerPortal: customerPortal })] }));
|
|
887
|
+
const debouncedSearch = useMemo(() => debounce(async (v) => {
|
|
888
|
+
searchLocation({ zip, location: v });
|
|
889
|
+
const googleResults = await getSuggestions({
|
|
890
|
+
input: v,
|
|
891
|
+
locationBias: bounds,
|
|
892
|
+
includedRegionCodes: ["US"],
|
|
893
|
+
language: "en-US",
|
|
894
|
+
region: "us",
|
|
895
|
+
});
|
|
896
|
+
setGoogleMapsPredictions(googleResults);
|
|
897
|
+
}, 400), [zip, bounds]);
|
|
898
|
+
return (_jsxs(_Fragment, { children: [_jsxs(FormControl, { children: [_jsx(FormLabel, { children: "Pick a location..." }), _jsx(JoyAutocomplete, { ...autoCompleteProps, size: "sm", value: location || null, inputValue: inputValue, freeSolo: true, options: [...(locationSuggestions ?? []), ...googleMapsPredictions], filterOptions: (x) => x, getOptionLabel: (option) => typeof option === "string"
|
|
899
|
+
? option
|
|
900
|
+
: locationEntityTypeGuard(option)
|
|
901
|
+
? option.name
|
|
902
|
+
: option.placePrediction?.mainText?.text || "", onChange: handleValueChange, onInputChange: (_, v) => {
|
|
903
|
+
setInputValue(v);
|
|
904
|
+
debouncedSearch(v);
|
|
905
|
+
}, endDecorator: location ? (_jsx(IconButton, { size: "small", onClick: () => setLocationFormOpen({
|
|
906
|
+
open: true,
|
|
907
|
+
place: location,
|
|
908
|
+
}), children: _jsx("i", { className: "fa-solid fa-pen-to-square" }) })) : null, renderOption: (props, c) => typeof c !== "string" ? (_jsx(LocationOption, { props: props, c: c, cellInput: false }, locationEntityTypeGuard(c) ? c.id : c.placePrediction?.placeId)) : (c) })] }), customerPortal ? (_jsx(LocationForm, { open: locationFormOpen.open, onClose: () => setLocationFormOpen({ open: false, place: undefined }), place: locationFormOpen.place, onConfirm: onChange })) : (_jsx(LocationFormSales, { open: locationFormOpen.open, onClose: () => setLocationFormOpen({ open: false, place: undefined }), place: locationFormOpen.place, onCreateLocation: onChange, onSaveLocation: onChange })), _jsx(ExistingLocations, { open: openDialog, close: () => setOpenDialog(false), existingLocations: existingLocations, updateCell: onChange, openLocationForm: (place, open) => setLocationFormOpen({ open, place }), customerPortal: customerPortal })] }));
|
|
953
909
|
};
|
|
954
910
|
/**
|
|
955
911
|
*
|