@economist/web-apple-pay 0.1.3-beta.4 → 0.1.3-beta.40
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 +885 -203
- package/dist/src/apple-pay-button.d.ts +5 -4
- package/dist/src/apple-pay-button.js +871 -198
- package/dist/src/apple-pay-button.stories.js +897 -206
- package/dist/src/apple-pay-logo.js +1 -1
- package/dist/src/apple-pay-modal.d.ts +16 -1
- package/dist/src/apple-pay-modal.js +600 -26
- package/dist/src/apple-pay-modal.stories.js +871 -198
- package/dist/src/clients/payment-checkout/apple-session.js +77 -51
- package/dist/src/clients/payment-checkout/detects.js +4 -7
- package/dist/src/clients/payment-checkout/index.js +0 -1
- package/dist/src/clients/payment-checkout/messages.d.ts +13 -14
- package/dist/src/clients/payment-checkout/messages.js +0 -4
- package/dist/src/clients/payment-checkout/payment-handler.d.ts +0 -8
- package/dist/src/clients/payment-checkout/payment-handler.js +46 -31
- package/dist/src/clients/payment-checkout/types.d.ts +7 -5
- package/dist/src/constants.d.ts +5 -0
- package/dist/src/constants.js +10 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +885 -203
- package/dist/src/stories/utils/story-env.js +18 -0
- package/dist/src/utils/expressCheckoutRedirect.d.ts +33 -7
- package/dist/src/utils/expressCheckoutRedirect.js +24 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -71,12 +71,547 @@ function ensureApplePayLogoSymbol() {
|
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
73
|
const tmp = document.createElement("div");
|
|
74
|
-
tmp.innerHTML = `<svg aria-hidden="true" style="display:none" id="${LOGO_DEFS_ID}"><defs><symbol id="apple-pay-logo" viewBox="0 0 51 22"><path d="${LOGO_PATH}" fill="
|
|
74
|
+
tmp.innerHTML = `<svg aria-hidden="true" style="display:none" id="${LOGO_DEFS_ID}"><defs><symbol id="apple-pay-logo" viewBox="0 0 51 22"><path d="${LOGO_PATH}" fill="currentColor"/></symbol></defs></svg>`;
|
|
75
75
|
document.body.prepend(tmp.firstElementChild);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
// src/templates/apple-pay-modal.template.html
|
|
79
|
-
var apple_pay_modal_template_default = '<style>\n .apm-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 97;\n background: rgba(13, 13, 13, 0.7);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--wall-gutter, 2rem);\n box-sizing: border-box;\n }\n\n .apm {\n position: relative;\n background: #fff;\n border-radius: 0.5rem 0.5rem 0 0;\n border: 0.0625rem solid #d9d9d9;\n padding: var(--mb-spacing-lg, 1.5rem);\n width: 25rem;\n max-width: 25rem;\n box-sizing: border-box;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n box-shadow: 0 0.25rem 1rem 0 rgba(13, 13, 13, 0.15);\n }\n\n .apm__close {\n position: absolute;\n top: 1.5rem;\n right: 1.3125rem;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .apm__close:focus {\n outline: solid 0.125rem var(--focus-border-color, #121212);\n border-radius: 0.25rem;\n }\n\n .apm__offer-name {\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-title-3-size, 1.25rem);\n font-weight: 500;\n color: var(--mb-colour-greyscale-london-5, #0d0d0d);\n line-height: var(--mb-typestyle-title-3-leading, 1.75rem);\n font-style: normal;\n margin: 0 1.5rem 0.5rem 0;\n }\n\n .apm__due-today {\n color: #1a1a1a;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-label-2-size, 0.9375rem);\n font-style: normal;\n font-weight: 400;\n line-height: var(--mb-typestyle-label-2-leading, 1.25rem);\n margin: 0 0 0.75rem 0;\n }\n\n .apm__rule {\n border: none;\n border-top: 0.0625rem solid #d9d9d9;\n margin: 0 0 1rem 0;\n }\n\n .apm__terms {\n color: #1a1a1a;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-label-2-size, 0.9375rem);\n font-style: normal;\n font-weight: 400;\n line-height: var(--mb-typestyle-label-2-leading, 1.25rem);\n margin: 0 0 1rem 0;\n }\n\n .apm__terms-bullets {\n list-style: disc outside;\n padding-left: 1.25rem;\n margin: 0 0 0.75rem 0;\n }\n\n .apm__terms-bullets li {\n margin-bottom: 0.375rem;\n }\n\n .apm__terms-legal {\n margin: 0;\n }\n\n .apm__passive-terms {\n font-family: var(--wall-type-system-sans);\n font-size: 0.9375rem;\n color: #0d0d0d;\n line-height: 1.4;\n margin: 0 0 8px 0;\n }\n\n .apm__passive-terms a {\n color: #1a1a1a;\n font-weight: 700;\n text-decoration: underline;\n }\n\n .apm__checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: var(--mb-spacing-sm, 0.5rem);\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-label-2-size, 0.9375rem);\n color: var(--mb-colour-greyscale-london-20, #1a1a1a);\n line-height: var(--mb-typestyle-label-2-leading, 1.25rem);\n cursor: pointer;\n margin: 0 0 1.5rem 0;\n }\n\n .apm__checkbox-label--error {\n margin-bottom: 0.25rem;\n }\n\n .apm__checkbox-wrapper {\n position: relative;\n flex-shrink: 0;\n width: 1.25rem;\n height: 1.25rem;\n margin-top: 0.0625rem;\n }\n\n .apm__checkbox-input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n cursor: pointer;\n margin: 0;\n z-index: 1;\n }\n\n .apm__checkbox-custom {\n position: absolute;\n top: 0;\n left: 0;\n width: 1.25rem;\n height: 1.25rem;\n pointer-events: none;\n }\n\n .apm__checkbox-custom svg {\n display: none;\n width: 1.25rem;\n height: 1.25rem;\n }\n\n .apm__checkbox-input:not(:checked) ~ .apm__checkbox-custom .svg-unchecked {\n display: block;\n }\n\n .apm__checkbox-input:checked ~ .apm__checkbox-custom .svg-checked {\n display: block;\n }\n\n .apm__checkbox-label--error\n .apm__checkbox-input:not(:checked)\n ~ .apm__checkbox-custom\n .svg-unchecked {\n display: none;\n }\n\n .apm__checkbox-label--error\n .apm__checkbox-input:not(:checked)\n ~ .apm__checkbox-custom\n .svg-error {\n display: block;\n }\n\n .apm__checkbox-input:focus-visible ~ .apm__checkbox-custom {\n outline: solid 0.125rem #c91d42;\n outline-offset: 0.125rem;\n border-radius: 0.25rem;\n }\n\n .apm__checkbox-label a {\n color: #1a1a1a;\n font-weight: 700;\n text-decoration: underline;\n }\n\n .apm__error {\n display: none;\n align-items: center;\n gap: 0.75rem;\n color: var(--mb-colour-greyscale-london-5, #0d0d0d);\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: 1.0625rem;\n font-style: normal;\n font-weight: 500;\n line-height: 1.5rem;\n margin-bottom: 1rem;\n }\n\n .apm__error--visible {\n display: flex;\n }\n\n .apm__cta {\n display: flex;\n width: 100%;\n height: 2.75rem;\n padding: 0.375rem 1rem;\n justify-content: center;\n align-items: center;\n gap: 0.375rem;\n border-radius: 0.25rem;\n background: #000;\n border: none;\n cursor: pointer;\n color: #fff;\n text-align: center;\n font-family: var(\n --mb-typeface-sans,\n var(--wall-type-system-sans, system-ui, sans-serif)\n );\n font-size: 1.25rem;\n font-style: normal;\n font-weight: 500;\n line-height: normal;\n }\n\n .apm__cta svg {\n flex-shrink: 0;\n display: block;\n }\n\n @media (min-width: 22.5rem) and (max-width: 37.5rem) {\n .apm {\n width: 24.375rem;\n max-width: 24.375rem;\n }\n }\n\n @media (min-width: 37.5625rem) {\n .apm {\n border-radius: 0.5rem;\n }\n }\n\n @media (max-width: 22.4375rem) {\n .apm {\n width: 20rem;\n max-width: 20rem;\n }\n }\n\n @media (max-width: 26.1875rem) {\n .apm__cta {\n font-size: 1.125rem;\n }\n }\n</style>\n\n<div class="apm-overlay" id="apple-pay-modal-overlay">\n <div\n class="apm"\n role="dialog"\n aria-modal="true"\n aria-labelledby="apple-pay-modal-offer-name"\n id="apple-pay-modal"\n tabindex="-1"\n >\n <button class="apm__close" id="apple-pay-modal-close" aria-label="Close">\n <svg\n aria-hidden="true"\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n >\n <g clip-path="url(#clip0_15712_93054)">\n <rect width="24" height="24" fill="white" fill-opacity="0.01" />\n <path\n fill-rule="evenodd"\n clip-rule="evenodd"\n d="M0 0H24V24H0V0Z"\n fill="white"\n fill-opacity="0.01"\n />\n <path\n fill-rule="evenodd"\n clip-rule="evenodd"\n d="M18.75 6.60964L17.3904 5.25L12 10.6404L6.60964 5.25L5.25 6.60964L10.6404 12L5.25 17.3904L6.60964 18.75L12 13.3596L17.3904 18.75L18.75 17.3904L13.3596 12L18.75 6.60964Z"\n fill="#333333"\n />\n </g>\n <defs>\n <clipPath id="clip0_15712_93054">\n <rect width="24" height="24" fill="white" />\n </clipPath>\n </defs>\n </svg>\n </button>\n <p class="apm__offer-name" id="apple-pay-modal-offer-name"></p>\n <p class="apm__due-today" id="apple-pay-modal-due-today"></p>\n <hr class="apm__rule" />\n <div class="apm__terms" id="apple-pay-modal-terms"></div>\n <p class="apm__passive-terms" id="apple-pay-modal-passive-terms"></p>\n <label\n class="apm__checkbox-label"\n id="apple-pay-modal-checkbox-label"\n for="apple-pay-modal-checkbox"\n >\n <div class="apm__checkbox-wrapper">\n <input\n class="apm__checkbox-input"\n type="checkbox"\n id="apple-pay-modal-checkbox"\n />\n <span class="apm__checkbox-custom">\n <svg\n aria-hidden="true"\n class="svg-unchecked"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <path\n d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"\n fill="white"\n stroke="#595959"\n />\n </svg>\n <svg\n aria-hidden="true"\n class="svg-checked"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <g clip-path="url(#clip0_20014_9555)">\n <path\n d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"\n fill="#333333"\n />\n <path\n d="M10.2857 17L6 12.6814L7.20857 11.4635L10.2857 14.5557L16.7914 8L18 9.22649L10.2857 17Z"\n fill="white"\n />\n </g>\n <defs>\n <clipPath id="clip0_20014_9555">\n <path\n d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"\n fill="white"\n />\n </clipPath>\n </defs>\n </svg>\n <svg\n aria-hidden="true"\n class="svg-error"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <path\n d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"\n fill="white"\n stroke="#C91D42"\n stroke-width="2"\n />\n </svg>\n </span>\n </div>\n <span id="apple-pay-modal-checkbox-text"></span>\n </label>\n <div class="apm__error" id="apple-pay-modal-error" role="alert">\n <svg\n aria-hidden="true"\n width="20"\n height="20"\n viewBox="0 0 20 20"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <path\n fill-rule="evenodd"\n clip-rule="evenodd"\n d="M10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2ZM0 10C0 4.47715 4.47715 0 10 0C15.5228 0 20 4.47715 20 10C20 15.5228 15.5228 20 10 20C4.47715 20 0 15.5228 0 10ZM11 13C11 13.5523 10.5523 14 10 14C9.44772 14 9 13.5523 9 13C9 12.4477 9.44772 12 10 12C10.5523 12 11 12.4477 11 13ZM10 6C10.5523 6 11 6.44772 11 7V10C11 10.5523 10.5523 11 10 11C9.44772 11 9 10.5523 9 10V7C9 6.44772 9.44772 6 10 6Z"\n fill="#C91D42"\n />\n </svg>\n Please accept the terms to continue\n </div>\n <button class="apm__cta" id="apple-pay-modal-cta">\n Continue with\n <svg width="51" height="22" aria-label="Apple Pay" role="img">\n <use href="#apple-pay-logo" />\n </svg>\n </button>\n </div>\n</div>\n\n';
|
|
79
|
+
var apple_pay_modal_template_default = `<style>
|
|
80
|
+
.apm-overlay {
|
|
81
|
+
position: fixed;
|
|
82
|
+
top: 0;
|
|
83
|
+
left: 0;
|
|
84
|
+
width: 100%;
|
|
85
|
+
height: 100%;
|
|
86
|
+
z-index: 97;
|
|
87
|
+
background: rgba(13, 13, 13, 0.7);
|
|
88
|
+
display: flex;
|
|
89
|
+
align-items: center;
|
|
90
|
+
justify-content: center;
|
|
91
|
+
padding: var(--wall-gutter, 2rem);
|
|
92
|
+
box-sizing: border-box;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.apm {
|
|
96
|
+
position: relative;
|
|
97
|
+
background: #fff;
|
|
98
|
+
border-radius: 0.5rem 0.5rem 0 0;
|
|
99
|
+
border: 0.0625rem solid #d9d9d9;
|
|
100
|
+
padding: var(--mb-spacing-lg, 1.5rem);
|
|
101
|
+
width: 25rem;
|
|
102
|
+
max-width: 25rem;
|
|
103
|
+
box-sizing: border-box;
|
|
104
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
105
|
+
box-shadow: 0 0.25rem 1rem 0 rgba(13, 13, 13, 0.15);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.apm__close {
|
|
109
|
+
position: absolute;
|
|
110
|
+
top: 1.5rem;
|
|
111
|
+
right: 1.3125rem;
|
|
112
|
+
background: transparent;
|
|
113
|
+
border: none;
|
|
114
|
+
cursor: pointer;
|
|
115
|
+
padding: 0;
|
|
116
|
+
width: 1.5rem;
|
|
117
|
+
height: 1.5rem;
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
justify-content: center;
|
|
121
|
+
color: var(--mb-colour-greyscale-london-20, #1a1a1a);
|
|
122
|
+
transition:
|
|
123
|
+
background-color ease-in-out 0.2s,
|
|
124
|
+
color ease-in-out 0.2s;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.apm__close:hover {
|
|
128
|
+
color: var(--mb-colour-base-chicago-30, #333333);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.apm__close:active {
|
|
132
|
+
background-color: var(--mb-colour-base-chicago-90, #e6e6e6);
|
|
133
|
+
color: var(--mb-colour-base-chicago-30, #333333);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.apm__close:focus {
|
|
137
|
+
background-color: var(--mb-colour-base-chicago-90, #e6e6e6);
|
|
138
|
+
outline: solid 0.125rem var(--focus-border-color, #121212);
|
|
139
|
+
border-radius: 0.25rem;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.apm__offer-name {
|
|
143
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
144
|
+
font-size: var(--mb-typestyle-title-3-size, 1.25rem);
|
|
145
|
+
font-weight: 500;
|
|
146
|
+
color: var(--mb-colour-greyscale-london-5, #0d0d0d);
|
|
147
|
+
line-height: var(--mb-typestyle-title-3-leading, 1.75rem);
|
|
148
|
+
font-style: normal;
|
|
149
|
+
margin: 0 1.5rem 0.5rem 0;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.apm__due-today {
|
|
153
|
+
color: #1a1a1a;
|
|
154
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
155
|
+
font-size: var(--mb-typestyle-label-2-size, 0.9375rem);
|
|
156
|
+
font-style: normal;
|
|
157
|
+
font-weight: 400;
|
|
158
|
+
line-height: var(--mb-typestyle-label-2-leading, 1.25rem);
|
|
159
|
+
margin: 0 0 0.75rem 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.apm__rule {
|
|
163
|
+
border: none;
|
|
164
|
+
border-top: 0.0625rem solid #d9d9d9;
|
|
165
|
+
margin: 0 0 1rem 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.apm__terms {
|
|
169
|
+
color: #1a1a1a;
|
|
170
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
171
|
+
font-size: var(--mb-typestyle-label-2-size, 0.9375rem);
|
|
172
|
+
font-style: normal;
|
|
173
|
+
font-weight: 400;
|
|
174
|
+
line-height: var(--mb-typestyle-label-2-leading, 1.25rem);
|
|
175
|
+
margin: 0 0 1rem 0;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.apm__terms-bullets {
|
|
179
|
+
list-style: disc outside;
|
|
180
|
+
padding-left: 1.25rem;
|
|
181
|
+
margin: 0 0 0.75rem 0;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.apm__terms-bullets li {
|
|
185
|
+
margin-bottom: 0.375rem;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.apm__terms-legal {
|
|
189
|
+
margin: 0;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.apm__passive-terms {
|
|
193
|
+
font-family: var(--wall-type-system-sans);
|
|
194
|
+
font-size: 0.9375rem;
|
|
195
|
+
color: #0d0d0d;
|
|
196
|
+
line-height: 1.4;
|
|
197
|
+
margin: 0 0 8px 0;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.apm__passive-terms a {
|
|
201
|
+
color: #1a1a1a;
|
|
202
|
+
font-weight: 700;
|
|
203
|
+
text-decoration: underline;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.apm__checkbox-label {
|
|
207
|
+
display: flex;
|
|
208
|
+
align-items: flex-start;
|
|
209
|
+
gap: var(--mb-spacing-sm, 0.5rem);
|
|
210
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
211
|
+
font-size: var(--mb-typestyle-label-2-size, 0.9375rem);
|
|
212
|
+
color: var(--mb-colour-greyscale-london-20, #1a1a1a);
|
|
213
|
+
line-height: var(--mb-typestyle-label-2-leading, 1.25rem);
|
|
214
|
+
cursor: pointer;
|
|
215
|
+
margin: 0 0 1.5rem 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.apm__checkbox-label--error {
|
|
219
|
+
margin-bottom: 0.25rem;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.apm__checkbox-wrapper {
|
|
223
|
+
position: relative;
|
|
224
|
+
flex-shrink: 0;
|
|
225
|
+
width: 1.25rem;
|
|
226
|
+
height: 1.25rem;
|
|
227
|
+
margin-top: 0.0625rem;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.apm__checkbox-input {
|
|
231
|
+
position: absolute;
|
|
232
|
+
opacity: 0;
|
|
233
|
+
width: 100%;
|
|
234
|
+
height: 100%;
|
|
235
|
+
cursor: pointer;
|
|
236
|
+
margin: 0;
|
|
237
|
+
z-index: 1;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.apm__checkbox-custom {
|
|
241
|
+
position: absolute;
|
|
242
|
+
top: 0;
|
|
243
|
+
left: 0;
|
|
244
|
+
width: 1.25rem;
|
|
245
|
+
height: 1.25rem;
|
|
246
|
+
pointer-events: none;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.apm__checkbox-custom svg {
|
|
250
|
+
display: none;
|
|
251
|
+
width: 1.25rem;
|
|
252
|
+
height: 1.25rem;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.apm__checkbox-input:not(:checked) ~ .apm__checkbox-custom .svg-unchecked {
|
|
256
|
+
display: block;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.apm__checkbox-input:checked ~ .apm__checkbox-custom .svg-checked {
|
|
260
|
+
display: block;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.apm__checkbox-label--error
|
|
264
|
+
.apm__checkbox-input:not(:checked)
|
|
265
|
+
~ .apm__checkbox-custom
|
|
266
|
+
.svg-unchecked {
|
|
267
|
+
display: none;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.apm__checkbox-label--error
|
|
271
|
+
.apm__checkbox-input:not(:checked)
|
|
272
|
+
~ .apm__checkbox-custom
|
|
273
|
+
.svg-error {
|
|
274
|
+
display: block;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.apm__checkbox-input:focus-visible ~ .apm__checkbox-custom {
|
|
278
|
+
outline: solid 0.125rem #c91d42;
|
|
279
|
+
outline-offset: 0.125rem;
|
|
280
|
+
border-radius: 0.25rem;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.apm__checkbox-label a {
|
|
284
|
+
color: #1a1a1a;
|
|
285
|
+
font-weight: 700;
|
|
286
|
+
text-decoration: underline;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.apm__error {
|
|
290
|
+
display: none;
|
|
291
|
+
align-items: center;
|
|
292
|
+
gap: 0.75rem;
|
|
293
|
+
color: var(--mb-colour-greyscale-london-5, #0d0d0d);
|
|
294
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
295
|
+
font-size: 1.0625rem;
|
|
296
|
+
font-style: normal;
|
|
297
|
+
font-weight: 500;
|
|
298
|
+
line-height: 1.5rem;
|
|
299
|
+
margin-bottom: 1rem;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.apm__error--visible {
|
|
303
|
+
display: flex;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.apm__cta {
|
|
307
|
+
display: flex;
|
|
308
|
+
width: 100%;
|
|
309
|
+
height: 2.75rem;
|
|
310
|
+
padding: 0.375rem 1rem;
|
|
311
|
+
justify-content: center;
|
|
312
|
+
align-items: center;
|
|
313
|
+
gap: 0.375rem;
|
|
314
|
+
border-radius: 0.25rem;
|
|
315
|
+
background: #000;
|
|
316
|
+
border: none;
|
|
317
|
+
cursor: pointer;
|
|
318
|
+
color: #fff;
|
|
319
|
+
text-align: center;
|
|
320
|
+
font-size: 1.25rem;
|
|
321
|
+
font-style: normal;
|
|
322
|
+
font-weight: 500;
|
|
323
|
+
line-height: normal;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.apm__cta:disabled {
|
|
327
|
+
cursor: not-allowed;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.apm__cta[aria-busy="true"] {
|
|
331
|
+
position: relative;
|
|
332
|
+
cursor: not-allowed;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.apm__cta-content {
|
|
336
|
+
display: flex;
|
|
337
|
+
align-items: center;
|
|
338
|
+
gap: 0.375rem;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.apm__cta-label {
|
|
342
|
+
display: inline-flex;
|
|
343
|
+
align-items: center;
|
|
344
|
+
gap: 0.375rem;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.apm__cta-loading {
|
|
348
|
+
display: none;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.apm__cta[aria-busy="true"]::before {
|
|
352
|
+
content: '';
|
|
353
|
+
position: absolute;
|
|
354
|
+
top: 50%;
|
|
355
|
+
left: 50%;
|
|
356
|
+
width: 1.25rem;
|
|
357
|
+
height: 1.25rem;
|
|
358
|
+
border: 2px solid rgba(255, 255, 255, 0.25);
|
|
359
|
+
border-top-color: #fff;
|
|
360
|
+
border-radius: 50%;
|
|
361
|
+
animation: apm-cta-spinner 0.8s linear infinite;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
@keyframes apm-cta-spinner {
|
|
365
|
+
from {
|
|
366
|
+
transform: translate(-50%, -50%) rotate(0deg);
|
|
367
|
+
}
|
|
368
|
+
to {
|
|
369
|
+
transform: translate(-50%, -50%) rotate(360deg);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.apm__cta svg {
|
|
374
|
+
flex-shrink: 0;
|
|
375
|
+
display: block;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
@media (min-width: 22.5rem) and (max-width: 37.5rem) {
|
|
379
|
+
.apm {
|
|
380
|
+
width: 24.375rem;
|
|
381
|
+
max-width: 24.375rem;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
@media (min-width: 37.5625rem) {
|
|
386
|
+
.apm {
|
|
387
|
+
border-radius: 0.5rem;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
@media (max-width: 22.4375rem) {
|
|
392
|
+
.apm {
|
|
393
|
+
width: 20rem;
|
|
394
|
+
max-width: 20rem;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
@media (max-width: 26.1875rem) {
|
|
399
|
+
.apm__cta {
|
|
400
|
+
font-size: 1.125rem;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
</style>
|
|
404
|
+
|
|
405
|
+
<div class="apm-overlay" id="apple-pay-modal-overlay">
|
|
406
|
+
<div
|
|
407
|
+
class="apm"
|
|
408
|
+
role="dialog"
|
|
409
|
+
aria-modal="true"
|
|
410
|
+
aria-labelledby="apple-pay-modal-offer-name"
|
|
411
|
+
id="apple-pay-modal"
|
|
412
|
+
tabindex="-1"
|
|
413
|
+
>
|
|
414
|
+
<button class="apm__close" id="apple-pay-modal-close" aria-label="Close">
|
|
415
|
+
<svg
|
|
416
|
+
aria-hidden="true"
|
|
417
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
418
|
+
width="24"
|
|
419
|
+
height="24"
|
|
420
|
+
viewBox="0 0 24 24"
|
|
421
|
+
fill="none"
|
|
422
|
+
>
|
|
423
|
+
<g clip-path="url(#clip0_15712_93054)">
|
|
424
|
+
<rect width="24" height="24" fill="white" fill-opacity="0.01" />
|
|
425
|
+
<path
|
|
426
|
+
fill-rule="evenodd"
|
|
427
|
+
clip-rule="evenodd"
|
|
428
|
+
d="M0 0H24V24H0V0Z"
|
|
429
|
+
fill="white"
|
|
430
|
+
fill-opacity="0.01"
|
|
431
|
+
/>
|
|
432
|
+
<path
|
|
433
|
+
fill-rule="evenodd"
|
|
434
|
+
clip-rule="evenodd"
|
|
435
|
+
d="M18.75 6.60964L17.3904 5.25L12 10.6404L6.60964 5.25L5.25 6.60964L10.6404 12L5.25 17.3904L6.60964 18.75L12 13.3596L17.3904 18.75L18.75 17.3904L13.3596 12L18.75 6.60964Z"
|
|
436
|
+
fill="currentColor"
|
|
437
|
+
/>
|
|
438
|
+
</g>
|
|
439
|
+
<defs>
|
|
440
|
+
<clipPath id="clip0_15712_93054">
|
|
441
|
+
<rect width="24" height="24" fill="white" />
|
|
442
|
+
</clipPath>
|
|
443
|
+
</defs>
|
|
444
|
+
</svg>
|
|
445
|
+
</button>
|
|
446
|
+
<p class="apm__offer-name" id="apple-pay-modal-offer-name"></p>
|
|
447
|
+
<p class="apm__due-today" id="apple-pay-modal-due-today"></p>
|
|
448
|
+
<hr class="apm__rule" />
|
|
449
|
+
<div class="apm__terms" id="apple-pay-modal-terms"></div>
|
|
450
|
+
<p class="apm__passive-terms" id="apple-pay-modal-passive-terms"></p>
|
|
451
|
+
<label
|
|
452
|
+
class="apm__checkbox-label"
|
|
453
|
+
id="apple-pay-modal-checkbox-label"
|
|
454
|
+
for="apple-pay-modal-checkbox"
|
|
455
|
+
>
|
|
456
|
+
<div class="apm__checkbox-wrapper">
|
|
457
|
+
<input
|
|
458
|
+
class="apm__checkbox-input"
|
|
459
|
+
type="checkbox"
|
|
460
|
+
id="apple-pay-modal-checkbox"
|
|
461
|
+
/>
|
|
462
|
+
<span class="apm__checkbox-custom">
|
|
463
|
+
<svg
|
|
464
|
+
aria-hidden="true"
|
|
465
|
+
class="svg-unchecked"
|
|
466
|
+
width="24"
|
|
467
|
+
height="24"
|
|
468
|
+
viewBox="0 0 24 24"
|
|
469
|
+
fill="none"
|
|
470
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
471
|
+
>
|
|
472
|
+
<path
|
|
473
|
+
d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"
|
|
474
|
+
fill="white"
|
|
475
|
+
stroke="#595959"
|
|
476
|
+
/>
|
|
477
|
+
</svg>
|
|
478
|
+
<svg
|
|
479
|
+
aria-hidden="true"
|
|
480
|
+
class="svg-checked"
|
|
481
|
+
width="24"
|
|
482
|
+
height="24"
|
|
483
|
+
viewBox="0 0 24 24"
|
|
484
|
+
fill="none"
|
|
485
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
486
|
+
>
|
|
487
|
+
<g clip-path="url(#clip0_20014_9555)">
|
|
488
|
+
<path
|
|
489
|
+
d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"
|
|
490
|
+
fill="#333333"
|
|
491
|
+
/>
|
|
492
|
+
<path
|
|
493
|
+
d="M10.2857 17L6 12.6814L7.20857 11.4635L10.2857 14.5557L16.7914 8L18 9.22649L10.2857 17Z"
|
|
494
|
+
fill="white"
|
|
495
|
+
/>
|
|
496
|
+
</g>
|
|
497
|
+
<defs>
|
|
498
|
+
<clipPath id="clip0_20014_9555">
|
|
499
|
+
<path
|
|
500
|
+
d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"
|
|
501
|
+
fill="white"
|
|
502
|
+
/>
|
|
503
|
+
</clipPath>
|
|
504
|
+
</defs>
|
|
505
|
+
</svg>
|
|
506
|
+
<svg
|
|
507
|
+
aria-hidden="true"
|
|
508
|
+
class="svg-error"
|
|
509
|
+
width="24"
|
|
510
|
+
height="24"
|
|
511
|
+
viewBox="0 0 24 24"
|
|
512
|
+
fill="none"
|
|
513
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
514
|
+
>
|
|
515
|
+
<path
|
|
516
|
+
d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"
|
|
517
|
+
fill="white"
|
|
518
|
+
stroke="#C91D42"
|
|
519
|
+
stroke-width="2"
|
|
520
|
+
/>
|
|
521
|
+
</svg>
|
|
522
|
+
</span>
|
|
523
|
+
</div>
|
|
524
|
+
<span id="apple-pay-modal-checkbox-text"></span>
|
|
525
|
+
</label>
|
|
526
|
+
<div class="apm__error" id="apple-pay-modal-error" role="alert">
|
|
527
|
+
<svg
|
|
528
|
+
aria-hidden="true"
|
|
529
|
+
width="20"
|
|
530
|
+
height="20"
|
|
531
|
+
viewBox="0 0 20 20"
|
|
532
|
+
fill="none"
|
|
533
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
534
|
+
>
|
|
535
|
+
<path
|
|
536
|
+
fill-rule="evenodd"
|
|
537
|
+
clip-rule="evenodd"
|
|
538
|
+
d="M10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2ZM0 10C0 4.47715 4.47715 0 10 0C15.5228 0 20 4.47715 20 10C20 15.5228 15.5228 20 10 20C4.47715 20 0 15.5228 0 10ZM11 13C11 13.5523 10.5523 14 10 14C9.44772 14 9 13.5523 9 13C9 12.4477 9.44772 12 10 12C10.5523 12 11 12.4477 11 13ZM10 6C10.5523 6 11 6.44772 11 7V10C11 10.5523 10.5523 11 10 11C9.44772 11 9 10.5523 9 10V7C9 6.44772 9.44772 6 10 6Z"
|
|
539
|
+
fill="#C91D42"
|
|
540
|
+
/>
|
|
541
|
+
</svg>
|
|
542
|
+
Please accept the terms to continue
|
|
543
|
+
</div>
|
|
544
|
+
<button class="apm__cta" id="apple-pay-modal-cta" aria-label="Continue with Apple Pay">
|
|
545
|
+
<span class="apm__cta-content">
|
|
546
|
+
<span class="apm__cta-label">
|
|
547
|
+
Continue with
|
|
548
|
+
<svg width="51" height="22" aria-hidden="true" role="img">
|
|
549
|
+
<use href="#apple-pay-logo" />
|
|
550
|
+
</svg>
|
|
551
|
+
</span>
|
|
552
|
+
</span>
|
|
553
|
+
<span class="apm__cta-loading" aria-hidden="true">Loading...</span>
|
|
554
|
+
</button>
|
|
555
|
+
</div>
|
|
556
|
+
</div>
|
|
557
|
+
|
|
558
|
+
`;
|
|
559
|
+
|
|
560
|
+
// src/clients/payment-checkout/config.ts
|
|
561
|
+
var runtimeConfig = null;
|
|
562
|
+
var configureApplePay = (config) => {
|
|
563
|
+
runtimeConfig = {
|
|
564
|
+
...config
|
|
565
|
+
};
|
|
566
|
+
};
|
|
567
|
+
var getApplePayConfig = () => runtimeConfig;
|
|
568
|
+
|
|
569
|
+
// src/utils/recaptcha.ts
|
|
570
|
+
var loadRecaptchaScript = (siteKey) => {
|
|
571
|
+
return new Promise((resolve, reject) => {
|
|
572
|
+
if (typeof grecaptcha !== "undefined") return resolve();
|
|
573
|
+
const existingScript = document.querySelector(
|
|
574
|
+
'script[src*="recaptcha/api.js"]'
|
|
575
|
+
);
|
|
576
|
+
if (existingScript) {
|
|
577
|
+
existingScript.addEventListener("load", () => resolve());
|
|
578
|
+
existingScript.addEventListener(
|
|
579
|
+
"error",
|
|
580
|
+
() => reject(new Error("Failed to load existing reCAPTCHA script"))
|
|
581
|
+
);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
const script = document.createElement("script");
|
|
585
|
+
script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
|
|
586
|
+
script.async = true;
|
|
587
|
+
script.defer = true;
|
|
588
|
+
script.onload = () => resolve();
|
|
589
|
+
script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
|
|
590
|
+
document.head.appendChild(script);
|
|
591
|
+
});
|
|
592
|
+
};
|
|
593
|
+
var getRecaptchaToken = async (action) => {
|
|
594
|
+
const siteKey = getApplePayConfig()?.recaptchaSiteKey;
|
|
595
|
+
if (!siteKey) {
|
|
596
|
+
throw new Error(
|
|
597
|
+
"[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
await loadRecaptchaScript(siteKey);
|
|
601
|
+
return new Promise((resolve, reject) => {
|
|
602
|
+
grecaptcha.ready(() => {
|
|
603
|
+
grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
|
|
604
|
+
});
|
|
605
|
+
});
|
|
606
|
+
};
|
|
607
|
+
var getPurchaseRecaptchaTokens = async () => {
|
|
608
|
+
const [checkEligibility, newBasket, registerUser] = await Promise.all([
|
|
609
|
+
getRecaptchaToken("checkEligibility"),
|
|
610
|
+
getRecaptchaToken("newBasket"),
|
|
611
|
+
getRecaptchaToken("registerUser")
|
|
612
|
+
]);
|
|
613
|
+
return { checkEligibility, newBasket, registerUser };
|
|
614
|
+
};
|
|
80
615
|
|
|
81
616
|
// src/apple-pay-modal.ts
|
|
82
617
|
function getRenewalDateText(unit, duration) {
|
|
@@ -128,6 +663,7 @@ function getOfferTypeText(offerType) {
|
|
|
128
663
|
}
|
|
129
664
|
var TERMS_LINK = '<a href="https://www.economistgroup.com/terms-of-use" target="_blank" rel="noopener noreferrer">Terms and Conditions</a>';
|
|
130
665
|
var PRIVACY_LINK = '<a href="https://www.economistgroup.com/privacy-policy" target="_blank" rel="noopener noreferrer">Privacy Policy</a>';
|
|
666
|
+
var MSG_RECAPTCHA_LOAD_ERROR = "Something went wrong. Please close and try again.";
|
|
131
667
|
function getCheckboxTermsHtml(isNYT, isLoggedIn, autoRenewal) {
|
|
132
668
|
const autoRenewalClause = autoRenewal ? " and auto-renewal terms above," : "";
|
|
133
669
|
if (isNYT) {
|
|
@@ -160,6 +696,8 @@ function renewalPeriodText(unit, duration) {
|
|
|
160
696
|
return "";
|
|
161
697
|
}
|
|
162
698
|
}
|
|
699
|
+
var LI_SEPARATOR = "\0LI_SEP\0";
|
|
700
|
+
var P_SEPARATOR = "\0P_SEP\0";
|
|
163
701
|
function buildTermsContext(offer, country) {
|
|
164
702
|
const isUS = country === "US";
|
|
165
703
|
const isCA = country === "CA";
|
|
@@ -196,19 +734,19 @@ function freeTrialTerms(offer, ctx) {
|
|
|
196
734
|
const trialDuration = offer.subscription_options?.trial_period?.duration ?? 1;
|
|
197
735
|
const trialDateStr = `on ${getRenewalDateText(trialUnit, trialDuration)}${ctx.verificationText}`;
|
|
198
736
|
if (ctx.isUS) {
|
|
199
|
-
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled{
|
|
737
|
+
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal until cancelled. ${ctx.usCancelNote}${ctx.taxFootnote}`;
|
|
200
738
|
}
|
|
201
|
-
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled{
|
|
739
|
+
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}`;
|
|
202
740
|
}
|
|
203
741
|
function nytTerms(ctx) {
|
|
204
742
|
const nytAccessText = "Your complimentary access to The New York Times is for one year only and does not auto-renew. We will send your instructions on how to redeem access to The New York Times by email.";
|
|
205
743
|
if (ctx.isUS) {
|
|
206
|
-
return `Your subscription to <em>The Economist</em> auto-renews ${ctx.periodText} until cancelled{
|
|
744
|
+
return `Your subscription to <em>The Economist</em> auto-renews ${ctx.periodText} until cancelled${LI_SEPARATOR}Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.renewalDateStr}${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal until cancelled. ${ctx.usCancelNote}${ctx.taxFootnote}${P_SEPARATOR}${nytAccessText}`;
|
|
207
745
|
}
|
|
208
746
|
if (ctx.isCA) {
|
|
209
|
-
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled
|
|
747
|
+
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled.${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}${P_SEPARATOR}${nytAccessText}`;
|
|
210
748
|
}
|
|
211
|
-
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled{
|
|
749
|
+
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime} ${nytAccessText}`;
|
|
212
750
|
}
|
|
213
751
|
function minTermContractTerms(offer, ctx) {
|
|
214
752
|
const duePrice = formatPrice(offer.price.purchase, offer.price.currency_code);
|
|
@@ -218,28 +756,28 @@ function minTermContractTerms(offer, ctx) {
|
|
|
218
756
|
const contractLength = mtDuration && mtUnit ? `${mtDuration} ${mtUnit}` : "";
|
|
219
757
|
const initialContractText = contractLength ? `your initial ${contractLength} contract` : "your initial contract";
|
|
220
758
|
const mtRenewalDateText = mtUnit && mtDuration ? getRenewalDateText(mtUnit, Number(mtDuration)) : ctx.renewalDateText;
|
|
221
|
-
return `You\u2019ll be charged ${duePrice} a month for the duration of ${initialContractText}{
|
|
759
|
+
return `You\u2019ll be charged ${duePrice} a month for the duration of ${initialContractText}${LI_SEPARATOR}Your subscription auto-renews annually at ${ctx.renewalPriceText} a month on ${mtRenewalDateText} until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}`;
|
|
222
760
|
}
|
|
223
761
|
function paidTrialTerms(offer, ctx) {
|
|
224
762
|
const trialUnit = offer.subscription_options?.trial_period?.unit ?? ctx.unit;
|
|
225
763
|
const trialDuration = offer.subscription_options?.trial_period?.duration ?? ctx.duration;
|
|
226
764
|
const trialDateText = getRenewalDateText(trialUnit, trialDuration);
|
|
227
765
|
if (ctx.isUS) {
|
|
228
|
-
return `Your subscription auto-renews ${ctx.periodText} until cancelled{
|
|
766
|
+
return `Your subscription auto-renews ${ctx.periodText} until cancelled${LI_SEPARATOR}Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} on ${trialDateText} when your paid trial ends${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.usCancelNote}${ctx.taxFootnote}`;
|
|
229
767
|
}
|
|
230
|
-
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} on ${trialDateText} when your paid trial ends, until cancelled{
|
|
768
|
+
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} on ${trialDateText} when your paid trial ends, until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}`;
|
|
231
769
|
}
|
|
232
770
|
function autoRenewalTerms(ctx) {
|
|
233
771
|
if (ctx.isUS) {
|
|
234
|
-
return `Your subscription auto-renews ${ctx.periodText} until cancelled{
|
|
772
|
+
return `Your subscription auto-renews ${ctx.periodText} until cancelled${LI_SEPARATOR}Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.renewalDateStr}${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal until cancelled. ${ctx.usCancelNote}${ctx.taxFootnote}`;
|
|
235
773
|
}
|
|
236
|
-
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled{
|
|
774
|
+
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}`;
|
|
237
775
|
}
|
|
238
776
|
function noAutoRenewalTerms(ctx) {
|
|
239
777
|
if (ctx.isUS || ctx.isCA) {
|
|
240
|
-
return `Your subscription does not renew automatically${ctx.taxFootnote}{
|
|
778
|
+
return `Your subscription does not renew automatically${ctx.taxFootnote}${LI_SEPARATOR}`;
|
|
241
779
|
}
|
|
242
|
-
return `Your subscription does not renew automatically{
|
|
780
|
+
return `Your subscription does not renew automatically${LI_SEPARATOR}`;
|
|
243
781
|
}
|
|
244
782
|
function generateApplePayModalTerms(offer, country) {
|
|
245
783
|
const ctx = buildTermsContext(offer, country);
|
|
@@ -262,9 +800,9 @@ function generateApplePayModalTerms(offer, country) {
|
|
|
262
800
|
return noAutoRenewalTerms(ctx);
|
|
263
801
|
}
|
|
264
802
|
function renderTermsHtml(termsText) {
|
|
265
|
-
const renewalTextLists = termsText.split(
|
|
803
|
+
const renewalTextLists = termsText.split(LI_SEPARATOR);
|
|
266
804
|
const lastPart = renewalTextLists.pop() || "";
|
|
267
|
-
const renewalTextParagraphs = lastPart.split(
|
|
805
|
+
const renewalTextParagraphs = lastPart.split(P_SEPARATOR);
|
|
268
806
|
const ulHtml = `<ul class="apm__terms-bullets">${renewalTextLists.map((value) => `<li>${value}</li>`).join("")}</ul>`;
|
|
269
807
|
const paragraphHtml = renewalTextParagraphs.filter(Boolean).map((value) => `<p class="apm__terms-legal">${value}</p>`).join("");
|
|
270
808
|
return ulHtml + paragraphHtml;
|
|
@@ -297,6 +835,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
297
835
|
#country = "";
|
|
298
836
|
#triggerElement = null;
|
|
299
837
|
#keyHandler = null;
|
|
838
|
+
#recaptchaTokens = null;
|
|
839
|
+
#recaptchaTokensPromise = null;
|
|
840
|
+
/**
|
|
841
|
+
* Synchronous callback invoked directly from the CTA click handler once the
|
|
842
|
+
* user confirms. The caller (ApplePayButton) must call startApplePaySession
|
|
843
|
+
* inside this callback to preserve the browser's user-gesture chain — Safari
|
|
844
|
+
* requires new ApplePaySession() to execute within the original click stack.
|
|
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.
|
|
849
|
+
*/
|
|
850
|
+
onConfirm = null;
|
|
300
851
|
set offer(value) {
|
|
301
852
|
this.#offer = value;
|
|
302
853
|
}
|
|
@@ -317,7 +868,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
317
868
|
const offer = this.#offer;
|
|
318
869
|
const country = this.#country;
|
|
319
870
|
if (!offer) {
|
|
320
|
-
console.error("ApplePayModal: Missing or invalid offer data");
|
|
321
871
|
this.remove();
|
|
322
872
|
return;
|
|
323
873
|
}
|
|
@@ -392,27 +942,56 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
392
942
|
}
|
|
393
943
|
});
|
|
394
944
|
}
|
|
945
|
+
if (this.#recaptchaTokensPromise) {
|
|
946
|
+
if (cta) {
|
|
947
|
+
cta.setAttribute("disabled", "");
|
|
948
|
+
cta.setAttribute("aria-disabled", "true");
|
|
949
|
+
cta.setAttribute("aria-busy", "true");
|
|
950
|
+
}
|
|
951
|
+
this.#recaptchaTokensPromise.then((tokens) => {
|
|
952
|
+
this.#recaptchaTokens = tokens;
|
|
953
|
+
if (cta) {
|
|
954
|
+
cta.removeAttribute("disabled");
|
|
955
|
+
cta.removeAttribute("aria-disabled");
|
|
956
|
+
cta.removeAttribute("aria-busy");
|
|
957
|
+
}
|
|
958
|
+
}).catch(() => {
|
|
959
|
+
if (cta) {
|
|
960
|
+
cta.removeAttribute("aria-busy");
|
|
961
|
+
}
|
|
962
|
+
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
963
|
+
if (existingError) {
|
|
964
|
+
const icon = existingError.querySelector("svg");
|
|
965
|
+
existingError.textContent = MSG_RECAPTCHA_LOAD_ERROR;
|
|
966
|
+
if (icon) existingError.prepend(icon);
|
|
967
|
+
existingError.classList.add("apm__error--visible");
|
|
968
|
+
} else {
|
|
969
|
+
const errorNotice = document.createElement("div");
|
|
970
|
+
errorNotice.setAttribute("role", "alert");
|
|
971
|
+
errorNotice.className = "apm__error apm__error--visible";
|
|
972
|
+
errorNotice.textContent = MSG_RECAPTCHA_LOAD_ERROR;
|
|
973
|
+
cta?.insertAdjacentElement("beforebegin", errorNotice);
|
|
974
|
+
}
|
|
975
|
+
});
|
|
976
|
+
}
|
|
395
977
|
cta?.addEventListener("click", () => {
|
|
396
978
|
if (isUS && checkbox && !checkbox.checked) {
|
|
397
979
|
errorElement?.classList.add("apm__error--visible");
|
|
398
980
|
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
399
981
|
return;
|
|
400
982
|
}
|
|
401
|
-
this
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
detail: { skuId: offer.sku_id, country }
|
|
406
|
-
})
|
|
407
|
-
);
|
|
408
|
-
this.close();
|
|
983
|
+
if (this.#recaptchaTokens) {
|
|
984
|
+
this.onConfirm?.(this.#recaptchaTokens);
|
|
985
|
+
this.close();
|
|
986
|
+
}
|
|
409
987
|
});
|
|
410
988
|
this.querySelector("#apple-pay-modal-close")?.addEventListener(
|
|
411
989
|
"click",
|
|
412
990
|
() => this.close()
|
|
413
991
|
);
|
|
414
992
|
}
|
|
415
|
-
open() {
|
|
993
|
+
open(recaptchaTokensPromise) {
|
|
994
|
+
this.#recaptchaTokensPromise = recaptchaTokensPromise ?? getPurchaseRecaptchaTokens();
|
|
416
995
|
this.#triggerElement = document.activeElement;
|
|
417
996
|
document.body.appendChild(this);
|
|
418
997
|
this.#keyHandler = (event) => {
|
|
@@ -439,16 +1018,101 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
439
1018
|
};
|
|
440
1019
|
|
|
441
1020
|
// src/templates/apple-pay-button.template.html
|
|
442
|
-
var apple_pay_button_template_default =
|
|
1021
|
+
var apple_pay_button_template_default = `<style>
|
|
1022
|
+
/* Use CSS variables for layout so parent walls can easily override placement and sizing */
|
|
1023
|
+
teg-apple-pay-button {
|
|
1024
|
+
display: block;
|
|
1025
|
+
margin: var(--apple-pay-margin, 0);
|
|
1026
|
+
width: 100%;
|
|
1027
|
+
height: 100%;
|
|
1028
|
+
}
|
|
443
1029
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
}
|
|
451
|
-
|
|
1030
|
+
teg-apple-pay-button .apple-pay-container {
|
|
1031
|
+
display: flex;
|
|
1032
|
+
flex-direction: column;
|
|
1033
|
+
align-items: stretch;
|
|
1034
|
+
width: 100%;
|
|
1035
|
+
height: 100%;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
teg-apple-pay-button .apple-pay-btn {
|
|
1039
|
+
display: flex;
|
|
1040
|
+
align-items: center;
|
|
1041
|
+
justify-content: center;
|
|
1042
|
+
gap: 0.375rem;
|
|
1043
|
+
width: 100%;
|
|
1044
|
+
min-width: 0;
|
|
1045
|
+
height: 100%;
|
|
1046
|
+
min-height: var(--apple-pay-height, 2.75rem);
|
|
1047
|
+
background-color: var(--apple-pay-background-color, #000);
|
|
1048
|
+
color: var(--apple-pay-foreground-color, #fff);
|
|
1049
|
+
border: none;
|
|
1050
|
+
border-radius: var(--apple-pay-border-radius, 1.375rem);
|
|
1051
|
+
cursor: pointer;
|
|
1052
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
1053
|
+
font-size: 1.0625rem;
|
|
1054
|
+
font-weight: 500;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
teg-apple-pay-button .apple-pay-btn svg {
|
|
1058
|
+
flex-shrink: 0;
|
|
1059
|
+
display: block;
|
|
1060
|
+
color: currentColor;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading {
|
|
1064
|
+
position: relative;
|
|
1065
|
+
cursor: default;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading::before {
|
|
1069
|
+
content: '';
|
|
1070
|
+
position: absolute;
|
|
1071
|
+
top: 50%;
|
|
1072
|
+
left: 50%;
|
|
1073
|
+
width: 1.25rem;
|
|
1074
|
+
height: 1.25rem;
|
|
1075
|
+
border: 2px solid var(--apple-pay-spinner-track-color, rgba(255, 255, 255, 0.25));
|
|
1076
|
+
border-top-color: var(--apple-pay-spinner-head-color, currentColor);
|
|
1077
|
+
border-radius: 50%;
|
|
1078
|
+
animation: wap-button-spinner 0.8s linear infinite;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
teg-apple-pay-button .apple-pay-btn__logo {
|
|
1082
|
+
display: inline-flex;
|
|
1083
|
+
align-items: center;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
teg-apple-pay-button .apple-pay-btn__loading {
|
|
1087
|
+
display: none;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
@keyframes wap-button-spinner {
|
|
1091
|
+
from {
|
|
1092
|
+
transform: translate(-50%, -50%) rotate(0deg);
|
|
1093
|
+
}
|
|
1094
|
+
to {
|
|
1095
|
+
transform: translate(-50%, -50%) rotate(360deg);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
</style>
|
|
1099
|
+
|
|
1100
|
+
<div class="apple-pay-container" aria-label="Express checkout with Apple Pay">
|
|
1101
|
+
<button
|
|
1102
|
+
class="apple-pay-btn"
|
|
1103
|
+
type="button"
|
|
1104
|
+
aria-label="Pay with Apple Pay"
|
|
1105
|
+
data-analytics="paywall:apple-pay-checkout"
|
|
1106
|
+
>
|
|
1107
|
+
<span class="apple-pay-btn__logo">
|
|
1108
|
+
<svg width="51" height="22" aria-label="Apple Pay" role="img">
|
|
1109
|
+
<use href="#apple-pay-logo" />
|
|
1110
|
+
</svg>
|
|
1111
|
+
</span>
|
|
1112
|
+
<span class="apple-pay-btn__loading" aria-hidden="true">Loading...</span>
|
|
1113
|
+
</button>
|
|
1114
|
+
</div>
|
|
1115
|
+
`;
|
|
452
1116
|
|
|
453
1117
|
// src/clients/payment-checkout/detects.ts
|
|
454
1118
|
var isAppleDeviceOrSafari = () => {
|
|
@@ -456,7 +1120,7 @@ var isAppleDeviceOrSafari = () => {
|
|
|
456
1120
|
const isSafariBrowser = navigator.userAgent.indexOf("Safari") > -1 && navigator.userAgent.indexOf("Chrome") === -1;
|
|
457
1121
|
return isIOSOrMacTouchDevice || isSafariBrowser;
|
|
458
1122
|
};
|
|
459
|
-
var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null
|
|
1123
|
+
var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null;
|
|
460
1124
|
var isApplePayAvailable = async () => {
|
|
461
1125
|
if (bypassApplePayChecks()) {
|
|
462
1126
|
return true;
|
|
@@ -477,14 +1141,11 @@ var isApplePayAvailable = async () => {
|
|
|
477
1141
|
}
|
|
478
1142
|
const merchantId = getApplePayConfig()?.merchantId;
|
|
479
1143
|
if (!merchantId) {
|
|
480
|
-
console.warn(
|
|
481
|
-
"[web-apple-pay] Missing merchantId. Call configureApplePay({ merchantId, ... }) before rendering Apple Pay components."
|
|
482
|
-
);
|
|
483
1144
|
return false;
|
|
484
1145
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
1146
|
+
const hasActiveCard = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
1147
|
+
return hasActiveCard;
|
|
1148
|
+
} catch {
|
|
488
1149
|
return false;
|
|
489
1150
|
}
|
|
490
1151
|
};
|
|
@@ -556,7 +1217,6 @@ var validateAppleMerchant = (data) => {
|
|
|
556
1217
|
});
|
|
557
1218
|
};
|
|
558
1219
|
var performPurchase = (data) => {
|
|
559
|
-
console.debug("[web-apple-pay] performPurchase request", JSON.stringify(data, null, 2));
|
|
560
1220
|
return apiFetch("/v1/wallet/purchase", {
|
|
561
1221
|
method: "POST",
|
|
562
1222
|
body: JSON.stringify(data),
|
|
@@ -573,13 +1233,25 @@ var getExpressCheckoutSession = () => {
|
|
|
573
1233
|
};
|
|
574
1234
|
|
|
575
1235
|
// src/utils/expressCheckoutRedirect.ts
|
|
576
|
-
var
|
|
577
|
-
var
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
1236
|
+
var CHECKOUT_REDIRECT_KEY = "checkout-redirect";
|
|
1237
|
+
var ALLOWED_REDIRECT_HOSTNAME = "economist.com";
|
|
1238
|
+
function isAllowedRedirectUrl(url) {
|
|
1239
|
+
if (url.startsWith("/")) return !url.startsWith("//");
|
|
1240
|
+
try {
|
|
1241
|
+
const { hostname } = new URL(url);
|
|
1242
|
+
return hostname === ALLOWED_REDIRECT_HOSTNAME || hostname.endsWith(`.${ALLOWED_REDIRECT_HOSTNAME}`);
|
|
1243
|
+
} catch {
|
|
1244
|
+
return false;
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
var writeCheckoutRedirect = (originUrl) => {
|
|
1248
|
+
if (!isAllowedRedirectUrl(originUrl)) return;
|
|
1249
|
+
try {
|
|
1250
|
+
localStorage.setItem(CHECKOUT_REDIRECT_KEY, originUrl);
|
|
1251
|
+
} catch {
|
|
1252
|
+
}
|
|
582
1253
|
};
|
|
1254
|
+
var captureOriginUrl = () => window.location.href;
|
|
583
1255
|
var decodeSku = (sku) => {
|
|
584
1256
|
try {
|
|
585
1257
|
return atob(sku.substring(sku.indexOf("-") + 1));
|
|
@@ -590,75 +1262,25 @@ var decodeSku = (sku) => {
|
|
|
590
1262
|
var redirectToCheckoutComplete = (params) => {
|
|
591
1263
|
const url = new URL("/checkout/complete", window.location.origin);
|
|
592
1264
|
url.searchParams.set("basketId", params.basketId);
|
|
593
|
-
if (params.queryString) {
|
|
594
|
-
const qs = params.queryString.startsWith("?") ? params.queryString.slice(1) : params.queryString;
|
|
595
|
-
new URLSearchParams(qs).forEach((v, k) => url.searchParams.set(k, v));
|
|
596
|
-
}
|
|
597
1265
|
url.searchParams.set("lmo_offer", params.skuId);
|
|
598
1266
|
url.searchParams.set("status", params.status);
|
|
599
1267
|
url.searchParams.set("redirectToCheckout", "true");
|
|
600
|
-
url.searchParams.set("
|
|
1268
|
+
if (params.email) url.searchParams.set("email", params.email);
|
|
1269
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
601
1270
|
return url.pathname + url.search;
|
|
602
1271
|
};
|
|
603
1272
|
var redirectToCheckoutFallback = (params) => {
|
|
604
1273
|
const url = new URL(window.location.href);
|
|
605
1274
|
url.pathname = "/checkout";
|
|
606
|
-
url.searchParams.set("lmo_offer", params.skuId);
|
|
1275
|
+
url.searchParams.set("lmo_offer", decodeSku(params.skuId));
|
|
607
1276
|
if (params.inlineError)
|
|
608
1277
|
url.searchParams.set("inlineError", params.inlineError);
|
|
609
1278
|
if (params.email) url.searchParams.set("email", params.email);
|
|
610
1279
|
if (params.emailError) url.searchParams.set("emailError", params.emailError);
|
|
611
|
-
url.searchParams.set("
|
|
1280
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
612
1281
|
return url.pathname + url.search;
|
|
613
1282
|
};
|
|
614
1283
|
|
|
615
|
-
// src/utils/recaptcha.ts
|
|
616
|
-
var loadRecaptchaScript = (siteKey) => {
|
|
617
|
-
return new Promise((resolve, reject) => {
|
|
618
|
-
if (typeof grecaptcha !== "undefined") return resolve();
|
|
619
|
-
const existingScript = document.querySelector(
|
|
620
|
-
'script[src*="recaptcha/api.js"]'
|
|
621
|
-
);
|
|
622
|
-
if (existingScript) {
|
|
623
|
-
existingScript.addEventListener("load", () => resolve());
|
|
624
|
-
existingScript.addEventListener(
|
|
625
|
-
"error",
|
|
626
|
-
() => reject(new Error("Failed to load existing reCAPTCHA script"))
|
|
627
|
-
);
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
const script = document.createElement("script");
|
|
631
|
-
script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
|
|
632
|
-
script.async = true;
|
|
633
|
-
script.defer = true;
|
|
634
|
-
script.onload = () => resolve();
|
|
635
|
-
script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
|
|
636
|
-
document.head.appendChild(script);
|
|
637
|
-
});
|
|
638
|
-
};
|
|
639
|
-
var getRecaptchaToken = async (action) => {
|
|
640
|
-
const siteKey = getApplePayConfig()?.recaptchaSiteKey;
|
|
641
|
-
if (!siteKey) {
|
|
642
|
-
throw new Error(
|
|
643
|
-
"[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
|
|
644
|
-
);
|
|
645
|
-
}
|
|
646
|
-
await loadRecaptchaScript(siteKey);
|
|
647
|
-
return new Promise((resolve, reject) => {
|
|
648
|
-
grecaptcha.ready(() => {
|
|
649
|
-
grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
|
|
650
|
-
});
|
|
651
|
-
});
|
|
652
|
-
};
|
|
653
|
-
var getPurchaseRecaptchaTokens = async () => {
|
|
654
|
-
const [checkEligibility, newBasket, registerUser] = await Promise.all([
|
|
655
|
-
getRecaptchaToken("checkEligibility"),
|
|
656
|
-
getRecaptchaToken("newBasket"),
|
|
657
|
-
getRecaptchaToken("registerUser")
|
|
658
|
-
]);
|
|
659
|
-
return { checkEligibility, newBasket, registerUser };
|
|
660
|
-
};
|
|
661
|
-
|
|
662
1284
|
// src/utils/expressCheckoutTracking.ts
|
|
663
1285
|
var EXPRESS_CHECKOUT_EVENTS = {
|
|
664
1286
|
/** Wallet button displayed */
|
|
@@ -739,11 +1361,42 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
|
|
|
739
1361
|
var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
|
|
740
1362
|
var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
|
|
741
1363
|
var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
742
|
-
var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
|
|
743
|
-
var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
|
|
744
1364
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
745
1365
|
|
|
746
1366
|
// src/clients/payment-checkout/apple-session.ts
|
|
1367
|
+
function redirectToFallbackCheckout(config) {
|
|
1368
|
+
writeCheckoutRedirect(config.returnUrl);
|
|
1369
|
+
trackFallbackCheckout(config.skuId);
|
|
1370
|
+
window.location.href = redirectToCheckoutFallback({
|
|
1371
|
+
skuId: config.skuId,
|
|
1372
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR,
|
|
1373
|
+
country: config.countryCode
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
async function handleMerchantValidation(event, session, config) {
|
|
1377
|
+
try {
|
|
1378
|
+
const validationHost = new URL(event.validationURL).host;
|
|
1379
|
+
if (!validationHost.endsWith("apple.com")) {
|
|
1380
|
+
session.abort();
|
|
1381
|
+
redirectToFallbackCheckout(config);
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
1385
|
+
const response = await validateAppleMerchant({
|
|
1386
|
+
validationURL: event.validationURL,
|
|
1387
|
+
recaptchaToken
|
|
1388
|
+
});
|
|
1389
|
+
if (!response?.merchantSession) {
|
|
1390
|
+
session.abort();
|
|
1391
|
+
redirectToFallbackCheckout(config);
|
|
1392
|
+
return;
|
|
1393
|
+
}
|
|
1394
|
+
session.completeMerchantValidation(response.merchantSession);
|
|
1395
|
+
} catch {
|
|
1396
|
+
session.abort();
|
|
1397
|
+
redirectToFallbackCheckout(config);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
747
1400
|
function startApplePaySession(config) {
|
|
748
1401
|
const paymentRequest = {
|
|
749
1402
|
countryCode: config.countryCode,
|
|
@@ -758,55 +1411,23 @@ function startApplePaySession(config) {
|
|
|
758
1411
|
// Only request email from Apple Pay sheet if user is NOT logged in
|
|
759
1412
|
...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
|
|
760
1413
|
};
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
recaptchaToken
|
|
779
|
-
});
|
|
780
|
-
if (!response?.merchantSession) {
|
|
781
|
-
trackFallbackCheckout(config.skuId);
|
|
782
|
-
session.abort();
|
|
783
|
-
window.location.href = redirectToCheckoutFallback({
|
|
784
|
-
skuId: config.skuId,
|
|
785
|
-
returnUrl: config.returnUrl,
|
|
786
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
787
|
-
});
|
|
788
|
-
return;
|
|
789
|
-
}
|
|
790
|
-
session.completeMerchantValidation(response.merchantSession);
|
|
791
|
-
} catch {
|
|
792
|
-
trackFallbackCheckout(config.skuId);
|
|
793
|
-
session.abort();
|
|
794
|
-
window.location.href = redirectToCheckoutFallback({
|
|
795
|
-
skuId: config.skuId,
|
|
796
|
-
returnUrl: config.returnUrl,
|
|
797
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
};
|
|
801
|
-
session.onpaymentauthorized = (event) => {
|
|
802
|
-
trackWalletPaymentAuthorised(config.skuId);
|
|
803
|
-
config.onPaymentAuthorized(event, session);
|
|
804
|
-
};
|
|
805
|
-
session.oncancel = () => {
|
|
806
|
-
config.onCancel?.();
|
|
807
|
-
};
|
|
808
|
-
trackWalletPaymentSheetOpen(config.skuId);
|
|
809
|
-
session.begin();
|
|
1414
|
+
try {
|
|
1415
|
+
const session = new ApplePaySession(3, paymentRequest);
|
|
1416
|
+
session.onvalidatemerchant = async (event) => {
|
|
1417
|
+
await handleMerchantValidation(event, session, config);
|
|
1418
|
+
};
|
|
1419
|
+
session.onpaymentauthorized = (event) => {
|
|
1420
|
+
trackWalletPaymentAuthorised(config.skuId);
|
|
1421
|
+
config.onPaymentAuthorized(event, session);
|
|
1422
|
+
};
|
|
1423
|
+
session.oncancel = () => {
|
|
1424
|
+
config.onCancel?.();
|
|
1425
|
+
};
|
|
1426
|
+
trackWalletPaymentSheetOpen(config.skuId);
|
|
1427
|
+
session.begin();
|
|
1428
|
+
} catch {
|
|
1429
|
+
redirectToFallbackCheckout(config);
|
|
1430
|
+
}
|
|
810
1431
|
}
|
|
811
1432
|
|
|
812
1433
|
// src/clients/payment-checkout/contact-validation.ts
|
|
@@ -926,8 +1547,6 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
926
1547
|
};
|
|
927
1548
|
|
|
928
1549
|
// src/clients/payment-checkout/payment-handler.ts
|
|
929
|
-
var MSG_ELIGIBILITY = "Something went wrong, please try again";
|
|
930
|
-
var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
|
|
931
1550
|
var failApplePaySession = (session, errors = []) => {
|
|
932
1551
|
session.completePayment({
|
|
933
1552
|
status: ApplePaySession.STATUS_FAILURE,
|
|
@@ -951,37 +1570,42 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
|
|
|
951
1570
|
}
|
|
952
1571
|
return void 0;
|
|
953
1572
|
}
|
|
954
|
-
function redirectFallback(skuId, returnUrl, options) {
|
|
1573
|
+
function redirectFallback(skuId, returnUrl, country, options) {
|
|
1574
|
+
writeCheckoutRedirect(returnUrl);
|
|
955
1575
|
trackFallbackCheckout(skuId);
|
|
956
1576
|
window.location.href = redirectToCheckoutFallback({
|
|
957
1577
|
skuId,
|
|
958
|
-
|
|
1578
|
+
country,
|
|
959
1579
|
...options
|
|
960
1580
|
});
|
|
961
1581
|
}
|
|
962
1582
|
var ERROR_HANDLERS = {
|
|
963
|
-
|
|
964
|
-
|
|
1583
|
+
// emailError flows as an inline field error on the email input.
|
|
1584
|
+
// email pre-populates the input so the user doesn't have to retype it.
|
|
1585
|
+
EMAIL_COLLISION: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1586
|
+
emailError: walletError.message,
|
|
1587
|
+
email: validatedEmail
|
|
1588
|
+
}),
|
|
1589
|
+
PAYMENT_DECLINED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1590
|
+
ELIGIBILITY_REJECTED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1591
|
+
REGISTRATION_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1592
|
+
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1593
|
+
emailError: walletError.message,
|
|
965
1594
|
email: validatedEmail
|
|
966
1595
|
}),
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR })
|
|
970
|
-
),
|
|
971
|
-
ELIGIBILITY_REJECTED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_ELIGIBILITY }),
|
|
972
|
-
REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
|
|
973
|
-
VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_RECAPTCHA_VALIDATION_FAILED })
|
|
1596
|
+
VALIDATION_ERROR: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1597
|
+
RECAPTCHA_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message })
|
|
974
1598
|
};
|
|
975
1599
|
function handleStructuredError(ctx) {
|
|
976
1600
|
const handler = ERROR_HANDLERS[ctx.walletError.errorType];
|
|
977
1601
|
if (handler) {
|
|
978
1602
|
handler(ctx);
|
|
979
1603
|
} else {
|
|
980
|
-
redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1604
|
+
redirectFallback(ctx.skuId, ctx.returnUrl, ctx.country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
981
1605
|
}
|
|
982
1606
|
}
|
|
983
1607
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
984
|
-
const { skuId, returnUrl,
|
|
1608
|
+
const { skuId, returnUrl, country } = config;
|
|
985
1609
|
let validatedEmail;
|
|
986
1610
|
try {
|
|
987
1611
|
validatedEmail = validateContacts(
|
|
@@ -989,7 +1613,6 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
989
1613
|
sessionData,
|
|
990
1614
|
config.supportedBillingCountries
|
|
991
1615
|
);
|
|
992
|
-
console.debug("[web-apple-pay] performPurchase currency", { skuId, currency: config.currency });
|
|
993
1616
|
const result = await performPurchase({
|
|
994
1617
|
applePayToken: event.payment.token,
|
|
995
1618
|
skuId: config.skuId,
|
|
@@ -1002,28 +1625,29 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1002
1625
|
});
|
|
1003
1626
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1004
1627
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1628
|
+
const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
|
|
1005
1629
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
1630
|
+
writeCheckoutRedirect(returnUrl);
|
|
1006
1631
|
window.location.href = redirectToCheckoutComplete({
|
|
1007
1632
|
basketId: result.basketId,
|
|
1008
1633
|
status: userStatus,
|
|
1009
1634
|
skuId: decodeSku(skuId),
|
|
1010
|
-
|
|
1011
|
-
|
|
1635
|
+
email: successEmail,
|
|
1636
|
+
country
|
|
1012
1637
|
});
|
|
1013
1638
|
} catch (err) {
|
|
1014
1639
|
if (err instanceof ContactValidationError) {
|
|
1015
1640
|
failApplePaySession(session, err.errors);
|
|
1016
1641
|
return;
|
|
1017
1642
|
}
|
|
1018
|
-
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1019
1643
|
const walletError = parseWalletApiError(err);
|
|
1020
1644
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1021
1645
|
failApplePaySession(session);
|
|
1022
1646
|
if (!walletError) {
|
|
1023
|
-
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1647
|
+
redirectFallback(skuId, returnUrl, country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1024
1648
|
return;
|
|
1025
1649
|
}
|
|
1026
|
-
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1650
|
+
handleStructuredError({ skuId, returnUrl, country, validatedEmail, walletError });
|
|
1027
1651
|
}
|
|
1028
1652
|
}
|
|
1029
1653
|
|
|
@@ -1289,11 +1913,9 @@ var getSupportedBillingCountries = (offerCountry, offerVariant) => {
|
|
|
1289
1913
|
};
|
|
1290
1914
|
|
|
1291
1915
|
// src/apple-pay-button.ts
|
|
1292
|
-
var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
|
|
1293
1916
|
var TOTAL_LABEL = "The Economist";
|
|
1294
1917
|
var DEFAULT_CURRENCY = "USD";
|
|
1295
1918
|
var DEFAULT_TOTAL = "0.00";
|
|
1296
|
-
var ERROR_INITIATE = "Failed to initiate Apple Pay session:";
|
|
1297
1919
|
var SEL_CONTAINER = ".apple-pay-container";
|
|
1298
1920
|
var SEL_BUTTON = ".apple-pay-btn";
|
|
1299
1921
|
var APPLE_PAY_EXCLUDED_VARIANTS = [
|
|
@@ -1306,19 +1928,22 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1306
1928
|
define(_ApplePayButton.tag, _ApplePayButton);
|
|
1307
1929
|
}
|
|
1308
1930
|
/**
|
|
1309
|
-
* Creates and configures an ApplePayButton if the
|
|
1931
|
+
* Creates and configures an ApplePayButton if the offer is eligible.
|
|
1310
1932
|
*/
|
|
1311
1933
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1312
|
-
if (!offer)
|
|
1313
|
-
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
|
|
1934
|
+
if (!offer) {
|
|
1314
1935
|
return null;
|
|
1315
|
-
|
|
1936
|
+
}
|
|
1937
|
+
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1316
1938
|
return null;
|
|
1939
|
+
}
|
|
1317
1940
|
_ApplePayButton.define();
|
|
1318
1941
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1319
1942
|
button.offer = offer;
|
|
1320
1943
|
button.country = country;
|
|
1321
|
-
|
|
1944
|
+
if (entryPoint) {
|
|
1945
|
+
button.entryPoint = entryPoint;
|
|
1946
|
+
}
|
|
1322
1947
|
return button;
|
|
1323
1948
|
}
|
|
1324
1949
|
/**
|
|
@@ -1340,6 +1965,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1340
1965
|
#returnUrl = "";
|
|
1341
1966
|
#supportedBillingCountries = [];
|
|
1342
1967
|
#entryPoint = "";
|
|
1968
|
+
#recaptchaTokensPromise = null;
|
|
1343
1969
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1344
1970
|
get offer() {
|
|
1345
1971
|
return this.#offer;
|
|
@@ -1404,20 +2030,25 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1404
2030
|
this.#paymentOptions = null;
|
|
1405
2031
|
this.#returnUrl = "";
|
|
1406
2032
|
this.#supportedBillingCountries = [];
|
|
2033
|
+
this.#recaptchaTokensPromise = null;
|
|
1407
2034
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1408
2035
|
}
|
|
1409
2036
|
// ─── Render pipeline ────────────────────────────────────────────────────────
|
|
1410
2037
|
async #run() {
|
|
1411
2038
|
try {
|
|
2039
|
+
this.#renderTemplate();
|
|
1412
2040
|
if (await this.#checkAvailability()) return;
|
|
1413
|
-
if (await this.#checkSession()) return;
|
|
1414
2041
|
if (this.#checkOffer()) return;
|
|
2042
|
+
if (await this.#checkSession()) return;
|
|
1415
2043
|
this.#captureReturnUrl();
|
|
1416
2044
|
this.#computeBillingCountries();
|
|
1417
2045
|
if (await this.#fetchAndCacheOptions()) return;
|
|
1418
|
-
|
|
1419
|
-
|
|
2046
|
+
console.log("[web-apple-pay] button shown \u2014 reason: all checks passed, Apple Pay is available and offer is eligible");
|
|
2047
|
+
this.#finishLoading();
|
|
2048
|
+
} catch (error) {
|
|
2049
|
+
console.warn("[web-apple-pay] button hidden \u2014 reason: unexpected error in render pipeline", error);
|
|
1420
2050
|
this.style.display = "none";
|
|
2051
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1421
2052
|
} finally {
|
|
1422
2053
|
this.#rendering = false;
|
|
1423
2054
|
}
|
|
@@ -1426,7 +2057,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1426
2057
|
async #checkAvailability() {
|
|
1427
2058
|
const available = await isApplePayAvailable();
|
|
1428
2059
|
if (!available) {
|
|
2060
|
+
console.log("[web-apple-pay] button removed from DOM \u2014 reason: Apple Pay unavailable on this device/browser");
|
|
1429
2061
|
this.style.display = "none";
|
|
2062
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1430
2063
|
return true;
|
|
1431
2064
|
}
|
|
1432
2065
|
return false;
|
|
@@ -1438,7 +2071,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1438
2071
|
async #checkSession() {
|
|
1439
2072
|
this.#sessionData = await this.#fetchSession();
|
|
1440
2073
|
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}"`);
|
|
1441
2075
|
this.style.display = "none";
|
|
2076
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1442
2077
|
return true;
|
|
1443
2078
|
}
|
|
1444
2079
|
return false;
|
|
@@ -1446,7 +2081,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1446
2081
|
/** Returns `true` (hide) when no offer has been set before mount. */
|
|
1447
2082
|
#checkOffer() {
|
|
1448
2083
|
if (!this.#offer) {
|
|
2084
|
+
console.log("[web-apple-pay] button removed from DOM \u2014 reason: no offer set on element before mount");
|
|
1449
2085
|
this.style.display = "none";
|
|
2086
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1450
2087
|
return true;
|
|
1451
2088
|
}
|
|
1452
2089
|
return false;
|
|
@@ -1472,32 +2109,43 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1472
2109
|
*/
|
|
1473
2110
|
async #fetchAndCacheOptions() {
|
|
1474
2111
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1475
|
-
if (!this.#paymentOptions?.apple_pay) {
|
|
2112
|
+
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
2113
|
+
console.log("[web-apple-pay] button removed from DOM \u2014 reason: payment options BFF reports Apple Pay unavailable for this offer");
|
|
1476
2114
|
this.style.display = "none";
|
|
2115
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1477
2116
|
return true;
|
|
1478
2117
|
}
|
|
1479
2118
|
return false;
|
|
1480
2119
|
}
|
|
1481
2120
|
/** Injects the button template and wires click and confirm event listeners. */
|
|
1482
2121
|
#renderTemplate() {
|
|
2122
|
+
console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
|
|
1483
2123
|
this.style.removeProperty("display");
|
|
1484
2124
|
ensureApplePayLogoSymbol();
|
|
1485
2125
|
const template = document.createElement("template");
|
|
1486
2126
|
template.innerHTML = apple_pay_button_template_default;
|
|
1487
2127
|
this.appendChild(template.content.cloneNode(true));
|
|
1488
|
-
this.#updateDisabledState();
|
|
1489
|
-
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
1490
|
-
entryPoint: this.#entryPoint,
|
|
1491
|
-
country: this.#country
|
|
1492
|
-
});
|
|
1493
2128
|
const button = this.querySelector(SEL_BUTTON);
|
|
2129
|
+
button.classList.add("wap-loading");
|
|
2130
|
+
button.setAttribute("disabled", "");
|
|
2131
|
+
button.setAttribute("aria-disabled", "true");
|
|
2132
|
+
button.setAttribute("aria-busy", "true");
|
|
1494
2133
|
button.addEventListener("click", () => {
|
|
2134
|
+
if (button.classList.contains("wap-loading")) return;
|
|
1495
2135
|
this.#openModal();
|
|
1496
2136
|
});
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
2137
|
+
}
|
|
2138
|
+
#finishLoading() {
|
|
2139
|
+
const button = this.querySelector(SEL_BUTTON);
|
|
2140
|
+
if (button) {
|
|
2141
|
+
button.classList.remove("wap-loading");
|
|
2142
|
+
this.#updateDisabledState();
|
|
2143
|
+
this.#scheduleRecaptchaTokens();
|
|
2144
|
+
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
2145
|
+
entryPoint: this.#entryPoint,
|
|
2146
|
+
country: this.#country
|
|
2147
|
+
});
|
|
2148
|
+
}
|
|
1501
2149
|
}
|
|
1502
2150
|
// ─── Private helpers ────────────────────────────────────────────────────────
|
|
1503
2151
|
#updateDisabledState() {
|
|
@@ -1506,13 +2154,19 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1506
2154
|
if (this.#offer) {
|
|
1507
2155
|
button.removeAttribute("disabled");
|
|
1508
2156
|
button.removeAttribute("aria-disabled");
|
|
2157
|
+
button.removeAttribute("aria-busy");
|
|
1509
2158
|
return;
|
|
1510
2159
|
}
|
|
1511
2160
|
button.setAttribute("disabled", "");
|
|
1512
2161
|
button.setAttribute("aria-disabled", "true");
|
|
1513
2162
|
}
|
|
1514
2163
|
#openModal() {
|
|
1515
|
-
if (!this.#offer
|
|
2164
|
+
if (!this.#offer) {
|
|
2165
|
+
return;
|
|
2166
|
+
}
|
|
2167
|
+
if (document.querySelector(ApplePayModal.tag)) {
|
|
2168
|
+
return;
|
|
2169
|
+
}
|
|
1516
2170
|
trackExpressWalletClick(this.#offer.sku_id);
|
|
1517
2171
|
ApplePayModal.define();
|
|
1518
2172
|
const modal = document.createElement(ApplePayModal.tag);
|
|
@@ -1521,7 +2175,29 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1521
2175
|
if (this.#sessionData?.loggedIn) {
|
|
1522
2176
|
modal.dataset.loggedIn = "true";
|
|
1523
2177
|
}
|
|
1524
|
-
|
|
2178
|
+
const skuId = this.#offer.sku_id;
|
|
2179
|
+
const country = this.#country;
|
|
2180
|
+
modal.onConfirm = (recaptchaTokens) => {
|
|
2181
|
+
this.#initiateApplePay(skuId, country, recaptchaTokens);
|
|
2182
|
+
this.#scheduleRecaptchaTokens();
|
|
2183
|
+
};
|
|
2184
|
+
modal.open(this.#recaptchaTokensPromise);
|
|
2185
|
+
}
|
|
2186
|
+
/**
|
|
2187
|
+
* Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
|
|
2188
|
+
* If the fetch rejects, the field is cleared so the next `modal.open()` call
|
|
2189
|
+
* falls back to a new attempt via the modal's own null-fallback path — preventing
|
|
2190
|
+
* a single transient failure from permanently disabling the CTA on all retries.
|
|
2191
|
+
* The identity guard prevents a late rejection from clobbering a newer attempt.
|
|
2192
|
+
*/
|
|
2193
|
+
#scheduleRecaptchaTokens() {
|
|
2194
|
+
const attempt = getPurchaseRecaptchaTokens();
|
|
2195
|
+
attempt.catch(() => {
|
|
2196
|
+
if (this.#recaptchaTokensPromise === attempt) {
|
|
2197
|
+
this.#recaptchaTokensPromise = null;
|
|
2198
|
+
}
|
|
2199
|
+
});
|
|
2200
|
+
this.#recaptchaTokensPromise = attempt;
|
|
1525
2201
|
}
|
|
1526
2202
|
async #fetchSession() {
|
|
1527
2203
|
try {
|
|
@@ -1548,7 +2224,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1548
2224
|
return {
|
|
1549
2225
|
countryCode: country,
|
|
1550
2226
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1551
|
-
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
2227
|
+
supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
|
|
1552
2228
|
totalAmount,
|
|
1553
2229
|
totalLabel: TOTAL_LABEL,
|
|
1554
2230
|
skuId,
|
|
@@ -1559,17 +2235,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1559
2235
|
country,
|
|
1560
2236
|
currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1561
2237
|
returnUrl: this.#returnUrl,
|
|
1562
|
-
queryString: buildQueryString(),
|
|
1563
2238
|
supportedBillingCountries: this.#supportedBillingCountries,
|
|
1564
2239
|
recaptchaTokens
|
|
1565
2240
|
})
|
|
1566
2241
|
};
|
|
1567
2242
|
}
|
|
1568
|
-
|
|
2243
|
+
#initiateApplePay(skuId, country, recaptchaTokens) {
|
|
1569
2244
|
try {
|
|
1570
2245
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
1571
2246
|
const paymentOptions = this.#paymentOptions;
|
|
1572
|
-
const recaptchaTokens = await getPurchaseRecaptchaTokens();
|
|
1573
2247
|
startApplePaySession(
|
|
1574
2248
|
this.#buildSessionParams(
|
|
1575
2249
|
skuId,
|
|
@@ -1579,12 +2253,19 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1579
2253
|
recaptchaTokens
|
|
1580
2254
|
)
|
|
1581
2255
|
);
|
|
1582
|
-
} catch
|
|
1583
|
-
console.error(ERROR_INITIATE, error);
|
|
2256
|
+
} catch {
|
|
1584
2257
|
}
|
|
1585
2258
|
}
|
|
1586
2259
|
};
|
|
1587
2260
|
|
|
2261
|
+
// src/constants.ts
|
|
2262
|
+
var ApplePayEntryPoint = /* @__PURE__ */ ((ApplePayEntryPoint2) => {
|
|
2263
|
+
ApplePayEntryPoint2["PAYWALL"] = "article_paywall";
|
|
2264
|
+
ApplePayEntryPoint2["REGWALL"] = "article_regwall";
|
|
2265
|
+
ApplePayEntryPoint2["DUAL_OFFER_BANNER"] = "dual_offer_banner";
|
|
2266
|
+
return ApplePayEntryPoint2;
|
|
2267
|
+
})(ApplePayEntryPoint || {});
|
|
2268
|
+
|
|
1588
2269
|
// src/index.ts
|
|
1589
2270
|
function defineApplePayElements() {
|
|
1590
2271
|
ApplePayButton.define();
|
|
@@ -1593,6 +2274,7 @@ function defineApplePayElements() {
|
|
|
1593
2274
|
export {
|
|
1594
2275
|
APPLE_PAY_EXCLUDED_VARIANTS,
|
|
1595
2276
|
ApplePayButton,
|
|
2277
|
+
ApplePayEntryPoint,
|
|
1596
2278
|
ApplePayModal,
|
|
1597
2279
|
configureApplePay,
|
|
1598
2280
|
defineApplePayElements,
|