@nuskin/address-lookup 1.0.1-pa-954.7 → 1.0.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 (45) hide show
  1. package/README.md +20 -3
  2. package/dist/AddressLookup.js +15 -0
  3. package/dist/AddressLookup.js.map +1 -1
  4. package/dist/components/SmartyIntlResults.js +257 -94
  5. package/dist/components/SmartyIntlResults.js.map +1 -1
  6. package/dist/components/SmartyUSResults.js +233 -91
  7. package/dist/components/SmartyUSResults.js.map +1 -1
  8. package/dist/config/address/postalCodeRules.js +1 -1
  9. package/dist/config/address/postalCodeRules.js.map +1 -1
  10. package/dist/hooks/useAddressValidationBase.js +118 -0
  11. package/dist/hooks/useAddressValidationBase.js.map +1 -0
  12. package/dist/hooks/useIntlAddressValidation.js +49 -54
  13. package/dist/hooks/useIntlAddressValidation.js.map +1 -1
  14. package/dist/hooks/useSmartyInternationalLookup.js +59 -70
  15. package/dist/hooks/useSmartyInternationalLookup.js.map +1 -1
  16. package/dist/hooks/useSmartyLookupBase.js +152 -0
  17. package/dist/hooks/useSmartyLookupBase.js.map +1 -0
  18. package/dist/hooks/useSmartyUSLookup.js +67 -63
  19. package/dist/hooks/useSmartyUSLookup.js.map +1 -1
  20. package/dist/hooks/useUSAddressValidation.js +53 -55
  21. package/dist/hooks/useUSAddressValidation.js.map +1 -1
  22. package/dist/styles/addressLookup.css +58 -3
  23. package/dist/utils/addressStatus.js +3 -1
  24. package/dist/utils/addressStatus.js.map +1 -1
  25. package/dist/utils/addressStrings.js +16 -10
  26. package/dist/utils/addressStrings.js.map +1 -1
  27. package/dist/utils/componentPropTypes.js +35 -0
  28. package/dist/utils/componentPropTypes.js.map +1 -0
  29. package/dist/utils/inFlightRequests.js +50 -0
  30. package/dist/utils/inFlightRequests.js.map +1 -0
  31. package/dist/utils/requestCache.js +44 -0
  32. package/dist/utils/requestCache.js.map +1 -0
  33. package/dist/utils/requestRateLimiter.js +53 -0
  34. package/dist/utils/requestRateLimiter.js.map +1 -0
  35. package/dist/utils/validators.js +20 -1
  36. package/dist/utils/validators.js.map +1 -1
  37. package/package.json +13 -8
  38. package/dist/components/EgonResults.js +0 -195
  39. package/dist/components/EgonResults.js.map +0 -1
  40. package/dist/components/SmartyResults.js +0 -327
  41. package/dist/components/SmartyResults.js.map +0 -1
  42. package/dist/hooks/useEgonLookup.js +0 -168
  43. package/dist/hooks/useEgonLookup.js.map +0 -1
  44. package/dist/hooks/useEgonNormalize.js +0 -105
  45. package/dist/hooks/useEgonNormalize.js.map +0 -1
package/README.md CHANGED
@@ -34,7 +34,7 @@ import AddressLookup, { COUNTRY_MAP } from '@nuskin/address-lookup'
34
34
 
35
35
  ```jsx
36
36
  import { useState } from 'react'
37
- import { AddressLookup } from '@nuskin/address-lookup'
37
+ import AddressLookup from '@nuskin/address-lookup'
38
38
 
39
39
  export default function ShippingAddress() {
40
40
  const [validationRequestId, setValidationRequestId] = useState(0)
@@ -71,6 +71,7 @@ export default function ShippingAddress() {
71
71
  - `language?: string` (default: `'en'`)
72
72
  - `address?: object | null` initial form values
73
73
  - `requireValidation?: boolean` (default: `true`)
74
+ - `showManualValidateButton?: boolean` (default: `false`)
74
75
  - `validationRequestId?: number` (default: `0`)
75
76
  - `strings?: object | null` optional label overrides
76
77
 
@@ -89,7 +90,8 @@ If passed, these labels are used instead of loading from Contentstack:
89
90
  emailLabel: 'Email',
90
91
  invalidEmail: 'Invalid email address.',
91
92
  fieldRequired: 'This field is required.',
92
- invalidPostalCode: 'Invalid postal code.'
93
+ invalidPostalCode: 'Invalid postal code.',
94
+ rateLimited: 'Too many requests. Please wait a moment and try again.'
93
95
  }
94
96
  ```
95
97
 
@@ -105,6 +107,7 @@ If passed, these labels are used instead of loading from Contentstack:
105
107
  - emitted when user selects a verification candidate
106
108
  - `validation-request`
107
109
  - emitted when parent increments `validationRequestId`
110
+ - reports current status only; does not trigger verification API calls
108
111
 
109
112
  Common payload shape:
110
113
 
@@ -119,6 +122,7 @@ Common payload shape:
119
122
  isValidEmail?: boolean,
