@shipengine/elements 0.3.6 → 0.3.11-beta.0

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.
@@ -1,10 +1,15 @@
1
1
  /// <reference types="react" />
2
- import SE from "@shipengine/elements-core";
2
+ import SE, { AddressPreference } from "@shipengine/elements-core";
3
3
  export declare type ShipmentFormMode = "browse_rates" | "select_service";
4
+ export declare type ShipmentUpdatedOptions = {
5
+ shouldCalculateRates?: boolean;
6
+ shouldResetAddressPreference?: boolean;
7
+ };
4
8
  export declare type ShipmentFormProps = {
9
+ addressPreference?: AddressPreference;
5
10
  onShipmentDirty: () => void;
6
- onShipmentUpdated: (shipment: SE.SalesOrderShipment) => void;
11
+ onShipmentUpdated: (shipment: SE.SalesOrderShipment, options?: ShipmentUpdatedOptions) => void;
7
12
  salesOrder: SE.SalesOrder;
8
13
  shipment?: SE.SalesOrderShipment;
9
14
  };
10
- export declare const ShipmentForm: ({ onShipmentDirty, onShipmentUpdated, salesOrder, shipment, }: ShipmentFormProps) => JSX.Element;
15
+ export declare const ShipmentForm: ({ addressPreference, onShipmentDirty, onShipmentUpdated, salesOrder, shipment, }: ShipmentFormProps) => JSX.Element;
package/index.cjs CHANGED
@@ -2731,14 +2731,13 @@ function __awaiter(thisArg, _arguments, P, generator) {
2731
2731
  }
2732
2732
 
