@economist/web-apple-pay 0.1.3-beta.41 → 0.1.3-beta.43
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/index.js +33 -82
- package/dist/src/apple-pay-button.d.ts +1 -1
- package/dist/src/apple-pay-button.js +33 -82
- package/dist/src/apple-pay-button.stories.js +33 -82
- package/dist/src/apple-pay-modal.d.ts +5 -9
- package/dist/src/apple-pay-modal.js +23 -38
- package/dist/src/apple-pay-modal.stories.js +33 -82
- package/dist/src/index.js +33 -82
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -835,17 +835,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
835
835
|
#country = "";
|
|
836
836
|
#triggerElement = null;
|
|
837
837
|
#keyHandler = null;
|
|
838
|
-
#
|
|
839
|
-
#recaptchaTokensPromise = null;
|
|
838
|
+
#isClosed = false;
|
|
840
839
|
/**
|
|
841
|
-
*
|
|
842
|
-
*
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
* reCAPTCHA tokens are guaranteed non-null here: the CTA remains disabled
|
|
847
|
-
* until the token pre-fetch resolves, so this callback is never reached
|
|
848
|
-
* without valid tokens.
|
|
840
|
+
* Callback invoked from the CTA click handler once the user confirms.
|
|
841
|
+
* The caller (ApplePayButton) must call startApplePaySession inside this
|
|
842
|
+
* callback to preserve the browser's user-gesture chain — Safari requires
|
|
843
|
+
* new ApplePaySession() to execute within the original click stack.
|
|
849
844
|
*/
|
|
850
845
|
onConfirm = null;
|
|
851
846
|
set offer(value) {
|
|
@@ -942,28 +937,29 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
942
937
|
}
|
|
943
938
|
});
|
|
944
939
|
}
|
|
945
|
-
|
|
946
|
-
if (cta)
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
940
|
+
cta?.addEventListener("click", () => {
|
|
941
|
+
if (cta.disabled) return;
|
|
942
|
+
if (isUS && checkbox && !checkbox.checked) {
|
|
943
|
+
errorElement?.classList.add("apm__error--visible");
|
|
944
|
+
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
945
|
+
return;
|
|
950
946
|
}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
947
|
+
errorElement?.classList.remove("apm__error--visible");
|
|
948
|
+
cta.disabled = true;
|
|
949
|
+
cta.setAttribute("aria-busy", "true");
|
|
950
|
+
getPurchaseRecaptchaTokens().then((recaptchaTokens) => {
|
|
951
|
+
if (this.#isClosed) return;
|
|
952
|
+
this.onConfirm?.(recaptchaTokens);
|
|
953
|
+
this.close();
|
|
958
954
|
}).catch(() => {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
}
|
|
955
|
+
cta.disabled = false;
|
|
956
|
+
cta.removeAttribute("aria-busy");
|
|
962
957
|
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
963
958
|
if (existingError) {
|
|
964
959
|
const icon = existingError.querySelector("svg");
|
|
965
960
|
existingError.textContent = MSG_RECAPTCHA_LOAD_ERROR;
|
|
966
961
|
if (icon) existingError.prepend(icon);
|
|
962
|
+
existingError.setAttribute("role", "alert");
|
|
967
963
|
existingError.classList.add("apm__error--visible");
|
|
968
964
|
} else {
|
|
969
965
|
const errorNotice = document.createElement("div");
|
|
@@ -973,25 +969,13 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
973
969
|
cta?.insertAdjacentElement("beforebegin", errorNotice);
|
|
974
970
|
}
|
|
975
971
|
});
|
|
976
|
-
}
|
|
977
|
-
cta?.addEventListener("click", () => {
|
|
978
|
-
if (isUS && checkbox && !checkbox.checked) {
|
|
979
|
-
errorElement?.classList.add("apm__error--visible");
|
|
980
|
-
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
981
|
-
return;
|
|
982
|
-
}
|
|
983
|
-
if (this.#recaptchaTokens) {
|
|
984
|
-
this.onConfirm?.(this.#recaptchaTokens);
|
|
985
|
-
this.close();
|
|
986
|
-
}
|
|
987
972
|
});
|
|
988
973
|
this.querySelector("#apple-pay-modal-close")?.addEventListener(
|
|
989
974
|
"click",
|
|
990
975
|
() => this.close()
|
|
991
976
|
);
|
|
992
977
|
}
|
|
993
|
-
open(
|
|
994
|
-
this.#recaptchaTokensPromise = recaptchaTokensPromise ?? getPurchaseRecaptchaTokens();
|
|
978
|
+
open() {
|
|
995
979
|
this.#triggerElement = document.activeElement;
|
|
996
980
|
document.body.appendChild(this);
|
|
997
981
|
this.#keyHandler = (event) => {
|
|
@@ -1006,6 +990,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
1006
990
|
this.querySelector("#apple-pay-modal")?.focus();
|
|
1007
991
|
}
|
|
1008
992
|
close() {
|
|
993
|
+
this.#isClosed = true;
|
|
1009
994
|
if (this.#keyHandler) {
|
|
1010
995
|
document.removeEventListener("keydown", this.#keyHandler, {
|
|
1011
996
|
capture: true
|
|
@@ -1913,6 +1898,7 @@ var getSupportedBillingCountries = (offerCountry, offerVariant) => {
|
|
|
1913
1898
|
};
|
|
1914
1899
|
|
|
1915
1900
|
// src/apple-pay-button.ts
|
|
1901
|
+
var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
|
|
1916
1902
|
var TOTAL_LABEL = "The Economist";
|
|
1917
1903
|
var DEFAULT_CURRENCY = "USD";
|
|
1918
1904
|
var DEFAULT_TOTAL = "0.00";
|
|
@@ -1928,7 +1914,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1928
1914
|
define(_ApplePayButton.tag, _ApplePayButton);
|
|
1929
1915
|
}
|
|
1930
1916
|
/**
|
|
1931
|
-
* Creates and configures an ApplePayButton if the
|
|
1917
|
+
* Creates and configures an ApplePayButton if the feature flag is present.
|
|
1932
1918
|
*/
|
|
1933
1919
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1934
1920
|
if (!offer) {
|
|
@@ -1937,6 +1923,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1937
1923
|
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1938
1924
|
return null;
|
|
1939
1925
|
}
|
|
1926
|
+
if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
|
|
1927
|
+
return null;
|
|
1928
|
+
}
|
|
1940
1929
|
_ApplePayButton.define();
|
|
1941
1930
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1942
1931
|
button.offer = offer;
|
|
@@ -1965,7 +1954,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1965
1954
|
#returnUrl = "";
|
|
1966
1955
|
#supportedBillingCountries = [];
|
|
1967
1956
|
#entryPoint = "";
|
|
1968
|
-
#recaptchaTokensPromise = null;
|
|
1969
1957
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1970
1958
|
get offer() {
|
|
1971
1959
|
return this.#offer;
|
|
@@ -2030,7 +2018,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2030
2018
|
this.#paymentOptions = null;
|
|
2031
2019
|
this.#returnUrl = "";
|
|
2032
2020
|
this.#supportedBillingCountries = [];
|
|
2033
|
-
this.#recaptchaTokensPromise = null;
|
|
2034
2021
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2035
2022
|
}
|
|
2036
2023
|
// ─── Render pipeline ────────────────────────────────────────────────────────
|
|
@@ -2043,10 +2030,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2043
2030
|
this.#captureReturnUrl();
|
|
2044
2031
|
this.#computeBillingCountries();
|
|
2045
2032
|
if (await this.#fetchAndCacheOptions()) return;
|
|
2046
|
-
console.log("[web-apple-pay] button shown \u2014 reason: all checks passed, Apple Pay is available and offer is eligible");
|
|
2047
2033
|
this.#finishLoading();
|
|
2048
|
-
} catch
|
|
2049
|
-
console.warn("[web-apple-pay] button hidden \u2014 reason: unexpected error in render pipeline", error);
|
|
2034
|
+
} catch {
|
|
2050
2035
|
this.style.display = "none";
|
|
2051
2036
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2052
2037
|
} finally {
|
|
@@ -2057,7 +2042,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2057
2042
|
async #checkAvailability() {
|
|
2058
2043
|
const available = await isApplePayAvailable();
|
|
2059
2044
|
if (!available) {
|
|
2060
|
-
console.log("[web-apple-pay] button removed from DOM \u2014 reason: Apple Pay unavailable on this device/browser");
|
|
2061
2045
|
this.style.display = "none";
|
|
2062
2046
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2063
2047
|
return true;
|
|
@@ -2071,7 +2055,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2071
2055
|
async #checkSession() {
|
|
2072
2056
|
this.#sessionData = await this.#fetchSession();
|
|
2073
2057
|
if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
|
|
2074
|
-
console.log(`[web-apple-pay] button removed from DOM \u2014 reason: session check failed, userType="${this.#sessionData.userType}"`);
|
|
2075
2058
|
this.style.display = "none";
|
|
2076
2059
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2077
2060
|
return true;
|
|
@@ -2081,7 +2064,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2081
2064
|
/** Returns `true` (hide) when no offer has been set before mount. */
|
|
2082
2065
|
#checkOffer() {
|
|
2083
2066
|
if (!this.#offer) {
|
|
2084
|
-
console.log("[web-apple-pay] button removed from DOM \u2014 reason: no offer set on element before mount");
|
|
2085
2067
|
this.style.display = "none";
|
|
2086
2068
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2087
2069
|
return true;
|
|
@@ -2109,16 +2091,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2109
2091
|
*/
|
|
2110
2092
|
async #fetchAndCacheOptions() {
|
|
2111
2093
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
2112
|
-
if (!this.#paymentOptions) {
|
|
2113
|
-
console.warn("[web-apple-pay] button removed from DOM \u2014 reason: getPaymentOptions threw an error (see previous log for details)");
|
|
2114
|
-
this.style.display = "none";
|
|
2115
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2116
|
-
return true;
|
|
2117
|
-
}
|
|
2118
|
-
if (!this.#paymentOptions.options?.apple_pay) {
|
|
2119
|
-
console.log("[web-apple-pay] button removed from DOM \u2014 reason: BFF responded but apple_pay is absent from payment options", {
|
|
2120
|
-
receivedOptions: this.#paymentOptions.options
|
|
2121
|
-
});
|
|
2094
|
+
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
2122
2095
|
this.style.display = "none";
|
|
2123
2096
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2124
2097
|
return true;
|
|
@@ -2127,7 +2100,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2127
2100
|
}
|
|
2128
2101
|
/** Injects the button template and wires click and confirm event listeners. */
|
|
2129
2102
|
#renderTemplate() {
|
|
2130
|
-
console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
|
|
2131
2103
|
this.style.removeProperty("display");
|
|
2132
2104
|
ensureApplePayLogoSymbol();
|
|
2133
2105
|
const template = document.createElement("template");
|
|
@@ -2148,7 +2120,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2148
2120
|
if (button) {
|
|
2149
2121
|
button.classList.remove("wap-loading");
|
|
2150
2122
|
this.#updateDisabledState();
|
|
2151
|
-
this.#scheduleRecaptchaTokens();
|
|
2152
2123
|
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
2153
2124
|
entryPoint: this.#entryPoint,
|
|
2154
2125
|
country: this.#country
|
|
@@ -2187,25 +2158,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2187
2158
|
const country = this.#country;
|
|
2188
2159
|
modal.onConfirm = (recaptchaTokens) => {
|
|
2189
2160
|
this.#initiateApplePay(skuId, country, recaptchaTokens);
|
|
2190
|
-
this.#scheduleRecaptchaTokens();
|
|
2191
2161
|
};
|
|
2192
|
-
modal.open(
|
|
2193
|
-
}
|
|
2194
|
-
/**
|
|
2195
|
-
* Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
|
|
2196
|
-
* If the fetch rejects, the field is cleared so the next `modal.open()` call
|
|
2197
|
-
* falls back to a new attempt via the modal's own null-fallback path — preventing
|
|
2198
|
-
* a single transient failure from permanently disabling the CTA on all retries.
|
|
2199
|
-
* The identity guard prevents a late rejection from clobbering a newer attempt.
|
|
2200
|
-
*/
|
|
2201
|
-
#scheduleRecaptchaTokens() {
|
|
2202
|
-
const attempt = getPurchaseRecaptchaTokens();
|
|
2203
|
-
attempt.catch(() => {
|
|
2204
|
-
if (this.#recaptchaTokensPromise === attempt) {
|
|
2205
|
-
this.#recaptchaTokensPromise = null;
|
|
2206
|
-
}
|
|
2207
|
-
});
|
|
2208
|
-
this.#recaptchaTokensPromise = attempt;
|
|
2162
|
+
modal.open();
|
|
2209
2163
|
}
|
|
2210
2164
|
async #fetchSession() {
|
|
2211
2165
|
try {
|
|
@@ -2216,16 +2170,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2216
2170
|
}
|
|
2217
2171
|
async #fetchPaymentOptions() {
|
|
2218
2172
|
try {
|
|
2219
|
-
|
|
2173
|
+
return await getPaymentOptions({
|
|
2220
2174
|
sku: this.#offer.sku_id,
|
|
2221
2175
|
countryCode: this.#country,
|
|
2222
2176
|
currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
2223
2177
|
checkoutUrl: this.#returnUrl
|
|
2224
2178
|
});
|
|
2225
|
-
|
|
2226
|
-
return options;
|
|
2227
|
-
} catch (error) {
|
|
2228
|
-
console.warn("[web-apple-pay] getPaymentOptions fetch failed \u2014 returning null", error);
|
|
2179
|
+
} catch {
|
|
2229
2180
|
return null;
|
|
2230
2181
|
}
|
|
2231
2182
|
}
|
|
@@ -6,7 +6,7 @@ export declare class ApplePayButton extends HTMLElement {
|
|
|
6
6
|
static readonly tag = "teg-apple-pay-button";
|
|
7
7
|
static define(): void;
|
|
8
8
|
/**
|
|
9
|
-
* Creates and configures an ApplePayButton if the
|
|
9
|
+
* Creates and configures an ApplePayButton if the feature flag is present.
|
|
10
10
|
*/
|
|
11
11
|
static createIfEnabled(offer: Offer | undefined, country: string, entryPoint?: ApplePayEntryPoint): ApplePayButton | null;
|
|
12
12
|
get offer(): Offer | null;
|
|
@@ -830,17 +830,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
830
830
|
#country = "";
|
|
831
831
|
#triggerElement = null;
|
|
832
832
|
#keyHandler = null;
|
|
833
|
-
#
|
|
834
|
-
#recaptchaTokensPromise = null;
|
|
833
|
+
#isClosed = false;
|
|
835
834
|
/**
|
|
836
|
-
*
|
|
837
|
-
*
|
|
838
|
-
*
|
|
839
|
-
*
|
|
840
|
-
*
|
|
841
|
-
* reCAPTCHA tokens are guaranteed non-null here: the CTA remains disabled
|
|
842
|
-
* until the token pre-fetch resolves, so this callback is never reached
|
|
843
|
-
* without valid tokens.
|
|
835
|
+
* Callback invoked from the CTA click handler once the user confirms.
|
|
836
|
+
* The caller (ApplePayButton) must call startApplePaySession inside this
|
|
837
|
+
* callback to preserve the browser's user-gesture chain — Safari requires
|
|
838
|
+
* new ApplePaySession() to execute within the original click stack.
|
|
844
839
|
*/
|
|
845
840
|
onConfirm = null;
|
|
846
841
|
set offer(value) {
|
|
@@ -937,28 +932,29 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
937
932
|
}
|
|
938
933
|
});
|
|
939
934
|
}
|
|
940
|
-
|
|
941
|
-
if (cta)
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
935
|
+
cta?.addEventListener("click", () => {
|
|
936
|
+
if (cta.disabled) return;
|
|
937
|
+
if (isUS && checkbox && !checkbox.checked) {
|
|
938
|
+
errorElement?.classList.add("apm__error--visible");
|
|
939
|
+
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
940
|
+
return;
|
|
945
941
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
942
|
+
errorElement?.classList.remove("apm__error--visible");
|
|
943
|
+
cta.disabled = true;
|
|
944
|
+
cta.setAttribute("aria-busy", "true");
|
|
945
|
+
getPurchaseRecaptchaTokens().then((recaptchaTokens) => {
|
|
946
|
+
if (this.#isClosed) return;
|
|
947
|
+
this.onConfirm?.(recaptchaTokens);
|
|
948
|
+
this.close();
|
|
953
949
|
}).catch(() => {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
}
|
|
950
|
+
cta.disabled = false;
|
|
951
|
+
cta.removeAttribute("aria-busy");
|
|
957
952
|
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
958
953
|
if (existingError) {
|
|
959
954
|
const icon = existingError.querySelector("svg");
|
|
960
955
|
existingError.textContent = MSG_RECAPTCHA_LOAD_ERROR;
|
|
961
956
|
if (icon) existingError.prepend(icon);
|
|
957
|
+
existingError.setAttribute("role", "alert");
|
|
962
958
|
existingError.classList.add("apm__error--visible");
|
|
963
959
|
} else {
|
|
964
960
|
const errorNotice = document.createElement("div");
|
|
@@ -968,25 +964,13 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
968
964
|
cta?.insertAdjacentElement("beforebegin", errorNotice);
|
|
969
965
|
}
|
|
970
966
|
});
|
|
971
|
-
}
|
|
972
|
-
cta?.addEventListener("click", () => {
|
|
973
|
-
if (isUS && checkbox && !checkbox.checked) {
|
|
974
|
-
errorElement?.classList.add("apm__error--visible");
|
|
975
|
-
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
976
|
-
return;
|
|
977
|
-
}
|
|
978
|
-
if (this.#recaptchaTokens) {
|
|
979
|
-
this.onConfirm?.(this.#recaptchaTokens);
|
|
980
|
-
this.close();
|
|
981
|
-
}
|
|
982
967
|
});
|
|
983
968
|
this.querySelector("#apple-pay-modal-close")?.addEventListener(
|
|
984
969
|
"click",
|
|
985
970
|
() => this.close()
|
|
986
971
|
);
|
|
987
972
|
}
|
|
988
|
-
open(
|
|
989
|
-
this.#recaptchaTokensPromise = recaptchaTokensPromise ?? getPurchaseRecaptchaTokens();
|
|
973
|
+
open() {
|
|
990
974
|
this.#triggerElement = document.activeElement;
|
|
991
975
|
document.body.appendChild(this);
|
|
992
976
|
this.#keyHandler = (event) => {
|
|
@@ -1001,6 +985,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
1001
985
|
this.querySelector("#apple-pay-modal")?.focus();
|
|
1002
986
|
}
|
|
1003
987
|
close() {
|
|
988
|
+
this.#isClosed = true;
|
|
1004
989
|
if (this.#keyHandler) {
|
|
1005
990
|
document.removeEventListener("keydown", this.#keyHandler, {
|
|
1006
991
|
capture: true
|
|
@@ -1908,6 +1893,7 @@ var getSupportedBillingCountries = (offerCountry, offerVariant) => {
|
|
|
1908
1893
|
};
|
|
1909
1894
|
|
|
1910
1895
|
// src/apple-pay-button.ts
|
|
1896
|
+
var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
|
|
1911
1897
|
var TOTAL_LABEL = "The Economist";
|
|
1912
1898
|
var DEFAULT_CURRENCY = "USD";
|
|
1913
1899
|
var DEFAULT_TOTAL = "0.00";
|
|
@@ -1923,7 +1909,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1923
1909
|
define(_ApplePayButton.tag, _ApplePayButton);
|
|
1924
1910
|
}
|
|
1925
1911
|
/**
|
|
1926
|
-
* Creates and configures an ApplePayButton if the
|
|
1912
|
+
* Creates and configures an ApplePayButton if the feature flag is present.
|
|
1927
1913
|
*/
|
|
1928
1914
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1929
1915
|
if (!offer) {
|
|
@@ -1932,6 +1918,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1932
1918
|
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1933
1919
|
return null;
|
|
1934
1920
|
}
|
|
1921
|
+
if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
|
|
1922
|
+
return null;
|
|
1923
|
+
}
|
|
1935
1924
|
_ApplePayButton.define();
|
|
1936
1925
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1937
1926
|
button.offer = offer;
|
|
@@ -1960,7 +1949,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1960
1949
|
#returnUrl = "";
|
|
1961
1950
|
#supportedBillingCountries = [];
|
|
1962
1951
|
#entryPoint = "";
|
|
1963
|
-
#recaptchaTokensPromise = null;
|
|
1964
1952
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1965
1953
|
get offer() {
|
|
1966
1954
|
return this.#offer;
|
|
@@ -2025,7 +2013,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2025
2013
|
this.#paymentOptions = null;
|
|
2026
2014
|
this.#returnUrl = "";
|
|
2027
2015
|
this.#supportedBillingCountries = [];
|
|
2028
|
-
this.#recaptchaTokensPromise = null;
|
|
2029
2016
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2030
2017
|
}
|
|
2031
2018
|
// ─── Render pipeline ────────────────────────────────────────────────────────
|
|
@@ -2038,10 +2025,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2038
2025
|
this.#captureReturnUrl();
|
|
2039
2026
|
this.#computeBillingCountries();
|
|
2040
2027
|
if (await this.#fetchAndCacheOptions()) return;
|
|
2041
|
-
console.log("[web-apple-pay] button shown \u2014 reason: all checks passed, Apple Pay is available and offer is eligible");
|
|
2042
2028
|
this.#finishLoading();
|
|
2043
|
-
} catch
|
|
2044
|
-
console.warn("[web-apple-pay] button hidden \u2014 reason: unexpected error in render pipeline", error);
|
|
2029
|
+
} catch {
|
|
2045
2030
|
this.style.display = "none";
|
|
2046
2031
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2047
2032
|
} finally {
|
|
@@ -2052,7 +2037,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2052
2037
|
async #checkAvailability() {
|
|
2053
2038
|
const available = await isApplePayAvailable();
|
|
2054
2039
|
if (!available) {
|
|
2055
|
-
console.log("[web-apple-pay] button removed from DOM \u2014 reason: Apple Pay unavailable on this device/browser");
|
|
2056
2040
|
this.style.display = "none";
|
|
2057
2041
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2058
2042
|
return true;
|
|
@@ -2066,7 +2050,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2066
2050
|
async #checkSession() {
|
|
2067
2051
|
this.#sessionData = await this.#fetchSession();
|
|
2068
2052
|
if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
|
|
2069
|
-
console.log(`[web-apple-pay] button removed from DOM \u2014 reason: session check failed, userType="${this.#sessionData.userType}"`);
|
|
2070
2053
|
this.style.display = "none";
|
|
2071
2054
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2072
2055
|
return true;
|
|
@@ -2076,7 +2059,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2076
2059
|
/** Returns `true` (hide) when no offer has been set before mount. */
|
|
2077
2060
|
#checkOffer() {
|
|
2078
2061
|
if (!this.#offer) {
|
|
2079
|
-
console.log("[web-apple-pay] button removed from DOM \u2014 reason: no offer set on element before mount");
|
|
2080
2062
|
this.style.display = "none";
|
|
2081
2063
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2082
2064
|
return true;
|
|
@@ -2104,16 +2086,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2104
2086
|
*/
|
|
2105
2087
|
async #fetchAndCacheOptions() {
|
|
2106
2088
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
2107
|
-
if (!this.#paymentOptions) {
|
|
2108
|
-
console.warn("[web-apple-pay] button removed from DOM \u2014 reason: getPaymentOptions threw an error (see previous log for details)");
|
|
2109
|
-
this.style.display = "none";
|
|
2110
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2111
|
-
return true;
|
|
2112
|
-
}
|
|
2113
|
-
if (!this.#paymentOptions.options?.apple_pay) {
|
|
2114
|
-
console.log("[web-apple-pay] button removed from DOM \u2014 reason: BFF responded but apple_pay is absent from payment options", {
|
|
2115
|
-
receivedOptions: this.#paymentOptions.options
|
|
2116
|
-
});
|
|
2089
|
+
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
2117
2090
|
this.style.display = "none";
|
|
2118
2091
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2119
2092
|
return true;
|
|
@@ -2122,7 +2095,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2122
2095
|
}
|
|
2123
2096
|
/** Injects the button template and wires click and confirm event listeners. */
|
|
2124
2097
|
#renderTemplate() {
|
|
2125
|
-
console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
|
|
2126
2098
|
this.style.removeProperty("display");
|
|
2127
2099
|
ensureApplePayLogoSymbol();
|
|
2128
2100
|
const template = document.createElement("template");
|
|
@@ -2143,7 +2115,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2143
2115
|
if (button) {
|
|
2144
2116
|
button.classList.remove("wap-loading");
|
|
2145
2117
|
this.#updateDisabledState();
|
|
2146
|
-
this.#scheduleRecaptchaTokens();
|
|
2147
2118
|
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
2148
2119
|
entryPoint: this.#entryPoint,
|
|
2149
2120
|
country: this.#country
|
|
@@ -2182,25 +2153,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2182
2153
|
const country = this.#country;
|
|
2183
2154
|
modal.onConfirm = (recaptchaTokens) => {
|
|
2184
2155
|
this.#initiateApplePay(skuId, country, recaptchaTokens);
|
|
2185
|
-
this.#scheduleRecaptchaTokens();
|
|
2186
2156
|
};
|
|
2187
|
-
modal.open(
|
|
2188
|
-
}
|
|
2189
|
-
/**
|
|
2190
|
-
* Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
|
|
2191
|
-
* If the fetch rejects, the field is cleared so the next `modal.open()` call
|
|
2192
|
-
* falls back to a new attempt via the modal's own null-fallback path — preventing
|
|
2193
|
-
* a single transient failure from permanently disabling the CTA on all retries.
|
|
2194
|
-
* The identity guard prevents a late rejection from clobbering a newer attempt.
|
|
2195
|
-
*/
|
|
2196
|
-
#scheduleRecaptchaTokens() {
|
|
2197
|
-
const attempt = getPurchaseRecaptchaTokens();
|
|
2198
|
-
attempt.catch(() => {
|
|
2199
|
-
if (this.#recaptchaTokensPromise === attempt) {
|
|
2200
|
-
this.#recaptchaTokensPromise = null;
|
|
2201
|
-
}
|
|
2202
|
-
});
|
|
2203
|
-
this.#recaptchaTokensPromise = attempt;
|
|
2157
|
+
modal.open();
|
|
2204
2158
|
}
|
|
2205
2159
|
async #fetchSession() {
|
|
2206
2160
|
try {
|
|
@@ -2211,16 +2165,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2211
2165
|
}
|
|
2212
2166
|
async #fetchPaymentOptions() {
|
|
2213
2167
|
try {
|
|
2214
|
-
|
|
2168
|
+
return await getPaymentOptions({
|
|
2215
2169
|
sku: this.#offer.sku_id,
|
|
2216
2170
|
countryCode: this.#country,
|
|
2217
2171
|
currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
2218
2172
|
checkoutUrl: this.#returnUrl
|
|
2219
2173
|
});
|
|
2220
|
-
|
|
2221
|
-
return options;
|
|
2222
|
-
} catch (error) {
|
|
2223
|
-
console.warn("[web-apple-pay] getPaymentOptions fetch failed \u2014 returning null", error);
|
|
2174
|
+
} catch {
|
|
2224
2175
|
return null;
|
|
2225
2176
|
}
|
|
2226
2177
|
}
|