120
123
  status: {
121
124
  verification: 'unverified' | 'autocomplete' | 'verified',
125
+ needsValidation: boolean,
122
126
  completeness: 'complete' | 'incomplete',
123
127
  missingFields: string[],
124
128
  mode: 'autocomplete' | 'manual',
@@ -141,6 +145,10 @@ Common payload shape:
141
145
  ## Validation behavior
142
146
 
143
147
  - Required fields are country-specific (`COUNTRY_MAP[code].config.requiredFields`)
148
+ - `status.needsValidation` is `true` when:
149
+ - `requireValidation=true`
150
+ - mode is `manual`
151
+ - address has not been verified yet
144
152
  - Required errors are shown when:
145
153
  - field loses focus, or
146
154
  - parent triggers validation via `validationRequestId`
@@ -153,6 +161,7 @@ Common payload shape:
153
161
  - `fieldRequired`
154
162
  - `invalidPostalCode`
155
163
  - `invalidEmail`
164
+ - `rateLimited`
156
165
  - Safe defaults are used when those validation strings are missing
157
166
 
158
167
  ## Autocomplete and manual mode
@@ -162,8 +171,10 @@ Common payload shape:
162
171
  - Typing in lookup creates a draft
163
172
  - Clicking outside while suggestions are open cancels draft and restores prior committed values
164
173
  - Manual mode:
165
- - with `requireValidation=true`, user can run verification
174
+ - with `requireValidation=true`, user can run verification explicitly
166
175
  - with `requireValidation=false`, no verification API call is made
176
+ - parent `validationRequestId` returns current status but does not perform verification
177
+ - optional `showManualValidateButton` renders a compact `Validate Address` button next to the lookup field actions
167
178
 
168
179
  ## Localization
169
180
 
@@ -191,6 +202,7 @@ Common class names:
191
202
  - `.ns-address-lookup__field--with-error`
192
203
  - `.ns-address-lookup__label-row`
193
204
  - `.ns-address-lookup__label`
205
+ - `.ns-address-lookup__actions`
194
206
  - `.ns-address-lookup__toggle`
195
207
  - `.ns-address-lookup__input`
196
208
  - `.ns-address-lookup__input--readonly`
@@ -201,11 +213,14 @@ Common class names:
201
213
  - `.ns-address-lookup__spinner`
202
214
  - `.ns-address-lookup__validation`
203
215
  - `.ns-address-lookup__button`
216
+ - `.ns-address-lookup__button--compact`
204
217
  - `.ns-address-lookup__list`
205
218
  - `.ns-address-lookup__list--suggestions`
206
219
  - `.ns-address-lookup__list--validation`
220
+ - `.ns-address-lookup__list--validation-inline`
207
221
  - `.ns-address-lookup__list-item`
208
222
  - `.ns-address-lookup__list-item--divided`
223
+ - `.ns-address-lookup__list-button`
209
224
  - `.ns-address-lookup__list-title`
210
225
  - `.ns-address-lookup__list-subtitle`
211
226
 
@@ -218,6 +233,8 @@ Supported CSS variables on `.ns-address-lookup`:
218
233
  - `--nsal-error-color`
219
234
  - `--nsal-surface-color`
220
235
  - `--nsal-disabled-surface`
236
+ - `--nsal-validation-surface`
237
+ - `--nsal-validation-border`
221
238
  - `--nsal-shadow`
222
239
  - `--nsal-radius`
223
240
  - `--nsal-field-gap`
@@ -4,9 +4,11 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _propTypes = _interopRequireDefault(require("prop-types"));
7
8
  require("./styles/addressLookup.css");
8
9
  var _SmartyUSResults = _interopRequireDefault(require("./components/SmartyUSResults"));
9
10
  var _SmartyIntlResults = _interopRequireDefault(require("./components/SmartyIntlResults"));
11
+ var _componentPropTypes = require("./utils/componentPropTypes");
10
12
  var _jsxRuntime = require("react/jsx-runtime");
11
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
14
  const AddressLookup = ({
@@ -14,6 +16,7 @@ const AddressLookup = ({
14
16
  country = 'US',
15
17
  address = null,
16
18
  requireValidation = true,
19
+ showManualValidateButton = false,
17
20
  validationRequestId = 0,
18
21
  language = 'en',
19
22
  strings = null
@@ -25,6 +28,7 @@ const AddressLookup = ({
25
28
  onSelect: onAddressSelect,
26
29
  initialAddress: address,
27
30
  requireValidation: requireValidation,
31
+ showManualValidateButton: showManualValidateButton,
28
32
  validationRequestId: validationRequestId,
29
33
  language: language,
30
34
  strings: strings
@@ -33,11 +37,22 @@ const AddressLookup = ({
33
37
  onSelect: onAddressSelect,
34
38
  initialAddress: address,
35
39
  requireValidation: requireValidation,
40
+ showManualValidateButton: showManualValidateButton,
36
41
  validationRequestId: validationRequestId,
37
42
  language: language,
38
43
  strings: strings
39
44
  })
40
45
  });
41
46
  };
47
+ AddressLookup.propTypes = {
48
+ onAddressSelect: _propTypes.default.func,
49
+ country: _propTypes.default.string,
50
+ address: _componentPropTypes.addressPropType,
51
+ requireValidation: _propTypes.default.bool,
52
+ showManualValidateButton: _propTypes.default.bool,
53
+ validationRequestId: _propTypes.default.number,
54
+ language: _propTypes.default.string,
55
+ strings: _componentPropTypes.labelStringsPropType
56
+ };
42
57
  var _default = exports.default = AddressLookup;
43
58
  //# sourceMappingURL=AddressLookup.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AddressLookup.js","names":["require","_SmartyUSResults","_interopRequireDefault","_SmartyIntlResults","_jsxRuntime","e","__esModule","default","AddressLookup","onAddressSelect","country","address","requireValidation","validationRequestId","language","strings","isUS","jsx","className","children","onSelect","initialAddress","countryCode","_default","exports"],"sources":["../src/AddressLookup.jsx"],"sourcesContent":["import './styles/addressLookup.css';\nimport SmartyUSResults from './components/SmartyUSResults';\nimport SmartyIntlResults from './components/SmartyIntlResults';\n\nconst AddressLookup = ({ \n onAddressSelect, \n country = 'US',\n address = null,\n requireValidation = true,\n validationRequestId = 0,\n language = 'en',\n strings = null\n}) => {\n const isUS = country === 'US';\n\n return (\n <div className='ns-address-lookup'>\n {isUS ? (\n <SmartyUSResults \n onSelect={onAddressSelect}\n initialAddress={address}\n requireValidation={requireValidation}\n validationRequestId={validationRequestId}\n language={language}\n strings={strings}\n />\n ) : (\n <SmartyIntlResults \n countryCode={country}\n onSelect={onAddressSelect}\n initialAddress={address}\n requireValidation={requireValidation}\n validationRequestId={validationRequestId}\n language={language}\n strings={strings}\n />\n )}\n </div>\n );\n};\n\nexport default AddressLookup;\n"],"mappings":";;;;;;AAAAA,OAAA;AACA,IAAAC,gBAAA,GAAAC,sBAAA,CAAAF,OAAA;AACA,IAAAG,kBAAA,GAAAD,sBAAA,CAAAF,OAAA;AAA+D,IAAAI,WAAA,GAAAJ,OAAA;AAAA,SAAAE,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAE/D,MAAMG,aAAa,GAAGA,CAAC;EACrBC,eAAe;EACfC,OAAO,GAAG,IAAI;EACdC,OAAO,GAAG,IAAI;EACdC,iBAAiB,GAAG,IAAI;EACxBC,mBAAmB,GAAG,CAAC;EACvBC,QAAQ,GAAG,IAAI;EACfC,OAAO,GAAG;AACZ,CAAC,KAAK;EACJ,MAAMC,IAAI,GAAGN,OAAO,KAAK,IAAI;EAE7B,oBACE,IAAAN,WAAA,CAAAa,GAAA;IAAKC,SAAS,EAAC,mBAAmB;IAAAC,QAAA,EAC/BH,IAAI,gBACH,IAAAZ,WAAA,CAAAa,GAAA,EAAChB,gBAAA,CAAAM,OAAe;MACda,QAAQ,EAAEX,eAAgB;MAC1BY,cAAc,EAAEV,OAAQ;MACxBC,iBAAiB,EAAEA,iBAAkB;MACrCC,mBAAmB,EAAEA,mBAAoB;MACzCC,QAAQ,EAAEA,QAAS;MACnBC,OAAO,EAAEA;IAAQ,CAClB,CAAC,gBAEF,IAAAX,WAAA,CAAAa,GAAA,EAACd,kBAAA,CAAAI,OAAiB;MAChBe,WAAW,EAAEZ,OAAQ;MACrBU,QAAQ,EAAEX,eAAgB;MAC1BY,cAAc,EAAEV,OAAQ;MACxBC,iBAAiB,EAAEA,iBAAkB;MACrCC,mBAAmB,EAAEA,mBAAoB;MACzCC,QAAQ,EAAEA,QAAS;MACnBC,OAAO,EAAEA;IAAQ,CAClB;EACF,CACE,CAAC;AAEV,CAAC;AAAC,IAAAQ,QAAA,GAAAC,OAAA,CAAAjB,OAAA,GAEaC,aAAa","ignoreList":[]}
1
+ {"version":3,"file":"AddressLookup.js","names":["_propTypes","_interopRequireDefault","require","_SmartyUSResults","_SmartyIntlResults","_componentPropTypes","_jsxRuntime","e","__esModule","default","AddressLookup","onAddressSelect","country","address","requireValidation","showManualValidateButton","validationRequestId","language","strings","isUS","jsx","className","children","onSelect","initialAddress","countryCode","propTypes","PropTypes","func","string","addressPropType","bool","number","labelStringsPropType","_default","exports"],"sources":["../src/AddressLookup.jsx"],"sourcesContent":["import PropTypes from 'prop-types';\nimport './styles/addressLookup.css';\nimport SmartyUSResults from './components/SmartyUSResults';\nimport SmartyIntlResults from './components/SmartyIntlResults';\nimport { addressPropType, labelStringsPropType } from './utils/componentPropTypes';\n\nconst AddressLookup = ({ \n onAddressSelect, \n country = 'US',\n address = null,\n requireValidation = true,\n showManualValidateButton = false,\n validationRequestId = 0,\n language = 'en',\n strings = null\n}) => {\n const isUS = country === 'US';\n\n return (\n <div className='ns-address-lookup'>\n {isUS ? (\n <SmartyUSResults \n onSelect={onAddressSelect}\n initialAddress={address}\n requireValidation={requireValidation}\n showManualValidateButton={showManualValidateButton}\n validationRequestId={validationRequestId}\n language={language}\n strings={strings}\n />\n ) : (\n <SmartyIntlResults \n countryCode={country}\n onSelect={onAddressSelect}\n initialAddress={address}\n requireValidation={requireValidation}\n showManualValidateButton={showManualValidateButton}\n validationRequestId={validationRequestId}\n language={language}\n strings={strings}\n />\n )}\n </div>\n );\n};\n\nAddressLookup.propTypes = {\n onAddressSelect: PropTypes.func,\n country: PropTypes.string,\n address: addressPropType,\n requireValidation: PropTypes.bool,\n showManualValidateButton: PropTypes.bool,\n validationRequestId: PropTypes.number,\n language: PropTypes.string,\n strings: labelStringsPropType\n};\n\nexport default AddressLookup;\n"],"mappings":";;;;;;AAAA,IAAAA,UAAA,GAAAC,sBAAA,CAAAC,OAAA;AACAA,OAAA;AACA,IAAAC,gBAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,kBAAA,GAAAH,sBAAA,CAAAC,OAAA;AACA,IAAAG,mBAAA,GAAAH,OAAA;AAAmF,IAAAI,WAAA,GAAAJ,OAAA;AAAA,SAAAD,uBAAAM,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAEnF,MAAMG,aAAa,GAAGA,CAAC;EACrBC,eAAe;EACfC,OAAO,GAAG,IAAI;EACdC,OAAO,GAAG,IAAI;EACdC,iBAAiB,GAAG,IAAI;EACxBC,wBAAwB,GAAG,KAAK;EAChCC,mBAAmB,GAAG,CAAC;EACvBC,QAAQ,GAAG,IAAI;EACfC,OAAO,GAAG;AACZ,CAAC,KAAK;EACJ,MAAMC,IAAI,GAAGP,OAAO,KAAK,IAAI;EAE7B,oBACE,IAAAN,WAAA,CAAAc,GAAA;IAAKC,SAAS,EAAC,mBAAmB;IAAAC,QAAA,EAC/BH,IAAI,gBACH,IAAAb,WAAA,CAAAc,GAAA,EAACjB,gBAAA,CAAAM,OAAe;MACdc,QAAQ,EAAEZ,eAAgB;MAC1Ba,cAAc,EAAEX,OAAQ;MACxBC,iBAAiB,EAAEA,iBAAkB;MACrCC,wBAAwB,EAAEA,wBAAyB;MACnDC,mBAAmB,EAAEA,mBAAoB;MACzCC,QAAQ,EAAEA,QAAS;MACnBC,OAAO,EAAEA;IAAQ,CAClB,CAAC,gBAEF,IAAAZ,WAAA,CAAAc,GAAA,EAAChB,kBAAA,CAAAK,OAAiB;MAChBgB,WAAW,EAAEb,OAAQ;MACrBW,QAAQ,EAAEZ,eAAgB;MAC1Ba,cAAc,EAAEX,OAAQ;MACxBC,iBAAiB,EAAEA,iBAAkB;MACrCC,wBAAwB,EAAEA,wBAAyB;MACnDC,mBAAmB,EAAEA,mBAAoB;MACzCC,QAAQ,EAAEA,QAAS;MACnBC,OAAO,EAAEA;IAAQ,CAClB;EACF,CACE,CAAC;AAEV,CAAC;AAEDR,aAAa,CAACgB,SAAS,GAAG;EACxBf,eAAe,EAAEgB,kBAAS,CAACC,IAAI;EAC/BhB,OAAO,EAAEe,kBAAS,CAACE,MAAM;EACzBhB,OAAO,EAAEiB,mCAAe;EACxBhB,iBAAiB,EAAEa,kBAAS,CAACI,IAAI;EACjChB,wBAAwB,EAAEY,kBAAS,CAACI,IAAI;EACxCf,mBAAmB,EAAEW,kBAAS,CAACK,MAAM;EACrCf,QAAQ,EAAEU,kBAAS,CAACE,MAAM;EAC1BX,OAAO,EAAEe;AACX,CAAC;AAAC,IAAAC,QAAA,GAAAC,OAAA,CAAA1B,OAAA,GAEaC,aAAa","ignoreList":[]}
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _propTypes = _interopRequireDefault(require("prop-types"));
7
8
  var _react = require("react");
8
9
  var _useSmartyInternationalLookup = _interopRequireDefault(require("../hooks/useSmartyInternationalLookup"));
9
10
  var _useIntlAddressValidation = _interopRequireDefault(require("../hooks/useIntlAddressValidation"));
@@ -12,6 +13,7 @@ var _countries = require("../countries");
12
13
  var _addressWrapper = require("../utils/addressWrapper");
13
14
  var _addressStatus = require("../utils/addressStatus");
14
15
  var _validators = require("../utils/validators");
16
+ var _componentPropTypes = require("../utils/componentPropTypes");
15
17
  var _jsxRuntime = require("react/jsx-runtime");
16
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
19
  const SmartyIntlResults = ({
@@ -19,6 +21,7 @@ const SmartyIntlResults = ({
19
21
  onSelect,
20
22
  initialAddress = null,
21
23
  requireValidation = true,
24
+ showManualValidateButton = false,
22
25
  validationRequestId = 0,
23
26
  language = 'en',
24
27
  strings = null
@@ -39,6 +42,8 @@ const SmartyIntlResults = ({
39
42
  const [hasPendingLookupDraft, setHasPendingLookupDraft] = (0, _react.useState)(false);
40
43
  const [touchedFields, setTouchedFields] = (0, _react.useState)({});
41
44
  const [showAllRequiredErrors, setShowAllRequiredErrors] = (0, _react.useState)(false);
45
+ const [lookupServiceError, setLookupServiceError] = (0, _react.useState)(null);
46
+ const [validationServiceError, setValidationServiceError] = (0, _react.useState)(null);
42
47
  const shouldSearchRef = (0, _react.useRef)(true);
43
48
  const fieldTimerRef = (0, _react.useRef)(null);
44
49
  const componentRef = (0, _react.useRef)(null);
@@ -54,6 +59,8 @@ const SmartyIntlResults = ({
54
59
  lookupDraftOriginalRef.current = initialAddress;
55
60
  setTouchedFields({});
56
61
  setShowAllRequiredErrors(false);
62
+ setLookupServiceError(null);
63
+ setValidationServiceError(null);
57
64
  }
58
65
  }, [initialAddress]);
59
66
  (0, _react.useEffect)(() => {
@@ -68,7 +75,8 @@ const SmartyIntlResults = ({
68
75
  countryCode,
69
76
  formData,
70
77
  verificationStatus,
71
- mode
78
+ mode,
79
+ requireValidation
72
80
  })
73
81
  });
74
82
  }, [validationRequestId]);
@@ -87,14 +95,95 @@ const SmartyIntlResults = ({
87
95
  const {
88
96
  suggestions,
89
97
  loading,
90
- error
98
+ error,
99
+ rateLimited
91
100
  } = (0, _useSmartyInternationalLookup.default)(shouldSearchRef.current && isAutocompleteMode ? query : '', countryCode, selectedIntlAddressId, 500);
92
101
  const {
93
102
  suggestions: validationSuggestions,
94
103
  loading: validationLoading,
95
- error: validationError
104
+ error: validationError,
105
+ rateLimited: validationRateLimited
96
106
  } = (0, _useIntlAddressValidation.default)(formData, countryCode, requireValidation ? validationTrigger : 0);
97
107
  const lookupValue = formData[lookupField];
108
+ const lookupErrorMessage = lookupServiceError !== null && lookupServiceError !== void 0 && lookupServiceError.rateLimited ? (fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.rateLimited) || 'Too many requests. Please wait a moment and try again.' : (fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.lookupError) || 'We could not look up that address right now.';
109
+ const validationErrorMessage = validationServiceError !== null && validationServiceError !== void 0 && validationServiceError.rateLimited ? (fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.rateLimited) || 'Too many requests. Please wait a moment and try again.' : (fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.validationError) || 'We could not validate that address right now.';
110
+ (0, _react.useEffect)(() => {
111
+ if (!error) {
112
+ setLookupServiceError(null);
113
+ return;
114
+ }
115
+ setLookupServiceError({
116
+ rateLimited,
117
+ rawMessage: error
118
+ });
119
+ }, [error, rateLimited]);
120
+ (0, _react.useEffect)(() => {
121
+ if (!validationError) {
122
+ setValidationServiceError(null);
123
+ return;
124
+ }
125
+ setValidationServiceError({
126
+ rateLimited: validationRateLimited,
127
+ rawMessage: validationError
128
+ });
129
+ }, [validationError, validationRateLimited]);
130
+ (0, _react.useEffect)(() => {
131
+ if (!lookupServiceError) {
132
+ return;
133
+ }
134
+ onSelect === null || onSelect === void 0 || onSelect({
135
+ type: 'lookup-error',
136
+ address: formData,
137
+ status: (0, _addressStatus.buildAddressStatus)({
138
+ countryCode,
139
+ formData,
140
+ verificationStatus,
141
+ mode,
142
+ requireValidation
143
+ }),
144
+ error: {
145
+ kind: lookupServiceError.rateLimited ? 'rate-limited' : 'api',
146
+ source: 'autocomplete',
147
+ message: lookupErrorMessage
148
+ }
149
+ });
150
+ }, [lookupServiceError]);
151
+ (0, _react.useEffect)(() => {
152
+ if (!validationServiceError) {
153
+ return;
154
+ }
155
+ onSelect === null || onSelect === void 0 || onSelect({
156
+ type: 'validation-error',
157
+ address: formData,
158
+ status: (0, _addressStatus.buildAddressStatus)({
159
+ countryCode,
160
+ formData,
161
+ verificationStatus,
162
+ mode,
163
+ requireValidation
164
+ }),
165
+ error: {
166
+ kind: validationServiceError.rateLimited ? 'rate-limited' : 'api',
167
+ source: 'validation',
168
+ message: validationErrorMessage
169
+ }
170
+ });
171
+ }, [validationServiceError]);
172
+ const clearServiceErrors = ({
173
+ lookup = true,
174
+ validation = true,
175
+ custom = false
176
+ } = {}) => {
177
+ if (lookup) {
178
+ setLookupServiceError(null);
179
+ }
180
+ if (validation) {
181
+ setValidationServiceError(null);
182
+ }
183
+ if (custom) {
184
+ setCustomError(null);
185
+ }
186
+ };
98
187
  (0, _react.useEffect)(() => {
99
188
  if (selectedIntlAddressId) {
100
189
  if (suggestions.length === 1 && suggestions[0].isDetailed) {
@@ -123,16 +212,19 @@ const SmartyIntlResults = ({
123
212
  }
124
213
  const handleDocumentMouseDown = event => {
125
214
  const component = componentRef.current;
126
- if (component && component.contains(event.target)) {
215
+ if (component !== null && component !== void 0 && component.contains(event.target)) {
127
216
  return;
128
217
  }
129
218
  const suggestionsList = suggestionsListRef.current;
130
- if (suggestionsList && !suggestionsList.contains(event.target)) {
219
+ if ((suggestionsList === null || suggestionsList === void 0 ? void 0 : suggestionsList.contains(event.target)) === false) {
131
220
  shouldSearchRef.current = false;
132
221
  setQuery('');
133
222
  setSelectedAddress(null);
134
223
  setSelectedIntlAddressId(null);
135
224
  setShowValidationSuggestions(false);
225
+ clearServiceErrors({
226
+ custom: true
227
+ });
136
228
  setFormData(lookupDraftOriginalRef.current);
137
229
  setHasPendingLookupDraft(false);
138
230
  }
@@ -165,6 +257,9 @@ const SmartyIntlResults = ({
165
257
  lastCommittedAddressRef.current = updatedFormData;
166
258
  lookupDraftOriginalRef.current = updatedFormData;
167
259
  setHasPendingLookupDraft(false);
260
+ clearServiceErrors({
261
+ custom: true
262
+ });
168
263
  const currentVerificationStatus = 'autocomplete';
169
264
  setVerificationStatus(currentVerificationStatus);
170
265
  onSelect === null || onSelect === void 0 || onSelect({
@@ -174,7 +269,8 @@ const SmartyIntlResults = ({
174
269
  countryCode,
175
270
  formData: updatedFormData,
176
271
  verificationStatus: currentVerificationStatus,
177
- mode
272
+ mode,
273
+ requireValidation
178
274
  })
179
275
  });
180
276
  if (requireValidation && config.verifyAfterAutocomplete) {
@@ -192,6 +288,9 @@ const SmartyIntlResults = ({
192
288
  setSelectedAddress(null);
193
289
  setSelectedIntlAddressId(null);
194
290
  setShowValidationSuggestions(false);
291
+ clearServiceErrors({
292
+ custom: true
293
+ });
195
294
  if (!hasPendingLookupDraft) {
196
295
  lookupDraftOriginalRef.current = formData;
197
296
  setHasPendingLookupDraft(true);
@@ -261,6 +360,9 @@ const SmartyIntlResults = ({
261
360
  if (field === lookupField) {
262
361
  setShowValidationSuggestions(false);
263
362
  }
363
+ clearServiceErrors({
364
+ custom: true
365
+ });
264
366
  const updatedFormData = {
265
367
  ...formData,
266
368
  [field]: value
@@ -281,7 +383,8 @@ const SmartyIntlResults = ({
281
383
  countryCode,
282
384
  formData: updatedFormData,
283
385
  verificationStatus: nextVerificationStatus,
284
- mode
386
+ mode,
387
+ requireValidation
285
388
  })
286
389
  };
287
390
  if (field === 'email' && value) {
@@ -291,6 +394,11 @@ const SmartyIntlResults = ({
291
394
  }, 500);
292
395
  };
293
396
  const handleSelect = address => {
397
+ clearServiceErrors({
398
+ lookup: true,
399
+ validation: false,
400
+ custom: true
401
+ });
294
402
  if (address.entries > 1 || address.entries === 1 && address.isDetailed === false) {
295
403
  shouldSearchRef.current = true;
296
404
  appliedSelectionKeyRef.current = null;
@@ -306,6 +414,11 @@ const SmartyIntlResults = ({
306
414
  };
307
415
  const handleValidationSelect = validatedAddress => {
308
416
  var _countryConfig$config;
417
+ clearServiceErrors({
418
+ lookup: false,
419
+ validation: true,
420
+ custom: false
421
+ });
309
422
  const components = validatedAddress.components || {};
310
423
  const config = (countryConfig === null || countryConfig === void 0 ? void 0 : countryConfig.addressForm) || [];
311
424
  const formFields = new Set(config.map(f => f.field));
@@ -350,7 +463,8 @@ const SmartyIntlResults = ({
350
463
  countryCode,
351
464
  formData: updatedFormData,
352
465
  verificationStatus: currentVerificationStatus,
353
- mode
466
+ mode,
467
+ requireValidation
354
468
  })
355
469
  });
356
470
  };
@@ -358,9 +472,129 @@ const SmartyIntlResults = ({
358
472
  if (!requireValidation) {
359
473
  return;
360
474
  }
475
+ clearServiceErrors({
476
+ lookup: false,
477
+ validation: true,
478
+ custom: false
479
+ });
361
480
  setShowValidationSuggestions(true);
362
481
  setValidationTrigger(prev => prev + 1);
363
482
  };
483
+ const getFieldKey = fieldConfig => fieldConfig.field;
484
+ const getSuggestionKey = suggestion => suggestion.address_id || [suggestion.displayText, suggestion.street, suggestion.address_text, suggestion.locality, suggestion.administrative_area, suggestion.postal_code, suggestion.entries].filter(value => value !== undefined && value !== null).join('|');
485
+ const getValidationSuggestionKey = suggestion => {
486
+ var _suggestion$component, _suggestion$component2, _suggestion$component3, _suggestion$component4, _suggestion$component5;
487
+ return [suggestion.displayText, suggestion.address1, suggestion.address2, suggestion.address3, (_suggestion$component = suggestion.components) === null || _suggestion$component === void 0 ? void 0 : _suggestion$component.thoroughfare, (_suggestion$component2 = suggestion.components) === null || _suggestion$component2 === void 0 ? void 0 : _suggestion$component2.premise, (_suggestion$component3 = suggestion.components) === null || _suggestion$component3 === void 0 ? void 0 : _suggestion$component3.locality, (_suggestion$component4 = suggestion.components) === null || _suggestion$component4 === void 0 ? void 0 : _suggestion$component4.administrative_area, (_suggestion$component5 = suggestion.components) === null || _suggestion$component5 === void 0 ? void 0 : _suggestion$component5.postal_code].filter(value => value !== undefined && value !== null).join('|');
488
+ };
489
+ const renderLookupActions = () => /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
490
+ className: "ns-address-lookup__actions",
491
+ children: [!isAutocompleteMode && requireValidation && showManualValidateButton && /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
492
+ type: "button",
493
+ onClick: handleValidate,
494
+ disabled: validationLoading || !String(formData[lookupField] || '').trim(),
495
+ className: "ns-address-lookup__button ns-address-lookup__button--compact",
496
+ children: validationLoading ? 'Validating...' : 'Validate Address'
497
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
498
+ type: "button",
499
+ onClick: () => {
500
+ setShowValidationSuggestions(false);
501
+ clearServiceErrors({
502
+ custom: true
503
+ });
504
+ setMode(mode === 'autocomplete' ? 'manual' : 'autocomplete');
505
+ },
506
+ className: "ns-address-lookup__toggle",
507
+ children: mode === 'autocomplete' ? 'Switch to Manual Entry' : 'Switch to Autocomplete'
508
+ })]
509
+ });
510
+ const renderLookupLists = isLookupField => {
511
+ if (!isLookupField) {
512
+ return null;
513
+ }
514
+ if (loading && isAutocompleteMode) {
515
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
516
+ className: "ns-address-lookup__spinner"
517
+ });
518
+ }
519
+ if (suggestions.length > 0 && !selectedAddress && isAutocompleteMode) {
520
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("ul", {
521
+ ref: suggestionsListRef,
522
+ className: "ns-address-lookup__list ns-address-lookup__list--suggestions",
523
+ children: suggestions.map((suggestion, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)("li", {
524
+ className: ['ns-address-lookup__list-item', index < suggestions.length - 1 ? 'ns-address-lookup__list-item--divided' : ''].filter(Boolean).join(' '),
525
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
526
+ type: "button",
527
+ onClick: () => handleSelect(suggestion),
528
+ className: "ns-address-lookup__list-button",
529
+ children: suggestion.displayText
530
+ })
531
+ }, getSuggestionKey(suggestion)))
532
+ });
533
+ }
534
+ if (!isAutocompleteMode && requireValidation && showValidationSuggestions && validationSuggestions.length > 0) {
535
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("ul", {
536
+ className: "ns-address-lookup__list ns-address-lookup__list--validation-inline",
537
+ children: validationSuggestions.map((suggestion, index) => {
538
+ var _suggestion$analysis;
539
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("li", {
540
+ className: ['ns-address-lookup__list-item', index < validationSuggestions.length - 1 ? 'ns-address-lookup__list-item--divided' : ''].filter(Boolean).join(' '),
541
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
542
+ type: "button",
543
+ onClick: () => handleValidationSelect(suggestion),
544
+ className: "ns-address-lookup__list-button",
545
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
546
+ className: "ns-address-lookup__list-title",
547
+ children: ((_suggestion$analysis = suggestion.analysis) === null || _suggestion$analysis === void 0 ? void 0 : _suggestion$analysis.verification_status) || 'Unknown'
548
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
549
+ className: "ns-address-lookup__list-subtitle",
550
+ children: suggestion.displayText
551
+ })]
552
+ })
553
+ }, getValidationSuggestionKey(suggestion));
554
+ })
555
+ });
556
+ }
557
+ return null;
558
+ };
559
+ const renderField = fieldConfig => {
560
+ const isLookupField = fieldConfig.field === lookupField;
561
+ const fieldError = getFieldErrorMessage(fieldConfig.field);
562
+ const isInvalid = hasVisibleFieldError(fieldConfig.field);
563
+ const isReadOnly = !fieldConfig.editable && !isLookupField && isAutocompleteMode;
564
+ const inputClassName = ['ns-address-lookup__input', isInvalid ? 'ns-address-lookup__input--invalid' : '', isReadOnly ? 'ns-address-lookup__input--readonly' : '', isLookupField && loading ? 'ns-address-lookup__input--loading' : ''].filter(Boolean).join(' ');
565
+ const fieldClassName = ['ns-address-lookup__field', isInvalid ? 'ns-address-lookup__field--with-error' : ''].filter(Boolean).join(' ');
566
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
567
+ className: fieldClassName,
568
+ style: {
569
+ width: fieldConfig.width === 'full' ? '100%' : '50%'
570
+ },
571
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
572
+ className: "ns-address-lookup__label-row",
573
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("label", {
574
+ className: "ns-address-lookup__label",
575
+ children: areLabelsLoading ? '' : (fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels[fieldConfig.field]) || fieldConfig.label
576
+ }), isLookupField && renderLookupActions()]
577
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("input", {
578
+ type: "text",
579
+ value: formData[fieldConfig.field] || '',
580
+ maxLength: fieldConfig.maxLength,
581
+ "aria-invalid": shouldShowFieldError(fieldConfig.field) ? 'true' : undefined,
582
+ onBlur: () => handleFieldBlur(fieldConfig.field),
583
+ onChange: e => {
584
+ if (isLookupField && isAutocompleteMode) {
585
+ handleInputChange(e);
586
+ } else {
587
+ handleEditableFieldChange(fieldConfig.field, e.target.value);
588
+ }
589
+ },
590
+ readOnly: !isAutocompleteMode && !fieldConfig.editable && !isLookupField ? false : !fieldConfig.editable && !isLookupField,
591
+ className: inputClassName
592
+ }), fieldError && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
593
+ className: "ns-address-lookup__error-text",
594
+ children: fieldError
595
+ }), renderLookupLists(isLookupField)]
596
+ }, getFieldKey(fieldConfig));
597
+ };
364
598
  (0, _react.useEffect)(() => {
365
599
  if (validationSuggestions.length === 1) {
366
600
  // Auto-select when exactly one validation result is returned
@@ -376,107 +610,36 @@ const SmartyIntlResults = ({
376
610
  });
377
611
  }
378
612
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
379
- children: config.map((fieldConfig, index) => {
380
- const isLookupField = fieldConfig.field === lookupField;
381
- const fieldError = getFieldErrorMessage(fieldConfig.field);
382
- const isInvalid = hasVisibleFieldError(fieldConfig.field);
383
- const isReadOnly = !fieldConfig.editable && !isLookupField && isAutocompleteMode;
384
- const inputClassName = ['ns-address-lookup__input', isInvalid ? 'ns-address-lookup__input--invalid' : '', isReadOnly ? 'ns-address-lookup__input--readonly' : '', isLookupField && loading ? 'ns-address-lookup__input--loading' : ''].filter(Boolean).join(' ');
385
- const fieldClassName = ['ns-address-lookup__field', isInvalid ? 'ns-address-lookup__field--with-error' : ''].filter(Boolean).join(' ');
386
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
387
- className: fieldClassName,
388
- style: {
389
- width: fieldConfig.width === 'full' ? '100%' : '50%'
390
- },
391
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
392
- className: "ns-address-lookup__label-row",
393
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("label", {
394
- className: "ns-address-lookup__label",
395
- children: areLabelsLoading ? '' : (fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels[fieldConfig.field]) || fieldConfig.label
396
- }), isLookupField && /*#__PURE__*/(0, _jsxRuntime.jsx)("a", {
397
- href: "#",
398
- onClick: e => {
399
- e.preventDefault();
400
- setShowValidationSuggestions(false);
401
- setMode(mode === 'autocomplete' ? 'manual' : 'autocomplete');
402
- },
403
- className: "ns-address-lookup__toggle",
404
- children: mode === 'autocomplete' ? 'Switch to Manual Entry' : 'Switch to Autocomplete'
405
- })]
406
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("input", {
407
- type: "text",
408
- value: formData[fieldConfig.field] || '',
409
- maxLength: fieldConfig.maxLength,
410
- "aria-invalid": shouldShowFieldError(fieldConfig.field) ? 'true' : undefined,
411
- onBlur: () => handleFieldBlur(fieldConfig.field),
412
- onChange: e => {
413
- if (isLookupField && isAutocompleteMode) {
414
- handleInputChange(e);
415
- } else {
416
- handleEditableFieldChange(fieldConfig.field, e.target.value);
417
- }
418
- },
419
- readOnly: !isAutocompleteMode && !fieldConfig.editable && !isLookupField ? false : !fieldConfig.editable && !isLookupField,
420
- className: inputClassName
421
- }), fieldError && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
422
- className: "ns-address-lookup__error-text",
423
- children: fieldError
424
- }), isLookupField && loading && isAutocompleteMode && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
425
- className: "ns-address-lookup__spinner"
426
- }), isLookupField && suggestions.length > 0 && !selectedAddress && isAutocompleteMode && /*#__PURE__*/(0, _jsxRuntime.jsx)("ul", {
427
- ref: suggestionsListRef,
428
- className: "ns-address-lookup__list ns-address-lookup__list--suggestions",
429
- children: suggestions.map((suggestion, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)("li", {
430
- onClick: () => handleSelect(suggestion),
431
- className: ['ns-address-lookup__list-item', index < suggestions.length - 1 ? 'ns-address-lookup__list-item--divided' : ''].filter(Boolean).join(' '),
432
- children: suggestion.displayText
433
- }, index))
434
- })]
435
- }, index);
436
- })
613
+ children: config.map(renderField)
437
614
  });