2733
2733
  const ShipmentForm = ({
2734
+ addressPreference,
2734
2735
  onShipmentDirty,
2735
2736
  // Must be referentially stable
2736
2737
  onShipmentUpdated,
2737
2738
  salesOrder,
2738
2739
  shipment
2739
2740
  }) => {
2740
- var _a;
2741
-
2742
2741
  const {
2743
2742
  t
2744
2743
  } = elementsCore.useTranslation(["purchase-label"]);
@@ -2751,46 +2750,73 @@ const ShipmentForm = ({
2751
2750
  const updateShipment = elementsCore.useUpdateShipment({
2752
2751
  shipmentId: shipment === null || shipment === void 0 ? void 0 : shipment.shipmentId
2753
2752
  });
2754
- const validateAddresses = elementsCore.useValidateAddresses();
2753
+ const parseAddress = elementsCore.useParseAddress();
2754
+ const customPackageTypes = elementsCore.useListCustomPackageTypes();
2755
2755
 
2756
- const handleSubmit = values => __awaiter(void 0, void 0, void 0, function* () {
2756
+ const createOrUpdateShipment = values => __awaiter(void 0, void 0, void 0, function* () {
2757
2757
  try {
2758
- let newOrUpdatedShipment; // If a shipment exists, update it. Otherwise, create a new shipment.
2759
-
2760
2758
  if (shipment) {
2761
- newOrUpdatedShipment = yield updateShipment.trigger(values);
2759
+ return yield updateShipment.trigger(values);
2762
2760
  } else {
2763
2761
  if (!salesOrder) throw new Error(t("purchase-label:salesOrderNotLoaded"));
2764
- newOrUpdatedShipment = yield createShipment.trigger(values);
2762
+ return yield createShipment.trigger(values);
2765
2763
  }
2766
-
2767
- if (newOrUpdatedShipment) onShipmentUpdated === null || onShipmentUpdated === void 0 ? void 0 : onShipmentUpdated(newOrUpdatedShipment);
2768
2764
  } catch (err) {
2765
+ // Swallow error but log it
2769
2766
  logger.error({
2770
2767
  err
2771
2768
  }, "Error updating shipment: %s", err.message);
2769
+ return undefined;
2772
2770
  }
2773
- }); // Validates the address on the sales order when it loads. The result of the
2774
- // validation will be available on validateAddresses.data.
2771
+ });
2775
2772
 
2773
+ const handleSubmit = values => __awaiter(void 0, void 0, void 0, function* () {
2774
+ const updatedShipment = yield createOrUpdateShipment(values);
2775
+ if (updatedShipment) onShipmentUpdated(updatedShipment, {
2776
+ shouldCalculateRates: true
2777
+ });
2778
+ }); // Handles any changes to the ship to address as well as handling user
2779
+ // selecting fall-back address
2776
2780
 
2777
- react.useEffect(() => {
2778
- if (salesOrder && !validateAddresses.data && !validateAddresses.isMutating) {
2779
- validateAddresses.trigger({
2780
- addresses: [salesOrder.shipTo]
2781
+
2782
+ const handleChangeAddress = (payload, options = {}) => __awaiter(void 0, void 0, void 0, function* () {
2783
+ const updatedShipment = yield createOrUpdateShipment(Object.assign(Object.assign(Object.assign({}, shipment), {
2784
+ shipTo: payload
2785
+ }), options.shouldValidate && {
2786
+ validateAddress: "validate_and_clean"
2787
+ }));
2788
+
2789
+ if (updatedShipment) {
2790
+ onShipmentUpdated(updatedShipment, {
2791
+ shouldCalculateRates: false,
2792
+ shouldResetAddressPreference: options.shouldValidate
2781
2793
  });
2782
2794
  }
2783
- }, [validateAddresses, salesOrder]);
2795
+ });
2796
+
2797
+ const handleSubmitParseShipTo = ({
2798
+ fullAddress
2799
+ }) => __awaiter(void 0, void 0, void 0, function* () {
2800
+ const parseResult = yield parseAddress.trigger({
2801
+ text: fullAddress
2802
+ });
2803
+ if (!parseResult) logger.warn("Address parser returned no results");
2804
+ return parseResult;
2805
+ });
2806
+
2784
2807
  const errors = [...(updateShipment.errors || []), ...(createShipment.errors || [])];
2785
2808
  return jsxRuntime.jsx(elementsUi.Templates.ShipmentForm, {
2809
+ addressPreference: addressPreference,
2810
+ carriers: carriers.data,
2811
+ customPackageTypes: customPackageTypes.data,
2786
2812
  errors: errors,
2813
+ onChangeAddress: handleChangeAddress,
2787
2814
  onDirty: onShipmentDirty,
2788
- shipToValidationStatus: (_a = validateAddresses.data) === null || _a === void 0 ? void 0 : _a[0].status,
2789
2815
  onSubmit: handleSubmit,
2790
- carriers: carriers.data,
2791
- warehouses: warehouses.data,
2816
+ onSubmitParseShipTo: handleSubmitParseShipTo,
2792
2817
  salesOrder: salesOrder,
2793
- shipment: shipment
2818
+ shipment: shipment,
2819
+ warehouses: warehouses.data
2794
2820
  });
2795
2821
  };
2796
2822
 
@@ -2833,7 +2859,8 @@ const RateForm = ({
2833
2859
  onSave: handleSave,
2834
2860
  onSubmit: handleSubmit,
2835
2861
  rates: rates,
2836
- shipment: shipment
2862
+ shipment: shipment,
2863
+ scrollToOnLoad: true
2837
2864
  });
2838
2865
  };
2839
2866
 
@@ -2845,12 +2872,16 @@ const SalesOrder = ({
2845
2872
  orderSourceCode,
2846
2873
  salesOrderId
2847
2874
  }) => {
2848
- var _a, _b, _c, _d;
2875
+ var _a, _b, _c, _d, _e, _f;
2849
2876
 
2850
2877
  const {
2851
2878
  t
2852
2879
  } = elementsCore.useTranslation(["common", "purchase-label"]);
2853
2880
  const logger = elementsCore.useLogger();
2881
+ const {
2882
+ addressPreference,
2883
+ resetAddressPreference
2884
+ } = elementsCore.useAddressPreference();
2854
2885
  const carriers = elementsCore.useListCarriers();
2855
2886
  const salesOrders = elementsCore.useListSalesOrders({
2856
2887
  externalOrderId,
@@ -2860,8 +2891,14 @@ const SalesOrder = ({
2860
2891
  const orderSources = elementsCore.useListOrderSources({
2861
2892
  orderSourceCode
2862
2893
  });
2894
+ const warehouses = elementsCore.useListWarehouses();
2863
2895
  const refreshOrderSource = elementsCore.useRefreshOrderSource();
2864
2896
  const calculateRates = elementsCore.useCalculateRates();
2897
+ const validateAddresses = elementsCore.useValidateAddresses();
2898
+ const createShipment = elementsCore.useCreateShipment({
2899
+ salesOrderId: (_b = (_a = salesOrders.data) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.salesOrderId
2900
+ });
2901
+ const customPackageTypes = elementsCore.useListCustomPackageTypes();
2865
2902
  const shipments = elementsCore.useListShipments({
2866
2903
  salesOrderIds: salesOrders.data ? salesOrders.data.map(s => s.salesOrderId) : undefined
2867
2904
  });
@@ -2886,7 +2923,7 @@ const SalesOrder = ({
2886
2923
  refresh();
2887
2924
  }, [orderSourceCode, refreshOrderSource, salesOrders, orderSources]);
2888
2925
  react.useEffect(() => {
2889
- // Executes the onLoad callback when both the sales order and it's shipments
2926
+ // Executes the onLoad callback when both the sales order and its shipments
2890
2927
  // have been loaded. This can be used to react to various states the order
2891
2928
  // or shipments may be in – for instance, redirecting to a shipment when the
2892
2929
  // order has already been fulfilled.
@@ -2894,26 +2931,91 @@ const SalesOrder = ({
2894
2931
  onLoad(salesOrders.data[0], shipments.data);
2895
2932
  }
2896
2933
  }, [onLoad, salesOrders.data, shipments.data]);
2897
- const handleShipmentUpdated = react.useCallback(shipment => __awaiter(void 0, void 0, void 0, function* () {
2898
- var _e, _f;
2934
+ react.useEffect(() => {
2935
+ // On page load, if no shipment exists, create a shipment with validated and cleaned addresses.
2936
+ // If a shipment already exists, validate and clean the addresses.
2937
+ void (() => __awaiter(void 0, void 0, void 0, function* () {
2938
+ var _a, _b, _c;
2939
+
2940
+ if (((_a = salesOrders.data) === null || _a === void 0 ? void 0 : _a.length) && shipments.data && !createShipment.data && !createShipment.errors && !createShipment.isMutating) {
2941
+ if (shipments.data.length === 0) {
2942
+ // We don't have a shipment yet; create one.
2943
+ const result = yield createShipment.trigger({
2944
+ // /v-beta/shipments/sales_order/:salesOrderId requires at minimum
2945
+ // a (warehouseId or shipFrom) and a package with weight defined.
2946
+ packages: [{
2947
+ weight: {
2948
+ value: 0,
2949
+ unit: "pound"
2950
+ }
2951
+ }],
2952
+ validateAddress: "validate_and_clean",
2953
+ warehouseId: (_b = warehouses.data) === null || _b === void 0 ? void 0 : _b[0].warehouseId
2954
+ });
2955
+
2956
+ if (!result) {
2957
+ logger.error("createShipment returned an undefined result");
2958
+ } else if (!result.addressValidation) {
2959
+ logger.error("createShipment returned an undefined addressValidation");
2960
+ } else {
2961
+ yield shipments.mutate();
2962
+ resetAddressPreference({
2963
+ validation: result.addressValidation,
2964
+ fallbackAddress: salesOrders.data[0].shipTo
2965
+ });
2966
+ }
2967
+ } else if (!validateAddresses.data && !validateAddresses.errors && !validateAddresses.isMutating) {
2968
+ // We have a preexisting shipment; validate the address
2969
+ const result = yield validateAddresses.trigger({
2970
+ addresses: [(_c = shipments.data) === null || _c === void 0 ? void 0 : _c[0].shipTo]
2971
+ });
2972
+ const addressValidation = result === null || result === void 0 ? void 0 : result[0];
2973
+
2974
+ if (addressValidation) {
2975
+ resetAddressPreference({
2976
+ validation: addressValidation,
2977
+ fallbackAddress: salesOrders.data[0].shipTo
2978
+ });
2979
+ }
2980
+ }
2981
+ }
2982
+ }))();
2983
+ }, [addressPreference, createShipment, logger, salesOrders.data, shipments, shipments.data, resetAddressPreference, validateAddresses, warehouses.data]);
2984
+ const hasCustomPackage = react.useCallback(shipment => {
2985
+ var _a;
2986
+
2987
+ return !!((_a = customPackageTypes.data) === null || _a === void 0 ? void 0 : _a.find(p => p.packageId === shipment.packages[0].packageId));
2988
+ }, [customPackageTypes]);
2989
+ const handleShipmentUpdated = react.useCallback((shipment, options = {}) => __awaiter(void 0, void 0, void 0, function* () {
2990
+ var _g, _h;
2899
2991
 
2900
2992
  yield shipments.mutate();
2901
- const result = yield calculateRates.trigger({
2902
- shipmentId: shipment.shipmentId,
2903
- rateOptions: {
2904
- carrierIds: shipment.carrierId ? [shipment.carrierId] : (_f = (_e = carriers.data) === null || _e === void 0 ? void 0 : _e.map(c => c.carrierId)) !== null && _f !== void 0 ? _f : [],
2905
- packageTypes: shipment.packages.map(pkg => pkg.packageCode),
2906
- serviceCodes: shipment.serviceCode ? [shipment.serviceCode] : undefined
2907
- }
2908
- }); // We are hiding, from the user, any errors in the rate response if the response
2909
- // contains rates. Log to the console any rate errors if the response has rates.
2910
2993
 
2911
- if ((result === null || result === void 0 ? void 0 : result.errors.length) && result.rates.length) {
2912
- logger.error({
2913
- obj: result.errors
2914
- }, `Rate response had errors`);
2994
+ if (options.shouldResetAddressPreference && shipment.addressValidation) {
2995
+ resetAddressPreference({
2996
+ validation: shipment.addressValidation
2997
+ });
2998
+ }
2999
+
3000
+ if (options.shouldCalculateRates) {
3001
+ const result = yield calculateRates.trigger({
3002
+ shipmentId: shipment.shipmentId,
3003
+ rateOptions: {
3004
+ carrierIds: shipment.carrierId ? [shipment.carrierId] : (_h = (_g = carriers.data) === null || _g === void 0 ? void 0 : _g.map(c => c.carrierId)) !== null && _h !== void 0 ? _h : [],
3005
+ serviceCodes: shipment.serviceCode ? [shipment.serviceCode] : undefined,
3006
+ packageTypes: hasCustomPackage(shipment) ? ["package"] // Only specify package types for non-custom packages
3007
+ : shipment.packages.map(pkg => pkg.packageCode)
3008
+ }
3009
+ }); // We are hiding, from the user, any errors in the rate response if the response
3010
+ // contains rates. Log to the console any rate errors if the response has rates.
3011
+
3012
+ if ((result === null || result === void 0 ? void 0 : result.errors.length) && result.rates.length) {
3013
+ logger.error({
3014
+ obj: result.errors
3015
+ }, `Rate response had errors`);
3016
+ }
2915
3017
  }
2916
- }), [calculateRates, carriers.data, logger, shipments]);
3018
+ }), [calculateRates, carriers.data, hasCustomPackage, logger, resetAddressPreference, shipments]);
2917
3019
  const handleShipmentDirty = react.useCallback(() => {
2918
3020
  calculateRates.reset();
2919
3021
  }, [calculateRates]);
@@ -2937,22 +3039,26 @@ const SalesOrder = ({
2937
3039
  });
2938
3040
  if (shipments.errors) throw new Error(shipments.errors.map(e => e.message).join(", "));
2939
3041
  if (!shipments.data) throw new Error(t("errorMessages.unableToLoad.shipment"));
3042
+ if (carriers.isLoading) return jsxRuntime.jsx(deprecatedUi.Spinner, {
3043
+ children: t("loading.carriers")
3044
+ });
2940
3045
  const salesOrder = salesOrders.data[0];
2941
3046
  const shipment = shipments.data.find(s => s.shipmentStatus === "pending");
2942
3047
  return jsxRuntime.jsxs(elementsUi.Templates.SalesOrder, Object.assign({
2943
3048
  salesOrder: salesOrder
2944
3049
  }, {
2945
3050
  children: [jsxRuntime.jsx(ShipmentForm, {
3051
+ addressPreference: addressPreference,
2946
3052
  onShipmentDirty: handleShipmentDirty,
2947
3053
  onShipmentUpdated: handleShipmentUpdated,
2948
3054
  salesOrder: salesOrder,
2949
3055
  shipment: shipment
2950
3056
  }), jsxRuntime.jsx(RateForm, {
2951
- errors: [...((_a = calculateRates.errors) !== null && _a !== void 0 ? _a : []), ...((_c = (_b = calculateRates.data) === null || _b === void 0 ? void 0 : _b.errors) !== null && _c !== void 0 ? _c : [])],
3057
+ errors: [...((_c = calculateRates.errors) !== null && _c !== void 0 ? _c : []), ...((_e = (_d = calculateRates.data) === null || _d === void 0 ? void 0 : _d.errors) !== null && _e !== void 0 ? _e : [])],
2952
3058
  loading: calculateRates.isMutating,
2953
3059
  onLabelCreated: handleLabelCreated,
2954
3060
  onRateSaved: handleShipmentUpdated,
2955
- rates: (_d = calculateRates.data) === null || _d === void 0 ? void 0 : _d.rates,
3061
+ rates: (_f = calculateRates.data) === null || _f === void 0 ? void 0 : _f.rates,
2956
3062
  shipment: shipment
2957
3063
  })]
2958
3064
  }));
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { useTranslation, useLogger, useListWarehouses, useListCarriers, useCreateShipment, useUpdateShipment, useValidateAddresses, useCreateLabel, useListSalesOrders, useListOrderSources, useRefreshOrderSource, useCalculateRates, useListShipments, registerElement, useGetShipment, useListLabels, useGetLabel, useVoidLabel } from '@shipengine/elements-core';
1
+ import { useTranslation, useLogger, useListWarehouses, useListCarriers, useCreateShipment, useUpdateShipment, useParseAddress, useListCustomPackageTypes, useCreateLabel, useAddressPreference, useListSalesOrders, useListOrderSources, useRefreshOrderSource, useCalculateRates, useValidateAddresses, useListShipments, registerElement, useGetShipment, useListLabels, useGetLabel, useVoidLabel } from '@shipengine/elements-core';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
  import { useEffect, useCallback } from 'react';
4
4
  import { Spinner } from '@shipengine/deprecated-ui';
@@ -2727,14 +2727,13 @@ function __awaiter(thisArg, _arguments, P, generator) {
2727
2727
  }
2728
2728
 
2729
2729
  const ShipmentForm = ({
2730
+ addressPreference,
2730
2731
  onShipmentDirty,
2731
2732
  // Must be referentially stable
2732
2733
  onShipmentUpdated,
2733
2734
  salesOrder,
2734
2735
  shipment
2735
2736
  }) => {
2736
- var _a;
2737
-
2738
2737
  const {
2739
2738
  t
2740
2739
  } = useTranslation(["purchase-label"]);
@@ -2747,46 +2746,73 @@ const ShipmentForm = ({
2747
2746
  const updateShipment = useUpdateShipment({
2748
2747
  shipmentId: shipment === null || shipment === void 0 ? void 0 : shipment.shipmentId
2749
2748
  });
2750
- const validateAddresses = useValidateAddresses();
2749
+ const parseAddress = useParseAddress();
2750
+ const customPackageTypes = useListCustomPackageTypes();
2751
2751
 
2752
- const handleSubmit = values => __awaiter(void 0, void 0, void 0, function* () {
2752
+ const createOrUpdateShipment = values => __awaiter(void 0, void 0, void 0, function* () {
2753
2753
  try {
2754
- let newOrUpdatedShipment; // If a shipment exists, update it. Otherwise, create a new shipment.
2755
-
2756
2754
  if (shipment) {
2757
- newOrUpdatedShipment = yield updateShipment.trigger(values);
2755
+ return yield updateShipment.trigger(values);
2758
2756
  } else {
2759
2757
  if (!salesOrder) throw new Error(t("purchase-label:salesOrderNotLoaded"));
2760
- newOrUpdatedShipment = yield createShipment.trigger(values);
2758
+ return yield createShipment.trigger(values);
2761
2759
  }
2762
-
2763
- if (newOrUpdatedShipment) onShipmentUpdated === null || onShipmentUpdated === void 0 ? void 0 : onShipmentUpdated(newOrUpdatedShipment);
2764
2760
  } catch (err) {
2761
+ // Swallow error but log it
2765
2762
  logger.error({
2766
2763
  err
2767
2764
  }, "Error updating shipment: %s", err.message);
2765
+ return undefined;
2768
2766
  }
2769
- }); // Validates the address on the sales order when it loads. The result of the
2770
- // validation will be available on validateAddresses.data.
2767
+ });
2771
2768
 
2769
+ const handleSubmit = values => __awaiter(void 0, void 0, void 0, function* () {
2770
+ const updatedShipment = yield createOrUpdateShipment(values);
2771
+ if (updatedShipment) onShipmentUpdated(updatedShipment, {
2772
+ shouldCalculateRates: true
2773
+ });
2774
+ }); // Handles any changes to the ship to address as well as handling user
2775
+ // selecting fall-back address
2772
2776
 
2773
- useEffect(() => {
2774
- if (salesOrder && !validateAddresses.data && !validateAddresses.isMutating) {
2775
- validateAddresses.trigger({
2776
- addresses: [salesOrder.shipTo]
2777
+
2778
+ const handleChangeAddress = (payload, options = {}) => __awaiter(void 0, void 0, void 0, function* () {
2779
+ const updatedShipment = yield createOrUpdateShipment(Object.assign(Object.assign(Object.assign({}, shipment), {
2780
+ shipTo: payload
2781
+ }), options.shouldValidate && {
2782
+ validateAddress: "validate_and_clean"
2783
+ }));
2784
+
2785
+ if (updatedShipment) {
2786
+ onShipmentUpdated(updatedShipment, {
2787
+ shouldCalculateRates: false,
2788
+ shouldResetAddressPreference: options.shouldValidate
2777
2789
  });
2778
2790
  }
2779
- }, [validateAddresses, salesOrder]);
2791
+ });
2792
+
2793
+ const handleSubmitParseShipTo = ({
2794
+ fullAddress
2795
+ }) => __awaiter(void 0, void 0, void 0, function* () {
2796
+ const parseResult = yield parseAddress.trigger({
2797
+ text: fullAddress
2798
+ });
2799
+ if (!parseResult) logger.warn("Address parser returned no results");
2800
+ return parseResult;
2801
+ });
2802
+
2780
2803
  const errors = [...(updateShipment.errors || []), ...(createShipment.errors || [])];
2781
2804
  return jsx(Templates.ShipmentForm, {
2805
+ addressPreference: addressPreference,
2806
+ carriers: carriers.data,
2807
+ customPackageTypes: customPackageTypes.data,
2782
2808
  errors: errors,
2809
+ onChangeAddress: handleChangeAddress,
2783
2810
  onDirty: onShipmentDirty,
2784
- shipToValidationStatus: (_a = validateAddresses.data) === null || _a === void 0 ? void 0 : _a[0].status,
2785
2811
  onSubmit: handleSubmit,
2786
- carriers: carriers.data,
2787
- warehouses: warehouses.data,
2812
+ onSubmitParseShipTo: handleSubmitParseShipTo,
2788
2813
  salesOrder: salesOrder,
2789
- shipment: shipment
2814
+ shipment: shipment,
2815
+ warehouses: warehouses.data
2790
2816
  });
2791
2817
  };
2792
2818
 
@@ -2829,7 +2855,8 @@ const RateForm = ({
2829
2855
  onSave: handleSave,
2830
2856
  onSubmit: handleSubmit,
2831
2857
  rates: rates,
2832
- shipment: shipment
2858
+ shipment: shipment,
2859
+ scrollToOnLoad: true
2833
2860
  });
2834
2861
  };
2835
2862
 
@@ -2841,12 +2868,16 @@ const SalesOrder = ({
2841
2868
  orderSourceCode,
2842
2869
  salesOrderId
2843
2870
  }) => {
2844
- var _a, _b, _c, _d;
2871
+ var _a, _b, _c, _d, _e, _f;
2845
2872
 
2846
2873
  const {
2847
2874
  t
2848
2875
  } = useTranslation(["common", "purchase-label"]);
2849
2876
  const logger = useLogger();
2877
+ const {
2878
+ addressPreference,
2879
+ resetAddressPreference
2880
+ } = useAddressPreference();
2850
2881
  const carriers = useListCarriers();
2851
2882
  const salesOrders = useListSalesOrders({
2852
2883
  externalOrderId,
@@ -2856,8 +2887,14 @@ const SalesOrder = ({
2856
2887
  const orderSources = useListOrderSources({
2857
2888
  orderSourceCode
2858
2889
  });
2890
+ const warehouses = useListWarehouses();
2859
2891
  const refreshOrderSource = useRefreshOrderSource();
2860
2892
  const calculateRates = useCalculateRates();
2893
+ const validateAddresses = useValidateAddresses();
2894
+ const createShipment = useCreateShipment({
2895
+ salesOrderId: (_b = (_a = salesOrders.data) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.salesOrderId
2896
+ });
2897
+ const customPackageTypes = useListCustomPackageTypes();
2861
2898
  const shipments = useListShipments({
2862
2899
  salesOrderIds: salesOrders.data ? salesOrders.data.map(s => s.salesOrderId) : undefined
2863
2900
  });
@@ -2882,7 +2919,7 @@ const SalesOrder = ({
2882
2919
  refresh();
2883
2920
  }, [orderSourceCode, refreshOrderSource, salesOrders, orderSources]);
2884
2921
  useEffect(() => {
2885
- // Executes the onLoad callback when both the sales order and it's shipments
2922
+ // Executes the onLoad callback when both the sales order and its shipments
2886
2923
  // have been loaded. This can be used to react to various states the order
2887
2924
  // or shipments may be in – for instance, redirecting to a shipment when the
2888
2925
  // order has already been fulfilled.
@@ -2890,26 +2927,91 @@ const SalesOrder = ({
2890
2927
  onLoad(salesOrders.data[0], shipments.data);
2891
2928
  }
2892
2929
  }, [onLoad, salesOrders.data, shipments.data]);
2893
- const handleShipmentUpdated = useCallback(shipment => __awaiter(void 0, void 0, void 0, function* () {
2894
- var _e, _f;
2930
+ useEffect(() => {
2931
+ // On page load, if no shipment exists, create a shipment with validated and cleaned addresses.
2932
+ // If a shipment already exists, validate and clean the addresses.
2933
+ void (() => __awaiter(void 0, void 0, void 0, function* () {
2934
+ var _a, _b, _c;
2935
+
2936
+ if (((_a = salesOrders.data) === null || _a === void 0 ? void 0 : _a.length) && shipments.data && !createShipment.data && !createShipment.errors && !createShipment.isMutating) {
2937
+ if (shipments.data.length === 0) {
2938
+ // We don't have a shipment yet; create one.
2939
+ const result = yield createShipment.trigger({
2940
+ // /v-beta/shipments/sales_order/:salesOrderId requires at minimum
2941
+ // a (warehouseId or shipFrom) and a package with weight defined.
2942
+ packages: [{
2943
+ weight: {
2944
+ value: 0,
2945
+ unit: "pound"
2946
+ }
2947
+ }],
2948
+ validateAddress: "validate_and_clean",
2949
+ warehouseId: (_b = warehouses.data) === null || _b === void 0 ? void 0 : _b[0].warehouseId
2950
+ });
2951
+
2952
+ if (!result) {
2953
+ logger.error("createShipment returned an undefined result");
2954
+ } else if (!result.addressValidation) {
2955
+ logger.error("createShipment returned an undefined addressValidation");
2956
+ } else {
2957
+ yield shipments.mutate();
2958
+ resetAddressPreference({
2959
+ validation: result.addressValidation,
2960
+ fallbackAddress: salesOrders.data[0].shipTo
2961
+ });
2962
+ }
2963
+ } else if (!validateAddresses.data && !validateAddresses.errors && !validateAddresses.isMutating) {
2964
+ // We have a preexisting shipment; validate the address
2965
+ const result = yield validateAddresses.trigger({
2966
+ addresses: [(_c = shipments.data) === null || _c === void 0 ? void 0 : _c[0].shipTo]
2967
+ });
2968
+ const addressValidation = result === null || result === void 0 ? void 0 : result[0];
2969
+
2970
+ if (addressValidation) {
2971
+ resetAddressPreference({
2972
+ validation: addressValidation,
2973
+ fallbackAddress: salesOrders.data[0].shipTo
2974
+ });
2975
+ }
2976
+ }
2977
+ }
2978
+ }))();
2979
+ }, [addressPreference, createShipment, logger, salesOrders.data, shipments, shipments.data, resetAddressPreference, validateAddresses, warehouses.data]);
2980
+ const hasCustomPackage = useCallback(shipment => {
2981
+ var _a;
2982
+
2983
+ return !!((_a = customPackageTypes.data) === null || _a === void 0 ? void 0 : _a.find(p => p.packageId === shipment.packages[0].packageId));
2984
+ }, [customPackageTypes]);
2985
+ const handleShipmentUpdated = useCallback((shipment, options = {}) => __awaiter(void 0, void 0, void 0, function* () {
2986
+ var _g, _h;
2895
2987
 
2896
2988
  yield shipments.mutate();
2897
- const result = yield calculateRates.trigger({
2898
- shipmentId: shipment.shipmentId,
2899
- rateOptions: {
2900
- carrierIds: shipment.carrierId ? [shipment.carrierId] : (_f = (_e = carriers.data) === null || _e === void 0 ? void 0 : _e.map(c => c.carrierId)) !== null && _f !== void 0 ? _f : [],
2901
- packageTypes: shipment.packages.map(pkg => pkg.packageCode),
2902
- serviceCodes: shipment.serviceCode ? [shipment.serviceCode] : undefined
2903
- }
2904
- }); // We are hiding, from the user, any errors in the rate response if the response
2905
- // contains rates. Log to the console any rate errors if the response has rates.
2906
2989
 
2907
- if ((result === null || result === void 0 ? void 0 : result.errors.length) && result.rates.length) {
2908
- logger.error({
2909
- obj: result.errors
2910
- }, `Rate response had errors`);
2990
+ if (options.shouldResetAddressPreference && shipment.addressValidation) {
2991
+ resetAddressPreference({
2992
+ validation: shipment.addressValidation
2993
+ });
2994
+ }
2995
+
2996
+ if (options.shouldCalculateRates) {
2997
+ const result = yield calculateRates.trigger({
2998
+ shipmentId: shipment.shipmentId,
2999
+ rateOptions: {
3000
+ carrierIds: shipment.carrierId ? [shipment.carrierId] : (_h = (_g = carriers.data) === null || _g === void 0 ? void 0 : _g.map(c => c.carrierId)) !== null && _h !== void 0 ? _h : [],
3001
+ serviceCodes: shipment.serviceCode ? [shipment.serviceCode] : undefined,
3002
+ packageTypes: hasCustomPackage(shipment) ? ["package"] // Only specify package types for non-custom packages
3003
+ : shipment.packages.map(pkg => pkg.packageCode)
3004
+ }
3005
+ }); // We are hiding, from the user, any errors in the rate response if the response
3006
+ // contains rates. Log to the console any rate errors if the response has rates.
3007
+
3008
+ if ((result === null || result === void 0 ? void 0 : result.errors.length) && result.rates.length) {
3009
+ logger.error({
3010
+ obj: result.errors
3011
+ }, `Rate response had errors`);
3012
+ }
2911
3013
  }
2912
- }), [calculateRates, carriers.data, logger, shipments]);
3014
+ }), [calculateRates, carriers.data, hasCustomPackage, logger, resetAddressPreference, shipments]);
2913
3015
  const handleShipmentDirty = useCallback(() => {
2914
3016
  calculateRates.reset();
2915
3017
  }, [calculateRates]);
@@ -2933,22 +3035,26 @@ const SalesOrder = ({
2933
3035
  });
2934
3036
  if (shipments.errors) throw new Error(shipments.errors.map(e => e.message).join(", "));
2935
3037
  if (!shipments.data) throw new Error(t("errorMessages.unableToLoad.shipment"));
3038
+ if (carriers.isLoading) return jsx(Spinner, {
3039
+ children: t("loading.carriers")
3040
+ });
2936
3041
  const salesOrder = salesOrders.data[0];
2937
3042
  const shipment = shipments.data.find(s => s.shipmentStatus === "pending");
2938
3043
  return jsxs(Templates.SalesOrder, Object.assign({
2939
3044
  salesOrder: salesOrder
2940
3045
  }, {
2941
3046
  children: [jsx(ShipmentForm, {
3047
+ addressPreference: addressPreference,
2942
3048
  onShipmentDirty: handleShipmentDirty,
2943
3049
  onShipmentUpdated: handleShipmentUpdated,
2944
3050
  salesOrder: salesOrder,
2945
3051
  shipment: shipment
2946
3052
  }), jsx(RateForm, {
2947
- errors: [...((_a = calculateRates.errors) !== null && _a !== void 0 ? _a : []), ...((_c = (_b = calculateRates.data) === null || _b === void 0 ? void 0 : _b.errors) !== null && _c !== void 0 ? _c : [])],
3053
+ errors: [...((_c = calculateRates.errors) !== null && _c !== void 0 ? _c : []), ...((_e = (_d = calculateRates.data) === null || _d === void 0 ? void 0 : _d.errors) !== null && _e !== void 0 ? _e : [])],
2948
3054
  loading: calculateRates.isMutating,
2949
3055
  onLabelCreated: handleLabelCreated,
2950
3056
  onRateSaved: handleShipmentUpdated,
2951
- rates: (_d = calculateRates.data) === null || _d === void 0 ? void 0 : _d.rates,
3057
+ rates: (_f = calculateRates.data) === null || _f === void 0 ? void 0 : _f.rates,
2952
3058
  shipment: shipment
2953
3059
  })]
2954
3060
  }));
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@shipengine/elements",
3
- "version": "0.3.6",
3
+ "version": "0.3.11-beta.0",
4
4
  "module": "./index.js",
5
5
  "main": "./index.cjs",
6
6
  "type": "module",
7
7
  "types": "./index.d.ts",
8
8
  "dependencies": {
9
- "@shipengine/elements-core": "0.3.6",
10
- "@shipengine/elements-ui": "0.3.6",
9
+ "@shipengine/elements-core": "0.3.11-beta.0",
10
+ "@shipengine/elements-ui": "0.3.11-beta.0",
11
11
  "react": "^18.2.0",
12
- "@shipengine/deprecated-ui": "0.3.6"
12
+ "@shipengine/deprecated-ui": "0.3.11-beta.0"
13
13
  },
14
14
  "peerDependencies": {}
15
15
  }