@economist/web-apple-pay 0.1.3-beta.0 → 0.1.3-beta.10
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 +729 -216
- package/dist/src/apple-pay-button.js +724 -205
- package/dist/src/apple-pay-button.stories.js +732 -220
- package/dist/src/apple-pay-modal.d.ts +15 -0
- package/dist/src/apple-pay-modal.js +536 -18
- package/dist/src/apple-pay-modal.stories.js +724 -205
- package/dist/src/clients/payment-checkout/apple-session.js +45 -55
- package/dist/src/clients/payment-checkout/config.js +0 -7
- package/dist/src/clients/payment-checkout/detects.js +8 -10
- package/dist/src/clients/payment-checkout/index.js +1 -0
- package/dist/src/clients/payment-checkout/payment-handler.d.ts +1 -0
- package/dist/src/clients/payment-checkout/payment-handler.js +3 -14
- package/dist/src/clients/payment-checkout/types.d.ts +1 -0
- package/dist/src/index.js +729 -216
- package/dist/src/stories/utils/story-env.js +0 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -76,7 +76,512 @@ 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">
|
|
520
|
+
Continue with
|
|
521
|
+
<svg width="51" height="22" aria-label="Apple Pay" role="img">
|
|
522
|
+
<use href="#apple-pay-logo" />
|
|
523
|
+
</svg>
|
|
524
|
+
</button>
|
|
525
|
+
</div>
|
|
526
|
+
</div>
|
|
527
|
+
|
|
528
|
+
`;
|
|
529
|
+
|
|
530
|
+
// src/clients/payment-checkout/config.ts
|
|
531
|
+
var runtimeConfig = null;
|
|
532
|
+
var configureApplePay = (config) => {
|
|
533
|
+
runtimeConfig = {
|
|
534
|
+
...config
|
|
535
|
+
};
|
|
536
|
+
};
|
|
537
|
+
var getApplePayConfig = () => runtimeConfig;
|
|
538
|
+
|
|
539
|
+
// src/utils/recaptcha.ts
|
|
540
|
+
var loadRecaptchaScript = (siteKey) => {
|
|
541
|
+
return new Promise((resolve, reject) => {
|
|
542
|
+
if (typeof grecaptcha !== "undefined") return resolve();
|
|
543
|
+
const existingScript = document.querySelector(
|
|
544
|
+
'script[src*="recaptcha/api.js"]'
|
|
545
|
+
);
|
|
546
|
+
if (existingScript) {
|
|
547
|
+
existingScript.addEventListener("load", () => resolve());
|
|
548
|
+
existingScript.addEventListener(
|
|
549
|
+
"error",
|
|
550
|
+
() => reject(new Error("Failed to load existing reCAPTCHA script"))
|
|
551
|
+
);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
const script = document.createElement("script");
|
|
555
|
+
script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
|
|
556
|
+
script.async = true;
|
|
557
|
+
script.defer = true;
|
|
558
|
+
script.onload = () => resolve();
|
|
559
|
+
script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
|
|
560
|
+
document.head.appendChild(script);
|
|
561
|
+
});
|
|
562
|
+
};
|
|
563
|
+
var getRecaptchaToken = async (action) => {
|
|
564
|
+
const siteKey = getApplePayConfig()?.recaptchaSiteKey;
|
|
565
|
+
if (!siteKey) {
|
|
566
|
+
throw new Error(
|
|
567
|
+
"[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
await loadRecaptchaScript(siteKey);
|
|
571
|
+
return new Promise((resolve, reject) => {
|
|
572
|
+
grecaptcha.ready(() => {
|
|
573
|
+
grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
|
|
574
|
+
});
|
|
575
|
+
});
|
|
576
|
+
};
|
|
577
|
+
var getPurchaseRecaptchaTokens = async () => {
|
|
578
|
+
const [checkEligibility, newBasket, registerUser] = await Promise.all([
|
|
579
|
+
getRecaptchaToken("checkEligibility"),
|
|
580
|
+
getRecaptchaToken("newBasket"),
|
|
581
|
+
getRecaptchaToken("registerUser")
|
|
582
|
+
]);
|
|
583
|
+
return { checkEligibility, newBasket, registerUser };
|
|
584
|
+
};
|
|
80
585
|
|
|
81
586
|
// src/apple-pay-modal.ts
|
|
82
587
|
function getRenewalDateText(unit, duration) {
|
|
@@ -297,6 +802,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
297
802
|
#country = "";
|
|
298
803
|
#triggerElement = null;
|
|
299
804
|
#keyHandler = null;
|
|
805
|
+
#recaptchaTokens = null;
|
|
806
|
+
#recaptchaTokensPromise = null;
|
|
807
|
+
/**
|
|
808
|
+
* Synchronous callback invoked directly from the CTA click handler once the
|
|
809
|
+
* user confirms. The caller (ApplePayButton) must call startApplePaySession
|
|
810
|
+
* inside this callback to preserve the browser's user-gesture chain — Safari
|
|
811
|
+
* requires new ApplePaySession() to execute within the original click stack.
|
|
812
|
+
*
|
|
813
|
+
* reCAPTCHA tokens are guaranteed non-null here: the CTA remains disabled
|
|
814
|
+
* until the token pre-fetch resolves, so this callback is never reached
|
|
815
|
+
* without valid tokens.
|
|
816
|
+
*/
|
|
817
|
+
onConfirm = null;
|
|
300
818
|
set offer(value) {
|
|
301
819
|
this.#offer = value;
|
|
302
820
|
}
|
|
@@ -307,9 +825,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
307
825
|
this.#country = value;
|
|
308
826
|
}
|
|
309
827
|
connectedCallback() {
|
|
310
|
-
console.log("[web-apple-pay] ApplePayModal connectedCallback");
|
|
311
828
|
if (this.querySelector(".apm-overlay")) {
|
|
312
|
-
console.log("[web-apple-pay] ApplePayModal connectedCallback: already rendered, skipping");
|
|
313
829
|
return;
|
|
314
830
|
}
|
|
315
831
|
ensureApplePayLogoSymbol();
|
|
@@ -319,11 +835,9 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
319
835
|
const offer = this.#offer;
|
|
320
836
|
const country = this.#country;
|
|
321
837
|
if (!offer) {
|
|
322
|
-
console.error("ApplePayModal: Missing or invalid offer data");
|
|
323
838
|
this.remove();
|
|
324
839
|
return;
|
|
325
840
|
}
|
|
326
|
-
console.log("[web-apple-pay] ApplePayModal: rendering for offer", { skuId: offer.sku_id, country });
|
|
327
841
|
const offerNameElement = this.querySelector(
|
|
328
842
|
"#apple-pay-modal-offer-name"
|
|
329
843
|
);
|
|
@@ -395,23 +909,33 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
395
909
|
}
|
|
396
910
|
});
|
|
397
911
|
}
|
|
912
|
+
if (this.#recaptchaTokensPromise) {
|
|
913
|
+
if (cta) {
|
|
914
|
+
cta.setAttribute("disabled", "");
|
|
915
|
+
cta.setAttribute("aria-disabled", "true");
|
|
916
|
+
cta.setAttribute("aria-busy", "true");
|
|
917
|
+
}
|
|
918
|
+
this.#recaptchaTokensPromise.then((tokens) => {
|
|
919
|
+
this.#recaptchaTokens = tokens;
|
|
920
|
+
if (cta) {
|
|
921
|
+
cta.removeAttribute("disabled");
|
|
922
|
+
cta.removeAttribute("aria-disabled");
|
|
923
|
+
cta.removeAttribute("aria-busy");
|
|
924
|
+
}
|
|
925
|
+
}).catch(() => {
|
|
926
|
+
console.error("[web-apple-pay] apple-pay-modal: failed to pre-fetch reCAPTCHA tokens; CTA remains disabled");
|
|
927
|
+
});
|
|
928
|
+
}
|
|
398
929
|
cta?.addEventListener("click", () => {
|
|
399
|
-
console.log("[web-apple-pay] ApplePayModal: CTA clicked", { skuId: offer.sku_id, country, isUS });
|
|
400
930
|
if (isUS && checkbox && !checkbox.checked) {
|
|
401
|
-
console.log("[web-apple-pay] ApplePayModal: T&C checkbox not accepted, showing error");
|
|
402
931
|
errorElement?.classList.add("apm__error--visible");
|
|
403
932
|
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
404
933
|
return;
|
|
405
934
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
composed: true,
|
|
411
|
-
detail: { skuId: offer.sku_id, country }
|
|
412
|
-
})
|
|
413
|
-
);
|
|
414
|
-
console.log("[web-apple-pay] ApplePayModal: dispatching apple-pay-confirmed-final", { skuId: offer.sku_id, country });
|
|
935
|
+
if (this.#recaptchaTokens) {
|
|
936
|
+
this.onConfirm?.(this.#recaptchaTokens);
|
|
937
|
+
}
|
|
938
|
+
this.close();
|
|
415
939
|
});
|
|
416
940
|
this.querySelector("#apple-pay-modal-close")?.addEventListener(
|
|
417
941
|
"click",
|
|
@@ -419,7 +943,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
419
943
|
);
|
|
420
944
|
}
|
|
421
945
|
open() {
|
|
422
|
-
|
|
946
|
+
this.#recaptchaTokensPromise = getPurchaseRecaptchaTokens();
|
|
423
947
|
this.#triggerElement = document.activeElement;
|
|
424
948
|
document.body.appendChild(this);
|
|
425
949
|
this.#keyHandler = (event) => {
|
|
@@ -434,7 +958,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
434
958
|
this.querySelector("#apple-pay-modal")?.focus();
|
|
435
959
|
}
|
|
436
960
|
close() {
|
|
437
|
-
console.log("[web-apple-pay] ApplePayModal: close()");
|
|
438
961
|
if (this.#keyHandler) {
|
|
439
962
|
document.removeEventListener("keydown", this.#keyHandler, {
|
|
440
963
|
capture: true
|
|
@@ -447,22 +970,91 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
447
970
|
};
|
|
448
971
|
|
|
449
972
|
// src/templates/apple-pay-button.template.html
|
|
450
|
-
var apple_pay_button_template_default =
|
|
973
|
+
var apple_pay_button_template_default = `<style>
|
|
974
|
+
/* Use CSS variables for layout so parent walls can easily override placement and sizing */
|
|
975
|
+
teg-apple-pay-button {
|
|
976
|
+
display: block;
|
|
977
|
+
margin: var(--apple-pay-margin, 0);
|
|
978
|
+
width: 100%;
|
|
979
|
+
height: 100%;
|
|
980
|
+
}
|
|
451
981
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
982
|
+
teg-apple-pay-button .apple-pay-container {
|
|
983
|
+
display: flex;
|
|
984
|
+
flex-direction: column;
|
|
985
|
+
align-items: stretch;
|
|
986
|
+
width: 100%;
|
|
987
|
+
height: 100%;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
teg-apple-pay-button .apple-pay-btn {
|
|
991
|
+
display: flex;
|
|
992
|
+
align-items: center;
|
|
993
|
+
justify-content: center;
|
|
994
|
+
gap: 0.375rem;
|
|
995
|
+
width: 100%;
|
|
996
|
+
min-width: 0;
|
|
997
|
+
height: 100%;
|
|
998
|
+
min-height: var(--apple-pay-height, 2.75rem);
|
|
999
|
+
background-color: #000;
|
|
1000
|
+
color: #fff;
|
|
1001
|
+
border: none;
|
|
1002
|
+
border-radius: var(--apple-pay-border-radius, 1.375rem);
|
|
1003
|
+
cursor: pointer;
|
|
1004
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
1005
|
+
font-size: 1.0625rem;
|
|
1006
|
+
font-weight: 500;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
teg-apple-pay-button .apple-pay-btn svg {
|
|
1010
|
+
flex-shrink: 0;
|
|
1011
|
+
display: block;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading {
|
|
1015
|
+
position: relative;
|
|
1016
|
+
cursor: default;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading svg {
|
|
1020
|
+
visibility: hidden;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading::after {
|
|
1024
|
+
content: '';
|
|
1025
|
+
position: absolute;
|
|
1026
|
+
left: 50%;
|
|
1027
|
+
top: 50%;
|
|
1028
|
+
margin-left: -0.625rem;
|
|
1029
|
+
margin-top: -0.625rem;
|
|
1030
|
+
width: 1.25rem;
|
|
1031
|
+
height: 1.25rem;
|
|
1032
|
+
border: 2px solid rgba(255, 255, 255, 0.2);
|
|
1033
|
+
border-top-color: #fff;
|
|
1034
|
+
border-radius: 50%;
|
|
1035
|
+
animation: wap-button-spinner 0.8s linear infinite;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
@keyframes wap-button-spinner {
|
|
1039
|
+
to {
|
|
1040
|
+
transform: rotate(360deg);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
</style>
|
|
1044
|
+
|
|
1045
|
+
<div class="apple-pay-container" aria-label="Express checkout with Apple Pay">
|
|
1046
|
+
<button
|
|
1047
|
+
class="apple-pay-btn"
|
|
1048
|
+
type="button"
|
|
1049
|
+
aria-label="Pay with Apple Pay"
|
|
1050
|
+
data-analytics="paywall:apple-pay-checkout"
|
|
1051
|
+
>
|
|
1052
|
+
<svg width="51" height="22" aria-label="Apple Pay" role="img">
|
|
1053
|
+
<use href="#apple-pay-logo" />
|
|
1054
|
+
</svg>
|
|
1055
|
+
</button>
|
|
1056
|
+
</div>
|
|
1057
|
+
`;
|
|
466
1058
|
|
|
467
1059
|
// src/clients/payment-checkout/detects.ts
|
|
468
1060
|
var isAppleDeviceOrSafari = () => {
|
|
@@ -472,27 +1064,26 @@ var isAppleDeviceOrSafari = () => {
|
|
|
472
1064
|
};
|
|
473
1065
|
var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
|
|
474
1066
|
var isApplePayAvailable = async () => {
|
|
475
|
-
console.log("[web-apple-pay] isApplePayAvailable: checking availability");
|
|
476
1067
|
if (bypassApplePayChecks()) {
|
|
477
|
-
console.
|
|
1068
|
+
console.debug("[web-apple-pay] isApplePayAvailable: bypass enabled, returning true");
|
|
478
1069
|
return true;
|
|
479
1070
|
}
|
|
480
1071
|
if (!isAppleDeviceOrSafari()) {
|
|
481
|
-
console.
|
|
1072
|
+
console.debug("[web-apple-pay] isApplePayAvailable: not an Apple device or Safari", { userAgent: navigator.userAgent });
|
|
482
1073
|
return false;
|
|
483
1074
|
}
|
|
484
1075
|
const applePaySession = window.ApplePaySession;
|
|
485
1076
|
if (!applePaySession) {
|
|
486
|
-
console.
|
|
1077
|
+
console.debug("[web-apple-pay] isApplePayAvailable: ApplePaySession not present on window");
|
|
487
1078
|
return false;
|
|
488
1079
|
}
|
|
489
1080
|
try {
|
|
490
1081
|
if (typeof applePaySession.canMakePayments !== "function") {
|
|
491
|
-
console.
|
|
1082
|
+
console.debug("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function");
|
|
492
1083
|
return false;
|
|
493
1084
|
}
|
|
494
1085
|
if (!applePaySession.canMakePayments()) {
|
|
495
|
-
console.
|
|
1086
|
+
console.debug("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false");
|
|
496
1087
|
return false;
|
|
497
1088
|
}
|
|
498
1089
|
const merchantId = getApplePayConfig()?.merchantId;
|
|
@@ -502,10 +1093,9 @@ var isApplePayAvailable = async () => {
|
|
|
502
1093
|
);
|
|
503
1094
|
return false;
|
|
504
1095
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
return result;
|
|
1096
|
+
const hasActiveCard = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
1097
|
+
console.debug("[web-apple-pay] isApplePayAvailable: canMakePaymentsWithActiveCard =", hasActiveCard, { merchantId });
|
|
1098
|
+
return hasActiveCard;
|
|
509
1099
|
} catch (error) {
|
|
510
1100
|
console.error("Error checking Apple Pay active card status:", error);
|
|
511
1101
|
return false;
|
|
@@ -579,6 +1169,7 @@ var validateAppleMerchant = (data) => {
|
|
|
579
1169
|
});
|
|
580
1170
|
};
|
|
581
1171
|
var performPurchase = (data) => {
|
|
1172
|
+
console.log("[web-apple-pay] performPurchase request", JSON.stringify(data, null, 2));
|
|
582
1173
|
return apiFetch("/v1/wallet/purchase", {
|
|
583
1174
|
method: "POST",
|
|
584
1175
|
body: JSON.stringify(data),
|
|
@@ -634,53 +1225,6 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
634
1225
|
return url.pathname + url.search;
|
|
635
1226
|
};
|
|
636
1227
|
|
|
637
|
-
// src/utils/recaptcha.ts
|
|
638
|
-
var loadRecaptchaScript = (siteKey) => {
|
|
639
|
-
return new Promise((resolve, reject) => {
|
|
640
|
-
if (typeof grecaptcha !== "undefined") return resolve();
|
|
641
|
-
const existingScript = document.querySelector(
|
|
642
|
-
'script[src*="recaptcha/api.js"]'
|
|
643
|
-
);
|
|
644
|
-
if (existingScript) {
|
|
645
|
-
existingScript.addEventListener("load", () => resolve());
|
|
646
|
-
existingScript.addEventListener(
|
|
647
|
-
"error",
|
|
648
|
-
() => reject(new Error("Failed to load existing reCAPTCHA script"))
|
|
649
|
-
);
|
|
650
|
-
return;
|
|
651
|
-
}
|
|
652
|
-
const script = document.createElement("script");
|
|
653
|
-
script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
|
|
654
|
-
script.async = true;
|
|
655
|
-
script.defer = true;
|
|
656
|
-
script.onload = () => resolve();
|
|
657
|
-
script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
|
|
658
|
-
document.head.appendChild(script);
|
|
659
|
-
});
|
|
660
|
-
};
|
|
661
|
-
var getRecaptchaToken = async (action) => {
|
|
662
|
-
const siteKey = getApplePayConfig()?.recaptchaSiteKey;
|
|
663
|
-
if (!siteKey) {
|
|
664
|
-
throw new Error(
|
|
665
|
-
"[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
|
|
666
|
-
);
|
|
667
|
-
}
|
|
668
|
-
await loadRecaptchaScript(siteKey);
|
|
669
|
-
return new Promise((resolve, reject) => {
|
|
670
|
-
grecaptcha.ready(() => {
|
|
671
|
-
grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
|
|
672
|
-
});
|
|
673
|
-
});
|
|
674
|
-
};
|
|
675
|
-
var getPurchaseRecaptchaTokens = async () => {
|
|
676
|
-
const [checkEligibility, newBasket, registerUser] = await Promise.all([
|
|
677
|
-
getRecaptchaToken("checkEligibility"),
|
|
678
|
-
getRecaptchaToken("newBasket"),
|
|
679
|
-
getRecaptchaToken("registerUser")
|
|
680
|
-
]);
|
|
681
|
-
return { checkEligibility, newBasket, registerUser };
|
|
682
|
-
};
|
|
683
|
-
|
|
684
1228
|
// src/utils/expressCheckoutTracking.ts
|
|
685
1229
|
var EXPRESS_CHECKOUT_EVENTS = {
|
|
686
1230
|
/** Wallet button displayed */
|
|
@@ -766,11 +1310,49 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
|
|
|
766
1310
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
767
1311
|
|
|
768
1312
|
// src/clients/payment-checkout/apple-session.ts
|
|
1313
|
+
function redirectToFallbackCheckout(config) {
|
|
1314
|
+
trackFallbackCheckout(config.skuId);
|
|
1315
|
+
window.location.href = redirectToCheckoutFallback({
|
|
1316
|
+
skuId: config.skuId,
|
|
1317
|
+
returnUrl: config.returnUrl,
|
|
1318
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
async function handleMerchantValidation(event, session, config) {
|
|
1322
|
+
console.debug("[web-apple-pay] onvalidatemerchant: validating", { validationURL: event.validationURL });
|
|
1323
|
+
try {
|
|
1324
|
+
const validationHost = new URL(event.validationURL).host;
|
|
1325
|
+
if (!validationHost.endsWith("apple.com")) {
|
|
1326
|
+
console.debug("[web-apple-pay] onvalidatemerchant: invalid host, aborting", { validationHost });
|
|
1327
|
+
session.abort();
|
|
1328
|
+
redirectToFallbackCheckout(config);
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
1332
|
+
const response = await validateAppleMerchant({
|
|
1333
|
+
validationURL: event.validationURL,
|
|
1334
|
+
recaptchaToken
|
|
1335
|
+
});
|
|
1336
|
+
if (!response?.merchantSession) {
|
|
1337
|
+
console.debug("[web-apple-pay] onvalidatemerchant: no merchantSession in response, aborting");
|
|
1338
|
+
session.abort();
|
|
1339
|
+
redirectToFallbackCheckout(config);
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
console.debug("[web-apple-pay] onvalidatemerchant: merchant validated successfully");
|
|
1343
|
+
session.completeMerchantValidation(response.merchantSession);
|
|
1344
|
+
} catch (err) {
|
|
1345
|
+
console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
|
|
1346
|
+
session.abort();
|
|
1347
|
+
redirectToFallbackCheckout(config);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
769
1350
|
function startApplePaySession(config) {
|
|
770
|
-
console.
|
|
1351
|
+
console.debug("[web-apple-pay] startApplePaySession: starting session", {
|
|
771
1352
|
skuId: config.skuId,
|
|
772
1353
|
countryCode: config.countryCode,
|
|
773
1354
|
currencyCode: config.currencyCode,
|
|
1355
|
+
supportedNetworks: config.supportedNetworks,
|
|
774
1356
|
totalAmount: config.totalAmount,
|
|
775
1357
|
userLoggedIn: config.userLoggedIn
|
|
776
1358
|
});
|
|
@@ -789,72 +1371,24 @@ function startApplePaySession(config) {
|
|
|
789
1371
|
};
|
|
790
1372
|
try {
|
|
791
1373
|
const session = new ApplePaySession(3, paymentRequest);
|
|
792
|
-
console.log("[web-apple-pay] startApplePaySession: ApplePaySession created");
|
|
793
1374
|
session.onvalidatemerchant = async (event) => {
|
|
794
|
-
|
|
795
|
-
try {
|
|
796
|
-
const validationHost = new URL(event.validationURL).host;
|
|
797
|
-
if (!validationHost.endsWith("apple.com")) {
|
|
798
|
-
console.warn("[web-apple-pay] onvalidatemerchant: invalid host, aborting", { validationHost });
|
|
799
|
-
trackFallbackCheckout(config.skuId);
|
|
800
|
-
session.abort();
|
|
801
|
-
window.location.href = redirectToCheckoutFallback({
|
|
802
|
-
skuId: config.skuId,
|
|
803
|
-
returnUrl: config.returnUrl,
|
|
804
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
805
|
-
});
|
|
806
|
-
return;
|
|
807
|
-
}
|
|
808
|
-
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
809
|
-
console.log("[web-apple-pay] onvalidatemerchant: calling validateAppleMerchant");
|
|
810
|
-
const response = await validateAppleMerchant({
|
|
811
|
-
validationURL: event.validationURL,
|
|
812
|
-
recaptchaToken
|
|
813
|
-
});
|
|
814
|
-
if (!response?.merchantSession) {
|
|
815
|
-
console.warn("[web-apple-pay] onvalidatemerchant: no merchantSession in response, aborting");
|
|
816
|
-
trackFallbackCheckout(config.skuId);
|
|
817
|
-
session.abort();
|
|
818
|
-
window.location.href = redirectToCheckoutFallback({
|
|
819
|
-
skuId: config.skuId,
|
|
820
|
-
returnUrl: config.returnUrl,
|
|
821
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
822
|
-
});
|
|
823
|
-
return;
|
|
824
|
-
}
|
|
825
|
-
console.log("[web-apple-pay] onvalidatemerchant: merchant validated successfully");
|
|
826
|
-
session.completeMerchantValidation(response.merchantSession);
|
|
827
|
-
} catch (err) {
|
|
828
|
-
console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
|
|
829
|
-
trackFallbackCheckout(config.skuId);
|
|
830
|
-
session.abort();
|
|
831
|
-
window.location.href = redirectToCheckoutFallback({
|
|
832
|
-
skuId: config.skuId,
|
|
833
|
-
returnUrl: config.returnUrl,
|
|
834
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
835
|
-
});
|
|
836
|
-
}
|
|
1375
|
+
await handleMerchantValidation(event, session, config);
|
|
837
1376
|
};
|
|
838
1377
|
session.onpaymentauthorized = (event) => {
|
|
839
|
-
console.
|
|
1378
|
+
console.debug("[web-apple-pay] onpaymentauthorized: payment authorised");
|
|
840
1379
|
trackWalletPaymentAuthorised(config.skuId);
|
|
841
1380
|
config.onPaymentAuthorized(event, session);
|
|
842
1381
|
};
|
|
843
1382
|
session.oncancel = () => {
|
|
844
|
-
console.
|
|
1383
|
+
console.debug("[web-apple-pay] oncancel: user cancelled Apple Pay sheet");
|
|
845
1384
|
config.onCancel?.();
|
|
846
1385
|
};
|
|
847
|
-
console.
|
|
1386
|
+
console.debug("[web-apple-pay] startApplePaySession: session.begin()");
|
|
848
1387
|
trackWalletPaymentSheetOpen(config.skuId);
|
|
849
1388
|
session.begin();
|
|
850
1389
|
} catch (err) {
|
|
851
|
-
console.error("[web-apple-pay] startApplePaySession: failed to create
|
|
852
|
-
|
|
853
|
-
window.location.href = redirectToCheckoutFallback({
|
|
854
|
-
skuId: config.skuId,
|
|
855
|
-
returnUrl: config.returnUrl,
|
|
856
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
857
|
-
});
|
|
1390
|
+
console.error("[web-apple-pay] startApplePaySession: failed to create session", err);
|
|
1391
|
+
redirectToFallbackCheckout(config);
|
|
858
1392
|
}
|
|
859
1393
|
}
|
|
860
1394
|
|
|
@@ -1032,27 +1566,23 @@ function handleStructuredError(ctx) {
|
|
|
1032
1566
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
1033
1567
|
const { skuId, returnUrl, queryString } = config;
|
|
1034
1568
|
let validatedEmail;
|
|
1035
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
|
|
1036
1569
|
try {
|
|
1037
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
|
|
1038
1570
|
validatedEmail = validateContacts(
|
|
1039
1571
|
event,
|
|
1040
1572
|
sessionData,
|
|
1041
1573
|
config.supportedBillingCountries
|
|
1042
1574
|
);
|
|
1043
|
-
console.log("[web-apple-pay]
|
|
1044
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
|
|
1575
|
+
console.log("[web-apple-pay] performPurchase currency", { skuId, currency: config.currency });
|
|
1045
1576
|
const result = await performPurchase({
|
|
1046
1577
|
applePayToken: event.payment.token,
|
|
1047
1578
|
skuId: config.skuId,
|
|
1579
|
+
currency: config.currency,
|
|
1048
1580
|
billingContact: event.payment.billingContact,
|
|
1049
1581
|
...event.payment.shippingContact && {
|
|
1050
1582
|
shippingContact: event.payment.shippingContact
|
|
1051
1583
|
},
|
|
1052
1584
|
recaptchaTokens: config.recaptchaTokens
|
|
1053
1585
|
});
|
|
1054
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: performPurchase succeeded", { basketId: result.basketId });
|
|
1055
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: step 3 \u2014 completing payment and redirecting");
|
|
1056
1586
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1057
1587
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1058
1588
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
@@ -1065,25 +1595,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1065
1595
|
});
|
|
1066
1596
|
} catch (err) {
|
|
1067
1597
|
if (err instanceof ContactValidationError) {
|
|
1068
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
|
|
1069
1598
|
failApplePaySession(session, err.errors);
|
|
1070
1599
|
return;
|
|
1071
1600
|
}
|
|
1072
1601
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1073
1602
|
const walletError = parseWalletApiError(err);
|
|
1074
|
-
console.error("[web-apple-pay] handlePaymentAuthorized: BFF/network error", {
|
|
1075
|
-
skuId,
|
|
1076
|
-
errorType: walletError?.errorType ?? "UNKNOWN",
|
|
1077
|
-
message: walletError?.message
|
|
1078
|
-
});
|
|
1079
1603
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1080
1604
|
failApplePaySession(session);
|
|
1081
1605
|
if (!walletError) {
|
|
1082
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
|
|
1083
1606
|
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1084
1607
|
return;
|
|
1085
1608
|
}
|
|
1086
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
|
|
1087
1609
|
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1088
1610
|
}
|
|
1089
1611
|
}
|
|
@@ -1371,18 +1893,14 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1371
1893
|
*/
|
|
1372
1894
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1373
1895
|
if (!offer) {
|
|
1374
|
-
console.log("[web-apple-pay] createIfEnabled: no offer provided \u2192 null");
|
|
1375
1896
|
return null;
|
|
1376
1897
|
}
|
|
1377
1898
|
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1378
|
-
console.log("[web-apple-pay] createIfEnabled: excluded variant \u2192 null", { variant: offer.product?.variant });
|
|
1379
1899
|
return null;
|
|
1380
1900
|
}
|
|
1381
1901
|
if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
|
|
1382
|
-
console.log("[web-apple-pay] createIfEnabled: feature flag absent \u2192 null");
|
|
1383
1902
|
return null;
|
|
1384
1903
|
}
|
|
1385
|
-
console.log("[web-apple-pay] createIfEnabled: creating button", { skuId: offer.sku_id, country, entryPoint });
|
|
1386
1904
|
_ApplePayButton.define();
|
|
1387
1905
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1388
1906
|
button.offer = offer;
|
|
@@ -1409,7 +1927,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1409
1927
|
#returnUrl = "";
|
|
1410
1928
|
#supportedBillingCountries = [];
|
|
1411
1929
|
#entryPoint = "";
|
|
1412
|
-
#recaptchaTokens = null;
|
|
1413
1930
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1414
1931
|
get offer() {
|
|
1415
1932
|
return this.#offer;
|
|
@@ -1451,9 +1968,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1451
1968
|
}
|
|
1452
1969
|
// ─── Lifecycle ──────────────────────────────────────────────────────────────
|
|
1453
1970
|
async connectedCallback() {
|
|
1454
|
-
console.log("[web-apple-pay] connectedCallback: element connected");
|
|
1455
1971
|
if (this.#rendering || this.querySelector(SEL_CONTAINER)) {
|
|
1456
|
-
console.log("[web-apple-pay] connectedCallback: already rendering or rendered, skipping");
|
|
1457
1972
|
return;
|
|
1458
1973
|
}
|
|
1459
1974
|
this.#rendering = true;
|
|
@@ -1470,7 +1985,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1470
1985
|
* and eliminating the implicit reliance on the DOM as a render-state flag.
|
|
1471
1986
|
*/
|
|
1472
1987
|
disconnectedCallback() {
|
|
1473
|
-
console.log("[web-apple-pay] disconnectedCallback: element removed from DOM, resetting state");
|
|
1474
1988
|
this.#rendering = false;
|
|
1475
1989
|
this.#readyPromise = null;
|
|
1476
1990
|
this.#sessionData = null;
|
|
@@ -1481,17 +1995,20 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1481
1995
|
}
|
|
1482
1996
|
// ─── Render pipeline ────────────────────────────────────────────────────────
|
|
1483
1997
|
async #run() {
|
|
1484
|
-
console.
|
|
1998
|
+
console.debug("[web-apple-pay] #run: start");
|
|
1485
1999
|
try {
|
|
1486
2000
|
if (await this.#checkAvailability()) return;
|
|
1487
|
-
if (await this.#checkSession()) return;
|
|
1488
2001
|
if (this.#checkOffer()) return;
|
|
2002
|
+
this.#renderTemplate();
|
|
2003
|
+
if (await this.#checkSession()) return;
|
|
1489
2004
|
this.#captureReturnUrl();
|
|
1490
2005
|
this.#computeBillingCountries();
|
|
1491
2006
|
if (await this.#fetchAndCacheOptions()) return;
|
|
1492
|
-
this.#
|
|
1493
|
-
} catch {
|
|
2007
|
+
this.#finishLoading();
|
|
2008
|
+
} catch (err) {
|
|
2009
|
+
console.error("[web-apple-pay] #run: unexpected error, hiding button", err);
|
|
1494
2010
|
this.style.display = "none";
|
|
2011
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1495
2012
|
} finally {
|
|
1496
2013
|
this.#rendering = false;
|
|
1497
2014
|
}
|
|
@@ -1500,11 +2017,11 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1500
2017
|
async #checkAvailability() {
|
|
1501
2018
|
const available = await isApplePayAvailable();
|
|
1502
2019
|
if (!available) {
|
|
1503
|
-
console.
|
|
2020
|
+
console.debug("[web-apple-pay] #checkAvailability: not available on this device/browser");
|
|
1504
2021
|
this.style.display = "none";
|
|
1505
2022
|
return true;
|
|
1506
2023
|
}
|
|
1507
|
-
console.
|
|
2024
|
+
console.debug("[web-apple-pay] #checkAvailability: ok");
|
|
1508
2025
|
return false;
|
|
1509
2026
|
}
|
|
1510
2027
|
/**
|
|
@@ -1513,28 +2030,29 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1513
2030
|
*/
|
|
1514
2031
|
async #checkSession() {
|
|
1515
2032
|
this.#sessionData = await this.#fetchSession();
|
|
1516
|
-
console.
|
|
2033
|
+
console.debug("[web-apple-pay] #checkSession: session data", { loggedIn: this.#sessionData?.loggedIn, userType: this.#sessionData?.userType });
|
|
1517
2034
|
if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
|
|
1518
|
-
console.
|
|
2035
|
+
console.debug("[web-apple-pay] #checkSession: ineligible user, hiding button", { userType: this.#sessionData.userType });
|
|
1519
2036
|
this.style.display = "none";
|
|
2037
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1520
2038
|
return true;
|
|
1521
2039
|
}
|
|
2040
|
+
console.debug("[web-apple-pay] #checkSession: ok");
|
|
1522
2041
|
return false;
|
|
1523
2042
|
}
|
|
1524
2043
|
/** Returns `true` (hide) when no offer has been set before mount. */
|
|
1525
2044
|
#checkOffer() {
|
|
1526
2045
|
if (!this.#offer) {
|
|
1527
|
-
console.
|
|
2046
|
+
console.debug("[web-apple-pay] #checkOffer: no offer set, hiding button");
|
|
1528
2047
|
this.style.display = "none";
|
|
1529
2048
|
return true;
|
|
1530
2049
|
}
|
|
1531
|
-
console.
|
|
2050
|
+
console.debug("[web-apple-pay] #checkOffer: ok", { skuId: this.#offer.sku_id });
|
|
1532
2051
|
return false;
|
|
1533
2052
|
}
|
|
1534
2053
|
/** Captures the current page URL once at mount for reuse across the session lifetime. */
|
|
1535
2054
|
#captureReturnUrl() {
|
|
1536
2055
|
this.#returnUrl = captureOriginUrl();
|
|
1537
|
-
console.log("[web-apple-pay] #captureReturnUrl:", this.#returnUrl);
|
|
1538
2056
|
}
|
|
1539
2057
|
/**
|
|
1540
2058
|
* Computes supported billing countries once at mount.
|
|
@@ -1546,7 +2064,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1546
2064
|
this.#country,
|
|
1547
2065
|
this.#offer.product?.variant ?? ""
|
|
1548
2066
|
);
|
|
1549
|
-
console.log("[web-apple-pay] #computeBillingCountries:", this.#supportedBillingCountries);
|
|
1550
2067
|
}
|
|
1551
2068
|
/**
|
|
1552
2069
|
* Returns `true` (hide) when the wallet BFF reports Apple Pay is unavailable
|
|
@@ -1554,36 +2071,45 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1554
2071
|
*/
|
|
1555
2072
|
async #fetchAndCacheOptions() {
|
|
1556
2073
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1557
|
-
console.
|
|
2074
|
+
console.debug("[web-apple-pay] #fetchAndCacheOptions: payment options", this.#paymentOptions);
|
|
1558
2075
|
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
1559
|
-
console.
|
|
2076
|
+
console.debug("[web-apple-pay] #fetchAndCacheOptions: apple_pay absent in options, hiding button");
|
|
1560
2077
|
this.style.display = "none";
|
|
2078
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1561
2079
|
return true;
|
|
1562
2080
|
}
|
|
2081
|
+
console.debug("[web-apple-pay] #fetchAndCacheOptions: ok", this.#paymentOptions.options.apple_pay);
|
|
1563
2082
|
return false;
|
|
1564
2083
|
}
|
|
1565
2084
|
/** Injects the button template and wires click and confirm event listeners. */
|
|
1566
2085
|
#renderTemplate() {
|
|
1567
|
-
console.
|
|
2086
|
+
console.debug("[web-apple-pay] #renderTemplate: injecting button template");
|
|
1568
2087
|
this.style.removeProperty("display");
|
|
1569
2088
|
ensureApplePayLogoSymbol();
|
|
1570
2089
|
const template = document.createElement("template");
|
|
1571
2090
|
template.innerHTML = apple_pay_button_template_default;
|
|
1572
2091
|
this.appendChild(template.content.cloneNode(true));
|
|
1573
|
-
this.#updateDisabledState();
|
|
1574
|
-
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
1575
|
-
entryPoint: this.#entryPoint,
|
|
1576
|
-
country: this.#country
|
|
1577
|
-
});
|
|
1578
2092
|
const button = this.querySelector(SEL_BUTTON);
|
|
2093
|
+
button.classList.add("wap-loading");
|
|
2094
|
+
button.setAttribute("disabled", "");
|
|
2095
|
+
button.setAttribute("aria-disabled", "true");
|
|
2096
|
+
button.setAttribute("aria-busy", "true");
|
|
1579
2097
|
button.addEventListener("click", () => {
|
|
2098
|
+
if (button.classList.contains("wap-loading")) return;
|
|
1580
2099
|
this.#openModal();
|
|
1581
2100
|
});
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
2101
|
+
}
|
|
2102
|
+
#finishLoading() {
|
|
2103
|
+
console.debug("[web-apple-pay] #finishLoading: all checks passed, enabling button");
|
|
2104
|
+
const button = this.querySelector(SEL_BUTTON);
|
|
2105
|
+
if (button) {
|
|
2106
|
+
button.classList.remove("wap-loading");
|
|
2107
|
+
this.#updateDisabledState();
|
|
2108
|
+
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
2109
|
+
entryPoint: this.#entryPoint,
|
|
2110
|
+
country: this.#country
|
|
2111
|
+
});
|
|
2112
|
+
}
|
|
1587
2113
|
}
|
|
1588
2114
|
// ─── Private helpers ────────────────────────────────────────────────────────
|
|
1589
2115
|
#updateDisabledState() {
|
|
@@ -1592,28 +2118,20 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1592
2118
|
if (this.#offer) {
|
|
1593
2119
|
button.removeAttribute("disabled");
|
|
1594
2120
|
button.removeAttribute("aria-disabled");
|
|
2121
|
+
button.removeAttribute("aria-busy");
|
|
1595
2122
|
return;
|
|
1596
2123
|
}
|
|
1597
2124
|
button.setAttribute("disabled", "");
|
|
1598
2125
|
button.setAttribute("aria-disabled", "true");
|
|
1599
2126
|
}
|
|
1600
2127
|
#openModal() {
|
|
1601
|
-
console.log("[web-apple-pay] #openModal: button clicked", { skuId: this.#offer?.sku_id });
|
|
1602
2128
|
if (!this.#offer) {
|
|
1603
|
-
console.warn("[web-apple-pay] #openModal: no offer set, ignoring click");
|
|
1604
2129
|
return;
|
|
1605
2130
|
}
|
|
1606
2131
|
if (document.querySelector(ApplePayModal.tag)) {
|
|
1607
|
-
console.warn("[web-apple-pay] #openModal: modal already open, ignoring click");
|
|
1608
2132
|
return;
|
|
1609
2133
|
}
|
|
1610
2134
|
trackExpressWalletClick(this.#offer.sku_id);
|
|
1611
|
-
getPurchaseRecaptchaTokens().then((tokens) => {
|
|
1612
|
-
console.log("[web-apple-pay] #openModal: reCAPTCHA tokens pre-fetched");
|
|
1613
|
-
this.#recaptchaTokens = tokens;
|
|
1614
|
-
}).catch((err) => {
|
|
1615
|
-
console.warn("[web-apple-pay] #openModal: reCAPTCHA pre-fetch failed", err);
|
|
1616
|
-
});
|
|
1617
2135
|
ApplePayModal.define();
|
|
1618
2136
|
const modal = document.createElement(ApplePayModal.tag);
|
|
1619
2137
|
modal.offer = this.#offer;
|
|
@@ -1621,35 +2139,32 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1621
2139
|
if (this.#sessionData?.loggedIn) {
|
|
1622
2140
|
modal.dataset.loggedIn = "true";
|
|
1623
2141
|
}
|
|
2142
|
+
const { skuId, country } = { skuId: this.#offer.sku_id, country: this.#country };
|
|
2143
|
+
modal.onConfirm = (recaptchaTokens) => {
|
|
2144
|
+
this.#initiateApplePay(skuId, country, recaptchaTokens);
|
|
2145
|
+
};
|
|
1624
2146
|
modal.open();
|
|
1625
2147
|
}
|
|
1626
2148
|
async #fetchSession() {
|
|
1627
2149
|
try {
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
return session;
|
|
1631
|
-
} catch (err) {
|
|
1632
|
-
console.warn("[web-apple-pay] #fetchSession: failed, falling back to anonymous session", err);
|
|
2150
|
+
return await getExpressCheckoutSession();
|
|
2151
|
+
} catch {
|
|
1633
2152
|
return null;
|
|
1634
2153
|
}
|
|
1635
2154
|
}
|
|
1636
2155
|
async #fetchPaymentOptions() {
|
|
1637
2156
|
try {
|
|
1638
|
-
|
|
2157
|
+
return await getPaymentOptions({
|
|
1639
2158
|
sku: this.#offer.sku_id,
|
|
1640
2159
|
countryCode: this.#country,
|
|
1641
2160
|
currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1642
2161
|
checkoutUrl: this.#returnUrl
|
|
1643
2162
|
});
|
|
1644
|
-
|
|
1645
|
-
return options;
|
|
1646
|
-
} catch (err) {
|
|
1647
|
-
console.warn("[web-apple-pay] #fetchPaymentOptions: failed", err);
|
|
2163
|
+
} catch {
|
|
1648
2164
|
return null;
|
|
1649
2165
|
}
|
|
1650
2166
|
}
|
|
1651
2167
|
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokens) {
|
|
1652
|
-
console.log("[web-apple-pay] #buildSessionParams", { skuId, country, userLoggedIn: sessionData.loggedIn });
|
|
1653
2168
|
const offer = this.#offer;
|
|
1654
2169
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
1655
2170
|
return {
|
|
@@ -1664,6 +2179,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1664
2179
|
onPaymentAuthorized: (event, session) => handlePaymentAuthorized(event, session, sessionData, {
|
|
1665
2180
|
skuId,
|
|
1666
2181
|
country,
|
|
2182
|
+
currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1667
2183
|
returnUrl: this.#returnUrl,
|
|
1668
2184
|
queryString: buildQueryString(),
|
|
1669
2185
|
supportedBillingCountries: this.#supportedBillingCountries,
|
|
@@ -1671,13 +2187,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1671
2187
|
})
|
|
1672
2188
|
};
|
|
1673
2189
|
}
|
|
1674
|
-
|
|
1675
|
-
console.log("[web-apple-pay] #initiateApplePay: starting", { skuId, country });
|
|
2190
|
+
#initiateApplePay(skuId, country, recaptchaTokens) {
|
|
1676
2191
|
try {
|
|
1677
2192
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
1678
2193
|
const paymentOptions = this.#paymentOptions;
|
|
1679
|
-
const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
|
|
1680
|
-
console.log("[web-apple-pay] #initiateApplePay: tokens ready, starting session", { prefetched: !!this.#recaptchaTokens });
|
|
1681
2194
|
startApplePaySession(
|
|
1682
2195
|
this.#buildSessionParams(
|
|
1683
2196
|
skuId,
|