@economist/web-apple-pay 1.7.2 → 1.7.4
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 +599 -82
- package/dist/src/apple-pay-button.js +594 -77
- package/dist/src/apple-pay-button.stories.js +620 -85
- package/dist/src/apple-pay-modal.d.ts +16 -1
- package/dist/src/apple-pay-modal.js +556 -10
- package/dist/src/apple-pay-modal.stories.js +594 -77
- package/dist/src/clients/payment-checkout/apple-session.js +4 -2
- package/dist/src/clients/payment-checkout/detects.js +2 -1
- package/dist/src/clients/payment-checkout/payment-handler.d.ts +1 -0
- package/dist/src/clients/payment-checkout/payment-handler.js +1 -0
- package/dist/src/clients/payment-checkout/types.d.ts +1 -0
- package/dist/src/index.js +599 -82
- package/dist/src/stories/utils/story-env.js +18 -0
- package/package.json +1 -1
|
@@ -76,7 +76,517 @@ function ensureApplePayLogoSymbol() {
|
|
|
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: none;
|
|
113
|
+
border: none;
|
|
114
|
+
cursor: pointer;
|
|
115
|
+
padding: 0;
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
justify-content: center;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.apm__close:focus {
|
|
122
|
+
outline: solid 0.125rem var(--focus-border-color, #121212);
|
|
123
|
+
border-radius: 0.25rem;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.apm__offer-name {
|
|
127
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
128
|
+
font-size: var(--mb-typestyle-title-3-size, 1.25rem);
|
|
129
|
+
font-weight: 500;
|
|
130
|
+
color: var(--mb-colour-greyscale-london-5, #0d0d0d);
|
|
131
|
+
line-height: var(--mb-typestyle-title-3-leading, 1.75rem);
|
|
132
|
+
font-style: normal;
|
|
133
|
+
margin: 0 1.5rem 0.5rem 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.apm__due-today {
|
|
137
|
+
color: #1a1a1a;
|
|
138
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
139
|
+
font-size: var(--mb-typestyle-label-2-size, 0.9375rem);
|
|
140
|
+
font-style: normal;
|
|
141
|
+
font-weight: 400;
|
|
142
|
+
line-height: var(--mb-typestyle-label-2-leading, 1.25rem);
|
|
143
|
+
margin: 0 0 0.75rem 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.apm__rule {
|
|
147
|
+
border: none;
|
|
148
|
+
border-top: 0.0625rem solid #d9d9d9;
|
|
149
|
+
margin: 0 0 1rem 0;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.apm__terms {
|
|
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 1rem 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.apm__terms-bullets {
|
|
163
|
+
list-style: disc outside;
|
|
164
|
+
padding-left: 1.25rem;
|
|
165
|
+
margin: 0 0 0.75rem 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.apm__terms-bullets li {
|
|
169
|
+
margin-bottom: 0.375rem;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.apm__terms-legal {
|
|
173
|
+
margin: 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.apm__passive-terms {
|
|
177
|
+
font-family: var(--wall-type-system-sans);
|
|
178
|
+
font-size: 0.9375rem;
|
|
179
|
+
color: #0d0d0d;
|
|
180
|
+
line-height: 1.4;
|
|
181
|
+
margin: 0 0 8px 0;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.apm__passive-terms a {
|
|
185
|
+
color: #1a1a1a;
|
|
186
|
+
font-weight: 700;
|
|
187
|
+
text-decoration: underline;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.apm__checkbox-label {
|
|
191
|
+
display: flex;
|
|
192
|
+
align-items: flex-start;
|
|
193
|
+
gap: var(--mb-spacing-sm, 0.5rem);
|
|
194
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
195
|
+
font-size: var(--mb-typestyle-label-2-size, 0.9375rem);
|
|
196
|
+
color: var(--mb-colour-greyscale-london-20, #1a1a1a);
|
|
197
|
+
line-height: var(--mb-typestyle-label-2-leading, 1.25rem);
|
|
198
|
+
cursor: pointer;
|
|
199
|
+
margin: 0 0 1.5rem 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.apm__checkbox-label--error {
|
|
203
|
+
margin-bottom: 0.25rem;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.apm__checkbox-wrapper {
|
|
207
|
+
position: relative;
|
|
208
|
+
flex-shrink: 0;
|
|
209
|
+
width: 1.25rem;
|
|
210
|
+
height: 1.25rem;
|
|
211
|
+
margin-top: 0.0625rem;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.apm__checkbox-input {
|
|
215
|
+
position: absolute;
|
|
216
|
+
opacity: 0;
|
|
217
|
+
width: 100%;
|
|
218
|
+
height: 100%;
|
|
219
|
+
cursor: pointer;
|
|
220
|
+
margin: 0;
|
|
221
|
+
z-index: 1;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.apm__checkbox-custom {
|
|
225
|
+
position: absolute;
|
|
226
|
+
top: 0;
|
|
227
|
+
left: 0;
|
|
228
|
+
width: 1.25rem;
|
|
229
|
+
height: 1.25rem;
|
|
230
|
+
pointer-events: none;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.apm__checkbox-custom svg {
|
|
234
|
+
display: none;
|
|
235
|
+
width: 1.25rem;
|
|
236
|
+
height: 1.25rem;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.apm__checkbox-input:not(:checked) ~ .apm__checkbox-custom .svg-unchecked {
|
|
240
|
+
display: block;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.apm__checkbox-input:checked ~ .apm__checkbox-custom .svg-checked {
|
|
244
|
+
display: block;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.apm__checkbox-label--error
|
|
248
|
+
.apm__checkbox-input:not(:checked)
|
|
249
|
+
~ .apm__checkbox-custom
|
|
250
|
+
.svg-unchecked {
|
|
251
|
+
display: none;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.apm__checkbox-label--error
|
|
255
|
+
.apm__checkbox-input:not(:checked)
|
|
256
|
+
~ .apm__checkbox-custom
|
|
257
|
+
.svg-error {
|
|
258
|
+
display: block;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.apm__checkbox-input:focus-visible ~ .apm__checkbox-custom {
|
|
262
|
+
outline: solid 0.125rem #c91d42;
|
|
263
|
+
outline-offset: 0.125rem;
|
|
264
|
+
border-radius: 0.25rem;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.apm__checkbox-label a {
|
|
268
|
+
color: #1a1a1a;
|
|
269
|
+
font-weight: 700;
|
|
270
|
+
text-decoration: underline;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.apm__error {
|
|
274
|
+
display: none;
|
|
275
|
+
align-items: center;
|
|
276
|
+
gap: 0.75rem;
|
|
277
|
+
color: var(--mb-colour-greyscale-london-5, #0d0d0d);
|
|
278
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
279
|
+
font-size: 1.0625rem;
|
|
280
|
+
font-style: normal;
|
|
281
|
+
font-weight: 500;
|
|
282
|
+
line-height: 1.5rem;
|
|
283
|
+
margin-bottom: 1rem;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.apm__error--visible {
|
|
287
|
+
display: flex;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.apm__cta {
|
|
291
|
+
display: flex;
|
|
292
|
+
width: 100%;
|
|
293
|
+
height: 2.75rem;
|
|
294
|
+
padding: 0.375rem 1rem;
|
|
295
|
+
justify-content: center;
|
|
296
|
+
align-items: center;
|
|
297
|
+
gap: 0.375rem;
|
|
298
|
+
border-radius: 0.25rem;
|
|
299
|
+
background: #000;
|
|
300
|
+
border: none;
|
|
301
|
+
cursor: pointer;
|
|
302
|
+
color: #fff;
|
|
303
|
+
text-align: center;
|
|
304
|
+
font-family: var(
|
|
305
|
+
--mb-typeface-sans,
|
|
306
|
+
var(--wall-type-system-sans, system-ui, sans-serif)
|
|
307
|
+
);
|
|
308
|
+
font-size: 1.25rem;
|
|
309
|
+
font-style: normal;
|
|
310
|
+
font-weight: 500;
|
|
311
|
+
line-height: normal;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.apm__cta:disabled {
|
|
315
|
+
cursor: not-allowed;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.apm__cta[aria-busy="true"] {
|
|
319
|
+
position: relative;
|
|
320
|
+
cursor: not-allowed;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.apm__cta[aria-busy="true"] > * {
|
|
324
|
+
visibility: hidden;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.apm__cta[aria-busy="true"]::after {
|
|
328
|
+
content: '';
|
|
329
|
+
position: absolute;
|
|
330
|
+
left: 50%;
|
|
331
|
+
top: 50%;
|
|
332
|
+
margin-left: -0.625rem;
|
|
333
|
+
margin-top: -0.625rem;
|
|
334
|
+
width: 1.25rem;
|
|
335
|
+
height: 1.25rem;
|
|
336
|
+
border: 2px solid rgba(255, 255, 255, 0.2);
|
|
337
|
+
border-top-color: #fff;
|
|
338
|
+
border-radius: 50%;
|
|
339
|
+
animation: apm-cta-spinner 0.8s linear infinite;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
@keyframes apm-cta-spinner {
|
|
343
|
+
to {
|
|
344
|
+
transform: rotate(360deg);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.apm__cta svg {
|
|
349
|
+
flex-shrink: 0;
|
|
350
|
+
display: block;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
@media (min-width: 22.5rem) and (max-width: 37.5rem) {
|
|
354
|
+
.apm {
|
|
355
|
+
width: 24.375rem;
|
|
356
|
+
max-width: 24.375rem;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
@media (min-width: 37.5625rem) {
|
|
361
|
+
.apm {
|
|
362
|
+
border-radius: 0.5rem;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
@media (max-width: 22.4375rem) {
|
|
367
|
+
.apm {
|
|
368
|
+
width: 20rem;
|
|
369
|
+
max-width: 20rem;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
@media (max-width: 26.1875rem) {
|
|
374
|
+
.apm__cta {
|
|
375
|
+
font-size: 1.125rem;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
</style>
|
|
379
|
+
|
|
380
|
+
<div class="apm-overlay" id="apple-pay-modal-overlay">
|
|
381
|
+
<div
|
|
382
|
+
class="apm"
|
|
383
|
+
role="dialog"
|
|
384
|
+
aria-modal="true"
|
|
385
|
+
aria-labelledby="apple-pay-modal-offer-name"
|
|
386
|
+
id="apple-pay-modal"
|
|
387
|
+
tabindex="-1"
|
|
388
|
+
>
|
|
389
|
+
<button class="apm__close" id="apple-pay-modal-close" aria-label="Close">
|
|
390
|
+
<svg
|
|
391
|
+
aria-hidden="true"
|
|
392
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
393
|
+
width="24"
|
|
394
|
+
height="24"
|
|
395
|
+
viewBox="0 0 24 24"
|
|
396
|
+
fill="none"
|
|
397
|
+
>
|
|
398
|
+
<g clip-path="url(#clip0_15712_93054)">
|
|
399
|
+
<rect width="24" height="24" fill="white" fill-opacity="0.01" />
|
|
400
|
+
<path
|
|
401
|
+
fill-rule="evenodd"
|
|
402
|
+
clip-rule="evenodd"
|
|
403
|
+
d="M0 0H24V24H0V0Z"
|
|
404
|
+
fill="white"
|
|
405
|
+
fill-opacity="0.01"
|
|
406
|
+
/>
|
|
407
|
+
<path
|
|
408
|
+
fill-rule="evenodd"
|
|
409
|
+
clip-rule="evenodd"
|
|
410
|
+
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"
|
|
411
|
+
fill="#333333"
|
|
412
|
+
/>
|
|
413
|
+
</g>
|
|
414
|
+
<defs>
|
|
415
|
+
<clipPath id="clip0_15712_93054">
|
|
416
|
+
<rect width="24" height="24" fill="white" />
|
|
417
|
+
</clipPath>
|
|
418
|
+
</defs>
|
|
419
|
+
</svg>
|
|
420
|
+
</button>
|
|
421
|
+
<p class="apm__offer-name" id="apple-pay-modal-offer-name"></p>
|
|
422
|
+
<p class="apm__due-today" id="apple-pay-modal-due-today"></p>
|
|
423
|
+
<hr class="apm__rule" />
|
|
424
|
+
<div class="apm__terms" id="apple-pay-modal-terms"></div>
|
|
425
|
+
<p class="apm__passive-terms" id="apple-pay-modal-passive-terms"></p>
|
|
426
|
+
<label
|
|
427
|
+
class="apm__checkbox-label"
|
|
428
|
+
id="apple-pay-modal-checkbox-label"
|
|
429
|
+
for="apple-pay-modal-checkbox"
|
|
430
|
+
>
|
|
431
|
+
<div class="apm__checkbox-wrapper">
|
|
432
|
+
<input
|
|
433
|
+
class="apm__checkbox-input"
|
|
434
|
+
type="checkbox"
|
|
435
|
+
id="apple-pay-modal-checkbox"
|
|
436
|
+
/>
|
|
437
|
+
<span class="apm__checkbox-custom">
|
|
438
|
+
<svg
|
|
439
|
+
aria-hidden="true"
|
|
440
|
+
class="svg-unchecked"
|
|
441
|
+
width="24"
|
|
442
|
+
height="24"
|
|
443
|
+
viewBox="0 0 24 24"
|
|
444
|
+
fill="none"
|
|
445
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
446
|
+
>
|
|
447
|
+
<path
|
|
448
|
+
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"
|
|
449
|
+
fill="white"
|
|
450
|
+
stroke="#595959"
|
|
451
|
+
/>
|
|
452
|
+
</svg>
|
|
453
|
+
<svg
|
|
454
|
+
aria-hidden="true"
|
|
455
|
+
class="svg-checked"
|
|
456
|
+
width="24"
|
|
457
|
+
height="24"
|
|
458
|
+
viewBox="0 0 24 24"
|
|
459
|
+
fill="none"
|
|
460
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
461
|
+
>
|
|
462
|
+
<g clip-path="url(#clip0_20014_9555)">
|
|
463
|
+
<path
|
|
464
|
+
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"
|
|
465
|
+
fill="#333333"
|
|
466
|
+
/>
|
|
467
|
+
<path
|
|
468
|
+
d="M10.2857 17L6 12.6814L7.20857 11.4635L10.2857 14.5557L16.7914 8L18 9.22649L10.2857 17Z"
|
|
469
|
+
fill="white"
|
|
470
|
+
/>
|
|
471
|
+
</g>
|
|
472
|
+
<defs>
|
|
473
|
+
<clipPath id="clip0_20014_9555">
|
|
474
|
+
<path
|
|
475
|
+
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"
|
|
476
|
+
fill="white"
|
|
477
|
+
/>
|
|
478
|
+
</clipPath>
|
|
479
|
+
</defs>
|
|
480
|
+
</svg>
|
|
481
|
+
<svg
|
|
482
|
+
aria-hidden="true"
|
|
483
|
+
class="svg-error"
|
|
484
|
+
width="24"
|
|
485
|
+
height="24"
|
|
486
|
+
viewBox="0 0 24 24"
|
|
487
|
+
fill="none"
|
|
488
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
489
|
+
>
|
|
490
|
+
<path
|
|
491
|
+
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"
|
|
492
|
+
fill="white"
|
|
493
|
+
stroke="#C91D42"
|
|
494
|
+
stroke-width="2"
|
|
495
|
+
/>
|
|
496
|
+
</svg>
|
|
497
|
+
</span>
|
|
498
|
+
</div>
|
|
499
|
+
<span id="apple-pay-modal-checkbox-text"></span>
|
|
500
|
+
</label>
|
|
501
|
+
<div class="apm__error" id="apple-pay-modal-error" role="alert">
|
|
502
|
+
<svg
|
|
503
|
+
aria-hidden="true"
|
|
504
|
+
width="20"
|
|
505
|
+
height="20"
|
|
506
|
+
viewBox="0 0 20 20"
|
|
507
|
+
fill="none"
|
|
508
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
509
|
+
>
|
|
510
|
+
<path
|
|
511
|
+
fill-rule="evenodd"
|
|
512
|
+
clip-rule="evenodd"
|
|
513
|
+
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"
|
|
514
|
+
fill="#C91D42"
|
|
515
|
+
/>
|
|
516
|
+
</svg>
|
|
517
|
+
Please accept the terms to continue
|
|
518
|
+
</div>
|
|
519
|
+
<button class="apm__cta" id="apple-pay-modal-cta" aria-label="Continue with Apple Pay">
|
|
520
|
+
<span class="apm__cta-content">
|
|
521
|
+
Continue with
|
|
522
|
+
<svg width="51" height="22" aria-hidden="true" role="img">
|
|
523
|
+
<use href="#apple-pay-logo" />
|
|
524
|
+
</svg>
|
|
525
|
+
</span>
|
|
526
|
+
</button>
|
|
527
|
+
</div>
|
|
528
|
+
</div>
|
|
529
|
+
|
|
530
|
+
`;
|
|
531
|
+
|
|
532
|
+
// src/clients/payment-checkout/config.ts
|
|
533
|
+
var runtimeConfig = null;
|
|
534
|
+
var configureApplePay = (config) => {
|
|
535
|
+
runtimeConfig = {
|
|
536
|
+
...config
|
|
537
|
+
};
|
|
538
|
+
};
|
|
539
|
+
var getApplePayConfig = () => runtimeConfig;
|
|
540
|
+
var resetApplePayConfig = () => {
|
|
541
|
+
runtimeConfig = null;
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
// src/utils/recaptcha.ts
|
|
545
|
+
var loadRecaptchaScript = (siteKey) => {
|
|
546
|
+
return new Promise((resolve, reject) => {
|
|
547
|
+
if (typeof grecaptcha !== "undefined") return resolve();
|
|
548
|
+
const existingScript = document.querySelector(
|
|
549
|
+
'script[src*="recaptcha/api.js"]'
|
|
550
|
+
);
|
|
551
|
+
if (existingScript) {
|
|
552
|
+
existingScript.addEventListener("load", () => resolve());
|
|
553
|
+
existingScript.addEventListener(
|
|
554
|
+
"error",
|
|
555
|
+
() => reject(new Error("Failed to load existing reCAPTCHA script"))
|
|
556
|
+
);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
const script = document.createElement("script");
|
|
560
|
+
script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
|
|
561
|
+
script.async = true;
|
|
562
|
+
script.defer = true;
|
|
563
|
+
script.onload = () => resolve();
|
|
564
|
+
script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
|
|
565
|
+
document.head.appendChild(script);
|
|
566
|
+
});
|
|
567
|
+
};
|
|
568
|
+
var getRecaptchaToken = async (action) => {
|
|
569
|
+
const siteKey = getApplePayConfig()?.recaptchaSiteKey;
|
|
570
|
+
if (!siteKey) {
|
|
571
|
+
throw new Error(
|
|
572
|
+
"[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
await loadRecaptchaScript(siteKey);
|
|
576
|
+
return new Promise((resolve, reject) => {
|
|
577
|
+
grecaptcha.ready(() => {
|
|
578
|
+
grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
|
|
579
|
+
});
|
|
580
|
+
});
|
|
581
|
+
};
|
|
582
|
+
var getPurchaseRecaptchaTokens = async () => {
|
|
583
|
+
const [checkEligibility, newBasket, registerUser] = await Promise.all([
|
|
584
|
+
getRecaptchaToken("checkEligibility"),
|
|
585
|
+
getRecaptchaToken("newBasket"),
|
|
586
|
+
getRecaptchaToken("registerUser")
|
|
587
|
+
]);
|
|
588
|
+
return { checkEligibility, newBasket, registerUser };
|
|
589
|
+
};
|
|
80
590
|
|
|
81
591
|
// src/apple-pay-modal.ts
|
|
82
592
|
function getRenewalDateText(unit, duration) {
|
|
@@ -128,6 +638,7 @@ function getOfferTypeText(offerType) {
|
|
|
128
638
|
}
|
|
129
639
|
var TERMS_LINK = '<a href="https://www.economistgroup.com/terms-of-use" target="_blank" rel="noopener noreferrer">Terms and Conditions</a>';
|
|
130
640
|
var PRIVACY_LINK = '<a href="https://www.economistgroup.com/privacy-policy" target="_blank" rel="noopener noreferrer">Privacy Policy</a>';
|
|
641
|
+
var MSG_RECAPTCHA_LOAD_ERROR = "Something went wrong. Please close and try again.";
|
|
131
642
|
function getCheckboxTermsHtml(isNYT, isLoggedIn, autoRenewal) {
|
|
132
643
|
const autoRenewalClause = autoRenewal ? " and auto-renewal terms above," : "";
|
|
133
644
|
if (isNYT) {
|
|
@@ -297,6 +808,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
297
808
|
#country = "";
|
|
298
809
|
#triggerElement = null;
|
|
299
810
|
#keyHandler = null;
|
|
811
|
+
#recaptchaTokens = null;
|
|
812
|
+
#recaptchaTokensPromise = null;
|
|
813
|
+
/**
|
|
814
|
+
* Synchronous callback invoked directly from the CTA click handler once the
|
|
815
|
+
* user confirms. The caller (ApplePayButton) must call startApplePaySession
|
|
816
|
+
* inside this callback to preserve the browser's user-gesture chain — Safari
|
|
817
|
+
* requires new ApplePaySession() to execute within the original click stack.
|
|
818
|
+
*
|
|
819
|
+
* reCAPTCHA tokens are guaranteed non-null here: the CTA remains disabled
|
|
820
|
+
* until the token pre-fetch resolves, so this callback is never reached
|
|
821
|
+
* without valid tokens.
|
|
822
|
+
*/
|
|
823
|
+
onConfirm = null;
|
|
300
824
|
set offer(value) {
|
|
301
825
|
this.#offer = value;
|
|
302
826
|
}
|
|
@@ -391,27 +915,57 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
391
915
|
}
|
|
392
916
|
});
|
|
393
917
|
}
|
|
918
|
+
if (this.#recaptchaTokensPromise) {
|
|
919
|
+
if (cta) {
|
|
920
|
+
cta.setAttribute("disabled", "");
|
|
921
|
+
cta.setAttribute("aria-disabled", "true");
|
|
922
|
+
cta.setAttribute("aria-busy", "true");
|
|
923
|
+
}
|
|
924
|
+
this.#recaptchaTokensPromise.then((tokens) => {
|
|
925
|
+
this.#recaptchaTokens = tokens;
|
|
926
|
+
if (cta) {
|
|
927
|
+
cta.removeAttribute("disabled");
|
|
928
|
+
cta.removeAttribute("aria-disabled");
|
|
929
|
+
cta.removeAttribute("aria-busy");
|
|
930
|
+
}
|
|
931
|
+
}).catch(() => {
|
|
932
|
+
console.error("[web-apple-pay] apple-pay-modal: failed to pre-fetch reCAPTCHA tokens; CTA remains disabled");
|
|
933
|
+
if (cta) {
|
|
934
|
+
cta.removeAttribute("aria-busy");
|
|
935
|
+
}
|
|
936
|
+
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
937
|
+
if (existingError) {
|
|
938
|
+
const icon = existingError.querySelector("svg");
|
|
939
|
+
existingError.textContent = MSG_RECAPTCHA_LOAD_ERROR;
|
|
940
|
+
if (icon) existingError.prepend(icon);
|
|
941
|
+
existingError.classList.add("apm__error--visible");
|
|
942
|
+
} else {
|
|
943
|
+
const errorNotice = document.createElement("div");
|
|
944
|
+
errorNotice.setAttribute("role", "alert");
|
|
945
|
+
errorNotice.className = "apm__error apm__error--visible";
|
|
946
|
+
errorNotice.textContent = MSG_RECAPTCHA_LOAD_ERROR;
|
|
947
|
+
cta?.insertAdjacentElement("beforebegin", errorNotice);
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
}
|
|
394
951
|
cta?.addEventListener("click", () => {
|
|
395
952
|
if (isUS && checkbox && !checkbox.checked) {
|
|
396
953
|
errorElement?.classList.add("apm__error--visible");
|
|
397
954
|
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
398
955
|
return;
|
|
399
956
|
}
|
|
400
|
-
this
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
detail: { skuId: offer.sku_id, country }
|
|
405
|
-
})
|
|
406
|
-
);
|
|
407
|
-
this.close();
|
|
957
|
+
if (this.#recaptchaTokens) {
|
|
958
|
+
this.onConfirm?.(this.#recaptchaTokens);
|
|
959
|
+
this.close();
|
|
960
|
+
}
|
|
408
961
|
});
|
|
409
962
|
this.querySelector("#apple-pay-modal-close")?.addEventListener(
|
|
410
963
|
"click",
|
|
411
964
|
() => this.close()
|
|
412
965
|
);
|
|
413
966
|
}
|
|
414
|
-
open() {
|
|
967
|
+
open(recaptchaTokensPromise) {
|
|
968
|
+
this.#recaptchaTokensPromise = recaptchaTokensPromise ?? getPurchaseRecaptchaTokens();
|
|
415
969
|
this.#triggerElement = document.activeElement;
|
|
416
970
|
document.body.appendChild(this);
|
|
417
971
|
this.#keyHandler = (event) => {
|
|
@@ -524,18 +1078,6 @@ var apple_pay_button_template_default = `<style>
|
|
|
524
1078
|
</div>
|
|
525
1079
|
`;
|
|
526
1080
|
|
|
527
|
-
// src/clients/payment-checkout/config.ts
|
|
528
|
-
var runtimeConfig = null;
|
|
529
|
-
var configureApplePay = (config) => {
|
|
530
|
-
runtimeConfig = {
|
|
531
|
-
...config
|
|
532
|
-
};
|
|
533
|
-
};
|
|
534
|
-
var getApplePayConfig = () => runtimeConfig;
|
|
535
|
-
var resetApplePayConfig = () => {
|
|
536
|
-
runtimeConfig = null;
|
|
537
|
-
};
|
|
538
|
-
|
|
539
1081
|
// src/clients/payment-checkout/detects.ts
|
|
540
1082
|
var isAppleDeviceOrSafari = () => {
|
|
541
1083
|
const isIOSOrMacTouchDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) || navigator.maxTouchPoints > 1 && /Macintosh/.test(navigator.userAgent);
|
|
@@ -568,7 +1110,8 @@ var isApplePayAvailable = async () => {
|
|
|
568
1110
|
);
|
|
569
1111
|
return false;
|
|
570
1112
|
}
|
|
571
|
-
|
|
1113
|
+
const hasActiveCard = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
1114
|
+
return hasActiveCard;
|
|
572
1115
|
} catch (error) {
|
|
573
1116
|
console.error("Error checking Apple Pay active card status:", error);
|
|
574
1117
|
return false;
|
|
@@ -697,53 +1240,6 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
697
1240
|
return url.pathname + url.search;
|
|
698
1241
|
};
|
|
699
1242
|
|
|
700
|
-
// src/utils/recaptcha.ts
|
|
701
|
-
var loadRecaptchaScript = (siteKey) => {
|
|
702
|
-
return new Promise((resolve, reject) => {
|
|
703
|
-
if (typeof grecaptcha !== "undefined") return resolve();
|
|
704
|
-
const existingScript = document.querySelector(
|
|
705
|
-
'script[src*="recaptcha/api.js"]'
|
|
706
|
-
);
|
|
707
|
-
if (existingScript) {
|
|
708
|
-
existingScript.addEventListener("load", () => resolve());
|
|
709
|
-
existingScript.addEventListener(
|
|
710
|
-
"error",
|
|
711
|
-
() => reject(new Error("Failed to load existing reCAPTCHA script"))
|
|
712
|
-
);
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
const script = document.createElement("script");
|
|
716
|
-
script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
|
|
717
|
-
script.async = true;
|
|
718
|
-
script.defer = true;
|
|
719
|
-
script.onload = () => resolve();
|
|
720
|
-
script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
|
|
721
|
-
document.head.appendChild(script);
|
|
722
|
-
});
|
|
723
|
-
};
|
|
724
|
-
var getRecaptchaToken = async (action) => {
|
|
725
|
-
const siteKey = getApplePayConfig()?.recaptchaSiteKey;
|
|
726
|
-
if (!siteKey) {
|
|
727
|
-
throw new Error(
|
|
728
|
-
"[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
|
|
729
|
-
);
|
|
730
|
-
}
|
|
731
|
-
await loadRecaptchaScript(siteKey);
|
|
732
|
-
return new Promise((resolve, reject) => {
|
|
733
|
-
grecaptcha.ready(() => {
|
|
734
|
-
grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
|
|
735
|
-
});
|
|
736
|
-
});
|
|
737
|
-
};
|
|
738
|
-
var getPurchaseRecaptchaTokens = async () => {
|
|
739
|
-
const [checkEligibility, newBasket, registerUser] = await Promise.all([
|
|
740
|
-
getRecaptchaToken("checkEligibility"),
|
|
741
|
-
getRecaptchaToken("newBasket"),
|
|
742
|
-
getRecaptchaToken("registerUser")
|
|
743
|
-
]);
|
|
744
|
-
return { checkEligibility, newBasket, registerUser };
|
|
745
|
-
};
|
|
746
|
-
|
|
747
1243
|
// src/utils/expressCheckoutTracking.ts
|
|
748
1244
|
var EXPRESS_CHECKOUT_EVENTS = {
|
|
749
1245
|
/** Wallet button displayed */
|
|
@@ -856,7 +1352,8 @@ async function handleMerchantValidation(event, session, config) {
|
|
|
856
1352
|
return;
|
|
857
1353
|
}
|
|
858
1354
|
session.completeMerchantValidation(response.merchantSession);
|
|
859
|
-
} catch {
|
|
1355
|
+
} catch (err) {
|
|
1356
|
+
console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
|
|
860
1357
|
session.abort();
|
|
861
1358
|
redirectToFallbackCheckout(config);
|
|
862
1359
|
}
|
|
@@ -889,7 +1386,8 @@ function startApplePaySession(config) {
|
|
|
889
1386
|
};
|
|
890
1387
|
trackWalletPaymentSheetOpen(config.skuId);
|
|
891
1388
|
session.begin();
|
|
892
|
-
} catch {
|
|
1389
|
+
} catch (err) {
|
|
1390
|
+
console.error("[web-apple-pay] startApplePaySession: failed to create session", err);
|
|
893
1391
|
redirectToFallbackCheckout(config);
|
|
894
1392
|
}
|
|
895
1393
|
}
|
|
@@ -1077,6 +1575,7 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1077
1575
|
const result = await performPurchase({
|
|
1078
1576
|
applePayToken: event.payment.token,
|
|
1079
1577
|
skuId: config.skuId,
|
|
1578
|
+
currency: config.currency,
|
|
1080
1579
|
billingContact: event.payment.billingContact,
|
|
1081
1580
|
...event.payment.shippingContact && {
|
|
1082
1581
|
shippingContact: event.payment.shippingContact
|
|
@@ -1427,7 +1926,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1427
1926
|
#returnUrl = "";
|
|
1428
1927
|
#supportedBillingCountries = [];
|
|
1429
1928
|
#entryPoint = "";
|
|
1430
|
-
#
|
|
1929
|
+
#recaptchaTokensPromise = null;
|
|
1431
1930
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1432
1931
|
get offer() {
|
|
1433
1932
|
return this.#offer;
|
|
@@ -1492,6 +1991,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1492
1991
|
this.#paymentOptions = null;
|
|
1493
1992
|
this.#returnUrl = "";
|
|
1494
1993
|
this.#supportedBillingCountries = [];
|
|
1994
|
+
this.#recaptchaTokensPromise = null;
|
|
1495
1995
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1496
1996
|
}
|
|
1497
1997
|
// ─── Render pipeline ────────────────────────────────────────────────────────
|
|
@@ -1505,7 +2005,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1505
2005
|
this.#computeBillingCountries();
|
|
1506
2006
|
if (await this.#fetchAndCacheOptions()) return;
|
|
1507
2007
|
this.#finishLoading();
|
|
1508
|
-
} catch {
|
|
2008
|
+
} catch (err) {
|
|
2009
|
+
console.error("[web-apple-pay] #run: unexpected error, hiding button", err);
|
|
1509
2010
|
this.style.display = "none";
|
|
1510
2011
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1511
2012
|
} finally {
|
|
@@ -1586,16 +2087,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1586
2087
|
if (button.classList.contains("wap-loading")) return;
|
|
1587
2088
|
this.#openModal();
|
|
1588
2089
|
});
|
|
1589
|
-
document.addEventListener("apple-pay-confirmed", (event) => {
|
|
1590
|
-
const { skuId, country } = event.detail;
|
|
1591
|
-
this.#initiateApplePay(skuId, country);
|
|
1592
|
-
}, { once: true });
|
|
1593
2090
|
}
|
|
1594
2091
|
#finishLoading() {
|
|
1595
2092
|
const button = this.querySelector(SEL_BUTTON);
|
|
1596
2093
|
if (button) {
|
|
1597
2094
|
button.classList.remove("wap-loading");
|
|
1598
2095
|
this.#updateDisabledState();
|
|
2096
|
+
this.#scheduleRecaptchaTokens();
|
|
1599
2097
|
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
1600
2098
|
entryPoint: this.#entryPoint,
|
|
1601
2099
|
country: this.#country
|
|
@@ -1623,10 +2121,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1623
2121
|
return;
|
|
1624
2122
|
}
|
|
1625
2123
|
trackExpressWalletClick(this.#offer.sku_id);
|
|
1626
|
-
getPurchaseRecaptchaTokens().then((tokens) => {
|
|
1627
|
-
this.#recaptchaTokens = tokens;
|
|
1628
|
-
}).catch(() => {
|
|
1629
|
-
});
|
|
1630
2124
|
ApplePayModal.define();
|
|
1631
2125
|
const modal = document.createElement(ApplePayModal.tag);
|
|
1632
2126
|
modal.offer = this.#offer;
|
|
@@ -1634,7 +2128,30 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1634
2128
|
if (this.#sessionData?.loggedIn) {
|
|
1635
2129
|
modal.dataset.loggedIn = "true";
|
|
1636
2130
|
}
|
|
1637
|
-
|
|
2131
|
+
const skuId = this.#offer.sku_id;
|
|
2132
|
+
const country = this.#country;
|
|
2133
|
+
modal.onConfirm = (recaptchaTokens) => {
|
|
2134
|
+
this.#initiateApplePay(skuId, country, recaptchaTokens);
|
|
2135
|
+
this.#scheduleRecaptchaTokens();
|
|
2136
|
+
};
|
|
2137
|
+
modal.open(this.#recaptchaTokensPromise);
|
|
2138
|
+
}
|
|
2139
|
+
/**
|
|
2140
|
+
* Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
|
|
2141
|
+
* If the fetch rejects, the field is cleared so the next `modal.open()` call
|
|
2142
|
+
* falls back to a new attempt via the modal's own null-fallback path — preventing
|
|
2143
|
+
* a single transient failure from permanently disabling the CTA on all retries.
|
|
2144
|
+
* The identity guard prevents a late rejection from clobbering a newer attempt.
|
|
2145
|
+
*/
|
|
2146
|
+
#scheduleRecaptchaTokens() {
|
|
2147
|
+
const attempt = getPurchaseRecaptchaTokens();
|
|
2148
|
+
attempt.catch((err) => {
|
|
2149
|
+
console.error("[web-apple-pay] reCAPTCHA token pre-fetch failed; will retry on modal open", err);
|
|
2150
|
+
if (this.#recaptchaTokensPromise === attempt) {
|
|
2151
|
+
this.#recaptchaTokensPromise = null;
|
|
2152
|
+
}
|
|
2153
|
+
});
|
|
2154
|
+
this.#recaptchaTokensPromise = attempt;
|
|
1638
2155
|
}
|
|
1639
2156
|
async #fetchSession() {
|
|
1640
2157
|
try {
|
|
@@ -1670,6 +2187,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1670
2187
|
onPaymentAuthorized: (event, session) => handlePaymentAuthorized(event, session, sessionData, {
|
|
1671
2188
|
skuId,
|
|
1672
2189
|
country,
|
|
2190
|
+
currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1673
2191
|
returnUrl: this.#returnUrl,
|
|
1674
2192
|
queryString: buildQueryString(),
|
|
1675
2193
|
supportedBillingCountries: this.#supportedBillingCountries,
|
|
@@ -1677,11 +2195,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1677
2195
|
})
|
|
1678
2196
|
};
|
|
1679
2197
|
}
|
|
1680
|
-
|
|
2198
|
+
#initiateApplePay(skuId, country, recaptchaTokens) {
|
|
1681
2199
|
try {
|
|
1682
2200
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
1683
2201
|
const paymentOptions = this.#paymentOptions;
|
|
1684
|
-
const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
|
|
1685
2202
|
startApplePaySession(
|
|
1686
2203
|
this.#buildSessionParams(
|
|
1687
2204
|
skuId,
|
|
@@ -1752,6 +2269,24 @@ var createFetchMock = (sessionResponse, sessionStatus = 200) => {
|
|
|
1752
2269
|
headers: { "content-type": "application/json" }
|
|
1753
2270
|
});
|
|
1754
2271
|
}
|
|
2272
|
+
if (requestUrl.includes("/v1/wallet/payment-options/sku/")) {
|
|
2273
|
+
return new Response(
|
|
2274
|
+
JSON.stringify({
|
|
2275
|
+
options: {
|
|
2276
|
+
apple_pay: {
|
|
2277
|
+
provider: "apple-pay",
|
|
2278
|
+
settings: {
|
|
2279
|
+
supported_networks: ["visa", "masterCard", "amex"]
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
}),
|
|
2284
|
+
{
|
|
2285
|
+
status: 200,
|
|
2286
|
+
headers: { "content-type": "application/json" }
|
|
2287
|
+
}
|
|
2288
|
+
);
|
|
2289
|
+
}
|
|
1755
2290
|
return new Response("Not Found", {
|
|
1756
2291
|
status: 404,
|
|
1757
2292
|
statusText: "Not Found"
|