@nerdjs/sales-kit 4.0.51 → 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.
Files changed (42) hide show
  1. package/dist/entities/accountingInvoice/accountingInvoice.d.ts +4 -0
  2. package/dist/entities/accountingInvoice/accountingInvoice.js +8 -0
  3. package/dist/entities/accountingInvoice/accountingInvoice.js.map +1 -1
  4. package/dist/entities/quote/quote.d.ts +2 -1
  5. package/dist/entities/record/record.d.ts +1 -0
  6. package/dist/entities/record/record.js +2 -0
  7. package/dist/entities/record/record.js.map +1 -1
  8. package/dist/helpers.d.ts +9 -0
  9. package/dist/helpers.js +54 -0
  10. package/dist/helpers.js.map +1 -1
  11. package/dist/hooks/lep/lepInvoiceDetails.js +1 -1
  12. package/dist/hooks/lep/lepInvoiceDetails.js.map +1 -1
  13. package/dist/hooks/lep/lepLoadLocation.d.ts +0 -6
  14. package/dist/hooks/lep/lepLoadLocation.js +207 -177
  15. package/dist/hooks/lep/lepLoadLocation.js.map +1 -1
  16. package/dist/hooks/lep/lepShipcons.js +25 -7
  17. package/dist/hooks/lep/lepShipcons.js.map +1 -1
  18. package/dist/hooks/lep/nerdMap/nerdMap.js +28 -40
  19. package/dist/hooks/lep/nerdMap/nerdMap.js.map +1 -1
  20. package/dist/hooks/locationsForm/locationFormSales/locationFormSales.d.ts +1 -1
  21. package/dist/hooks/locationsForm/locationFormSales/locationFormSales.js +4 -3
  22. package/dist/hooks/locationsForm/locationFormSales/locationFormSales.js.map +1 -1
  23. package/dist/hooks/locationsForm/locationFormSales/locationFormSalesMain.d.ts +0 -5
  24. package/dist/hooks/locationsForm/locationFormSales/locationFormSalesMain.js +173 -56
  25. package/dist/hooks/locationsForm/locationFormSales/locationFormSalesMain.js.map +1 -1
  26. package/dist/hooks/quote/constants.js +2 -2
  27. package/dist/hooks/quote/constants.js.map +1 -1
  28. package/dist/hooks/quote/form.js +16 -5
  29. package/dist/hooks/quote/form.js.map +1 -1
  30. package/dist/hooks/quote/helpers.d.ts +1 -0
  31. package/dist/hooks/quote/helpers.js +286 -330
  32. package/dist/hooks/quote/helpers.js.map +1 -1
  33. package/dist/hooks/quote/template.js +2 -2
  34. package/dist/hooks/quote/template.js.map +1 -1
  35. package/dist/redux/locationV1/locationV1Endpoints.d.ts +12 -12
  36. package/dist/redux/quote/quoteAction.d.ts +2 -3
  37. package/dist/redux/quote/quoteAction.js +2 -3
  38. package/dist/redux/quote/quoteAction.js.map +1 -1
  39. package/dist/redux/quote/quoteReducer.js +5 -5
  40. package/dist/redux/quote/quoteReducer.js.map +1 -1
  41. package/dist/redux/quote/quoteSalesEndpoints.d.ts +2 -0
  42. 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.key === row.key) + 1;
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
- else
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
- else
98
+ }
99
+ else {
100
+ console.warn(value, "HOHO");
93
101
  return {
94
102
  ...row,
95
103
  locationId: value,
104
+ placeId: undefined,
96
105
  };
97
- else
98
- return { ...row, locationId: undefined };
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.key));
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 fetchAutocompleteSuggestions = google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions;
280
- const [googleMapsPredictions, setGoogleMapsPredictions] = useState([]);
290
+ const ZipCodeRenderCell = ({ value, errors, row, id, }) => {
291
+ const apiRef = useGridApiContext();
292
+ const { getSuggestions } = useGoogleMapsAutocompleteCache();
281
293
  useEffect(() => {
282
- if (value) {
283
- fetchAutocompleteSuggestions({
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(({ suggestions }) => {
290
- setGoogleMapsPredictions(suggestions);
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: value || errors ? 1 : 0.5,
297
- color: (theme) => errors && !value ? theme.palette.danger[500] : undefined,
298
- }, children: googleMapsPredictions?.[0]
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 = ({ value: _value, id, field, hasFocus, }) => {
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
- if (_value)
319
- fetchAutocompleteSuggestions({
320
- input: _value,
321
- includedPrimaryTypes: ["(regions)"],
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
- else {
363
- apiRef.current?.setEditCellValue({
364
- id,
365
- field,
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
- const getGoogleAddresses = async (_event, value) => {
371
- if (value) {
372
- const { suggestions } = await fetchAutocompleteSuggestions({
373
- input: value,
374
- includedRegionCodes: ["US"],
375
- includedPrimaryTypes: ["(regions)"],
376
- language: "en-US",
377
- region: "us",
378
- });
379
- setGoogleMapsPredictions(suggestions);
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
- const debouncedChangeHandler = useMemo(() => debounce(getGoogleAddresses, 300), []);
383
- return (_jsx(Autocomplete, { fullWidth: true, sx: {
384
- "& fieldset": {
385
- borderWidth: "0px !important",
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
- }, onClose: () => {
388
- setOpen(false);
389
- }, options: googleMapsPredictions || [], open: open, onOpen: () => setOpen(true), value: value || "", freeSolo: true, onChange: handleValueChange, onKeyDown: (e) => {
390
- if (e.key === "Enter" && open) {
391
- e.stopPropagation();
392
- setOpen(false);
393
- }
394
- }, onInputChange: (e, v) => {
395
- debouncedChangeHandler(e, v);
396
- apiRef.current?.setEditCellValue({
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
- }, getOptionLabel: (option) => {
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, value, field, hasFocus, onEditLocationClick, customerPortal } = props;
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 [open, setOpen] = useState(false);
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 id = Number(value);
695
- if (id) {
696
- getLocation(id, true);
697
- }
698
- }, [value]);
699
- useEffect(() => {
700
- if (props.row.zip || props.row.quoteZip) {
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: props.row.zip || props.row.quoteZip,
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 != undefined) {
748
- const result = results.find((r) => r.address_components.find((a) => a.types.includes("country"))
749
- ?.short_name === "US") || results[0];
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: 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
- const getGoogleAddresses = async (searchText) => {
763
- if (searchText) {
764
- const { suggestions } = await fetchAutocompleteSuggestions({
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 onInputChange = useCallback((e) => {
775
- const zip = props.row.zip || props.row.quoteZip || "";
776
- const _zip = [...zip.matchAll(/\d/g)].map((m) => m[0]).join("");
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: _zip ? _zip : zip,
779
- location: e.target.value,
761
+ zip,
762
+ location: value,
780
763
  });
781
- getGoogleAddresses(e.target.value);
782
- }, [props.row]);
783
- const debouncedChangeHandler = useMemo(() => debounce(onInputChange, 500), []);
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
- setOpen(false);
793
- }, onOpen: () => setOpen(true), value: location || "", onChange: handleValueChange, inputValue: locationInputValue, onKeyDown: (e) => {
794
- if (e.key === "Enter" && open) {
795
- e.stopPropagation();
796
- setOpen(false);
797
- }
798
- }, freeSolo: true, onInputChange: (_e, v) => setLocationInputValue(v), getOptionLabel: (option) => {
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: 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 [locationInputValue, setLocationInputValue] = useState("");
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((d) => setLocation(d))
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
- findBounds();
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 != undefined) {
887
- const result = results[0];
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: center,
853
+ center: loc,
893
854
  radius: 10000,
894
855
  });
895
- const bounds = circle.getBounds() || undefined;
896
- setBounds(bounds);
856
+ setBounds(circle.getBounds() || undefined);
897
857
  }
898
858
  });
899
- };
900
- const getGoogleAddresses = async (searchText) => {
901
- if (searchText) {
902
- const { suggestions } = await fetchAutocompleteSuggestions({
903
- input: searchText,
904
- locationBias: bounds,
905
- language: "en-US",
906
- region: "us",
907
- includedRegionCodes: ["US"],
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
- setGoogleMapsPredictions(suggestions);
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 onInputChange = useCallback((v) => {
913
- searchLocation({ zip: zip, location: v });
914
- getGoogleAddresses(v);
915
- }, [zip]);
916
- const debouncedChangeHandler = useMemo(() => debounce(onInputChange, 500), []);
917
- return (_jsxs(_Fragment, { children: [_jsxs(FormControl, { children: [_jsx(FormLabel, { children: "Pick a location..." }), _jsx(JoyAutocomplete, { size: "sm", ...autoCompleteProps, slotProps: {
918
- listbox: {
919
- sx: {
920
- zIndex: (theme) => theme.zIndex.modal,
921
- },
922
- },
923
- }, options: [
924
- ...(locationSuggestions ?? []),
925
- ...(googleMapsPredictions ?? []),
926
- ], filterOptions: (x) => x, value: location || "", onChange: handleValueChange, inputValue: locationInputValue, freeSolo: true, onInputChange: (_e, v) => {
927
- setLocationInputValue(v);
928
- debouncedChangeHandler(v);
929
- }, getOptionLabel: (option) => {
930
- if (typeof option != "string") {
931
- if (locationEntityTypeGuard(option)) {
932
- return option.name;
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
  *