438
615
  };
439
616
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
440
617
  ref: componentRef,
441
618
  className: "ns-address-lookup__panel",
442
- children: [error && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
619
+ children: [lookupServiceError && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
443
620
  className: "ns-address-lookup__message",
444
- children: ["Error: ", error]
621
+ children: lookupErrorMessage
445
622
  }), customError && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
446
623
  className: "ns-address-lookup__message",
447
624
  children: customError
448
- }), requireValidation && validationError && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
625
+ }), requireValidation && validationServiceError && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
449
626
  className: "ns-address-lookup__message",
450
- children: ["Validation Error: ", validationError]
627
+ children: validationErrorMessage
451
628
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
452
629
  className: "ns-address-lookup__form",
453
630
  children: renderAddressForm()
454
- }), !isAutocompleteMode && requireValidation && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
455
- className: "ns-address-lookup__validation",
456
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
457
- onClick: handleValidate,
458
- disabled: validationLoading || !formData.address1,
459
- className: "ns-address-lookup__button",
460
- children: validationLoading ? 'Validating...' : 'Validate Address'
461
- }), showValidationSuggestions && validationSuggestions.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)("ul", {
462
- className: "ns-address-lookup__list ns-address-lookup__list--validation",
463
- children: validationSuggestions.map((suggestion, index) => {
464
- var _suggestion$analysis;
465
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)("li", {
466
- onClick: () => handleValidationSelect(suggestion),
467
- className: ['ns-address-lookup__list-item', index < validationSuggestions.length - 1 ? 'ns-address-lookup__list-item--divided' : ''].filter(Boolean).join(' '),
468
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
469
- className: "ns-address-lookup__list-title",
470
- children: ((_suggestion$analysis = suggestion.analysis) === null || _suggestion$analysis === void 0 ? void 0 : _suggestion$analysis.verification_status) || 'Unknown'
471
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
472
- className: "ns-address-lookup__list-subtitle",
473
- children: suggestion.displayText
474
- })]
475
- }, index);
476
- })
477
- })]
478
631
  })]
479
632
  });
480
633
  };
634
+ SmartyIntlResults.propTypes = {
635
+ countryCode: _propTypes.default.string.isRequired,
636
+ onSelect: _propTypes.default.func,
637
+ initialAddress: _componentPropTypes.addressPropType,
638
+ requireValidation: _propTypes.default.bool,
639
+ showManualValidateButton: _propTypes.default.bool,
640
+ validationRequestId: _propTypes.default.number,
641
+ language: _propTypes.default.string,
642
+ strings: _componentPropTypes.labelStringsPropType
643
+ };
481
644
  var _default = exports.default = SmartyIntlResults;
482
645
  //# sourceMappingURL=SmartyIntlResults.js.map