@zonos/elements 1.4.1 → 1.5.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.
- package/dist/cjs/index.cjs.js +7 -7
- package/dist/cjs/zonos-cart-items_12.cjs.entry.js +66 -3
- package/dist/cjs/zonos-checkout.cjs.entry.js +97 -10
- package/dist/collection/components/checkout/zonos-checkout/zonos-cart-items/zonos-cart-items.css +10 -0
- package/dist/collection/components/checkout/zonos-checkout/zonos-cart-items/zonos-cart-items.js +6 -2
- package/dist/collection/components/checkout/zonos-checkout/zonos-checkout.js +7 -10
- package/dist/collection/components/utils/checkout/isBigCommerceCheckoutBypassEnabled.js +74 -0
- package/dist/collection/components/utils/checkout/isHostedVsNativeTestAllowed.js +13 -0
- package/dist/collection/components/utils/checkout/itemCustomization.js +53 -0
- package/dist/collection/components/utils/checkout/parseItemCustomizations.js +6 -0
- package/dist/collection/components/utils/checkout/watchImmediateBigcommerceDomesticCheckoutRedirect.js +8 -0
- package/dist/collection/types/checkout/itemCustomization.js +1 -0
- package/dist/collection/types/index.js +1 -0
- package/dist/esm/index.js +7 -7
- package/dist/esm/zonos-cart-items_12.entry.js +66 -3
- package/dist/esm/zonos-checkout.entry.js +97 -10
- package/dist/esm-es5/index.js +4 -4
- package/dist/esm-es5/zonos-cart-items_12.entry.js +23 -10
- package/dist/esm-es5/zonos-checkout.entry.js +44 -19
- package/dist/scripts/index.d.ts +14 -0
- package/dist/scripts/index.js +1 -1
- package/dist/scripts/loadZonos.js +1 -1
- package/dist/scripts/zonos.js +1 -1
- package/dist/types/components/utils/checkout/isBigCommerceCheckoutBypassEnabled.d.ts +11 -0
- package/dist/types/components/utils/checkout/isHostedVsNativeTestAllowed.d.ts +11 -0
- package/dist/types/components/utils/checkout/itemCustomization.d.ts +23 -0
- package/dist/types/components/utils/checkout/parseItemCustomizations.d.ts +7 -0
- package/dist/types/types/checkout/CheckoutConfig.d.ts +14 -0
- package/dist/types/types/checkout/itemCustomization.d.ts +4 -0
- package/dist/types/types/index.d.ts +1 -0
- package/dist/zonos-elements/index.esm.js +1 -1
- package/dist/zonos-elements/p-30b3c9d3.entry.js +1 -0
- package/dist/zonos-elements/p-5873ab8e.entry.js +1 -0
- package/dist/zonos-elements/{p-5236c676.system.entry.js → p-7f031592.system.entry.js} +84 -59
- package/dist/zonos-elements/p-Bu9WCfUC.system.js +1 -1
- package/dist/zonos-elements/{p-DPZSD7Kg.system.js → p-CXxvn4GX.system.js} +4 -4
- package/dist/zonos-elements/{p-5016d71b.system.entry.js → p-d82fd8a9.system.entry.js} +68 -54
- package/dist/zonos-elements/zonos-elements.esm.js +1 -1
- package/item-customization.d.ts +25 -0
- package/item-customization.js +52 -0
- package/package.json +7 -4
- package/dist/zonos-elements/p-34656e6c.entry.js +0 -1
- package/dist/zonos-elements/p-f8b50aa0.entry.js +0 -1
package/dist/cjs/index.cjs.js
CHANGED
|
@@ -131,7 +131,7 @@ const getZonosQaUrl = () => {
|
|
|
131
131
|
return null;
|
|
132
132
|
}
|
|
133
133
|
const qaUrl = extractZonosQaUrl(window.location.href);
|
|
134
|
-
const cdnUrl = "https://v1.
|
|
134
|
+
const cdnUrl = "https://v1.5.0.js.zonos.com";
|
|
135
135
|
// when the qaUrl is not set and the built URL is from the test domain, use the test domain for testing
|
|
136
136
|
if (!qaUrl &&
|
|
137
137
|
(cdnUrl.includes('test.') ||
|
|
@@ -420,10 +420,10 @@ const zonosLoadUrl = (() => {
|
|
|
420
420
|
return null;
|
|
421
421
|
})();
|
|
422
422
|
const startLoadTime = Date.now();
|
|
423
|
-
const ZONOS_URL = "https://v1.
|
|
424
|
-
const JS_DELIVR_ZONOS_URL = zonosLoadUrl || "https://cdn.jsdelivr.net/npm/@zonos/elements@1.
|
|
425
|
-
const UNPKG_ZONOS_URL = "https://unpkg.com/@zonos/elements@1.
|
|
426
|
-
const CDNJS_ZONOS_URL = "https://cdnjs.cloudflare.com/ajax/libs/zonos-elements/1.
|
|
423
|
+
const ZONOS_URL = "https://v1.5.0.js.zonos.com";
|
|
424
|
+
const JS_DELIVR_ZONOS_URL = zonosLoadUrl || "https://cdn.jsdelivr.net/npm/@zonos/elements@1.5.0";
|
|
425
|
+
const UNPKG_ZONOS_URL = "https://unpkg.com/@zonos/elements@1.5.0";
|
|
426
|
+
const CDNJS_ZONOS_URL = "https://cdnjs.cloudflare.com/ajax/libs/zonos-elements/1.5.0";
|
|
427
427
|
const GOOGLE_FONT_URL = 'https://fonts.googleapis.com';
|
|
428
428
|
const GOOGLE_FONT_REGEX = /^https:\/\/fonts\.googleapis\.com/;
|
|
429
429
|
class Zonos {
|
|
@@ -441,7 +441,7 @@ Zonos.iframeLogType = typeof window !== 'undefined'
|
|
|
441
441
|
? new URLSearchParams(window.location.search).get('iframeLogType')
|
|
442
442
|
: null;
|
|
443
443
|
Zonos.isBigCommerce = false;
|
|
444
|
-
Zonos.releaseDate = "
|
|
444
|
+
Zonos.releaseDate = "1792773585238";
|
|
445
445
|
Zonos.isLegacyCheckout = false;
|
|
446
446
|
Zonos.googleAnalyticId = null;
|
|
447
447
|
Zonos.googleAnalyticReady = false;
|
|
@@ -466,7 +466,7 @@ Zonos.isNpm = true;
|
|
|
466
466
|
Zonos.zonosQaUrl = null;
|
|
467
467
|
Zonos.zonosQaUrlApi = null;
|
|
468
468
|
Zonos.trackEventLogs = [];
|
|
469
|
-
Zonos.version = `v${"1.
|
|
469
|
+
Zonos.version = `v${"1.5.0"}`;
|
|
470
470
|
Zonos.modeAlerted = false;
|
|
471
471
|
Zonos.cartData = null;
|
|
472
472
|
Zonos.paypal = null;
|
|
@@ -30,7 +30,67 @@ require('./debounce-Cd2emZPn.js');
|
|
|
30
30
|
require('./debounce-vY0QYT6o.js');
|
|
31
31
|
require('./ShortAddressCode-C5l520-F.js');
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Import-free so `scripts/buildItemCustomization.mjs` can emit one module.
|
|
35
|
+
* demo-app imports the generated `item-customization.js`, not this file.
|
|
36
|
+
*/
|
|
37
|
+
const ITEM_CUSTOMIZATION_ATTRIBUTE_KEY = 'itemCustomization';
|
|
38
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
39
|
+
/** Drops an empty name, a non-string value, and the unselected value "0". */
|
|
40
|
+
const readDisplayableItemCustomization = (value) => {
|
|
41
|
+
if (!isRecord(value)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const { name } = value;
|
|
45
|
+
if (typeof name !== 'string' || name === '') {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const choiceValue = value.value;
|
|
49
|
+
if (typeof choiceValue !== 'string' || choiceValue === '0') {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
name,
|
|
54
|
+
value: choiceValue,
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
const parseJson = (value) => {
|
|
58
|
+
try {
|
|
59
|
+
// The generated package entry cannot import the shared jsonParse helper.
|
|
60
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
61
|
+
return JSON.parse(value);
|
|
62
|
+
}
|
|
63
|
+
catch (_a) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
/** Selected customization entries, with the original object for extra ids. */
|
|
68
|
+
const readItemCustomizationEntries = (attributes) => {
|
|
69
|
+
var _a;
|
|
70
|
+
const rawValue = (_a = attributes === null || attributes === void 0 ? void 0 : attributes.find(attribute => (attribute === null || attribute === void 0 ? void 0 : attribute.key) === ITEM_CUSTOMIZATION_ATTRIBUTE_KEY)) === null || _a === void 0 ? void 0 : _a.value;
|
|
71
|
+
if (!rawValue) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const parsed = parseJson(rawValue);
|
|
75
|
+
if (!Array.isArray(parsed)) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
return parsed.flatMap(entry => {
|
|
79
|
+
const choice = readDisplayableItemCustomization(entry);
|
|
80
|
+
if (!choice || !isRecord(entry)) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
return [{ choice, raw: entry }];
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Reads a cart row's `itemCustomization` attribute into display pairs.
|
|
89
|
+
* Unreadable data is an empty list.
|
|
90
|
+
*/
|
|
91
|
+
const parseItemCustomizations = (attributes) => readItemCustomizationEntries(attributes).map(entry => entry.choice);
|
|
92
|
+
|
|
93
|
+
const zonosCartItemsCss = () => `:host{font-family:var(--zonos--font-family, Inter), Inter;display:block;white-space:normal}:host *{font-family:var(--zonos--font-family, Inter), Inter}:host img{max-width:100%}:host dl,:host dd,:host h1,:host h2,:host h3,:host h4,:host h5,:host h6,:host hr,:host figure,:host p,:host pre{margin:0}:host{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}:host .zonos--cart-table{width:100%;border:none;border-collapse:collapse;overflow:auto;font-size:var(--zonos-elements-font-size-base)}:host .zonos--cart-table .zonos--column{padding:8px;font-size:var(--zonos-elements-font-size-base)}:host .zonos--cart-table .zonos--column:last-child{text-align:right}:host .zonos--cart-table .zonos--column:first-child{width:60px}:host .zonos--cart-table td{vertical-align:top}:host .zonos--cart-item-name{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;gap:12px}:host .zonos--cart-item-name .zonos--cart-item-choices{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;gap:4px;min-width:0}:host .zonos--cart-item-name .zonos--cart-item-choices zonos-text{overflow-wrap:break-word;white-space:normal}:host .zonos--cart-item-name .zonos--cart-item-quantity>*{display:inline-block}:host .zonos--cart-item-price zonos-text{white-space:nowrap}:host img{min-width:40px;margin-top:6px}`;
|
|
34
94
|
|
|
35
95
|
const ZonosCartItems = class {
|
|
36
96
|
constructor(hostRef) {
|
|
@@ -40,15 +100,18 @@ const ZonosCartItems = class {
|
|
|
40
100
|
render() {
|
|
41
101
|
const emptyItemImg = index.getAssetPath('./assets/empty-item.jpeg');
|
|
42
102
|
const nonRestrictedItems = cart.cartStore.items.filter(item => !item.isRestricted);
|
|
43
|
-
return (index.h(index.Host, { key: '
|
|
103
|
+
return (index.h(index.Host, { key: 'eeb10f76fbab43d256e6130fe2ab88a33c1598aa', class: "zonos--cart-items zonos--elements" }, index.h("table", { key: '61ae44a57c1386f5ca6afb17c388ae9fcf29d8a1', class: "zonos--cart-table" }, index.h("tbody", { key: '8471ae46186543cee754685e0182c4057d982967' }, nonRestrictedItems.map(item => {
|
|
44
104
|
const itemImg = item.imageUrl;
|
|
45
105
|
const cleanedItemNames = cleanHtmlMarkdown.cleanHtmlMarkdown(item.name);
|
|
106
|
+
const choices = parseItemCustomizations(item.attributes);
|
|
46
107
|
const amount = item.amount * item.quantity;
|
|
47
108
|
return (index.h("tr", { class: "zonos--cart-item" }, index.h("td", { class: "zonos--column zonos--cart-item-image" }, itemImg && !this.errorImages.includes(itemImg) ? (index.h("img", { alt: item.name, onError: () => {
|
|
48
109
|
this.errorImages = [...this.errorImages, itemImg];
|
|
49
110
|
}, src: item.imageUrl, style: {
|
|
50
111
|
'min-width': '40px',
|
|
51
|
-
}, width: 40 })) : (index.h("img", { alt: item.name, src: emptyItemImg, width: 40 }))), index.h("td", { class: "zonos--column zonos--cart-item-name" }, index.h("div", null, cleanedItemNames.map(name => (index.h("zonos-text", { type: "label" }, name)))),
|
|
112
|
+
}, width: 40 })) : (index.h("img", { alt: item.name, src: emptyItemImg, width: 40 }))), index.h("td", { class: "zonos--column zonos--cart-item-name" }, index.h("div", null, cleanedItemNames.map(name => (index.h("zonos-text", { type: "label" }, name)))), choices.length > 0 && (index.h("div", { class: "zonos--cart-item-choices" }, choices.map(choice => (index.h("zonos-text", { textColor: "gray-600", type: "caption" }, choice.value === ''
|
|
113
|
+
? choice.name
|
|
114
|
+
: `${choice.name}: ${choice.value}`))))), index.h("zonos-text", { textColor: "gray-600", type: "caption" }, localization.translate('Quantity'), ": ", item.quantity)), index.h("td", { class: "zonos--column zonos--cart-item-price" }, index.h("zonos-text", { type: "semiBoldLabel", weight: 600 }, renderCheckoutCurrency.renderCheckoutCurrency({
|
|
52
115
|
amount,
|
|
53
116
|
isForeign: false,
|
|
54
117
|
})))));
|
|
@@ -675,6 +675,20 @@ const isDisabledCountry = (showLog = true) => {
|
|
|
675
675
|
return false;
|
|
676
676
|
};
|
|
677
677
|
|
|
678
|
+
/**
|
|
679
|
+
* BigCommerce checkout depends on storefront callbacks (clear cart, inventory).
|
|
680
|
+
* The hosted variant leaves the storefront, so the test does not apply there.
|
|
681
|
+
*/
|
|
682
|
+
const isHostedVsNativeTestAllowed = ({ createCartId, enabledTestKeys, isBigCommerce, }) => {
|
|
683
|
+
if (isBigCommerce) {
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
if (typeof createCartId !== 'function') {
|
|
687
|
+
return false;
|
|
688
|
+
}
|
|
689
|
+
return enabledTestKeys.includes('hosted_vs_native');
|
|
690
|
+
};
|
|
691
|
+
|
|
678
692
|
const isShippableCountry = (showLog = true,
|
|
679
693
|
/**
|
|
680
694
|
* If provided, will check if the country is shippable based on the provided country code instead of the Hello selected country code
|
|
@@ -700,6 +714,76 @@ providedCountryCode) => {
|
|
|
700
714
|
return true;
|
|
701
715
|
};
|
|
702
716
|
|
|
717
|
+
const ZBYPASS_ON_VALUES = ['1', 'true', 'yes'];
|
|
718
|
+
/**
|
|
719
|
+
* Page-load result of reading the checkout `zBypass` query. Later calls on the
|
|
720
|
+
* same checkout URL reuse this so stripping the parameter does not change the
|
|
721
|
+
* answer.
|
|
722
|
+
*/
|
|
723
|
+
let consumedZBypassQuery = null;
|
|
724
|
+
const isCheckoutPage = () => {
|
|
725
|
+
return window.location.pathname.includes('/checkout');
|
|
726
|
+
};
|
|
727
|
+
const isAcceptedZBypassQuery = (rawValue) => {
|
|
728
|
+
if (rawValue === null) {
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
return ZBYPASS_ON_VALUES.includes(rawValue.trim().toLowerCase());
|
|
732
|
+
};
|
|
733
|
+
/**
|
|
734
|
+
* True only when zonos-settings set
|
|
735
|
+
* `checkoutSettings.plugins.bigcommerce.allowBypassQuery` to `true`.
|
|
736
|
+
*/
|
|
737
|
+
const isBypassQueryAllowed = () => {
|
|
738
|
+
var _a, _b;
|
|
739
|
+
return (((_b = (_a = zonosStore.zonosStore.checkoutSettings.plugins) === null || _a === void 0 ? void 0 : _a.bigcommerce) === null || _b === void 0 ? void 0 : _b.allowBypassQuery) === true);
|
|
740
|
+
};
|
|
741
|
+
/**
|
|
742
|
+
* Read an accepted `zBypass` query on the checkout page once, then remove it
|
|
743
|
+
* from the URL. A later call on that same URL returns the same answer.
|
|
744
|
+
*/
|
|
745
|
+
const readCheckoutZBypassQuery = () => {
|
|
746
|
+
const { pathname, search } = window.location;
|
|
747
|
+
if (consumedZBypassQuery &&
|
|
748
|
+
consumedZBypassQuery.pathname === pathname &&
|
|
749
|
+
consumedZBypassQuery.search === search) {
|
|
750
|
+
return consumedZBypassQuery.enabled;
|
|
751
|
+
}
|
|
752
|
+
const params = new URLSearchParams(search);
|
|
753
|
+
const accepted = isAcceptedZBypassQuery(params.get('zBypass'));
|
|
754
|
+
if (!accepted) {
|
|
755
|
+
consumedZBypassQuery = { enabled: false, pathname, search };
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
params.delete('zBypass');
|
|
759
|
+
const nextSearch = params.toString();
|
|
760
|
+
const hash = window.location.hash || '';
|
|
761
|
+
const nextUrl = `${pathname}${nextSearch ? `?${nextSearch}` : ''}${hash}`;
|
|
762
|
+
window.history.replaceState(window.history.state, document.title, nextUrl);
|
|
763
|
+
const enabled = isBypassQueryAllowed();
|
|
764
|
+
consumedZBypassQuery = {
|
|
765
|
+
enabled,
|
|
766
|
+
pathname,
|
|
767
|
+
search: window.location.search,
|
|
768
|
+
};
|
|
769
|
+
return enabled;
|
|
770
|
+
};
|
|
771
|
+
/**
|
|
772
|
+
* True when this BigCommerce checkout page should skip address detection.
|
|
773
|
+
* That is only when zonos-settings allows the `zBypass` query and this
|
|
774
|
+
* checkout URL has an accepted value. Storefront pages are never bypassed, so
|
|
775
|
+
* the query stays in the URL until checkout. The query is removed once, and
|
|
776
|
+
* later calls on that checkout URL keep the same answer. Nothing is written
|
|
777
|
+
* to storage.
|
|
778
|
+
*/
|
|
779
|
+
const isBigCommerceCheckoutBypassEnabled = () => {
|
|
780
|
+
var _a;
|
|
781
|
+
if (!((_a = window.Zonos) === null || _a === void 0 ? void 0 : _a.isBigCommerce) || !isCheckoutPage()) {
|
|
782
|
+
return false;
|
|
783
|
+
}
|
|
784
|
+
return readCheckoutZBypassQuery();
|
|
785
|
+
};
|
|
786
|
+
|
|
703
787
|
const FALLBACK_SHIP_TO_COUNTRY_SELECTOR = 'select[name="shippingAddress.countryCode"]';
|
|
704
788
|
/**
|
|
705
789
|
* Native BigCommerce shipping-step "Continue" button. Clicking it commits the
|
|
@@ -800,6 +884,13 @@ const watchImmediateBigcommerceDomesticCheckoutRedirect = ({ domesticRedirectedB
|
|
|
800
884
|
if (!window.Zonos.isBigCommerce) {
|
|
801
885
|
return;
|
|
802
886
|
}
|
|
887
|
+
// Only the native checkout page skips address detection. Storefront pages
|
|
888
|
+
// still run the domestic-session handoff below, and they do not consume
|
|
889
|
+
// a `zBypass` query, so the parameter can survive until `/checkout`.
|
|
890
|
+
if (window.location.pathname.includes('/checkout') &&
|
|
891
|
+
isBigCommerceCheckoutBypassEnabled()) {
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
803
894
|
/**
|
|
804
895
|
* Keep checking.
|
|
805
896
|
* @returns `true` if the caller should stop polling — either because the user
|
|
@@ -1605,16 +1696,12 @@ const ZonosCheckout = class {
|
|
|
1605
1696
|
};
|
|
1606
1697
|
};
|
|
1607
1698
|
this.shouldAllowHostedVsNativeTest = () => {
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
if (!hostedVsNativeTest) {
|
|
1615
|
-
return false;
|
|
1616
|
-
}
|
|
1617
|
-
return true;
|
|
1699
|
+
var _a;
|
|
1700
|
+
return isHostedVsNativeTestAllowed({
|
|
1701
|
+
createCartId: zonosStore.zonosStore.checkoutSettings.createCartId,
|
|
1702
|
+
enabledTestKeys: zonosStore.zonosStore.enabledVariantTestKeys,
|
|
1703
|
+
isBigCommerce: Boolean((_a = window.Zonos) === null || _a === void 0 ? void 0 : _a.isBigCommerce),
|
|
1704
|
+
});
|
|
1618
1705
|
};
|
|
1619
1706
|
// Register test hosted vs native if needed to get the variant selection for this test
|
|
1620
1707
|
this.registerTestHostedVsNative = async () => {
|
package/dist/collection/components/checkout/zonos-checkout/zonos-cart-items/zonos-cart-items.css
CHANGED
|
@@ -56,6 +56,16 @@
|
|
|
56
56
|
flex-direction: column;
|
|
57
57
|
gap: 12px;
|
|
58
58
|
}
|
|
59
|
+
:host .zonos--cart-item-name .zonos--cart-item-choices {
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
gap: 4px;
|
|
63
|
+
min-width: 0;
|
|
64
|
+
}
|
|
65
|
+
:host .zonos--cart-item-name .zonos--cart-item-choices zonos-text {
|
|
66
|
+
overflow-wrap: break-word;
|
|
67
|
+
white-space: normal;
|
|
68
|
+
}
|
|
59
69
|
:host .zonos--cart-item-name .zonos--cart-item-quantity > * {
|
|
60
70
|
display: inline-block;
|
|
61
71
|
}
|
package/dist/collection/components/checkout/zonos-checkout/zonos-cart-items/zonos-cart-items.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getAssetPath, h, Host } from "@stencil/core";
|
|
2
2
|
import { cartStore } from "../../../store/checkout/cart";
|
|
3
3
|
import { translate } from "../../../store/translationStore";
|
|
4
|
+
import { parseItemCustomizations } from "../../../utils/checkout/parseItemCustomizations";
|
|
4
5
|
import { renderCheckoutCurrency } from "../../../utils/checkout/renderCheckoutCurrency";
|
|
5
6
|
import { cleanHtmlMarkdown } from "../../../utils/cleanHtmlMarkdown";
|
|
6
7
|
export class ZonosCartItems {
|
|
@@ -10,15 +11,18 @@ export class ZonosCartItems {
|
|
|
10
11
|
render() {
|
|
11
12
|
const emptyItemImg = getAssetPath('./assets/empty-item.jpeg');
|
|
12
13
|
const nonRestrictedItems = cartStore.items.filter(item => !item.isRestricted);
|
|
13
|
-
return (h(Host, { key: '
|
|
14
|
+
return (h(Host, { key: 'eeb10f76fbab43d256e6130fe2ab88a33c1598aa', class: "zonos--cart-items zonos--elements" }, h("table", { key: '61ae44a57c1386f5ca6afb17c388ae9fcf29d8a1', class: "zonos--cart-table" }, h("tbody", { key: '8471ae46186543cee754685e0182c4057d982967' }, nonRestrictedItems.map(item => {
|
|
14
15
|
const itemImg = item.imageUrl;
|
|
15
16
|
const cleanedItemNames = cleanHtmlMarkdown(item.name);
|
|
17
|
+
const choices = parseItemCustomizations(item.attributes);
|
|
16
18
|
const amount = item.amount * item.quantity;
|
|
17
19
|
return (h("tr", { class: "zonos--cart-item" }, h("td", { class: "zonos--column zonos--cart-item-image" }, itemImg && !this.errorImages.includes(itemImg) ? (h("img", { alt: item.name, onError: () => {
|
|
18
20
|
this.errorImages = [...this.errorImages, itemImg];
|
|
19
21
|
}, src: item.imageUrl, style: {
|
|
20
22
|
'min-width': '40px',
|
|
21
|
-
}, width: 40 })) : (h("img", { alt: item.name, src: emptyItemImg, width: 40 }))), h("td", { class: "zonos--column zonos--cart-item-name" }, h("div", null, cleanedItemNames.map(name => (h("zonos-text", { type: "label" }, name)))),
|
|
23
|
+
}, width: 40 })) : (h("img", { alt: item.name, src: emptyItemImg, width: 40 }))), h("td", { class: "zonos--column zonos--cart-item-name" }, h("div", null, cleanedItemNames.map(name => (h("zonos-text", { type: "label" }, name)))), choices.length > 0 && (h("div", { class: "zonos--cart-item-choices" }, choices.map(choice => (h("zonos-text", { textColor: "gray-600", type: "caption" }, choice.value === ''
|
|
24
|
+
? choice.name
|
|
25
|
+
: `${choice.name}: ${choice.value}`))))), h("zonos-text", { textColor: "gray-600", type: "caption" }, translate('Quantity'), ": ", item.quantity)), h("td", { class: "zonos--column zonos--cart-item-price" }, h("zonos-text", { type: "semiBoldLabel", weight: 600 }, renderCheckoutCurrency({
|
|
22
26
|
amount,
|
|
23
27
|
isForeign: false,
|
|
24
28
|
})))));
|
|
@@ -27,6 +27,7 @@ import { getIsStagingMode } from "../../utils/checkout/getIsStagingMode";
|
|
|
27
27
|
import { getIsTestMode } from "../../utils/checkout/getIsTestMode";
|
|
28
28
|
import { isCheckoutMobile } from "../../utils/checkout/isCheckoutMobile";
|
|
29
29
|
import { isDisabledCountry } from "../../utils/checkout/isDisabledCountry";
|
|
30
|
+
import { isHostedVsNativeTestAllowed } from "../../utils/checkout/isHostedVsNativeTestAllowed";
|
|
30
31
|
import { isShippableCountry } from "../../utils/checkout/isShippableCountry";
|
|
31
32
|
import { watchImmediateBigcommerceDomesticCheckoutRedirect } from "../../utils/checkout/watchImmediateBigcommerceDomesticCheckoutRedirect";
|
|
32
33
|
import { classes } from "../../utils/classes";
|
|
@@ -296,16 +297,12 @@ export class ZonosCheckout {
|
|
|
296
297
|
};
|
|
297
298
|
};
|
|
298
299
|
this.shouldAllowHostedVsNativeTest = () => {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if (!hostedVsNativeTest) {
|
|
306
|
-
return false;
|
|
307
|
-
}
|
|
308
|
-
return true;
|
|
300
|
+
var _a;
|
|
301
|
+
return isHostedVsNativeTestAllowed({
|
|
302
|
+
createCartId: zonosStore.checkoutSettings.createCartId,
|
|
303
|
+
enabledTestKeys: zonosStore.enabledVariantTestKeys,
|
|
304
|
+
isBigCommerce: Boolean((_a = window.Zonos) === null || _a === void 0 ? void 0 : _a.isBigCommerce),
|
|
305
|
+
});
|
|
309
306
|
};
|
|
310
307
|
// Register test hosted vs native if needed to get the variant selection for this test
|
|
311
308
|
this.registerTestHostedVsNative = async () => {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { zonosStore } from "../../store/zonosStore";
|
|
2
|
+
const ZBYPASS_ON_VALUES = ['1', 'true', 'yes'];
|
|
3
|
+
/**
|
|
4
|
+
* Page-load result of reading the checkout `zBypass` query. Later calls on the
|
|
5
|
+
* same checkout URL reuse this so stripping the parameter does not change the
|
|
6
|
+
* answer.
|
|
7
|
+
*/
|
|
8
|
+
let consumedZBypassQuery = null;
|
|
9
|
+
const isCheckoutPage = () => {
|
|
10
|
+
return window.location.pathname.includes('/checkout');
|
|
11
|
+
};
|
|
12
|
+
const isAcceptedZBypassQuery = (rawValue) => {
|
|
13
|
+
if (rawValue === null) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
return ZBYPASS_ON_VALUES.includes(rawValue.trim().toLowerCase());
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* True only when zonos-settings set
|
|
20
|
+
* `checkoutSettings.plugins.bigcommerce.allowBypassQuery` to `true`.
|
|
21
|
+
*/
|
|
22
|
+
const isBypassQueryAllowed = () => {
|
|
23
|
+
var _a, _b;
|
|
24
|
+
return (((_b = (_a = zonosStore.checkoutSettings.plugins) === null || _a === void 0 ? void 0 : _a.bigcommerce) === null || _b === void 0 ? void 0 : _b.allowBypassQuery) === true);
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Read an accepted `zBypass` query on the checkout page once, then remove it
|
|
28
|
+
* from the URL. A later call on that same URL returns the same answer.
|
|
29
|
+
*/
|
|
30
|
+
const readCheckoutZBypassQuery = () => {
|
|
31
|
+
const { pathname, search } = window.location;
|
|
32
|
+
if (consumedZBypassQuery &&
|
|
33
|
+
consumedZBypassQuery.pathname === pathname &&
|
|
34
|
+
consumedZBypassQuery.search === search) {
|
|
35
|
+
return consumedZBypassQuery.enabled;
|
|
36
|
+
}
|
|
37
|
+
const params = new URLSearchParams(search);
|
|
38
|
+
const accepted = isAcceptedZBypassQuery(params.get('zBypass'));
|
|
39
|
+
if (!accepted) {
|
|
40
|
+
consumedZBypassQuery = { enabled: false, pathname, search };
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
params.delete('zBypass');
|
|
44
|
+
const nextSearch = params.toString();
|
|
45
|
+
const hash = window.location.hash || '';
|
|
46
|
+
const nextUrl = `${pathname}${nextSearch ? `?${nextSearch}` : ''}${hash}`;
|
|
47
|
+
window.history.replaceState(window.history.state, document.title, nextUrl);
|
|
48
|
+
const enabled = isBypassQueryAllowed();
|
|
49
|
+
consumedZBypassQuery = {
|
|
50
|
+
enabled,
|
|
51
|
+
pathname,
|
|
52
|
+
search: window.location.search,
|
|
53
|
+
};
|
|
54
|
+
return enabled;
|
|
55
|
+
};
|
|
56
|
+
/** Clears the page-load query result. Tests use this between cases. */
|
|
57
|
+
export const resetBigCommerceCheckoutBypassCache = () => {
|
|
58
|
+
consumedZBypassQuery = null;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* True when this BigCommerce checkout page should skip address detection.
|
|
62
|
+
* That is only when zonos-settings allows the `zBypass` query and this
|
|
63
|
+
* checkout URL has an accepted value. Storefront pages are never bypassed, so
|
|
64
|
+
* the query stays in the URL until checkout. The query is removed once, and
|
|
65
|
+
* later calls on that checkout URL keep the same answer. Nothing is written
|
|
66
|
+
* to storage.
|
|
67
|
+
*/
|
|
68
|
+
export const isBigCommerceCheckoutBypassEnabled = () => {
|
|
69
|
+
var _a;
|
|
70
|
+
if (!((_a = window.Zonos) === null || _a === void 0 ? void 0 : _a.isBigCommerce) || !isCheckoutPage()) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return readCheckoutZBypassQuery();
|
|
74
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BigCommerce checkout depends on storefront callbacks (clear cart, inventory).
|
|
3
|
+
* The hosted variant leaves the storefront, so the test does not apply there.
|
|
4
|
+
*/
|
|
5
|
+
export const isHostedVsNativeTestAllowed = ({ createCartId, enabledTestKeys, isBigCommerce, }) => {
|
|
6
|
+
if (isBigCommerce) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
if (typeof createCartId !== 'function') {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
return enabledTestKeys.includes('hosted_vs_native');
|
|
13
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import-free so `scripts/buildItemCustomization.mjs` can emit one module.
|
|
3
|
+
* demo-app imports the generated `item-customization.js`, not this file.
|
|
4
|
+
*/
|
|
5
|
+
export const ITEM_CUSTOMIZATION_ATTRIBUTE_KEY = 'itemCustomization';
|
|
6
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
7
|
+
/** Drops an empty name, a non-string value, and the unselected value "0". */
|
|
8
|
+
export const readDisplayableItemCustomization = (value) => {
|
|
9
|
+
if (!isRecord(value)) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const { name } = value;
|
|
13
|
+
if (typeof name !== 'string' || name === '') {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const choiceValue = value.value;
|
|
17
|
+
if (typeof choiceValue !== 'string' || choiceValue === '0') {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
name,
|
|
22
|
+
value: choiceValue,
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
const parseJson = (value) => {
|
|
26
|
+
try {
|
|
27
|
+
// The generated package entry cannot import the shared jsonParse helper.
|
|
28
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
29
|
+
return JSON.parse(value);
|
|
30
|
+
}
|
|
31
|
+
catch (_a) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
/** Selected customization entries, with the original object for extra ids. */
|
|
36
|
+
export const readItemCustomizationEntries = (attributes) => {
|
|
37
|
+
var _a;
|
|
38
|
+
const rawValue = (_a = attributes === null || attributes === void 0 ? void 0 : attributes.find(attribute => (attribute === null || attribute === void 0 ? void 0 : attribute.key) === ITEM_CUSTOMIZATION_ATTRIBUTE_KEY)) === null || _a === void 0 ? void 0 : _a.value;
|
|
39
|
+
if (!rawValue) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
const parsed = parseJson(rawValue);
|
|
43
|
+
if (!Array.isArray(parsed)) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
return parsed.flatMap(entry => {
|
|
47
|
+
const choice = readDisplayableItemCustomization(entry);
|
|
48
|
+
if (!choice || !isRecord(entry)) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
return [{ choice, raw: entry }];
|
|
52
|
+
});
|
|
53
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { readItemCustomizationEntries, } from "./itemCustomization";
|
|
2
|
+
/**
|
|
3
|
+
* Reads a cart row's `itemCustomization` attribute into display pairs.
|
|
4
|
+
* Unreadable data is an empty list.
|
|
5
|
+
*/
|
|
6
|
+
export const parseItemCustomizations = (attributes) => readItemCustomizationEntries(attributes).map(entry => entry.choice);
|
|
@@ -5,6 +5,7 @@ import { fetchBigCommerceCheckout, fetchCheckoutId, } from "./bigcommerceStorefr
|
|
|
5
5
|
import { buildBigcommerceRedirectUrl } from "./buildBigcommerceRedirectUrl";
|
|
6
6
|
import { checkBigCommerceBypassCustomerGroup } from "./checkBigCommerceBypassCustomerGroup";
|
|
7
7
|
import { checkBigCommerceForceLogin } from "./checkBigCommerceForceLogin";
|
|
8
|
+
import { isBigCommerceCheckoutBypassEnabled } from "./isBigCommerceCheckoutBypassEnabled";
|
|
8
9
|
import { isShippableCountry } from "./isShippableCountry";
|
|
9
10
|
import { log } from "../logging/log";
|
|
10
11
|
import { logError } from "../logging/logError";
|
|
@@ -108,6 +109,13 @@ export const watchImmediateBigcommerceDomesticCheckoutRedirect = ({ domesticRedi
|
|
|
108
109
|
if (!window.Zonos.isBigCommerce) {
|
|
109
110
|
return;
|
|
110
111
|
}
|
|
112
|
+
// Only the native checkout page skips address detection. Storefront pages
|
|
113
|
+
// still run the domestic-session handoff below, and they do not consume
|
|
114
|
+
// a `zBypass` query, so the parameter can survive until `/checkout`.
|
|
115
|
+
if (window.location.pathname.includes('/checkout') &&
|
|
116
|
+
isBigCommerceCheckoutBypassEnabled()) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
111
119
|
/**
|
|
112
120
|
* Keep checking.
|
|
113
121
|
* @returns `true` if the caller should stop polling — either because the user
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -14,6 +14,7 @@ export * from './checkout/api/StoreDiscountEnabled';
|
|
|
14
14
|
export * from './checkout/api/ValidateAddress';
|
|
15
15
|
export * from './checkout/api/VarianceTest';
|
|
16
16
|
export * from './checkout/CheckoutConfig';
|
|
17
|
+
export * from './checkout/itemCustomization';
|
|
17
18
|
export * from './checkout/ShortAddressCode';
|
|
18
19
|
export * from './checkout/TaxId';
|
|
19
20
|
export * from './ConversionEvent';
|
package/dist/esm/index.js
CHANGED
|
@@ -131,7 +131,7 @@ const getZonosQaUrl = () => {
|
|
|
131
131
|
return null;
|
|
132
132
|
}
|
|
133
133
|
const qaUrl = extractZonosQaUrl(window.location.href);
|
|
134
|
-
const cdnUrl = "https://v1.
|
|
134
|
+
const cdnUrl = "https://v1.5.0.js.zonos.com";
|
|
135
135
|
// when the qaUrl is not set and the built URL is from the test domain, use the test domain for testing
|
|
136
136
|
if (!qaUrl &&
|
|
137
137
|
(cdnUrl.includes('test.') ||
|
|
@@ -420,10 +420,10 @@ const zonosLoadUrl = (() => {
|
|
|
420
420
|
return null;
|
|
421
421
|
})();
|
|
422
422
|
const startLoadTime = Date.now();
|
|
423
|
-
const ZONOS_URL = "https://v1.
|
|
424
|
-
const JS_DELIVR_ZONOS_URL = zonosLoadUrl || "https://cdn.jsdelivr.net/npm/@zonos/elements@1.
|
|
425
|
-
const UNPKG_ZONOS_URL = "https://unpkg.com/@zonos/elements@1.
|
|
426
|
-
const CDNJS_ZONOS_URL = "https://cdnjs.cloudflare.com/ajax/libs/zonos-elements/1.
|
|
423
|
+
const ZONOS_URL = "https://v1.5.0.js.zonos.com";
|
|
424
|
+
const JS_DELIVR_ZONOS_URL = zonosLoadUrl || "https://cdn.jsdelivr.net/npm/@zonos/elements@1.5.0";
|
|
425
|
+
const UNPKG_ZONOS_URL = "https://unpkg.com/@zonos/elements@1.5.0";
|
|
426
|
+
const CDNJS_ZONOS_URL = "https://cdnjs.cloudflare.com/ajax/libs/zonos-elements/1.5.0";
|
|
427
427
|
const GOOGLE_FONT_URL = 'https://fonts.googleapis.com';
|
|
428
428
|
const GOOGLE_FONT_REGEX = /^https:\/\/fonts\.googleapis\.com/;
|
|
429
429
|
class Zonos {
|
|
@@ -441,7 +441,7 @@ Zonos.iframeLogType = typeof window !== 'undefined'
|
|
|
441
441
|
? new URLSearchParams(window.location.search).get('iframeLogType')
|
|
442
442
|
: null;
|
|
443
443
|
Zonos.isBigCommerce = false;
|
|
444
|
-
Zonos.releaseDate = "
|
|
444
|
+
Zonos.releaseDate = "1792773585238";
|
|
445
445
|
Zonos.isLegacyCheckout = false;
|
|
446
446
|
Zonos.googleAnalyticId = null;
|
|
447
447
|
Zonos.googleAnalyticReady = false;
|
|
@@ -466,7 +466,7 @@ Zonos.isNpm = true;
|
|
|
466
466
|
Zonos.zonosQaUrl = null;
|
|
467
467
|
Zonos.zonosQaUrlApi = null;
|
|
468
468
|
Zonos.trackEventLogs = [];
|
|
469
|
-
Zonos.version = `v${"1.
|
|
469
|
+
Zonos.version = `v${"1.5.0"}`;
|
|
470
470
|
Zonos.modeAlerted = false;
|
|
471
471
|
Zonos.cartData = null;
|
|
472
472
|
Zonos.paypal = null;
|