@economist/web-apple-pay 0.1.3-beta.47 → 0.1.3-beta.48
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 +108 -41
- package/dist/src/apple-pay-button.d.ts +29 -1
- package/dist/src/apple-pay-button.js +102 -33
- package/dist/src/apple-pay-button.stories.js +102 -33
- package/dist/src/apple-pay-modal.d.ts +2 -2
- package/dist/src/apple-pay-modal.js +5 -5
- package/dist/src/apple-pay-modal.stories.js +102 -33
- package/dist/src/constants.d.ts +16 -0
- package/dist/src/constants.js +7 -0
- package/dist/src/index.js +108 -41
- package/dist/src/utils/recaptcha.d.ts +2 -4
- package/dist/src/utils/recaptcha.js +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -605,7 +605,7 @@ var getRecaptchaToken = async (action) => {
|
|
|
605
605
|
});
|
|
606
606
|
});
|
|
607
607
|
};
|
|
608
|
-
var
|
|
608
|
+
var getPurchaseRecaptchaToken = () => {
|
|
609
609
|
return getRecaptchaToken("walletPurchase");
|
|
610
610
|
};
|
|
611
611
|
|
|
@@ -834,7 +834,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
834
834
|
#isClosed = false;
|
|
835
835
|
/**
|
|
836
836
|
* Callback invoked synchronously from the CTA click handler.
|
|
837
|
-
* Receives a Promise of reCAPTCHA
|
|
837
|
+
* Receives a Promise of a reCAPTCHA token — the promise is already in-flight
|
|
838
838
|
* by the time this is called. The caller (ApplePayButton) must call
|
|
839
839
|
* new ApplePaySession() synchronously inside this callback to stay within
|
|
840
840
|
* Safari's user-gesture window. The token promise resolves before
|
|
@@ -946,12 +946,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
946
946
|
this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
|
|
947
947
|
cta.disabled = true;
|
|
948
948
|
cta.setAttribute("aria-busy", "true");
|
|
949
|
-
const
|
|
949
|
+
const recaptchaTokenPromise = getPurchaseRecaptchaToken();
|
|
950
950
|
if (!this.#isClosed && this.onConfirm) {
|
|
951
|
-
this.onConfirm(
|
|
951
|
+
this.onConfirm(recaptchaTokenPromise);
|
|
952
952
|
this.close();
|
|
953
953
|
}
|
|
954
|
-
|
|
954
|
+
recaptchaTokenPromise.catch(() => {
|
|
955
955
|
if (this.#isClosed) return;
|
|
956
956
|
cta.disabled = false;
|
|
957
957
|
cta.removeAttribute("aria-busy");
|
|
@@ -1006,7 +1006,10 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
1006
1006
|
|
|
1007
1007
|
// src/templates/apple-pay-button.template.html
|
|
1008
1008
|
var apple_pay_button_template_default = `<style>
|
|
1009
|
-
/*
|
|
1009
|
+
/*
|
|
1010
|
+
* Entry CTA: \u201CSubscribe with\u201D + Apple Pay wordmark (Figma 1118:14088).
|
|
1011
|
+
* \u201CSubscribe with\u201D matches Continue to checkout typography (EconomistSans Regular / 17 / 24 / 400).
|
|
1012
|
+
*/
|
|
1010
1013
|
teg-apple-pay-button {
|
|
1011
1014
|
display: block;
|
|
1012
1015
|
margin: var(--apple-pay-margin, 0);
|
|
@@ -1026,25 +1029,50 @@ var apple_pay_button_template_default = `<style>
|
|
|
1026
1029
|
display: flex;
|
|
1027
1030
|
align-items: center;
|
|
1028
1031
|
justify-content: center;
|
|
1029
|
-
gap: 0.375rem;
|
|
1030
1032
|
width: 100%;
|
|
1031
1033
|
min-width: 0;
|
|
1032
1034
|
height: 100%;
|
|
1033
|
-
min-height: var(--apple-pay-height, 2.
|
|
1034
|
-
|
|
1035
|
+
min-height: var(--apple-pay-height, 2.5rem);
|
|
1036
|
+
padding: 0;
|
|
1037
|
+
box-sizing: border-box;
|
|
1038
|
+
background-color: var(--apple-pay-background-color, #1a1a1a);
|
|
1035
1039
|
color: var(--apple-pay-foreground-color, #fff);
|
|
1036
1040
|
border: none;
|
|
1037
|
-
border-radius: var(--apple-pay-border-radius,
|
|
1041
|
+
border-radius: var(--apple-pay-border-radius, 0.25rem);
|
|
1038
1042
|
cursor: pointer;
|
|
1039
|
-
|
|
1040
|
-
font-
|
|
1041
|
-
|
|
1043
|
+
/* Same as wall Continue to checkout / Marber button large */
|
|
1044
|
+
font-family: var(
|
|
1045
|
+
--mb-typeface-sans,
|
|
1046
|
+
var(--wall-type-system-sans, 'EconomistSans', system-ui, sans-serif)
|
|
1047
|
+
);
|
|
1048
|
+
font-size: var(--mb-button-font-size, 1.0625rem);
|
|
1049
|
+
font-weight: var(--mb-font-weight-regular, 400);
|
|
1050
|
+
line-height: 1;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
teg-apple-pay-button .apple-pay-btn__label {
|
|
1054
|
+
display: inline-flex;
|
|
1055
|
+
align-items: center;
|
|
1056
|
+
/* No flex gap \u2014 spacing after \u201Cwith\u201D uses the same word-space as \u201CSubscribe with\u201D */
|
|
1057
|
+
gap: 0;
|
|
1058
|
+
white-space: nowrap;
|
|
1042
1059
|
}
|
|
1043
1060
|
|
|
1044
|
-
teg-apple-pay-button .apple-pay-
|
|
1061
|
+
teg-apple-pay-button .apple-pay-btn__caption {
|
|
1062
|
+
/* One typographic word space after \u201Cwith\u201D, matching Subscribe\u2194with */
|
|
1063
|
+
padding-right: 0.25em;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
teg-apple-pay-button .apple-pay-btn__logo {
|
|
1045
1067
|
flex-shrink: 0;
|
|
1046
1068
|
display: block;
|
|
1069
|
+
/* Match caption font-size so mark aligns with text metrics */
|
|
1070
|
+
height: 1.05em;
|
|
1071
|
+
width: auto;
|
|
1072
|
+
aspect-ratio: 51 / 22;
|
|
1047
1073
|
color: currentColor;
|
|
1074
|
+
/* Optical nudge \u2014 SVG viewBox sits slightly high vs EconomistSans caps */
|
|
1075
|
+
transform: translateY(0.06em);
|
|
1048
1076
|
}
|
|
1049
1077
|
|
|
1050
1078
|
teg-apple-pay-button .apple-pay-btn.wap-loading {
|
|
@@ -1052,6 +1080,10 @@ var apple_pay_button_template_default = `<style>
|
|
|
1052
1080
|
cursor: default;
|
|
1053
1081
|
}
|
|
1054
1082
|
|
|
1083
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading .apple-pay-btn__label {
|
|
1084
|
+
visibility: hidden;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1055
1087
|
teg-apple-pay-button .apple-pay-btn.wap-loading::before {
|
|
1056
1088
|
content: '';
|
|
1057
1089
|
position: absolute;
|
|
@@ -1065,11 +1097,6 @@ var apple_pay_button_template_default = `<style>
|
|
|
1065
1097
|
animation: wap-button-spinner 0.8s linear infinite;
|
|
1066
1098
|
}
|
|
1067
1099
|
|
|
1068
|
-
teg-apple-pay-button .apple-pay-btn__logo {
|
|
1069
|
-
display: inline-flex;
|
|
1070
|
-
align-items: center;
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
1100
|
teg-apple-pay-button .apple-pay-btn__loading {
|
|
1074
1101
|
display: none;
|
|
1075
1102
|
}
|
|
@@ -1084,18 +1111,26 @@ var apple_pay_button_template_default = `<style>
|
|
|
1084
1111
|
}
|
|
1085
1112
|
</style>
|
|
1086
1113
|
|
|
1087
|
-
<div class="apple-pay-container" aria-label="
|
|
1114
|
+
<div class="apple-pay-container" aria-label="Subscribe with Apple Pay">
|
|
1088
1115
|
<button
|
|
1089
1116
|
class="apple-pay-btn"
|
|
1090
1117
|
type="button"
|
|
1091
|
-
aria-label="
|
|
1118
|
+
aria-label="Subscribe with Apple Pay"
|
|
1092
1119
|
data-analytics="paywall:apple-pay-checkout"
|
|
1093
1120
|
>
|
|
1094
|
-
<span class="apple-pay-
|
|
1095
|
-
|
|
1121
|
+
<span class="apple-pay-btn__label"
|
|
1122
|
+
><span class="apple-pay-btn__caption">Subscribe with</span
|
|
1123
|
+
><svg
|
|
1124
|
+
class="apple-pay-btn__logo"
|
|
1125
|
+
width="42"
|
|
1126
|
+
height="18"
|
|
1127
|
+
viewBox="0 0 51 22"
|
|
1128
|
+
aria-hidden="true"
|
|
1129
|
+
role="img"
|
|
1130
|
+
>
|
|
1096
1131
|
<use href="#apple-pay-logo" />
|
|
1097
|
-
</svg
|
|
1098
|
-
|
|
1132
|
+
</svg
|
|
1133
|
+
></span>
|
|
1099
1134
|
<span class="apple-pay-btn__loading" aria-hidden="true">Loading...</span>
|
|
1100
1135
|
</button>
|
|
1101
1136
|
</div>
|
|
@@ -1902,6 +1937,19 @@ var getSupportedBillingCountries = (offerCountry, offerVariant) => {
|
|
|
1902
1937
|
return [...zoneCountries];
|
|
1903
1938
|
};
|
|
1904
1939
|
|
|
1940
|
+
// src/constants.ts
|
|
1941
|
+
var ApplePayEntryPoint = /* @__PURE__ */ ((ApplePayEntryPoint3) => {
|
|
1942
|
+
ApplePayEntryPoint3["PAYWALL"] = "article_paywall";
|
|
1943
|
+
ApplePayEntryPoint3["REGWALL"] = "article_regwall";
|
|
1944
|
+
ApplePayEntryPoint3["DUAL_OFFER_BANNER"] = "dual_offer_banner";
|
|
1945
|
+
return ApplePayEntryPoint3;
|
|
1946
|
+
})(ApplePayEntryPoint || {});
|
|
1947
|
+
var APPLE_PAY_EXPRESS_BANNERS_EXPERIMENT_KEY = "subscribe-experiment-calibration";
|
|
1948
|
+
var APPLE_PAY_EXPRESS_BANNERS_VARIANTS = {
|
|
1949
|
+
CONTROL: "control",
|
|
1950
|
+
TREATMENT: "treatment"
|
|
1951
|
+
};
|
|
1952
|
+
|
|
1905
1953
|
// src/apple-pay-button.ts
|
|
1906
1954
|
var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
|
|
1907
1955
|
var TOTAL_LABEL = "The Economist";
|
|
@@ -1919,7 +1967,23 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1919
1967
|
define(_ApplePayButton.tag, _ApplePayButton);
|
|
1920
1968
|
}
|
|
1921
1969
|
/**
|
|
1922
|
-
* Creates and configures an ApplePayButton
|
|
1970
|
+
* Creates and configures an ApplePayButton when the Amplitude experiment is enabled.
|
|
1971
|
+
*
|
|
1972
|
+
* Reads the experiment variant from `window.experimentIntegration.getVariant` using
|
|
1973
|
+
* {@link APPLE_PAY_EXPRESS_BANNERS_EXPERIMENT_KEY}. The host page is responsible
|
|
1974
|
+
* for setting up `window.experimentIntegration` before calling this method.
|
|
1975
|
+
*
|
|
1976
|
+
* - `treatment` → button created and returned
|
|
1977
|
+
* - `control` / missing / anything else → returns null (button suppressed)
|
|
1978
|
+
*
|
|
1979
|
+
* **Transition period:** the legacy `FEATURE_APPLE_PAY_EXPRESS_CHECKOUT` URL param
|
|
1980
|
+
* gate is also evaluated as a fallback until all host apps have integrated
|
|
1981
|
+
* `window.experimentIntegration`. Once all consumers are migrated, the URL param
|
|
1982
|
+
* fallback will be removed.
|
|
1983
|
+
*
|
|
1984
|
+
* @param offer - The offer to display in the Apple Pay flow.
|
|
1985
|
+
* @param country - The user's country code.
|
|
1986
|
+
* @param entryPoint - Where the button is being rendered (e.g. paywall, banner).
|
|
1923
1987
|
*/
|
|
1924
1988
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1925
1989
|
if (!offer) {
|
|
@@ -1928,7 +1992,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1928
1992
|
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1929
1993
|
return null;
|
|
1930
1994
|
}
|
|
1931
|
-
|
|
1995
|
+
const experimentValue = window.experimentIntegration?.getVariant?.(
|
|
1996
|
+
APPLE_PAY_EXPRESS_BANNERS_EXPERIMENT_KEY
|
|
1997
|
+
);
|
|
1998
|
+
const isTreatment = experimentValue === APPLE_PAY_EXPRESS_BANNERS_VARIANTS.TREATMENT;
|
|
1999
|
+
const hasUrlParamFlag = new URLSearchParams(window.location.search).has(
|
|
2000
|
+
FEATURE_APPLE_PAY_EXPRESS_CHECKOUT
|
|
2001
|
+
);
|
|
2002
|
+
console.log(`Apple Pay button experiment: variant="${experimentValue}`);
|
|
2003
|
+
if (!isTreatment && !hasUrlParamFlag) {
|
|
2004
|
+
console.log(
|
|
2005
|
+
`Apple Pay button suppressed: experiment variant is "${experimentValue}" and URL param "${FEATURE_APPLE_PAY_EXPRESS_CHECKOUT}" is not present.`
|
|
2006
|
+
);
|
|
1932
2007
|
return null;
|
|
1933
2008
|
}
|
|
1934
2009
|
_ApplePayButton.define();
|
|
@@ -2161,8 +2236,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2161
2236
|
}
|
|
2162
2237
|
const skuId = this.#offer.sku_id;
|
|
2163
2238
|
const country = this.#country;
|
|
2164
|
-
modal.onConfirm = (
|
|
2165
|
-
this.#initiateApplePay(skuId, country,
|
|
2239
|
+
modal.onConfirm = (recaptchaTokenPromise) => {
|
|
2240
|
+
this.#initiateApplePay(skuId, country, recaptchaTokenPromise);
|
|
2166
2241
|
};
|
|
2167
2242
|
modal.open();
|
|
2168
2243
|
}
|
|
@@ -2185,7 +2260,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2185
2260
|
return null;
|
|
2186
2261
|
}
|
|
2187
2262
|
}
|
|
2188
|
-
#buildSessionParams(skuId, country, sessionData, paymentOptions,
|
|
2263
|
+
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokenPromise) {
|
|
2189
2264
|
const offer = this.#offer;
|
|
2190
2265
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
2191
2266
|
return {
|
|
@@ -2198,7 +2273,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2198
2273
|
returnUrl: this.#returnUrl,
|
|
2199
2274
|
userLoggedIn: sessionData.loggedIn,
|
|
2200
2275
|
onPaymentAuthorized: async (event, session) => {
|
|
2201
|
-
const recaptchaToken = await
|
|
2276
|
+
const recaptchaToken = await recaptchaTokenPromise;
|
|
2202
2277
|
return handlePaymentAuthorized(event, session, sessionData, {
|
|
2203
2278
|
skuId,
|
|
2204
2279
|
country,
|
|
@@ -2210,7 +2285,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2210
2285
|
}
|
|
2211
2286
|
};
|
|
2212
2287
|
}
|
|
2213
|
-
#initiateApplePay(skuId, country,
|
|
2288
|
+
#initiateApplePay(skuId, country, recaptchaTokenPromise) {
|
|
2214
2289
|
try {
|
|
2215
2290
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
2216
2291
|
const paymentOptions = this.#paymentOptions;
|
|
@@ -2223,7 +2298,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2223
2298
|
country,
|
|
2224
2299
|
sessionData,
|
|
2225
2300
|
paymentOptions,
|
|
2226
|
-
|
|
2301
|
+
recaptchaTokenPromise
|
|
2227
2302
|
)
|
|
2228
2303
|
);
|
|
2229
2304
|
} catch {
|
|
@@ -2236,14 +2311,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2236
2311
|
}
|
|
2237
2312
|
};
|
|
2238
2313
|
|
|
2239
|
-
// src/constants.ts
|
|
2240
|
-
var ApplePayEntryPoint = /* @__PURE__ */ ((ApplePayEntryPoint2) => {
|
|
2241
|
-
ApplePayEntryPoint2["PAYWALL"] = "article_paywall";
|
|
2242
|
-
ApplePayEntryPoint2["REGWALL"] = "article_regwall";
|
|
2243
|
-
ApplePayEntryPoint2["DUAL_OFFER_BANNER"] = "dual_offer_banner";
|
|
2244
|
-
return ApplePayEntryPoint2;
|
|
2245
|
-
})(ApplePayEntryPoint || {});
|
|
2246
|
-
|
|
2247
2314
|
// src/index.ts
|
|
2248
2315
|
function defineApplePayElements() {
|
|
2249
2316
|
ApplePayButton.define();
|
|
@@ -1,12 +1,40 @@
|
|
|
1
1
|
import type { Offer, ProductVariant } from './types/offer.types';
|
|
2
2
|
import { ApplePayEntryPoint } from './constants';
|
|
3
|
+
/**
|
|
4
|
+
* The host page is responsible for setting up `window.experimentIntegration`
|
|
5
|
+
* with a `getVariant` method that returns the variant value for a given flag key.
|
|
6
|
+
* web-apple-pay reads the experiment variant from here to decide whether to show or hide the button.
|
|
7
|
+
*/
|
|
8
|
+
declare global {
|
|
9
|
+
interface Window {
|
|
10
|
+
experimentIntegration?: {
|
|
11
|
+
getVariant: (flagKey: string) => string | undefined;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
3
15
|
export declare const APPLE_PAY_EXCLUDED_VARIANTS: readonly ProductVariant[];
|
|
4
16
|
export declare class ApplePayButton extends HTMLElement {
|
|
5
17
|
#private;
|
|
6
18
|
static readonly tag = "teg-apple-pay-button";
|
|
7
19
|
static define(): void;
|
|
8
20
|
/**
|
|
9
|
-
* Creates and configures an ApplePayButton
|
|
21
|
+
* Creates and configures an ApplePayButton when the Amplitude experiment is enabled.
|
|
22
|
+
*
|
|
23
|
+
* Reads the experiment variant from `window.experimentIntegration.getVariant` using
|
|
24
|
+
* {@link APPLE_PAY_EXPRESS_BANNERS_EXPERIMENT_KEY}. The host page is responsible
|
|
25
|
+
* for setting up `window.experimentIntegration` before calling this method.
|
|
26
|
+
*
|
|
27
|
+
* - `treatment` → button created and returned
|
|
28
|
+
* - `control` / missing / anything else → returns null (button suppressed)
|
|
29
|
+
*
|
|
30
|
+
* **Transition period:** the legacy `FEATURE_APPLE_PAY_EXPRESS_CHECKOUT` URL param
|
|
31
|
+
* gate is also evaluated as a fallback until all host apps have integrated
|
|
32
|
+
* `window.experimentIntegration`. Once all consumers are migrated, the URL param
|
|
33
|
+
* fallback will be removed.
|
|
34
|
+
*
|
|
35
|
+
* @param offer - The offer to display in the Apple Pay flow.
|
|
36
|
+
* @param country - The user's country code.
|
|
37
|
+
* @param entryPoint - Where the button is being rendered (e.g. paywall, banner).
|
|
10
38
|
*/
|
|
11
39
|
static createIfEnabled(offer: Offer | undefined, country: string, entryPoint?: ApplePayEntryPoint): ApplePayButton | null;
|
|
12
40
|
get offer(): Offer | null;
|
|
@@ -600,7 +600,7 @@ var getRecaptchaToken = async (action) => {
|
|
|
600
600
|
});
|
|
601
601
|
});
|
|
602
602
|
};
|
|
603
|
-
var
|
|
603
|
+
var getPurchaseRecaptchaToken = () => {
|
|
604
604
|
return getRecaptchaToken("walletPurchase");
|
|
605
605
|
};
|
|
606
606
|
|
|
@@ -829,7 +829,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
829
829
|
#isClosed = false;
|
|
830
830
|
/**
|
|
831
831
|
* Callback invoked synchronously from the CTA click handler.
|
|
832
|
-
* Receives a Promise of reCAPTCHA
|
|
832
|
+
* Receives a Promise of a reCAPTCHA token — the promise is already in-flight
|
|
833
833
|
* by the time this is called. The caller (ApplePayButton) must call
|
|
834
834
|
* new ApplePaySession() synchronously inside this callback to stay within
|
|
835
835
|
* Safari's user-gesture window. The token promise resolves before
|
|
@@ -941,12 +941,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
941
941
|
this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
|
|
942
942
|
cta.disabled = true;
|
|
943
943
|
cta.setAttribute("aria-busy", "true");
|
|
944
|
-
const
|
|
944
|
+
const recaptchaTokenPromise = getPurchaseRecaptchaToken();
|
|
945
945
|
if (!this.#isClosed && this.onConfirm) {
|
|
946
|
-
this.onConfirm(
|
|
946
|
+
this.onConfirm(recaptchaTokenPromise);
|
|
947
947
|
this.close();
|
|
948
948
|
}
|
|
949
|
-
|
|
949
|
+
recaptchaTokenPromise.catch(() => {
|
|
950
950
|
if (this.#isClosed) return;
|
|
951
951
|
cta.disabled = false;
|
|
952
952
|
cta.removeAttribute("aria-busy");
|
|
@@ -1001,7 +1001,10 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
1001
1001
|
|
|
1002
1002
|
// src/templates/apple-pay-button.template.html
|
|
1003
1003
|
var apple_pay_button_template_default = `<style>
|
|
1004
|
-
/*
|
|
1004
|
+
/*
|
|
1005
|
+
* Entry CTA: \u201CSubscribe with\u201D + Apple Pay wordmark (Figma 1118:14088).
|
|
1006
|
+
* \u201CSubscribe with\u201D matches Continue to checkout typography (EconomistSans Regular / 17 / 24 / 400).
|
|
1007
|
+
*/
|
|
1005
1008
|
teg-apple-pay-button {
|
|
1006
1009
|
display: block;
|
|
1007
1010
|
margin: var(--apple-pay-margin, 0);
|
|
@@ -1021,25 +1024,50 @@ var apple_pay_button_template_default = `<style>
|
|
|
1021
1024
|
display: flex;
|
|
1022
1025
|
align-items: center;
|
|
1023
1026
|
justify-content: center;
|
|
1024
|
-
gap: 0.375rem;
|
|
1025
1027
|
width: 100%;
|
|
1026
1028
|
min-width: 0;
|
|
1027
1029
|
height: 100%;
|
|
1028
|
-
min-height: var(--apple-pay-height, 2.
|
|
1029
|
-
|
|
1030
|
+
min-height: var(--apple-pay-height, 2.5rem);
|
|
1031
|
+
padding: 0;
|
|
1032
|
+
box-sizing: border-box;
|
|
1033
|
+
background-color: var(--apple-pay-background-color, #1a1a1a);
|
|
1030
1034
|
color: var(--apple-pay-foreground-color, #fff);
|
|
1031
1035
|
border: none;
|
|
1032
|
-
border-radius: var(--apple-pay-border-radius,
|
|
1036
|
+
border-radius: var(--apple-pay-border-radius, 0.25rem);
|
|
1033
1037
|
cursor: pointer;
|
|
1034
|
-
|
|
1035
|
-
font-
|
|
1036
|
-
|
|
1038
|
+
/* Same as wall Continue to checkout / Marber button large */
|
|
1039
|
+
font-family: var(
|
|
1040
|
+
--mb-typeface-sans,
|
|
1041
|
+
var(--wall-type-system-sans, 'EconomistSans', system-ui, sans-serif)
|
|
1042
|
+
);
|
|
1043
|
+
font-size: var(--mb-button-font-size, 1.0625rem);
|
|
1044
|
+
font-weight: var(--mb-font-weight-regular, 400);
|
|
1045
|
+
line-height: 1;
|
|
1037
1046
|
}
|
|
1038
1047
|
|
|
1039
|
-
teg-apple-pay-button .apple-pay-
|
|
1048
|
+
teg-apple-pay-button .apple-pay-btn__label {
|
|
1049
|
+
display: inline-flex;
|
|
1050
|
+
align-items: center;
|
|
1051
|
+
/* No flex gap \u2014 spacing after \u201Cwith\u201D uses the same word-space as \u201CSubscribe with\u201D */
|
|
1052
|
+
gap: 0;
|
|
1053
|
+
white-space: nowrap;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
teg-apple-pay-button .apple-pay-btn__caption {
|
|
1057
|
+
/* One typographic word space after \u201Cwith\u201D, matching Subscribe\u2194with */
|
|
1058
|
+
padding-right: 0.25em;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
teg-apple-pay-button .apple-pay-btn__logo {
|
|
1040
1062
|
flex-shrink: 0;
|
|
1041
1063
|
display: block;
|
|
1064
|
+
/* Match caption font-size so mark aligns with text metrics */
|
|
1065
|
+
height: 1.05em;
|
|
1066
|
+
width: auto;
|
|
1067
|
+
aspect-ratio: 51 / 22;
|
|
1042
1068
|
color: currentColor;
|
|
1069
|
+
/* Optical nudge \u2014 SVG viewBox sits slightly high vs EconomistSans caps */
|
|
1070
|
+
transform: translateY(0.06em);
|
|
1043
1071
|
}
|
|
1044
1072
|
|
|
1045
1073
|
teg-apple-pay-button .apple-pay-btn.wap-loading {
|
|
@@ -1047,6 +1075,10 @@ var apple_pay_button_template_default = `<style>
|
|
|
1047
1075
|
cursor: default;
|
|
1048
1076
|
}
|
|
1049
1077
|
|
|
1078
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading .apple-pay-btn__label {
|
|
1079
|
+
visibility: hidden;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1050
1082
|
teg-apple-pay-button .apple-pay-btn.wap-loading::before {
|
|
1051
1083
|
content: '';
|
|
1052
1084
|
position: absolute;
|
|
@@ -1060,11 +1092,6 @@ var apple_pay_button_template_default = `<style>
|
|
|
1060
1092
|
animation: wap-button-spinner 0.8s linear infinite;
|
|
1061
1093
|
}
|
|
1062
1094
|
|
|
1063
|
-
teg-apple-pay-button .apple-pay-btn__logo {
|
|
1064
|
-
display: inline-flex;
|
|
1065
|
-
align-items: center;
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
1095
|
teg-apple-pay-button .apple-pay-btn__loading {
|
|
1069
1096
|
display: none;
|
|
1070
1097
|
}
|
|
@@ -1079,18 +1106,26 @@ var apple_pay_button_template_default = `<style>
|
|
|
1079
1106
|
}
|
|
1080
1107
|
</style>
|
|
1081
1108
|
|
|
1082
|
-
<div class="apple-pay-container" aria-label="
|
|
1109
|
+
<div class="apple-pay-container" aria-label="Subscribe with Apple Pay">
|
|
1083
1110
|
<button
|
|
1084
1111
|
class="apple-pay-btn"
|
|
1085
1112
|
type="button"
|
|
1086
|
-
aria-label="
|
|
1113
|
+
aria-label="Subscribe with Apple Pay"
|
|
1087
1114
|
data-analytics="paywall:apple-pay-checkout"
|
|
1088
1115
|
>
|
|
1089
|
-
<span class="apple-pay-
|
|
1090
|
-
|
|
1116
|
+
<span class="apple-pay-btn__label"
|
|
1117
|
+
><span class="apple-pay-btn__caption">Subscribe with</span
|
|
1118
|
+
><svg
|
|
1119
|
+
class="apple-pay-btn__logo"
|
|
1120
|
+
width="42"
|
|
1121
|
+
height="18"
|
|
1122
|
+
viewBox="0 0 51 22"
|
|
1123
|
+
aria-hidden="true"
|
|
1124
|
+
role="img"
|
|
1125
|
+
>
|
|
1091
1126
|
<use href="#apple-pay-logo" />
|
|
1092
|
-
</svg
|
|
1093
|
-
|
|
1127
|
+
</svg
|
|
1128
|
+
></span>
|
|
1094
1129
|
<span class="apple-pay-btn__loading" aria-hidden="true">Loading...</span>
|
|
1095
1130
|
</button>
|
|
1096
1131
|
</div>
|
|
@@ -1897,6 +1932,13 @@ var getSupportedBillingCountries = (offerCountry, offerVariant) => {
|
|
|
1897
1932
|
return [...zoneCountries];
|
|
1898
1933
|
};
|
|
1899
1934
|
|
|
1935
|
+
// src/constants.ts
|
|
1936
|
+
var APPLE_PAY_EXPRESS_BANNERS_EXPERIMENT_KEY = "subscribe-experiment-calibration";
|
|
1937
|
+
var APPLE_PAY_EXPRESS_BANNERS_VARIANTS = {
|
|
1938
|
+
CONTROL: "control",
|
|
1939
|
+
TREATMENT: "treatment"
|
|
1940
|
+
};
|
|
1941
|
+
|
|
1900
1942
|
// src/apple-pay-button.ts
|
|
1901
1943
|
var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
|
|
1902
1944
|
var TOTAL_LABEL = "The Economist";
|
|
@@ -1914,7 +1956,23 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1914
1956
|
define(_ApplePayButton.tag, _ApplePayButton);
|
|
1915
1957
|
}
|
|
1916
1958
|
/**
|
|
1917
|
-
* Creates and configures an ApplePayButton
|
|
1959
|
+
* Creates and configures an ApplePayButton when the Amplitude experiment is enabled.
|
|
1960
|
+
*
|
|
1961
|
+
* Reads the experiment variant from `window.experimentIntegration.getVariant` using
|
|
1962
|
+
* {@link APPLE_PAY_EXPRESS_BANNERS_EXPERIMENT_KEY}. The host page is responsible
|
|
1963
|
+
* for setting up `window.experimentIntegration` before calling this method.
|
|
1964
|
+
*
|
|
1965
|
+
* - `treatment` → button created and returned
|
|
1966
|
+
* - `control` / missing / anything else → returns null (button suppressed)
|
|
1967
|
+
*
|
|
1968
|
+
* **Transition period:** the legacy `FEATURE_APPLE_PAY_EXPRESS_CHECKOUT` URL param
|
|
1969
|
+
* gate is also evaluated as a fallback until all host apps have integrated
|
|
1970
|
+
* `window.experimentIntegration`. Once all consumers are migrated, the URL param
|
|
1971
|
+
* fallback will be removed.
|
|
1972
|
+
*
|
|
1973
|
+
* @param offer - The offer to display in the Apple Pay flow.
|
|
1974
|
+
* @param country - The user's country code.
|
|
1975
|
+
* @param entryPoint - Where the button is being rendered (e.g. paywall, banner).
|
|
1918
1976
|
*/
|
|
1919
1977
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1920
1978
|
if (!offer) {
|
|
@@ -1923,7 +1981,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1923
1981
|
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1924
1982
|
return null;
|
|
1925
1983
|
}
|
|
1926
|
-
|
|
1984
|
+
const experimentValue = window.experimentIntegration?.getVariant?.(
|
|
1985
|
+
APPLE_PAY_EXPRESS_BANNERS_EXPERIMENT_KEY
|
|
1986
|
+
);
|
|
1987
|
+
const isTreatment = experimentValue === APPLE_PAY_EXPRESS_BANNERS_VARIANTS.TREATMENT;
|
|
1988
|
+
const hasUrlParamFlag = new URLSearchParams(window.location.search).has(
|
|
1989
|
+
FEATURE_APPLE_PAY_EXPRESS_CHECKOUT
|
|
1990
|
+
);
|
|
1991
|
+
console.log(`Apple Pay button experiment: variant="${experimentValue}`);
|
|
1992
|
+
if (!isTreatment && !hasUrlParamFlag) {
|
|
1993
|
+
console.log(
|
|
1994
|
+
`Apple Pay button suppressed: experiment variant is "${experimentValue}" and URL param "${FEATURE_APPLE_PAY_EXPRESS_CHECKOUT}" is not present.`
|
|
1995
|
+
);
|
|
1927
1996
|
return null;
|
|
1928
1997
|
}
|
|
1929
1998
|
_ApplePayButton.define();
|
|
@@ -2156,8 +2225,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2156
2225
|
}
|
|
2157
2226
|
const skuId = this.#offer.sku_id;
|
|
2158
2227
|
const country = this.#country;
|
|
2159
|
-
modal.onConfirm = (
|
|
2160
|
-
this.#initiateApplePay(skuId, country,
|
|
2228
|
+
modal.onConfirm = (recaptchaTokenPromise) => {
|
|
2229
|
+
this.#initiateApplePay(skuId, country, recaptchaTokenPromise);
|
|
2161
2230
|
};
|
|
2162
2231
|
modal.open();
|
|
2163
2232
|
}
|
|
@@ -2180,7 +2249,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2180
2249
|
return null;
|
|
2181
2250
|
}
|
|
2182
2251
|
}
|
|
2183
|
-
#buildSessionParams(skuId, country, sessionData, paymentOptions,
|
|
2252
|
+
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokenPromise) {
|
|
2184
2253
|
const offer = this.#offer;
|
|
2185
2254
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
2186
2255
|
return {
|
|
@@ -2193,7 +2262,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2193
2262
|
returnUrl: this.#returnUrl,
|
|
2194
2263
|
userLoggedIn: sessionData.loggedIn,
|
|
2195
2264
|
onPaymentAuthorized: async (event, session) => {
|
|
2196
|
-
const recaptchaToken = await
|
|
2265
|
+
const recaptchaToken = await recaptchaTokenPromise;
|
|
2197
2266
|
return handlePaymentAuthorized(event, session, sessionData, {
|
|
2198
2267
|
skuId,
|
|
2199
2268
|
country,
|
|
@@ -2205,7 +2274,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2205
2274
|
}
|
|
2206
2275
|
};
|
|
2207
2276
|
}
|
|
2208
|
-
#initiateApplePay(skuId, country,
|
|
2277
|
+
#initiateApplePay(skuId, country, recaptchaTokenPromise) {
|
|
2209
2278
|
try {
|
|
2210
2279
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
2211
2280
|
const paymentOptions = this.#paymentOptions;
|
|
@@ -2218,7 +2287,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2218
2287
|
country,
|
|
2219
2288
|
sessionData,
|
|
2220
2289
|
paymentOptions,
|
|
2221
|
-
|
|
2290
|
+
recaptchaTokenPromise
|
|
2222
2291
|
)
|
|
2223
2292
|
);
|
|
2224
2293
|
} catch {
|