@zonos/elements 1.2.1 → 1.2.3

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 (114) hide show
  1. package/dist/cjs/{cart-7b70853c.js → cart-55512e32.js} +12 -2
  2. package/dist/cjs/index.cjs.js +2 -2
  3. package/dist/cjs/{localization-387a8a65.js → localization-d7fe7290.js} +40 -13
  4. package/dist/cjs/{submitGtag-bf6e7c5e.js → submitGtag-d65003f9.js} +1 -1
  5. package/dist/cjs/zonos-address_2.cjs.entry.js +7 -2
  6. package/dist/cjs/zonos-cart-items_10.cjs.entry.js +6 -7
  7. package/dist/cjs/zonos-checkout.cjs.entry.js +8 -4
  8. package/dist/cjs/zonos-controller.cjs.entry.js +49 -3
  9. package/dist/cjs/zonos-country-flag_4.cjs.entry.js +1 -1
  10. package/dist/cjs/zonos-hello-dialog.cjs.entry.js +15 -7
  11. package/dist/cjs/zonos-hello.cjs.entry.js +1 -1
  12. package/dist/cjs/zonos-payment.cjs.entry.js +2 -2
  13. package/dist/cjs/zonos-shipping-rich-radio.cjs.entry.js +1 -1
  14. package/dist/collection/components/checkout/zonos-checkout/zonos-checkout.css +2 -2
  15. package/dist/collection/components/checkout/zonos-checkout/zonos-checkout.js +4 -0
  16. package/dist/collection/components/checkout/zonos-checkout/zonos-shipping/zonos-shipping.js +3 -5
  17. package/dist/collection/components/common/zonos-shipping-rich-radio/zonos-shipping-rich-radio.css +1 -0
  18. package/dist/collection/components/hello/zonos-hello-dialog/zonos-hello-dialog.js +15 -7
  19. package/dist/collection/components/main/zonos-controller.js +46 -0
  20. package/dist/collection/components/store/checkout/stripe.js +11 -1
  21. package/dist/collection/components/store/hello/localization.js +31 -9
  22. package/dist/collection/components/stripe/zonos-address/zonos-address.js +5 -0
  23. package/dist/collection/components/utils/api/getExchangeRate.js +9 -4
  24. package/dist/collection/components/utils/checkout/initCheckout.js +1 -1
  25. package/dist/collection/environment.js +22 -13
  26. package/dist/collection/scripts/zonos.js +84 -3
  27. package/dist/collection/utils/generateVercelDeployUrl.js +3 -2
  28. package/dist/components/cart.js +11 -1
  29. package/dist/components/localization.js +40 -13
  30. package/dist/components/zonos-address2.js +5 -0
  31. package/dist/components/zonos-checkout.js +5 -1
  32. package/dist/components/zonos-controller.js +47 -1
  33. package/dist/components/zonos-hello-dialog2.js +15 -7
  34. package/dist/components/zonos-shipping-rich-radio2.js +1 -1
  35. package/dist/components/zonos-shipping2.js +4 -5
  36. package/dist/esm/{cart-07091d2a.js → cart-17650017.js} +12 -2
  37. package/dist/esm/index.js +2 -2
  38. package/dist/esm/{localization-b3c2a9a9.js → localization-f3828793.js} +40 -13
  39. package/dist/esm/{submitGtag-c0b655ad.js → submitGtag-a901ece5.js} +1 -1
  40. package/dist/esm/zonos-address_2.entry.js +7 -2
  41. package/dist/esm/zonos-cart-items_10.entry.js +6 -7
  42. package/dist/esm/zonos-checkout.entry.js +8 -4
  43. package/dist/esm/zonos-controller.entry.js +49 -3
  44. package/dist/esm/zonos-country-flag_4.entry.js +1 -1
  45. package/dist/esm/zonos-hello-dialog.entry.js +15 -7
  46. package/dist/esm/zonos-hello.entry.js +1 -1
  47. package/dist/esm/zonos-payment.entry.js +2 -2
  48. package/dist/esm/zonos-shipping-rich-radio.entry.js +1 -1
  49. package/dist/esm-es5/cart-17650017.js +1 -0
  50. package/dist/esm-es5/index.js +1 -1
  51. package/dist/esm-es5/{localization-b3c2a9a9.js → localization-f3828793.js} +1 -1
  52. package/dist/esm-es5/{submitGtag-c0b655ad.js → submitGtag-a901ece5.js} +1 -1
  53. package/dist/esm-es5/zonos-address_2.entry.js +1 -1
  54. package/dist/esm-es5/zonos-cart-items_10.entry.js +1 -1
  55. package/dist/esm-es5/zonos-checkout.entry.js +1 -1
  56. package/dist/esm-es5/zonos-controller.entry.js +1 -1
  57. package/dist/esm-es5/zonos-country-flag_4.entry.js +1 -1
  58. package/dist/esm-es5/zonos-hello-dialog.entry.js +1 -1
  59. package/dist/esm-es5/zonos-hello.entry.js +1 -1
  60. package/dist/esm-es5/zonos-payment.entry.js +1 -1
  61. package/dist/esm-es5/zonos-shipping-rich-radio.entry.js +1 -1
  62. package/dist/scripts/loadZonos.js +86 -5
  63. package/dist/scripts/zonos.js +86 -5
  64. package/dist/types/components/main/zonos-controller.d.ts +1 -0
  65. package/dist/types/components/store/checkout/stripe.d.ts +2 -1
  66. package/dist/types/components/store/hello/localization.d.ts +2 -0
  67. package/dist/types/components/utils/api/getExchangeRate.d.ts +9 -3
  68. package/dist/types/components/utils/changeDeepProperty.d.ts +1 -1
  69. package/dist/types/components/utils/changeDeepPropertyAtIndex.d.ts +1 -1
  70. package/dist/types/components/utils/checkout/initCheckout.d.ts +1 -1
  71. package/dist/types/environment.d.ts +6 -1
  72. package/dist/types/scripts/zonos.d.ts +3 -0
  73. package/dist/types/types/generated/graphql.customer.types.d.ts +1 -0
  74. package/dist/types/types/generated/graphql.customer.types.ts +1 -0
  75. package/dist/zonos-elements/assets/RemoveIcon.svg +1 -1
  76. package/dist/zonos-elements/index.esm.js +1 -1
  77. package/dist/zonos-elements/p-0ed3bb9f.system.entry.js +1 -0
  78. package/dist/zonos-elements/{p-42ba069d.system.js → p-164fae93.system.js} +1 -1
  79. package/dist/zonos-elements/{p-9b86e655.system.entry.js → p-224125da.system.entry.js} +1 -1
  80. package/dist/zonos-elements/{p-9dc9cbc8.entry.js → p-28681677.entry.js} +1 -1
  81. package/dist/zonos-elements/p-3a56c240.entry.js +1 -0
  82. package/dist/zonos-elements/p-3f3fbcea.entry.js +1 -0
  83. package/dist/zonos-elements/{p-bb36a9f8.js → p-770c959e.js} +1 -1
  84. package/dist/zonos-elements/p-8378d94e.js +1 -0
  85. package/dist/zonos-elements/{p-37db3842.system.entry.js → p-84b00605.system.entry.js} +1 -1
  86. package/dist/zonos-elements/{p-f23749e4.system.js → p-8aabbb9b.system.js} +1 -1
  87. package/dist/zonos-elements/p-8b415737.system.entry.js +1 -0
  88. package/dist/zonos-elements/{p-98105ede.entry.js → p-9202375f.entry.js} +1 -1
  89. package/dist/zonos-elements/p-a1fa50fb.entry.js +1 -0
  90. package/dist/zonos-elements/{p-a20b97e9.system.entry.js → p-aca66238.system.entry.js} +1 -1
  91. package/dist/zonos-elements/{p-87f324c5.entry.js → p-bc2c42f5.entry.js} +1 -1
  92. package/dist/zonos-elements/{p-c28157ec.system.entry.js → p-c8ad044e.system.entry.js} +1 -1
  93. package/dist/zonos-elements/{p-343071d5.entry.js → p-cc070c1c.entry.js} +1 -1
  94. package/dist/zonos-elements/{p-4524a84f.system.entry.js → p-cc1c785c.system.entry.js} +1 -1
  95. package/dist/zonos-elements/p-cd71e41e.entry.js +1 -0
  96. package/dist/zonos-elements/{p-0f7233fd.system.entry.js → p-cf97cc68.system.entry.js} +1 -1
  97. package/dist/zonos-elements/p-d6b8563b.system.entry.js +1 -0
  98. package/dist/zonos-elements/{p-96a3c767.entry.js → p-e5908de2.entry.js} +1 -1
  99. package/dist/zonos-elements/p-f6add79c.system.js +1 -0
  100. package/dist/zonos-elements/{p-6df1eaee.js → p-f7875c40.js} +1 -1
  101. package/dist/zonos-elements/p-f8491335.system.js +1 -1
  102. package/dist/zonos-elements/{p-b64bbf38.system.js → p-f95ac9ec.system.js} +1 -1
  103. package/dist/zonos-elements/zonos-elements.esm.js +1 -1
  104. package/package.json +3 -3
  105. package/dist/esm-es5/cart-07091d2a.js +0 -1
  106. package/dist/zonos-elements/p-0a788f68.entry.js +0 -1
  107. package/dist/zonos-elements/p-23b0b4a2.system.entry.js +0 -1
  108. package/dist/zonos-elements/p-2c20c082.entry.js +0 -1
  109. package/dist/zonos-elements/p-30fd29fb.js +0 -1
  110. package/dist/zonos-elements/p-37fc9f6b.entry.js +0 -1
  111. package/dist/zonos-elements/p-79f9e330.system.js +0 -1
  112. package/dist/zonos-elements/p-914ce305.system.entry.js +0 -1
  113. package/dist/zonos-elements/p-9adf546f.system.entry.js +0 -1
  114. package/dist/zonos-elements/p-d43749bd.entry.js +0 -1
