@economist/web-apple-pay 0.1.3-beta.0 → 0.1.3-beta.2
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 +215 -108
- package/dist/src/apple-pay-button.js +215 -108
- package/dist/src/apple-pay-button.stories.js +215 -108
- package/dist/src/apple-pay-modal.js +1 -10
- package/dist/src/apple-pay-modal.stories.js +215 -108
- package/dist/src/clients/payment-checkout/apple-session.js +80 -51
- package/dist/src/clients/payment-checkout/payment-handler.js +21 -0
- package/dist/src/clients/payment-checkout/shipping-contact-details.js +21 -0
- package/dist/src/index.js +215 -108
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -307,9 +307,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
307
307
|
this.#country = value;
|
|
308
308
|
}
|
|
309
309
|
connectedCallback() {
|
|
310
|
-
console.log("[web-apple-pay] ApplePayModal connectedCallback");
|
|
311
310
|
if (this.querySelector(".apm-overlay")) {
|
|
312
|
-
console.log("[web-apple-pay] ApplePayModal connectedCallback: already rendered, skipping");
|
|
313
311
|
return;
|
|
314
312
|
}
|
|
315
313
|
ensureApplePayLogoSymbol();
|
|
@@ -319,11 +317,9 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
319
317
|
const offer = this.#offer;
|
|
320
318
|
const country = this.#country;
|
|
321
319
|
if (!offer) {
|
|
322
|
-
console.error("ApplePayModal: Missing or invalid offer data");
|
|
323
320
|
this.remove();
|
|
324
321
|
return;
|
|
325
322
|
}
|
|
326
|
-
console.log("[web-apple-pay] ApplePayModal: rendering for offer", { skuId: offer.sku_id, country });
|
|
327
323
|
const offerNameElement = this.querySelector(
|
|
328
324
|
"#apple-pay-modal-offer-name"
|
|
329
325
|
);
|
|
@@ -396,14 +392,11 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
396
392
|
});
|
|
397
393
|
}
|
|
398
394
|
cta?.addEventListener("click", () => {
|
|
399
|
-
console.log("[web-apple-pay] ApplePayModal: CTA clicked", { skuId: offer.sku_id, country, isUS });
|
|
400
395
|
if (isUS && checkbox && !checkbox.checked) {
|
|
401
|
-
console.log("[web-apple-pay] ApplePayModal: T&C checkbox not accepted, showing error");
|
|
402
396
|
errorElement?.classList.add("apm__error--visible");
|
|
403
397
|
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
404
398
|
return;
|
|
405
399
|
}
|
|
406
|
-
console.log("[web-apple-pay] ApplePayModal: dispatching apple-pay-confirmed", { skuId: offer.sku_id, country });
|
|
407
400
|
this.dispatchEvent(
|
|
408
401
|
new CustomEvent("apple-pay-confirmed", {
|
|
409
402
|
bubbles: true,
|
|
@@ -411,7 +404,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
411
404
|
detail: { skuId: offer.sku_id, country }
|
|
412
405
|
})
|
|
413
406
|
);
|
|
414
|
-
|
|
407
|
+
this.close();
|
|
415
408
|
});
|
|
416
409
|
this.querySelector("#apple-pay-modal-close")?.addEventListener(
|
|
417
410
|
"click",
|
|
@@ -419,7 +412,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
419
412
|
);
|
|
420
413
|
}
|
|
421
414
|
open() {
|
|
422
|
-
console.log("[web-apple-pay] ApplePayModal: open()");
|
|
423
415
|
this.#triggerElement = document.activeElement;
|
|
424
416
|
document.body.appendChild(this);
|
|
425
417
|
this.#keyHandler = (event) => {
|
|
@@ -434,7 +426,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
434
426
|
this.querySelector("#apple-pay-modal")?.focus();
|
|
435
427
|
}
|
|
436
428
|
close() {
|
|
437
|
-
console.log("[web-apple-pay] ApplePayModal: close()");
|
|
438
429
|
if (this.#keyHandler) {
|
|
439
430
|
document.removeEventListener("keydown", this.#keyHandler, {
|
|
440
431
|
capture: true
|
|
@@ -447,7 +438,91 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
447
438
|
};
|
|
448
439
|
|
|
449
440
|
// src/templates/apple-pay-button.template.html
|
|
450
|
-
var apple_pay_button_template_default =
|
|
441
|
+
var apple_pay_button_template_default = `<style>
|
|
442
|
+
/* Use CSS variables for layout so parent walls can easily override placement and sizing */
|
|
443
|
+
teg-apple-pay-button {
|
|
444
|
+
display: block;
|
|
445
|
+
margin: var(--apple-pay-margin, 0);
|
|
446
|
+
width: 100%;
|
|
447
|
+
height: 100%;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
teg-apple-pay-button .apple-pay-container {
|
|
451
|
+
display: flex;
|
|
452
|
+
flex-direction: column;
|
|
453
|
+
align-items: stretch;
|
|
454
|
+
width: 100%;
|
|
455
|
+
height: 100%;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
teg-apple-pay-button .apple-pay-btn {
|
|
459
|
+
display: flex;
|
|
460
|
+
align-items: center;
|
|
461
|
+
justify-content: center;
|
|
462
|
+
gap: 0.375rem;
|
|
463
|
+
width: 100%;
|
|
464
|
+
min-width: 0;
|
|
465
|
+
height: 100%;
|
|
466
|
+
min-height: var(--apple-pay-height, 2.75rem);
|
|
467
|
+
background-color: #000;
|
|
468
|
+
color: #fff;
|
|
469
|
+
border: none;
|
|
470
|
+
border-radius: var(--apple-pay-border-radius, 1.375rem);
|
|
471
|
+
cursor: pointer;
|
|
472
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
473
|
+
font-size: 1.0625rem;
|
|
474
|
+
font-weight: 500;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
teg-apple-pay-button .apple-pay-btn svg {
|
|
478
|
+
flex-shrink: 0;
|
|
479
|
+
display: block;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading {
|
|
483
|
+
position: relative;
|
|
484
|
+
cursor: default;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading svg {
|
|
488
|
+
visibility: hidden;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading::after {
|
|
492
|
+
content: '';
|
|
493
|
+
position: absolute;
|
|
494
|
+
left: 50%;
|
|
495
|
+
top: 50%;
|
|
496
|
+
margin-left: -0.625rem;
|
|
497
|
+
margin-top: -0.625rem;
|
|
498
|
+
width: 1.25rem;
|
|
499
|
+
height: 1.25rem;
|
|
500
|
+
border: 2px solid rgba(255, 255, 255, 0.2);
|
|
501
|
+
border-top-color: #fff;
|
|
502
|
+
border-radius: 50%;
|
|
503
|
+
animation: wap-button-spinner 0.8s linear infinite;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
@keyframes wap-button-spinner {
|
|
507
|
+
to {
|
|
508
|
+
transform: rotate(360deg);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
</style>
|
|
512
|
+
|
|
513
|
+
<div class="apple-pay-container" aria-label="Express checkout with Apple Pay">
|
|
514
|
+
<button
|
|
515
|
+
class="apple-pay-btn"
|
|
516
|
+
type="button"
|
|
517
|
+
aria-label="Pay with Apple Pay"
|
|
518
|
+
data-analytics="paywall:apple-pay-checkout"
|
|
519
|
+
>
|
|
520
|
+
<svg width="51" height="22" aria-label="Apple Pay" role="img">
|
|
521
|
+
<use href="#apple-pay-logo" />
|
|
522
|
+
</svg>
|
|
523
|
+
</button>
|
|
524
|
+
</div>
|
|
525
|
+
`;
|
|
451
526
|
|
|
452
527
|
// src/clients/payment-checkout/config.ts
|
|
453
528
|
var runtimeConfig = null;
|
|
@@ -766,6 +841,65 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
|
|
|
766
841
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
767
842
|
|
|
768
843
|
// src/clients/payment-checkout/apple-session.ts
|
|
844
|
+
function redirectToFallbackCheckout(config) {
|
|
845
|
+
console.warn("[web-apple-pay] redirectToFallbackCheckout", {
|
|
846
|
+
skuId: config.skuId,
|
|
847
|
+
returnUrl: config.returnUrl,
|
|
848
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
849
|
+
});
|
|
850
|
+
trackFallbackCheckout(config.skuId);
|
|
851
|
+
window.location.href = redirectToCheckoutFallback({
|
|
852
|
+
skuId: config.skuId,
|
|
853
|
+
returnUrl: config.returnUrl,
|
|
854
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
async function handleMerchantValidation(event, session, config) {
|
|
858
|
+
console.log("[web-apple-pay] handleMerchantValidation: start", {
|
|
859
|
+
skuId: config.skuId,
|
|
860
|
+
validationURL: event.validationURL
|
|
861
|
+
});
|
|
862
|
+
try {
|
|
863
|
+
const validationHost = new URL(event.validationURL).host;
|
|
864
|
+
console.log("[web-apple-pay] handleMerchantValidation: host parsed", {
|
|
865
|
+
validationHost
|
|
866
|
+
});
|
|
867
|
+
if (!validationHost.endsWith("apple.com")) {
|
|
868
|
+
console.warn(
|
|
869
|
+
"[web-apple-pay] handleMerchantValidation: invalid validation host",
|
|
870
|
+
{ validationHost }
|
|
871
|
+
);
|
|
872
|
+
session.abort();
|
|
873
|
+
redirectToFallbackCheckout(config);
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
console.log("[web-apple-pay] handleMerchantValidation: requesting recaptcha token");
|
|
877
|
+
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
878
|
+
console.log("[web-apple-pay] handleMerchantValidation: recaptcha token received");
|
|
879
|
+
const response = await validateAppleMerchant({
|
|
880
|
+
validationURL: event.validationURL,
|
|
881
|
+
recaptchaToken
|
|
882
|
+
});
|
|
883
|
+
if (!response?.merchantSession) {
|
|
884
|
+
console.warn(
|
|
885
|
+
"[web-apple-pay] handleMerchantValidation: missing merchantSession in response"
|
|
886
|
+
);
|
|
887
|
+
session.abort();
|
|
888
|
+
redirectToFallbackCheckout(config);
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
console.log("[web-apple-pay] handleMerchantValidation: completing merchant validation");
|
|
892
|
+
session.completeMerchantValidation(response.merchantSession);
|
|
893
|
+
console.log("[web-apple-pay] handleMerchantValidation: success");
|
|
894
|
+
} catch (err) {
|
|
895
|
+
console.error("[web-apple-pay] handleMerchantValidation: failed", {
|
|
896
|
+
skuId: config.skuId,
|
|
897
|
+
err
|
|
898
|
+
});
|
|
899
|
+
session.abort();
|
|
900
|
+
redirectToFallbackCheckout(config);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
769
903
|
function startApplePaySession(config) {
|
|
770
904
|
console.log("[web-apple-pay] startApplePaySession", {
|
|
771
905
|
skuId: config.skuId,
|
|
@@ -787,74 +921,44 @@ function startApplePaySession(config) {
|
|
|
787
921
|
// Only request email from Apple Pay sheet if user is NOT logged in
|
|
788
922
|
...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
|
|
789
923
|
};
|
|
924
|
+
console.log("[web-apple-pay] startApplePaySession: payment request created", {
|
|
925
|
+
skuId: config.skuId,
|
|
926
|
+
requiredShippingContactFields: paymentRequest.requiredShippingContactFields
|
|
927
|
+
});
|
|
790
928
|
try {
|
|
791
929
|
const session = new ApplePaySession(3, paymentRequest);
|
|
792
930
|
console.log("[web-apple-pay] startApplePaySession: ApplePaySession created");
|
|
793
931
|
session.onvalidatemerchant = async (event) => {
|
|
794
|
-
console.log("[web-apple-pay] onvalidatemerchant:
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
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
|
-
}
|
|
932
|
+
console.log("[web-apple-pay] onvalidatemerchant: invoked", {
|
|
933
|
+
skuId: config.skuId
|
|
934
|
+
});
|
|
935
|
+
await handleMerchantValidation(event, session, config);
|
|
837
936
|
};
|
|
838
937
|
session.onpaymentauthorized = (event) => {
|
|
839
|
-
console.log("[web-apple-pay] onpaymentauthorized:
|
|
938
|
+
console.log("[web-apple-pay] onpaymentauthorized: invoked", {
|
|
939
|
+
skuId: config.skuId
|
|
940
|
+
});
|
|
840
941
|
trackWalletPaymentAuthorised(config.skuId);
|
|
841
942
|
config.onPaymentAuthorized(event, session);
|
|
842
943
|
};
|
|
843
944
|
session.oncancel = () => {
|
|
844
|
-
console.log("[web-apple-pay] oncancel:
|
|
945
|
+
console.log("[web-apple-pay] oncancel: invoked", {
|
|
946
|
+
skuId: config.skuId
|
|
947
|
+
});
|
|
845
948
|
config.onCancel?.();
|
|
846
949
|
};
|
|
847
|
-
console.log("[web-apple-pay] startApplePaySession:
|
|
950
|
+
console.log("[web-apple-pay] startApplePaySession: opening payment sheet", {
|
|
951
|
+
skuId: config.skuId
|
|
952
|
+
});
|
|
848
953
|
trackWalletPaymentSheetOpen(config.skuId);
|
|
849
954
|
session.begin();
|
|
955
|
+
console.log("[web-apple-pay] startApplePaySession: session begin called");
|
|
850
956
|
} catch (err) {
|
|
851
|
-
console.error("[web-apple-pay] startApplePaySession: failed to
|
|
852
|
-
trackFallbackCheckout(config.skuId);
|
|
853
|
-
window.location.href = redirectToCheckoutFallback({
|
|
957
|
+
console.error("[web-apple-pay] startApplePaySession: failed to start session", {
|
|
854
958
|
skuId: config.skuId,
|
|
855
|
-
|
|
856
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
959
|
+
err
|
|
857
960
|
});
|
|
961
|
+
redirectToFallbackCheckout(config);
|
|
858
962
|
}
|
|
859
963
|
}
|
|
860
964
|
|
|
@@ -944,13 +1048,25 @@ var billingContactDetails = (contact, supportedBillingCountries) => {
|
|
|
944
1048
|
// src/clients/payment-checkout/shipping-contact-details.ts
|
|
945
1049
|
var EMAIL_FORMAT_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
946
1050
|
var shippingContactDetails = (shippingContact) => {
|
|
1051
|
+
console.log("[web-apple-pay] shippingContactDetails: start", {
|
|
1052
|
+
hasShippingContact: Boolean(shippingContact),
|
|
1053
|
+
hasEmailAddress: shippingContact?.emailAddress !== void 0
|
|
1054
|
+
});
|
|
947
1055
|
const errors = [];
|
|
948
1056
|
let emailAddress = "";
|
|
949
1057
|
if (shippingContact?.emailAddress === void 0 || shippingContact?.emailAddress === "") {
|
|
1058
|
+
console.log(
|
|
1059
|
+
"[web-apple-pay] shippingContactDetails: email missing or empty"
|
|
1060
|
+
);
|
|
950
1061
|
pushRequiredFieldError(errors, "shipping", "emailAddress");
|
|
951
1062
|
} else {
|
|
1063
|
+
console.log("[web-apple-pay] shippingContactDetails: email provided");
|
|
952
1064
|
emailAddress = shippingContact.emailAddress.trim();
|
|
1065
|
+
console.log("[web-apple-pay] shippingContactDetails: email trimmed", {
|
|
1066
|
+
emailLength: emailAddress.length
|
|
1067
|
+
});
|
|
953
1068
|
if (emailAddress.length > 80) {
|
|
1069
|
+
console.log("[web-apple-pay] shippingContactDetails: email too long");
|
|
954
1070
|
pushFieldError(
|
|
955
1071
|
errors,
|
|
956
1072
|
"shipping",
|
|
@@ -959,6 +1075,9 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
959
1075
|
MSG_EMAIL_TOO_LONG
|
|
960
1076
|
);
|
|
961
1077
|
} else if (!EMAIL_FORMAT_REGEX.test(emailAddress)) {
|
|
1078
|
+
console.log(
|
|
1079
|
+
"[web-apple-pay] shippingContactDetails: email format invalid"
|
|
1080
|
+
);
|
|
962
1081
|
pushFieldError(
|
|
963
1082
|
errors,
|
|
964
1083
|
"shipping",
|
|
@@ -966,11 +1085,17 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
966
1085
|
"format",
|
|
967
1086
|
MSG_EMAIL_WRONG_FORMAT
|
|
968
1087
|
);
|
|
1088
|
+
} else {
|
|
1089
|
+
console.log("[web-apple-pay] shippingContactDetails: email valid");
|
|
969
1090
|
}
|
|
970
1091
|
}
|
|
971
1092
|
if (errors.length > 0) {
|
|
1093
|
+
console.log("[web-apple-pay] shippingContactDetails: throwing validation error", {
|
|
1094
|
+
errorCount: errors.length
|
|
1095
|
+
});
|
|
972
1096
|
throw new ContactValidationError(errors);
|
|
973
1097
|
}
|
|
1098
|
+
console.log("[web-apple-pay] shippingContactDetails: success");
|
|
974
1099
|
return { emailAddress };
|
|
975
1100
|
};
|
|
976
1101
|
|
|
@@ -1371,18 +1496,14 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1371
1496
|
*/
|
|
1372
1497
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1373
1498
|
if (!offer) {
|
|
1374
|
-
console.log("[web-apple-pay] createIfEnabled: no offer provided \u2192 null");
|
|
1375
1499
|
return null;
|
|
1376
1500
|
}
|
|
1377
1501
|
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
1502
|
return null;
|
|
1380
1503
|
}
|
|
1381
1504
|
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
1505
|
return null;
|
|
1384
1506
|
}
|
|
1385
|
-
console.log("[web-apple-pay] createIfEnabled: creating button", { skuId: offer.sku_id, country, entryPoint });
|
|
1386
1507
|
_ApplePayButton.define();
|
|
1387
1508
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1388
1509
|
button.offer = offer;
|
|
@@ -1451,9 +1572,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1451
1572
|
}
|
|
1452
1573
|
// ─── Lifecycle ──────────────────────────────────────────────────────────────
|
|
1453
1574
|
async connectedCallback() {
|
|
1454
|
-
console.log("[web-apple-pay] connectedCallback: element connected");
|
|
1455
1575
|
if (this.#rendering || this.querySelector(SEL_CONTAINER)) {
|
|
1456
|
-
console.log("[web-apple-pay] connectedCallback: already rendering or rendered, skipping");
|
|
1457
1576
|
return;
|
|
1458
1577
|
}
|
|
1459
1578
|
this.#rendering = true;
|
|
@@ -1470,7 +1589,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1470
1589
|
* and eliminating the implicit reliance on the DOM as a render-state flag.
|
|
1471
1590
|
*/
|
|
1472
1591
|
disconnectedCallback() {
|
|
1473
|
-
console.log("[web-apple-pay] disconnectedCallback: element removed from DOM, resetting state");
|
|
1474
1592
|
this.#rendering = false;
|
|
1475
1593
|
this.#readyPromise = null;
|
|
1476
1594
|
this.#sessionData = null;
|
|
@@ -1481,17 +1599,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1481
1599
|
}
|
|
1482
1600
|
// ─── Render pipeline ────────────────────────────────────────────────────────
|
|
1483
1601
|
async #run() {
|
|
1484
|
-
console.log("[web-apple-pay] #run: starting render pipeline");
|
|
1485
1602
|
try {
|
|
1486
1603
|
if (await this.#checkAvailability()) return;
|
|
1487
|
-
if (await this.#checkSession()) return;
|
|
1488
1604
|
if (this.#checkOffer()) return;
|
|
1605
|
+
this.#renderTemplate();
|
|
1606
|
+
if (await this.#checkSession()) return;
|
|
1489
1607
|
this.#captureReturnUrl();
|
|
1490
1608
|
this.#computeBillingCountries();
|
|
1491
1609
|
if (await this.#fetchAndCacheOptions()) return;
|
|
1492
|
-
this.#
|
|
1610
|
+
this.#finishLoading();
|
|
1493
1611
|
} catch {
|
|
1494
1612
|
this.style.display = "none";
|
|
1613
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1495
1614
|
} finally {
|
|
1496
1615
|
this.#rendering = false;
|
|
1497
1616
|
}
|
|
@@ -1500,11 +1619,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1500
1619
|
async #checkAvailability() {
|
|
1501
1620
|
const available = await isApplePayAvailable();
|
|
1502
1621
|
if (!available) {
|
|
1503
|
-
console.log("[web-apple-pay] #checkAvailability: Apple Pay unavailable \u2192 hiding");
|
|
1504
1622
|
this.style.display = "none";
|
|
1505
1623
|
return true;
|
|
1506
1624
|
}
|
|
1507
|
-
console.log("[web-apple-pay] #checkAvailability: Apple Pay available");
|
|
1508
1625
|
return false;
|
|
1509
1626
|
}
|
|
1510
1627
|
/**
|
|
@@ -1513,10 +1630,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1513
1630
|
*/
|
|
1514
1631
|
async #checkSession() {
|
|
1515
1632
|
this.#sessionData = await this.#fetchSession();
|
|
1516
|
-
console.log("[web-apple-pay] #checkSession: session fetched", { loggedIn: this.#sessionData?.loggedIn, userType: this.#sessionData?.userType });
|
|
1517
1633
|
if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
|
|
1518
|
-
console.log("[web-apple-pay] #checkSession: ineligible user \u2192 hiding", { userType: this.#sessionData.userType });
|
|
1519
1634
|
this.style.display = "none";
|
|
1635
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1520
1636
|
return true;
|
|
1521
1637
|
}
|
|
1522
1638
|
return false;
|
|
@@ -1524,17 +1640,14 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1524
1640
|
/** Returns `true` (hide) when no offer has been set before mount. */
|
|
1525
1641
|
#checkOffer() {
|
|
1526
1642
|
if (!this.#offer) {
|
|
1527
|
-
console.log("[web-apple-pay] #checkOffer: no offer set \u2192 hiding");
|
|
1528
1643
|
this.style.display = "none";
|
|
1529
1644
|
return true;
|
|
1530
1645
|
}
|
|
1531
|
-
console.log("[web-apple-pay] #checkOffer: offer present", { skuId: this.#offer.sku_id });
|
|
1532
1646
|
return false;
|
|
1533
1647
|
}
|
|
1534
1648
|
/** Captures the current page URL once at mount for reuse across the session lifetime. */
|
|
1535
1649
|
#captureReturnUrl() {
|
|
1536
1650
|
this.#returnUrl = captureOriginUrl();
|
|
1537
|
-
console.log("[web-apple-pay] #captureReturnUrl:", this.#returnUrl);
|
|
1538
1651
|
}
|
|
1539
1652
|
/**
|
|
1540
1653
|
* Computes supported billing countries once at mount.
|
|
@@ -1546,7 +1659,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1546
1659
|
this.#country,
|
|
1547
1660
|
this.#offer.product?.variant ?? ""
|
|
1548
1661
|
);
|
|
1549
|
-
console.log("[web-apple-pay] #computeBillingCountries:", this.#supportedBillingCountries);
|
|
1550
1662
|
}
|
|
1551
1663
|
/**
|
|
1552
1664
|
* Returns `true` (hide) when the wallet BFF reports Apple Pay is unavailable
|
|
@@ -1554,37 +1666,45 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1554
1666
|
*/
|
|
1555
1667
|
async #fetchAndCacheOptions() {
|
|
1556
1668
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1557
|
-
console.log("[web-apple-pay] #fetchAndCacheOptions: fetched payment options", { paymentOptions: this.#paymentOptions });
|
|
1558
1669
|
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
1559
|
-
console.log("[web-apple-pay] #fetchAndCacheOptions: apple_pay not in options \u2192 hiding");
|
|
1560
1670
|
this.style.display = "none";
|
|
1671
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1561
1672
|
return true;
|
|
1562
1673
|
}
|
|
1563
1674
|
return false;
|
|
1564
1675
|
}
|
|
1565
1676
|
/** Injects the button template and wires click and confirm event listeners. */
|
|
1566
1677
|
#renderTemplate() {
|
|
1567
|
-
console.log("[web-apple-pay] #renderTemplate: rendering Apple Pay button", { skuId: this.#offer?.sku_id, country: this.#country });
|
|
1568
1678
|
this.style.removeProperty("display");
|
|
1569
1679
|
ensureApplePayLogoSymbol();
|
|
1570
1680
|
const template = document.createElement("template");
|
|
1571
1681
|
template.innerHTML = apple_pay_button_template_default;
|
|
1572
1682
|
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
1683
|
const button = this.querySelector(SEL_BUTTON);
|
|
1684
|
+
button.classList.add("wap-loading");
|
|
1685
|
+
button.setAttribute("disabled", "");
|
|
1686
|
+
button.setAttribute("aria-disabled", "true");
|
|
1687
|
+
button.setAttribute("aria-busy", "true");
|
|
1579
1688
|
button.addEventListener("click", () => {
|
|
1689
|
+
if (button.classList.contains("wap-loading")) return;
|
|
1580
1690
|
this.#openModal();
|
|
1581
1691
|
});
|
|
1582
1692
|
document.addEventListener("apple-pay-confirmed", (event) => {
|
|
1583
1693
|
const { skuId, country } = event.detail;
|
|
1584
|
-
console.log("[web-apple-pay] apple-pay-confirmed received on document", { skuId, country });
|
|
1585
1694
|
this.#initiateApplePay(skuId, country);
|
|
1586
1695
|
}, { once: true });
|
|
1587
1696
|
}
|
|
1697
|
+
#finishLoading() {
|
|
1698
|
+
const button = this.querySelector(SEL_BUTTON);
|
|
1699
|
+
if (button) {
|
|
1700
|
+
button.classList.remove("wap-loading");
|
|
1701
|
+
this.#updateDisabledState();
|
|
1702
|
+
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
1703
|
+
entryPoint: this.#entryPoint,
|
|
1704
|
+
country: this.#country
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1588
1708
|
// ─── Private helpers ────────────────────────────────────────────────────────
|
|
1589
1709
|
#updateDisabledState() {
|
|
1590
1710
|
const button = this.querySelector(SEL_BUTTON);
|
|
@@ -1592,27 +1712,23 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1592
1712
|
if (this.#offer) {
|
|
1593
1713
|
button.removeAttribute("disabled");
|
|
1594
1714
|
button.removeAttribute("aria-disabled");
|
|
1715
|
+
button.removeAttribute("aria-busy");
|
|
1595
1716
|
return;
|
|
1596
1717
|
}
|
|
1597
1718
|
button.setAttribute("disabled", "");
|
|
1598
1719
|
button.setAttribute("aria-disabled", "true");
|
|
1599
1720
|
}
|
|
1600
1721
|
#openModal() {
|
|
1601
|
-
console.log("[web-apple-pay] #openModal: button clicked", { skuId: this.#offer?.sku_id });
|
|
1602
1722
|
if (!this.#offer) {
|
|
1603
|
-
console.warn("[web-apple-pay] #openModal: no offer set, ignoring click");
|
|
1604
1723
|
return;
|
|
1605
1724
|
}
|
|
1606
1725
|
if (document.querySelector(ApplePayModal.tag)) {
|
|
1607
|
-
console.warn("[web-apple-pay] #openModal: modal already open, ignoring click");
|
|
1608
1726
|
return;
|
|
1609
1727
|
}
|
|
1610
1728
|
trackExpressWalletClick(this.#offer.sku_id);
|
|
1611
1729
|
getPurchaseRecaptchaTokens().then((tokens) => {
|
|
1612
|
-
console.log("[web-apple-pay] #openModal: reCAPTCHA tokens pre-fetched");
|
|
1613
1730
|
this.#recaptchaTokens = tokens;
|
|
1614
|
-
}).catch((
|
|
1615
|
-
console.warn("[web-apple-pay] #openModal: reCAPTCHA pre-fetch failed", err);
|
|
1731
|
+
}).catch(() => {
|
|
1616
1732
|
});
|
|
1617
1733
|
ApplePayModal.define();
|
|
1618
1734
|
const modal = document.createElement(ApplePayModal.tag);
|
|
@@ -1625,31 +1741,24 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1625
1741
|
}
|
|
1626
1742
|
async #fetchSession() {
|
|
1627
1743
|
try {
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
return session;
|
|
1631
|
-
} catch (err) {
|
|
1632
|
-
console.warn("[web-apple-pay] #fetchSession: failed, falling back to anonymous session", err);
|
|
1744
|
+
return await getExpressCheckoutSession();
|
|
1745
|
+
} catch {
|
|
1633
1746
|
return null;
|
|
1634
1747
|
}
|
|
1635
1748
|
}
|
|
1636
1749
|
async #fetchPaymentOptions() {
|
|
1637
1750
|
try {
|
|
1638
|
-
|
|
1751
|
+
return await getPaymentOptions({
|
|
1639
1752
|
sku: this.#offer.sku_id,
|
|
1640
1753
|
countryCode: this.#country,
|
|
1641
1754
|
currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1642
1755
|
checkoutUrl: this.#returnUrl
|
|
1643
1756
|
});
|
|
1644
|
-
|
|
1645
|
-
return options;
|
|
1646
|
-
} catch (err) {
|
|
1647
|
-
console.warn("[web-apple-pay] #fetchPaymentOptions: failed", err);
|
|
1757
|
+
} catch {
|
|
1648
1758
|
return null;
|
|
1649
1759
|
}
|
|
1650
1760
|
}
|
|
1651
1761
|
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokens) {
|
|
1652
|
-
console.log("[web-apple-pay] #buildSessionParams", { skuId, country, userLoggedIn: sessionData.loggedIn });
|
|
1653
1762
|
const offer = this.#offer;
|
|
1654
1763
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
1655
1764
|
return {
|
|
@@ -1672,12 +1781,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1672
1781
|
};
|
|
1673
1782
|
}
|
|
1674
1783
|
async #initiateApplePay(skuId, country) {
|
|
1675
|
-
console.log("[web-apple-pay] #initiateApplePay: starting", { skuId, country });
|
|
1676
1784
|
try {
|
|
1677
1785
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
1678
1786
|
const paymentOptions = this.#paymentOptions;
|
|
1679
1787
|
const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
|
|
1680
|
-
console.log("[web-apple-pay] #initiateApplePay: tokens ready, starting session", { prefetched: !!this.#recaptchaTokens });
|
|
1681
1788
|
startApplePaySession(
|
|
1682
1789
|
this.#buildSessionParams(
|
|
1683
1790
|
skuId,
|