@@ -20,6 +20,7 @@ const { onChange, reset, state: stripeStore, } = createStore(() => ({
20
20
  stripeAddressEventData: null,
21
21
  stripeAddressUsedWhenFetchingLC: null,
22
22
  stripeElements: null,
23
+ stripeElementsOptions: null,
23
24
  stripeLinkElement: null,
24
25
  stripeLinkEventData: null,
25
26
  stripeLinkUsedWhenFetchingLC: null,
@@ -60,13 +61,22 @@ const initStripeElements = async (props) => {
60
61
  overridePrimaryColor: props === null || props === void 0 ? void 0 : props.overridePrimaryColor,
61
62
  overrideTheme: props === null || props === void 0 ? void 0 : props.overrideTheme,
62
63
  });
64
+ // compare with the previous options to see if we need to update
65
+ const isSameOptions = JSON.stringify(stripeOptions) ===
66
+ JSON.stringify(stripeStore.stripeElementsOptions);
63
67
  if (!stripeStore.stripeElements) {
64
68
  // init stripe elements if it doesn't exist
65
69
  stripeStore.stripeElements = (_a = stripeStore.stripe) === null || _a === void 0 ? void 0 : _a.elements(stripeOptions);
70
+ // save stripe elements options for later comparison
71
+ stripeStore.stripeElementsOptions = stripeOptions;
72
+ log('Stripe elements initialized');
73
+ return;
66
74
  }
67
- else {
75
+ if (!isSameOptions) {
68
76
  // update elements with new option if it already exists
69
77
  stripeStore.stripeElements.update(stripeOptions);
78
+ // save stripe elements options for later comparison
79
+ stripeStore.stripeElementsOptions = stripeOptions;
70
80
  }
71
81
  log('Stripe elements initialized');
72
82
  }
@@ -22,23 +22,45 @@ const { state: localizationStore } = createStore({
22
22
  shippingZoneCountries: null,
23
23
  targetCurrency: 'USD',
24
24
  });
25
+ const triggerGetExchangeRate = async (isGuaranteed) => {
26
+ const { exchangeRate, maxAge } = await getExchangeRate({
27
+ country: localizationStore.selectedCountryCode,
28
+ isGuaranteed,
29
+ sourceCurrency: zonosStore.sourceCurrency,
30
+ targetCurrency: localizationStore.targetCurrency,
31
+ });
32
+ if (exchangeRate) {
33
+ localizationStore.exchangeRate = exchangeRate;
34
+ currencyDisplay();
35
+ }
36
+ return { maxAge };
37
+ };
38
+ // This recursive function is for users who step away from their computer and come back needing a new exchange rate
39
+ const startExchangeRateTimeout = ({ isGuaranteed, maxAge, }) => {
40
+ if (localizationStore.exchangeRateTimeout) {
41
+ clearTimeout(localizationStore.exchangeRateTimeout);
42
+ }
43
+ // maxAge comes in seconds, convert to milliseconds
44
+ const defaultMaxAge = 5 * 60;
45
+ const maxAgeToUse = maxAge || defaultMaxAge;
46
+ // Recursively set timeouts to get new exchange rates when the current one expires
47
+ localizationStore.exchangeRateTimeout = setTimeout(async () => {
48
+ const { maxAge: newMaxAge } = await triggerGetExchangeRate(isGuaranteed);
49
+ startExchangeRateTimeout({ isGuaranteed, maxAge: newMaxAge });
50
+ }, maxAgeToUse * 1000);
51
+ };
25
52
  const getNewLocalization = async () => {
26
53
  log('get new localization store');
27
54
  const { isShippableCountry, selectedCountryCode } = localizationStore;
28
- const isGuaranteed = zonosStore.checkoutSettings.visibilityStatus === 'ENABLED';
29
55
  if (zonosStore.helloSettings.currencyBehavior === 'DISABLED' ||
30
56
  !isShippableCountry ||
31
57
  !selectedCountryCode) {
32
58
  return;
33
59
  }
34
- localizationStore.exchangeRate = await getExchangeRate({
35
- country: localizationStore.selectedCountryCode,
36
- isGuaranteed,
37
- sourceCurrency: zonosStore.sourceCurrency,
38
- targetCurrency: localizationStore.targetCurrency,
39
- });
40
- if (localizationStore.exchangeRate) {
41
- currencyDisplay();
60
+ if (zonosStore.sourceCurrency !== localizationStore.targetCurrency) {
61
+ const isGuaranteed = zonosStore.checkoutSettings.visibilityStatus === 'ENABLED';
62
+ const { maxAge } = await triggerGetExchangeRate(isGuaranteed);
63
+ startExchangeRateTimeout({ isGuaranteed, maxAge });
42
64
  }
43
65
  localizationStore.countryLandedCost = await getCountryLandedCost(localizationStore.selectedCountryCode);
44
66
  };
@@ -33,6 +33,11 @@ export class ZonosAddress {
33
33
  ? Object.values(shippableCountries).map(country => country.code)
34
34
  : [],
35
35
  contacts: this.defaultAddress ? [this.defaultAddress] : undefined,
36
+ defaultValues: {
37
+ address: {
38
+ country: localizationStore.selectedCountryCode || 'AL',
39
+ },
40
+ },
36
41
  display: {
37
42
  name: 'split',
38
43
  },
@@ -2,16 +2,21 @@ import { handleFetch } from "../handleFetch";
2
2
  import { logError } from "../logging/logError";
3
3
  export const getExchangeRate = async ({ country, isGuaranteed, sourceCurrency, targetCurrency, }) => {
4
4
  var _a;
5
+ // If source currency matches target currency (US -> US) and is not a guaranteed rate, return null
6
+ if (sourceCurrency === targetCurrency && !isGuaranteed) {
7
+ return { exchangeRate: null, maxAge: null };
8
+ }
5
9
  const url = `${process.env.NEXT_PUBLIC_ZONOS_ROUTE_URL}/api/exchange-rates?sourceCurrency=${sourceCurrency}&targetCurrency=${targetCurrency}&isGuaranteed=${isGuaranteed}&country=${country}}`;
6
10
  const { errors, json } = await handleFetch(url);
7
11
  if (errors.length || !json) {
8
12
  logError(`Error fetching country landed cost: ${(_a = errors.find(Boolean)) === null || _a === void 0 ? void 0 : _a.message}`);
9
- return null;
13
+ return { exchangeRate: null, maxAge: null };
10
14
  }
11
- const { rate, targetFormat } = json.exchangeRateCreate;
15
+ const { maxAge, rate, targetFormat } = json.exchangeRateCreate;
12
16
  if (rate) {
13
17
  sessionStorage.setItem(country + '_rate', JSON.stringify(rate));
14
- return { rate, targetFormat };
18
+ const exchangeRate = { rate, targetFormat };
19
+ return { exchangeRate, maxAge };
15
20
  }
16
- return null;
21
+ return { exchangeRate: null, maxAge: null };
17
22
  };
@@ -8,7 +8,7 @@ const injectCheckoutElement = () => {
8
8
  document.body.appendChild(newCheckoutElement);
9
9
  }
10
10
  };
11
- export const initCheckout = async (config) => {
11
+ export const initCheckout = (config) => {
12
12
  if (!config.placeOrderButtonSelector) {
13
13
  // do nothing if checkout button anchor is not set
14
14
  return;
@@ -3,6 +3,9 @@
3
3
  import { createEnv } from "@t3-oss/env-core";
4
4
  import { config } from "dotenv";
5
5
  import { z } from "zod";
6
+ // rollup and ts somehow can't compile this with absolute path
7
+ // eslint-disable-next-line no-relative-import-paths/no-relative-import-paths
8
+ import { generateVercelDeployUrl } from "./utils/generateVercelDeployUrl";
6
9
  export const isClientSide = typeof window !== 'undefined';
7
10
  export const inProdEnvironment = process.env.NODE_ENV === 'production';
8
11
  export const inTestEnvironment = process.env.NODE_ENV === 'test';
@@ -15,7 +18,6 @@ let packageVersion = `${process.env.npm_package_version}` ||
15
18
  process.env.NEXT_PUBLIC_ZONOS_PACKAGE_VERSION;
16
19
  const UNPKG_ZONOS_URL = `https://unpkg.com/@zonos/elements@${packageVersion}`;
17
20
  export const formattedUrl = ({ packageVersion: _packageVersion, type = 'full', url, }) => {
18
- var _a;
19
21
  if (!url) {
20
22
  // return origin value so t3 can throw error when it's empty
21
23
  return url;
@@ -29,17 +31,11 @@ export const formattedUrl = ({ packageVersion: _packageVersion, type = 'full', u
29
31
  // only run this in Vercel, ignore in CI
30
32
  if (isVercelPreview || (inVercel && type === 'vercel-git')) {
31
33
  // use vercel branch_url instead of the production url
32
- const vercelGitBranchUrl = process.env.VERCEL_BRANCH_URL;
33
- if (!vercelGitBranchUrl) {
34
- throw new Error('Fail to get vercel branch url');
34
+ const vercelGitCommitMessage = process.env.VERCEL_GIT_COMMIT_MESSAGE;
35
+ const branchName = process.env.VERCEL_GIT_COMMIT_REF;
36
+ if (!vercelGitCommitMessage || !branchName) {
37
+ throw new Error('Fail to get vercel commit ref or branch name');
35
38
  }
36
- // extract the git suffix from the vercel git branch url
37
- // ex: zonos-elements-storybook-git-fix-e2e-cron-test-zonos.vercel.app => git-fix-e2e-cron-test-zonos.vercel.app
38
- const gitSuffix = (_a = /.*-git-(.*)/g.exec(vercelGitBranchUrl)) === null || _a === void 0 ? void 0 : _a[1];
39
- if (!gitSuffix) {
40
- throw new Error(`Fail to get git suffix from url ${url}`);
41
- }
42
- // replace the git suffix with the project name
43
39
  // get project name based on the `${url}`
44
40
  const isStorybook =
45
41
  // url: storybook.js.zonos.com
@@ -56,7 +52,12 @@ export const formattedUrl = ({ packageVersion: _packageVersion, type = 'full', u
56
52
  : isServerless
57
53
  ? 'zonos-elements-serverless'
58
54
  : 'zonos-elements';
59
- return `https://${projectName}-git-${gitSuffix}`;
55
+ // generate generated deploy url based on the branch name
56
+ const vercelGitBranchSuffix = generateVercelDeployUrl({
57
+ branchName,
58
+ projectName,
59
+ });
60
+ return `https://${vercelGitBranchSuffix}`;
60
61
  }
61
62
  // only require package version in production and in CI, so that we still can use dev url (no version prefix).
62
63
  if (!_packageVersion && (isVercelProd || inCI)) {
@@ -140,8 +141,16 @@ export const env = createEnv({
140
141
  * Env object that has all of native env variable used in code to replace them with
141
142
  * actual values from .env
142
143
  */
143
- export const getReplaceEnv = () => Object.keys(env).reduce((prev, curr) => {
144
+ export const getReplaceEnv = (props) => Object.keys(env).reduce((prev, curr) => {
144
145
  const currEnv = curr;
146
+ const override = props === null || props === void 0 ? void 0 : props.override;
147
+ const foundOverride = !!override && currEnv in override;
148
+ // return the override value if it's found
149
+ if (foundOverride) {
150
+ // @ts-expect-error
151
+ prev[`process.env.${currEnv}`] = `"${override[currEnv]}"`;
152
+ return prev;
153
+ }
145
154
  if (currEnv) {
146
155
  // @ts-expect-error
147
156
  prev[`process.env.${currEnv}`] = `"${env[currEnv] || ''}"`;
@@ -2,7 +2,42 @@ var _a;
2
2
  import { log } from "../components/utils/logging/log";
3
3
  import { logError } from "../components/utils/logging/logError";
4
4
  import { zonosLoadStripe } from "./loadStripe";
5
- const ZONOS_URL = process.env.NEXT_PUBLIC_ZONOS_CDN_URL;
5
+ // 3 hours
6
+ const EXPIRED_QA_TIME = 3 * 60 * 60 * 1000;
7
+ // validate the time format (yyyymmddhhmmss) in the qa params if exceeds 1 hour, don't use qa
8
+ const isZonosQa = (() => {
9
+ const zonosQaTime = window.location.search.match(/\?.*(&*)zonosQa=(\d+)/);
10
+ if (!zonosQaTime) {
11
+ return false;
12
+ }
13
+ const [, , zonosQaTimeExtracted] = zonosQaTime;
14
+ if (!zonosQaTimeExtracted) {
15
+ return false;
16
+ }
17
+ const zonosQaTimeValue = parseInt(zonosQaTimeExtracted, 10);
18
+ const now = new Date();
19
+ const nowTime = now.getTime();
20
+ const isValid = nowTime - zonosQaTimeValue < EXPIRED_QA_TIME;
21
+ if (isValid) {
22
+ // Zonos class is not available in here yet, so we use console.warn instead of log util
23
+ // eslint-disable-next-line no-console
24
+ console.warn(`[ZONOS-WARNING] USING DEBUG DOMAIN, THIS IS ONLY FOR ZONOS DEVELOPER TO DEBUG, PLEASE REMOVE zonosQa=xxx OUT OF URL IF YOU DON'T KNOW WHAT YOU'RE DOING`);
25
+ }
26
+ else {
27
+ // Zonos class is not available in here yet, so we use console.warn instead of log util
28
+ // eslint-disable-next-line no-console
29
+ console.warn(`[ZONOS-WARNING] QA DOMAIN IS EXPIRED, USING PRODUCTION DOMAIN NOW`);
30
+ // remove the zonosQa param from url
31
+ const urlSearchParams = new URLSearchParams(window.location.search);
32
+ urlSearchParams.delete('zonosQa');
33
+ const newUrl = `${window.location.pathname}?${urlSearchParams.toString()}`;
34
+ window.history.replaceState({}, '', newUrl);
35
+ }
36
+ return isValid;
37
+ })();
38
+ const ZONOS_URL = isZonosQa
39
+ ? 'https://debug.js.zonos.com'
40
+ : process.env.NEXT_PUBLIC_ZONOS_CDN_URL;
6
41
  const UNPKG_ZONOS_URL = process.env.NEXT_PUBLIC_ZONOS_UNPKG_CDN_URL;
7
42
  const INTER_FONT_URL = 'https://rsms.me';
8
43
  const INTER_FONT_REGEX = /^https:\/\/rsms\.me\/inter\/inter\.css(.*)$/;
@@ -15,6 +50,7 @@ Zonos.debug = !!window.location.search.match(/\?.*(&*)zonosDebug=1/);
15
50
  Zonos.isBigCommerce = false;
16
51
  Zonos.internationalHideSelector = '';
17
52
  Zonos.version = `v${process.env.NEXT_PUBLIC_ZONOS_PACKAGE_VERSION}`;
53
+ Zonos.getCurrentTimestamp = () => new Date().getTime();
18
54
  Zonos.init = async ({ appearance, checkoutSettings, currencyConverter, helloSettings, zonosApiKey, }) => {
19
55
  if (Zonos.doneInit) {
20
56
  // do nothing if zonos is already initializeds
@@ -26,7 +62,6 @@ Zonos.init = async ({ appearance, checkoutSettings, currencyConverter, helloSett
26
62
  return;
27
63
  }
28
64
  _a.zonosApiKey = zonosApiKey;
29
- // eslint-disable-next-line no-console
30
65
  log('init zonos');
31
66
  // inject zonos cdn
32
67
  Zonos.injectZonosCdn();
@@ -56,10 +91,56 @@ Zonos.showNotification = (notification) => {
56
91
  const zonosController = document.querySelector('zonos-controller');
57
92
  void (zonosController === null || zonosController === void 0 ? void 0 : zonosController.showNotification(notification));
58
93
  };
94
+ Zonos.disablePlaceOrderButtons = ({ autoEnable = true, disable, placeOrderButtonSelector, }) => {
95
+ // if placeOrderAnchor is passed in the config for checkoutSettings, disable the place order button until zonos is initialized
96
+ if (placeOrderButtonSelector) {
97
+ const placeOrderButton = document.querySelectorAll(placeOrderButtonSelector);
98
+ const disableEvent = (e) => {
99
+ const target = e.target;
100
+ // prevent default and propagation when the item has disabled attribute
101
+ if (target.getAttribute('disabled')) {
102
+ e.preventDefault();
103
+ e.stopPropagation();
104
+ }
105
+ };
106
+ placeOrderButton.forEach(button => {
107
+ if (disable) {
108
+ button.setAttribute('disabled', 'true');
109
+ // prevent the selector to perform default action when it's disabled
110
+ button.addEventListener('click', disableEvent);
111
+ }
112
+ else {
113
+ button.removeAttribute('disabled');
114
+ // clean up the event listener
115
+ button.removeEventListener('click', disableEvent);
116
+ }
117
+ });
118
+ // only auto enable if autoEnable is true and we are setting button disable
119
+ if (autoEnable && disable) {
120
+ setTimeout(() => {
121
+ // release it if zonos is not initialized after 5 seconds (this is to prevent the place order button from being disabled forever due to api)
122
+ placeOrderButton.forEach(button => {
123
+ button.removeAttribute('disabled');
124
+ // clean up the event listener if exists
125
+ button.removeEventListener('click', disableEvent);
126
+ });
127
+ }, 5000);
128
+ }
129
+ }
130
+ };
59
131
  Zonos.injectController = ({ config, zonosApiKey, }) => {
132
+ var _b;
60
133
  if (document.querySelector('zonos-controller')) {
61
134
  return;
62
135
  }
136
+ // if placeOrderAnchor is passed in the config for checkoutSettings, disable the place order button until zonos is initialized
137
+ if ((_b = config.checkoutSettings) === null || _b === void 0 ? void 0 : _b.placeOrderButtonSelector) {
138
+ const placeOrderButtonSelector = config.checkoutSettings.placeOrderButtonSelector;
139
+ _a.disablePlaceOrderButtons({
140
+ disable: true,
141
+ placeOrderButtonSelector,
142
+ });
143
+ }
63
144
  const zonosController = document.createElement('zonos-controller');
64
145
  zonosController.config = config;
65
146
  zonosController.zonosApiKey = zonosApiKey;
@@ -167,7 +248,7 @@ Zonos.injectStylesheet = ({ fallBackDomain, stylesheetDomain, theRestUrl, }) =>
167
248
  };
168
249
  Zonos.injectZonosCss = () => {
169
250
  const findStyleLink = () => {
170
- return !!document.querySelector(`link[rel="stylesheet"][href^="${ZONOS_URL}/dist/zonos-elements/zonos-elements.css"]`);
251
+ return !!document.querySelector(`link[rel="stylesheet"][href*="/dist/zonos-elements/zonos-elements.css"]`);
171
252
  };
172
253
  if (findStyleLink()) {
173
254
  // eslint-disable-next-line no-console
@@ -1,5 +1,6 @@
1
- // eslint-disable-next-line import/no-extraneous-dependencies
2
- import sha256 from "crypto-js/sha256";
1
+ // For some reason, rollup couldn't bundle this file without specifying .js extension
2
+ // eslint-disable-next-line import/no-extraneous-dependencies, import/extensions
3
+ import sha256 from "crypto-js/sha256.js";
3
4
  /**
4
5
  * Generate a Vercel deploy URL based on the branch name and project name
5
6
  * @note not including https://
@@ -90,6 +90,7 @@ const { onChange: onChange$1, reset: reset$1, state: stripeStore, } = createStor
90
90
  stripeAddressEventData: null,
91
91
  stripeAddressUsedWhenFetchingLC: null,
92
92
  stripeElements: null,
93
+ stripeElementsOptions: null,
93
94
  stripeLinkElement: null,
94
95
  stripeLinkEventData: null,
95
96
  stripeLinkUsedWhenFetchingLC: null,
@@ -130,13 +131,22 @@ const initStripeElements = async (props) => {
130
131
  overridePrimaryColor: props === null || props === void 0 ? void 0 : props.overridePrimaryColor,
131
132
  overrideTheme: props === null || props === void 0 ? void 0 : props.overrideTheme,
132
133
  });
134
+ // compare with the previous options to see if we need to update
135
+ const isSameOptions = JSON.stringify(stripeOptions) ===
136
+ JSON.stringify(stripeStore.stripeElementsOptions);
133
137
  if (!stripeStore.stripeElements) {
134
138
  // init stripe elements if it doesn't exist
135
139
  stripeStore.stripeElements = (_a = stripeStore.stripe) === null || _a === void 0 ? void 0 : _a.elements(stripeOptions);
140
+ // save stripe elements options for later comparison
141
+ stripeStore.stripeElementsOptions = stripeOptions;
142
+ log('Stripe elements initialized');
143
+ return;
136
144
  }
137
- else {
145
+ if (!isSameOptions) {
138
146
  // update elements with new option if it already exists
139
147
  stripeStore.stripeElements.update(stripeOptions);
148
+ // save stripe elements options for later comparison
149
+ stripeStore.stripeElementsOptions = stripeOptions;
140
150
  }
141
151
  log('Stripe elements initialized');
142
152
  }
@@ -3196,18 +3196,23 @@ const getCountryLandedCost = async (countryCode) => {
3196
3196
 
3197
3197
  const getExchangeRate = async ({ country, isGuaranteed, sourceCurrency, targetCurrency, }) => {
3198
3198
  var _a;
3199
+ // If source currency matches target currency (US -> US) and is not a guaranteed rate, return null
3200
+ if (sourceCurrency === targetCurrency && !isGuaranteed) {
3201
+ return { exchangeRate: null, maxAge: null };
3202
+ }
3199
3203
  const url = `${"https://v1.route.js.zonos.com"}/api/exchange-rates?sourceCurrency=${sourceCurrency}&targetCurrency=${targetCurrency}&isGuaranteed=${isGuaranteed}&country=${country}}`;
3200
3204
  const { errors, json } = await handleFetch(url);
3201
3205
  if (errors.length || !json) {
3202
3206
  logError(`Error fetching country landed cost: ${(_a = errors.find(Boolean)) === null || _a === void 0 ? void 0 : _a.message}`);
3203
- return null;
3207
+ return { exchangeRate: null, maxAge: null };
3204
3208
  }
3205
- const { rate, targetFormat } = json.exchangeRateCreate;
3209
+ const { maxAge, rate, targetFormat } = json.exchangeRateCreate;
3206
3210
  if (rate) {
3207
3211
  sessionStorage.setItem(country + '_rate', JSON.stringify(rate));
3208
- return { rate, targetFormat };
3212
+ const exchangeRate = { rate, targetFormat };
3213
+ return { exchangeRate, maxAge };
3209
3214
  }
3210
- return null;
3215
+ return { exchangeRate: null, maxAge: null };
3211
3216
  };
3212
3217
 
3213
3218
  const getLocaleMessages = async ({ countryCode, localeTo, storeId, }) => {
@@ -3465,23 +3470,45 @@ const { state: localizationStore } = createStore({
3465
3470
  shippingZoneCountries: null,
3466
3471
  targetCurrency: 'USD',
3467
3472
  });
3473
+ const triggerGetExchangeRate = async (isGuaranteed) => {
3474
+ const { exchangeRate, maxAge } = await getExchangeRate({
3475
+ country: localizationStore.selectedCountryCode,
3476
+ isGuaranteed,
3477
+ sourceCurrency: zonosStore.sourceCurrency,
3478
+ targetCurrency: localizationStore.targetCurrency,
3479
+ });
3480
+ if (exchangeRate) {
3481
+ localizationStore.exchangeRate = exchangeRate;
3482
+ currencyDisplay();
3483
+ }
3484
+ return { maxAge };
3485
+ };
3486
+ // This recursive function is for users who step away from their computer and come back needing a new exchange rate
3487
+ const startExchangeRateTimeout = ({ isGuaranteed, maxAge, }) => {
3488
+ if (localizationStore.exchangeRateTimeout) {
3489
+ clearTimeout(localizationStore.exchangeRateTimeout);
3490
+ }
3491
+ // maxAge comes in seconds, convert to milliseconds
3492
+ const defaultMaxAge = 5 * 60;
3493
+ const maxAgeToUse = maxAge || defaultMaxAge;
3494
+ // Recursively set timeouts to get new exchange rates when the current one expires
3495
+ localizationStore.exchangeRateTimeout = setTimeout(async () => {
3496
+ const { maxAge: newMaxAge } = await triggerGetExchangeRate(isGuaranteed);
3497
+ startExchangeRateTimeout({ isGuaranteed, maxAge: newMaxAge });
3498
+ }, maxAgeToUse * 1000);
3499
+ };
3468
3500
  const getNewLocalization = async () => {
3469
3501
  log('get new localization store');
3470
3502
  const { isShippableCountry, selectedCountryCode } = localizationStore;
3471
- const isGuaranteed = zonosStore.checkoutSettings.visibilityStatus === 'ENABLED';
3472
3503
  if (zonosStore.helloSettings.currencyBehavior === 'DISABLED' ||
3473
3504
  !isShippableCountry ||
3474
3505
  !selectedCountryCode) {
3475
3506
  return;
3476
3507
  }
3477
- localizationStore.exchangeRate = await getExchangeRate({
3478
- country: localizationStore.selectedCountryCode,
3479
- isGuaranteed,
3480
- sourceCurrency: zonosStore.sourceCurrency,
3481
- targetCurrency: localizationStore.targetCurrency,
3482
- });
3483
- if (localizationStore.exchangeRate) {
3484
- currencyDisplay();
3508
+ if (zonosStore.sourceCurrency !== localizationStore.targetCurrency) {
3509
+ const isGuaranteed = zonosStore.checkoutSettings.visibilityStatus === 'ENABLED';
3510
+ const { maxAge } = await triggerGetExchangeRate(isGuaranteed);
3511
+ startExchangeRateTimeout({ isGuaranteed, maxAge });
3485
3512
  }
3486
3513
  localizationStore.countryLandedCost = await getCountryLandedCost(localizationStore.selectedCountryCode);
3487
3514
  };
@@ -34,6 +34,11 @@ const ZonosAddress = /*@__PURE__*/ proxyCustomElement(class ZonosAddress extends
34
34
  ? Object.values(shippableCountries).map(country => country.code)
35
35
  : [],
36
36
  contacts: this.defaultAddress ? [this.defaultAddress] : undefined,
37
+ defaultValues: {
38
+ address: {
39
+ country: localizationStore.selectedCountryCode || 'AL',
40
+ },
41
+ },
37
42
  display: {
38
43
  name: 'split',
39
44
  },
@@ -39,7 +39,7 @@ const MessageIcon = `<svg width="18" height="18" viewBox="0 0 18 18" fill="none"
39
39
 
40
40
  const RemoveIcon = `<svg color="var(--amino-gray-800)" fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="https://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10Z" data-is-secondary-color="true" fill="var(--amino-gray-200)" fill-rule="evenodd"></path><path clip-rule="evenodd" d="M8.293 8.293a1 1 0 0 1 1.414 0L12 10.586l2.293-2.293a1 1 0 1 1 1.414 1.414L13.414 12l2.293 2.293a1 1 0 0 1-1.414 1.414L12 13.414l-2.293 2.293a1 1 0 0 1-1.414-1.414L10.586 12 8.293 9.707a1 1 0 0 1 0-1.414Z" fill="currentColor" fill-rule="evenodd"></path></svg>`;
41
41
 
42
- const zonosCheckoutCss = ".sc-zonos-checkout-h{font-family:Inter;display:block}.sc-zonos-checkout-h img.sc-zonos-checkout{max-width:100%}.sc-zonos-checkout-h dl.sc-zonos-checkout,.sc-zonos-checkout-h dd.sc-zonos-checkout,.sc-zonos-checkout-h h1.sc-zonos-checkout,.sc-zonos-checkout-h h2.sc-zonos-checkout,.sc-zonos-checkout-h h3.sc-zonos-checkout,.sc-zonos-checkout-h h4.sc-zonos-checkout,.sc-zonos-checkout-h h5.sc-zonos-checkout,.sc-zonos-checkout-h h6.sc-zonos-checkout,.sc-zonos-checkout-h hr.sc-zonos-checkout,.sc-zonos-checkout-h figure.sc-zonos-checkout,.sc-zonos-checkout-h p.sc-zonos-checkout,.sc-zonos-checkout-h pre.sc-zonos-checkout{margin:0}.sc-zonos-checkout-h{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}.sc-zonos-checkout-h *.sc-zonos-checkout::-webkit-scrollbar{width:10px}.sc-zonos-checkout-h *.sc-zonos-checkout::-webkit-scrollbar-track{background:var(--amino-gray-50)}.sc-zonos-checkout-h *.sc-zonos-checkout::-webkit-scrollbar-thumb{border-radius:10px;background:#cccccc;border:3px solid transparent;background-clip:content-box}.sc-zonos-checkout-h *.sc-zonos-checkout::-webkit-scrollbar-thumb:hover{background:#d6d6d6}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout{display:-ms-flexbox;display:flex;height:100%;overflow:hidden;border-radius:var(--border-radius, var(--amino-radius-10))}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--left.sc-zonos-checkout,.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--right.sc-zonos-checkout{-ms-flex:1;flex:1;padding:var(--amino-space-48) var(--amino-space-56)}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--left.sc-zonos-checkout{background-color:var(--primary-color, var(--amino-gray-0));border-right:1px solid var(--amino-gray-200)}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--right.sc-zonos-checkout{background-color:var(--amino-gray-0);padding-bottom:var(--amino-space-80)}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout{width:100%;max-height:100%;height:100%;overflow:auto;-ms-flex-direction:column;flex-direction:column;background-color:var(--amino-gray-0);-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;padding:var(--amino-space-24);padding-bottom:50px}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout .zonos--header.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-align:center;align-items:center;width:100%}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout .zonos--header.sc-zonos-checkout img.sc-zonos-checkout{width:150px;min-width:150px}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout .zonos--logo.sc-zonos-checkout{margin-bottom:0}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout zonos-checkout-finish.sc-zonos-checkout{-ms-flex:1;flex:1}.sc-zonos-checkout-h .zonos--left.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.sc-zonos-checkout-h .zonos--left.sc-zonos-checkout .zonos--back-button.sc-zonos-checkout{margin-bottom:var(--amino-space-24)}.sc-zonos-checkout-h .zonos--left.sc-zonos-checkout .zonos--wrapper.sc-zonos-checkout{padding:0 var(--amino-space-8) var(--amino-space-8)}.sc-zonos-checkout-h .zonos--left.sc-zonos-checkout .zonos--payment-error-banner.sc-zonos-checkout{margin-top:var(--amino-space-24)}.sc-zonos-checkout-h .zonos--right.sc-zonos-checkout{position:relative}.sc-zonos-checkout-h .zonos--right.sc-zonos-checkout .zonos--close-button.sc-zonos-checkout{position:absolute;right:var(--amino-space-32);top:var(--amino-space-32)}.sc-zonos-checkout-h .zonos--footer.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-pack:end;justify-content:flex-end;-ms-flex-align:center;align-items:center;position:absolute;bottom:var(--amino-space-32);right:var(--amino-space-56);gap:var(--amino-space-8)}.sc-zonos-checkout-h .zonos--wrapper.sc-zonos-checkout{overflow:auto;max-height:100%;position:relative}.sc-zonos-checkout-h .flex--wrapper.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;max-height:100%}.sc-zonos-checkout-h .zonos--logo.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.sc-zonos-checkout-h .zonos--checkout-default-message.sc-zonos-checkout{margin-left:var(--amino-space-76);margin-bottom:var(--amino-space-8)}.preview.sc-zonos-checkout-h{min-width:500px;margin:auto}.preview.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout{border:var(--amino-border)}.preview.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout{padding:var(--amino-space-32)}.mobile.sc-zonos-checkout-h{min-width:auto}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;overflow:auto;border-radius:0;max-height:100%;height:100%;border:0}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--left.sc-zonos-checkout,.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--right.sc-zonos-checkout{padding:var(--amino-space-12)}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--left.sc-zonos-checkout{-ms-flex-order:2;order:2}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--right.sc-zonos-checkout{-ms-flex-order:1;order:1;padding-top:var(--amino-space-16)}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--right.sc-zonos-checkout .zonos--wrapper.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;gap:var(--amino-space-16);margin-top:var(--amino-space-24);border:var(--amino-border);border-radius:var(--border-radius, var(--amino-radius-10));background-color:var(--amino-gray-50);padding:var(--amino-space-12);margin-top:var(--amino-space-32)}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--wrapper.sc-zonos-checkout{max-height:100%}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--footer.sc-zonos-checkout{-ms-flex-order:3;order:3}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout{width:auto}.mobile.sc-zonos-checkout-h .zonos--cart-subtotal.sc-zonos-checkout{margin:0}.mobile.sc-zonos-checkout-h .zonos--footer.sc-zonos-checkout{bottom:0;left:0;padding:var(--amino-space-12);position:relative;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;background-color:var(--amino-gray-0)}";
42
+ const zonosCheckoutCss = ".sc-zonos-checkout-h{font-family:Inter;display:block}.sc-zonos-checkout-h img.sc-zonos-checkout{max-width:100%}.sc-zonos-checkout-h dl.sc-zonos-checkout,.sc-zonos-checkout-h dd.sc-zonos-checkout,.sc-zonos-checkout-h h1.sc-zonos-checkout,.sc-zonos-checkout-h h2.sc-zonos-checkout,.sc-zonos-checkout-h h3.sc-zonos-checkout,.sc-zonos-checkout-h h4.sc-zonos-checkout,.sc-zonos-checkout-h h5.sc-zonos-checkout,.sc-zonos-checkout-h h6.sc-zonos-checkout,.sc-zonos-checkout-h hr.sc-zonos-checkout,.sc-zonos-checkout-h figure.sc-zonos-checkout,.sc-zonos-checkout-h p.sc-zonos-checkout,.sc-zonos-checkout-h pre.sc-zonos-checkout{margin:0}.sc-zonos-checkout-h{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}.sc-zonos-checkout-h *.sc-zonos-checkout::-webkit-scrollbar{width:10px}.sc-zonos-checkout-h *.sc-zonos-checkout::-webkit-scrollbar-track{background:var(--amino-gray-50)}.sc-zonos-checkout-h *.sc-zonos-checkout::-webkit-scrollbar-thumb{border-radius:10px;background:#cccccc;border:3px solid transparent;background-clip:content-box}.sc-zonos-checkout-h *.sc-zonos-checkout::-webkit-scrollbar-thumb:hover{background:#d6d6d6}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout{display:-ms-flexbox;display:flex;height:100%;overflow:hidden;border-radius:var(--border-radius, var(--amino-radius-10))}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--left.sc-zonos-checkout,.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--right.sc-zonos-checkout{-ms-flex:1;flex:1;padding:var(--amino-space-48) var(--amino-space-56)}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--left.sc-zonos-checkout{background-color:var(--primary-color, var(--amino-gray-0));border-right:1px solid var(--amino-gray-200)}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--right.sc-zonos-checkout{background-color:var(--amino-gray-0);padding-bottom:var(--amino-space-80)}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout{width:100%;max-height:100%;height:100%;overflow:auto;-ms-flex-direction:column;flex-direction:column;background-color:var(--amino-gray-0);-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;padding:var(--amino-space-24);padding-bottom:50px}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout .zonos--header.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-align:center;align-items:center;width:100%}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout .zonos--header.sc-zonos-checkout img.sc-zonos-checkout{width:150px;min-width:150px}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout .zonos--logo.sc-zonos-checkout{margin-bottom:0}.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout zonos-checkout-finish.sc-zonos-checkout{-ms-flex:1;flex:1}.sc-zonos-checkout-h .zonos--left.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.sc-zonos-checkout-h .zonos--left.sc-zonos-checkout .zonos--back-button.sc-zonos-checkout{margin-bottom:var(--amino-space-24)}.sc-zonos-checkout-h .zonos--left.sc-zonos-checkout .zonos--wrapper.sc-zonos-checkout{padding:0 var(--amino-space-8) var(--amino-space-8)}.sc-zonos-checkout-h .zonos--left.sc-zonos-checkout .zonos--payment-error-banner.sc-zonos-checkout{margin-top:var(--amino-space-24)}.sc-zonos-checkout-h .zonos--right.sc-zonos-checkout{position:relative}.sc-zonos-checkout-h .zonos--right.sc-zonos-checkout .zonos--close-button.sc-zonos-checkout{position:absolute;right:var(--amino-space-24);top:var(--amino-space-24)}.sc-zonos-checkout-h .zonos--footer.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-pack:end;justify-content:flex-end;-ms-flex-align:center;align-items:center;position:absolute;bottom:var(--amino-space-32);right:var(--amino-space-56);gap:var(--amino-space-8)}.sc-zonos-checkout-h .zonos--wrapper.sc-zonos-checkout{overflow:auto;max-height:100%;position:relative}.sc-zonos-checkout-h .flex--wrapper.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;max-height:100%}.sc-zonos-checkout-h .zonos--logo.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.sc-zonos-checkout-h .zonos--checkout-default-message.sc-zonos-checkout{margin-left:var(--amino-space-76);margin-bottom:var(--amino-space-8)}.preview.sc-zonos-checkout-h{min-width:500px;margin:auto}.preview.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout{border:var(--amino-border)}.preview.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout{padding:var(--amino-space-32)}.mobile.sc-zonos-checkout-h{min-width:auto}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;overflow:auto;border-radius:0;max-height:100%;height:100%;border:0}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--left.sc-zonos-checkout,.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--right.sc-zonos-checkout{padding:var(--amino-space-12)}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--left.sc-zonos-checkout{-ms-flex-order:2;order:2}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--right.sc-zonos-checkout{-ms-flex-order:1;order:1;padding-top:var(--amino-space-16)}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--right.sc-zonos-checkout .zonos--wrapper.sc-zonos-checkout{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;gap:var(--amino-space-16);margin-top:var(--amino-space-24);border:var(--amino-border);border-radius:var(--border-radius, var(--amino-radius-10));background-color:var(--amino-gray-50);padding:var(--amino-space-12);margin-top:var(--amino-space-32)}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--wrapper.sc-zonos-checkout{max-height:100%}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--footer.sc-zonos-checkout{-ms-flex-order:3;order:3}.mobile.sc-zonos-checkout-h .zonos--content.sc-zonos-checkout .zonos--done.sc-zonos-checkout{width:auto}.mobile.sc-zonos-checkout-h .zonos--cart-subtotal.sc-zonos-checkout{margin:0}.mobile.sc-zonos-checkout-h .zonos--footer.sc-zonos-checkout{bottom:0;left:0;padding:var(--amino-space-12);position:relative;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;background-color:var(--amino-gray-0)}";
43
43
 
44
44
  const ZonosCheckout$1 = /*@__PURE__*/ proxyCustomElement(class ZonosCheckout extends HTMLElement {
45
45
  constructor() {
@@ -155,6 +155,8 @@ const ZonosCheckout$1 = /*@__PURE__*/ proxyCustomElement(class ZonosCheckout ext
155
155
  e.preventDefault();
156
156
  e.stopPropagation();
157
157
  log('zonos checkout button clicked');
158
+ // start loading
159
+ stripeStore.isFetchingSession = true;
158
160
  this.open = true;
159
161
  try {
160
162
  // buildCartDetail need to be catch since it may throw error
@@ -165,6 +167,8 @@ const ZonosCheckout$1 = /*@__PURE__*/ proxyCustomElement(class ZonosCheckout ext
165
167
  submitGtag('zonos-checkout-start');
166
168
  }
167
169
  catch (err) {
170
+ // stop loading
171
+ stripeStore.isFetchingSession = false;
168
172
  cartStoreUpdateToErrorState({
169
173
  messages: [
170
174
  translate("There's been an error creating your checkout session. Please reload and try again or contact support if the error persists"),
@@ -23,7 +23,7 @@ const injectCheckoutElement = () => {
23
23
  document.body.appendChild(newCheckoutElement);
24
24
  }
25
25
  };
26
- const initCheckout = async (config) => {
26
+ const initCheckout = (config) => {
27
27
  if (!config.placeOrderButtonSelector) {
28
28
  // do nothing if checkout button anchor is not set
29
29
  return;
@@ -64,6 +64,44 @@ const ZonosController$1 = /*@__PURE__*/ proxyCustomElement(class ZonosController
64
64
  this.__registerHost();
65
65
  this.__attachShadow();
66
66
  this.stripeInitEvent = createEvent(this, "stripeInitEvent", 7);
67
+ this.disablePlaceOrderButtons = ({ disable }) => {
68
+ const placeOrderButtonSelector = zonosStore.checkoutSettings.placeOrderButtonSelector;
69
+ if (!placeOrderButtonSelector) {
70
+ return;
71
+ }
72
+ const disableEvent = (e) => {
73
+ const target = e.target;
74
+ // prevent default and propagation when the item has disabled attribute
75
+ if (target.getAttribute('disabled')) {
76
+ e.preventDefault();
77
+ e.stopPropagation();
78
+ }
79
+ };
80
+ const placeOrderButton = document.querySelectorAll(placeOrderButtonSelector);
81
+ placeOrderButton.forEach(button => {
82
+ if (disable) {
83
+ button.setAttribute('disabled', 'true');
84
+ // prevent the selector to perform default action when it's disabled
85
+ button.addEventListener('click', disableEvent);
86
+ }
87
+ else {
88
+ button.removeAttribute('disabled');
89
+ // clean up the event listener
90
+ button.removeEventListener('click', disableEvent);
91
+ }
92
+ });
93
+ // only auto enable if autoEnable is true and the state is enable
94
+ if (disable) {
95
+ setTimeout(() => {
96
+ // release it if zonos is not initialized after 5 seconds (this is to prevent the place order button from being disabled forever due to api)
97
+ placeOrderButton.forEach(button => {
98
+ button.removeAttribute('disabled');
99
+ // clean up the event listener if exists
100
+ button.removeEventListener('click', disableEvent);
101
+ });
102
+ }, 5000);
103
+ }
104
+ };
67
105
  this.config = undefined;
68
106
  this.zonosApiKey = undefined;
69
107
  }
@@ -79,6 +117,10 @@ const ZonosController$1 = /*@__PURE__*/ proxyCustomElement(class ZonosController
79
117
  stripeStore.stripe = stripe;
80
118
  void initCheckout(zonosStore.checkoutSettings);
81
119
  log('init checkout element');
120
+ // enable place order button after checkout is loaded
121
+ this.disablePlaceOrderButtons({
122
+ disable: false,
123
+ });
82
124
  }
83
125
  /**
84
126
  * Init zonos notification
@@ -101,6 +143,10 @@ const ZonosController$1 = /*@__PURE__*/ proxyCustomElement(class ZonosController
101
143
  log('Failed to load zonos settings. This domain may not have access', 'warn');
102
144
  return;
103
145
  }
146
+ // disable place order button until checkout is loaded
147
+ this.disablePlaceOrderButtons({
148
+ disable: true,
149
+ });
104
150
  // init zonos notification
105
151
  this.initZonosNotification();
106
152
  // load default setting if fail to load user setting
@@ -1,5 +1,5 @@
1
1
  import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/core/internal/client';
2
- import { f as currencyConvertAndFormat, t as translate, b as localizationStore } from './localization.js';
2
+ import { j as currencyFormat, b as localizationStore, t as translate } from './localization.js';
3
3
  import { z as zonosStore } from './zonosStore.js';
4
4
  import { c as classes } from './classes.js';
5
5
  import { d as defineCustomElement$b } from './zonos-banner2.js';
@@ -97,18 +97,26 @@ const ZonosHelloDialog = /*@__PURE__*/ proxyCustomElement(class ZonosHelloDialog
97
97
  const { countryLandedCost, selectedCountryCode } = localizationStore;
98
98
  // Our Robby API spells deminimis wrong here
99
99
  const dutyDeminimis = (countryLandedCost === null || countryLandedCost === void 0 ? void 0 : countryLandedCost.dutyDeminimus)
100
- ? currencyConvertAndFormat(countryLandedCost.dutyDeminimus)
100
+ ? currencyFormat(countryLandedCost.dutyDeminimus)
101
101
  : null;
102
+ // If Canada, use 40 CAD (courier duty de minimis)
103
+ const dutyDeminimisToUse = localizationStore.selectedCountryCode === 'CA'
104
+ ? currencyFormat(40)
105
+ : dutyDeminimis;
102
106
  // If deminimis is undefined or null, assume it's $0
103
- const dutyDeMinimisMessage = dutyDeminimis
104
- ? `${translate('Spend')} ${dutyDeminimis} ${translate('duty free')}`
107
+ const dutyDeMinimisMessage = dutyDeminimisToUse
108
+ ? `${translate('Spend')} ${dutyDeminimisToUse} ${translate('duty free')}`
105
109
  : translate('Duties will apply to all orders');
106
110
  // Our Robby API spells deminimis wrong here
107
111
  const taxDeminimis = (countryLandedCost === null || countryLandedCost === void 0 ? void 0 : countryLandedCost.vatTaxDeminimus)
108
- ? currencyConvertAndFormat(countryLandedCost.vatTaxDeminimus)
112
+ ? currencyFormat(countryLandedCost.vatTaxDeminimus)
109
113
  : null;
110
- const taxDeMinimisMessage = taxDeminimis
111
- ? `${translate('Spend')} ${taxDeminimis} ${translate('tax free')}`
114
+ // If Canada, use 150 CAD (courier tax de minimis)
115
+ const taxDeminimisToUse = localizationStore.selectedCountryCode === 'CA'
116
+ ? currencyFormat(150)
117
+ : taxDeminimis;
118
+ const taxDeMinimisMessage = taxDeminimisToUse
119
+ ? `${translate('Spend')} ${taxDeminimisToUse} ${translate('tax free')}`
112
120
  : translate('Taxes will apply to all orders');
113
121
  const animateLeft = this.animateFromLeftOverride ||
114
122
  (this.dialogRef && getHasMoreSpaceOnRight(this.dialogRef));