@economist/web-apple-pay 0.1.3-beta.2 → 0.1.3-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +70 -285
- package/dist/src/apple-pay-button.js +70 -279
- package/dist/src/apple-pay-button.stories.js +70 -286
- package/dist/src/apple-pay-modal.js +1 -0
- package/dist/src/apple-pay-modal.stories.js +70 -279
- package/dist/src/clients/payment-checkout/apple-session.js +47 -103
- package/dist/src/clients/payment-checkout/config.js +0 -7
- package/dist/src/clients/payment-checkout/detects.js +1 -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 -35
- package/dist/src/clients/payment-checkout/shipping-contact-details.js +0 -21
- package/dist/src/clients/payment-checkout/types.d.ts +5 -6
- package/dist/src/index.js +70 -285
- package/dist/src/stories/utils/story-env.js +0 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -317,6 +317,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
317
317
|
const offer = this.#offer;
|
|
318
318
|
const country = this.#country;
|
|
319
319
|
if (!offer) {
|
|
320
|
+
console.error("ApplePayModal: Missing or invalid offer data");
|
|
320
321
|
this.remove();
|
|
321
322
|
return;
|
|
322
323
|
}
|
|
@@ -438,101 +439,11 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
438
439
|
};
|
|
439
440
|
|
|
440
441
|
// src/templates/apple-pay-button.template.html
|
|
441
|
-
var apple_pay_button_template_default =
|
|
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
|
-
`;
|
|
442
|
+
var apple_pay_button_template_default = '<style>\n /* Use CSS variables for layout so parent walls can easily override placement and sizing */\n teg-apple-pay-button {\n display: block;\n margin: var(--apple-pay-margin, 0);\n width: 100%;\n height: 100%;\n }\n\n teg-apple-pay-button .apple-pay-container {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n height: 100%;\n }\n\n teg-apple-pay-button .apple-pay-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n width: 100%;\n min-width: 0;\n height: 100%;\n min-height: var(--apple-pay-height, 2.75rem);\n background-color: #000;\n color: #fff;\n border: none;\n border-radius: var(--apple-pay-border-radius, 1.375rem);\n cursor: pointer;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: 1.0625rem;\n font-weight: 500;\n }\n\n teg-apple-pay-button .apple-pay-btn svg {\n flex-shrink: 0;\n display: block;\n }\n</style>\n\n<div class="apple-pay-container" aria-label="Express checkout with Apple Pay">\n <button\n class="apple-pay-btn"\n type="button"\n aria-label="Pay with Apple Pay"\n data-analytics="paywall:apple-pay-checkout"\n >\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';
|
|
526
443
|
|
|
527
444
|
// src/clients/payment-checkout/config.ts
|
|
528
445
|
var runtimeConfig = null;
|
|
529
446
|
var configureApplePay = (config) => {
|
|
530
|
-
console.log("[web-apple-pay] configureApplePay called", {
|
|
531
|
-
merchantId: config.merchantId,
|
|
532
|
-
walletApiBaseUrl: config.walletApiBaseUrl,
|
|
533
|
-
debugBypassEnabled: config.debugBypassEnabled,
|
|
534
|
-
recaptchaSiteKey: config.recaptchaSiteKey ? "***" : void 0
|
|
535
|
-
});
|
|
536
447
|
runtimeConfig = {
|
|
537
448
|
...config
|
|
538
449
|
};
|
|
@@ -547,27 +458,21 @@ var isAppleDeviceOrSafari = () => {
|
|
|
547
458
|
};
|
|
548
459
|
var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
|
|
549
460
|
var isApplePayAvailable = async () => {
|
|
550
|
-
console.log("[web-apple-pay] isApplePayAvailable: checking availability");
|
|
551
461
|
if (bypassApplePayChecks()) {
|
|
552
|
-
console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
|
|
553
462
|
return true;
|
|
554
463
|
}
|
|
555
464
|
if (!isAppleDeviceOrSafari()) {
|
|
556
|
-
console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
|
|
557
465
|
return false;
|
|
558
466
|
}
|
|
559
467
|
const applePaySession = window.ApplePaySession;
|
|
560
468
|
if (!applePaySession) {
|
|
561
|
-
console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
|
|
562
469
|
return false;
|
|
563
470
|
}
|
|
564
471
|
try {
|
|
565
472
|
if (typeof applePaySession.canMakePayments !== "function") {
|
|
566
|
-
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
|
|
567
473
|
return false;
|
|
568
474
|
}
|
|
569
475
|
if (!applePaySession.canMakePayments()) {
|
|
570
|
-
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
|
|
571
476
|
return false;
|
|
572
477
|
}
|
|
573
478
|
const merchantId = getApplePayConfig()?.merchantId;
|
|
@@ -577,10 +482,7 @@ var isApplePayAvailable = async () => {
|
|
|
577
482
|
);
|
|
578
483
|
return false;
|
|
579
484
|
}
|
|
580
|
-
|
|
581
|
-
const result = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
582
|
-
console.log("[web-apple-pay] isApplePayAvailable: canMakePaymentsWithActiveCard \u2192", result);
|
|
583
|
-
return result;
|
|
485
|
+
return await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
584
486
|
} catch (error) {
|
|
585
487
|
console.error("Error checking Apple Pay active card status:", error);
|
|
586
488
|
return false;
|
|
@@ -654,6 +556,7 @@ var validateAppleMerchant = (data) => {
|
|
|
654
556
|
});
|
|
655
557
|
};
|
|
656
558
|
var performPurchase = (data) => {
|
|
559
|
+
console.debug("[web-apple-pay] performPurchase request", JSON.stringify(data, null, 2));
|
|
657
560
|
return apiFetch("/v1/wallet/purchase", {
|
|
658
561
|
method: "POST",
|
|
659
562
|
body: JSON.stringify(data),
|
|
@@ -841,73 +744,7 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
|
|
|
841
744
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
842
745
|
|
|
843
746
|
// 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
|
-
}
|
|
903
747
|
function startApplePaySession(config) {
|
|
904
|
-
console.log("[web-apple-pay] startApplePaySession", {
|
|
905
|
-
skuId: config.skuId,
|
|
906
|
-
countryCode: config.countryCode,
|
|
907
|
-
currencyCode: config.currencyCode,
|
|
908
|
-
totalAmount: config.totalAmount,
|
|
909
|
-
userLoggedIn: config.userLoggedIn
|
|
910
|
-
});
|
|
911
748
|
const paymentRequest = {
|
|
912
749
|
countryCode: config.countryCode,
|
|
913
750
|
currencyCode: config.currencyCode,
|
|
@@ -921,45 +758,55 @@ function startApplePaySession(config) {
|
|
|
921
758
|
// Only request email from Apple Pay sheet if user is NOT logged in
|
|
922
759
|
...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
|
|
923
760
|
};
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
761
|
+
const session = new ApplePaySession(3, paymentRequest);
|
|
762
|
+
session.onvalidatemerchant = async (event) => {
|
|
763
|
+
try {
|
|
764
|
+
const validationHost = new URL(event.validationURL).host;
|
|
765
|
+
if (!validationHost.endsWith("apple.com")) {
|
|
766
|
+
trackFallbackCheckout(config.skuId);
|
|
767
|
+
session.abort();
|
|
768
|
+
window.location.href = redirectToCheckoutFallback({
|
|
769
|
+
skuId: config.skuId,
|
|
770
|
+
returnUrl: config.returnUrl,
|
|
771
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
772
|
+
});
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
776
|
+
const response = await validateAppleMerchant({
|
|
777
|
+
validationURL: event.validationURL,
|
|
778
|
+
recaptchaToken
|
|
940
779
|
});
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
780
|
+
if (!response?.merchantSession) {
|
|
781
|
+
trackFallbackCheckout(config.skuId);
|
|
782
|
+
session.abort();
|
|
783
|
+
window.location.href = redirectToCheckoutFallback({
|
|
784
|
+
skuId: config.skuId,
|
|
785
|
+
returnUrl: config.returnUrl,
|
|
786
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
787
|
+
});
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
session.completeMerchantValidation(response.merchantSession);
|
|
791
|
+
} catch {
|
|
792
|
+
trackFallbackCheckout(config.skuId);
|
|
793
|
+
session.abort();
|
|
794
|
+
window.location.href = redirectToCheckoutFallback({
|
|
795
|
+
skuId: config.skuId,
|
|
796
|
+
returnUrl: config.returnUrl,
|
|
797
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
947
798
|
});
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
err
|
|
960
|
-
});
|
|
961
|
-
redirectToFallbackCheckout(config);
|
|
962
|
-
}
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
session.onpaymentauthorized = (event) => {
|
|
802
|
+
trackWalletPaymentAuthorised(config.skuId);
|
|
803
|
+
config.onPaymentAuthorized(event, session);
|
|
804
|
+
};
|
|
805
|
+
session.oncancel = () => {
|
|
806
|
+
config.onCancel?.();
|
|
807
|
+
};
|
|
808
|
+
trackWalletPaymentSheetOpen(config.skuId);
|
|
809
|
+
session.begin();
|
|
963
810
|
}
|
|
964
811
|
|
|
965
812
|
// src/clients/payment-checkout/contact-validation.ts
|
|
@@ -1048,25 +895,13 @@ var billingContactDetails = (contact, supportedBillingCountries) => {
|
|
|
1048
895
|
// src/clients/payment-checkout/shipping-contact-details.ts
|
|
1049
896
|
var EMAIL_FORMAT_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1050
897
|
var shippingContactDetails = (shippingContact) => {
|
|
1051
|
-
console.log("[web-apple-pay] shippingContactDetails: start", {
|
|
1052
|
-
hasShippingContact: Boolean(shippingContact),
|
|
1053
|
-
hasEmailAddress: shippingContact?.emailAddress !== void 0
|
|
1054
|
-
});
|
|
1055
898
|
const errors = [];
|
|
1056
899
|
let emailAddress = "";
|
|
1057
900
|
if (shippingContact?.emailAddress === void 0 || shippingContact?.emailAddress === "") {
|
|
1058
|
-
console.log(
|
|
1059
|
-
"[web-apple-pay] shippingContactDetails: email missing or empty"
|
|
1060
|
-
);
|
|
1061
901
|
pushRequiredFieldError(errors, "shipping", "emailAddress");
|
|
1062
902
|
} else {
|
|
1063
|
-
console.log("[web-apple-pay] shippingContactDetails: email provided");
|
|
1064
903
|
emailAddress = shippingContact.emailAddress.trim();
|
|
1065
|
-
console.log("[web-apple-pay] shippingContactDetails: email trimmed", {
|
|
1066
|
-
emailLength: emailAddress.length
|
|
1067
|
-
});
|
|
1068
904
|
if (emailAddress.length > 80) {
|
|
1069
|
-
console.log("[web-apple-pay] shippingContactDetails: email too long");
|
|
1070
905
|
pushFieldError(
|
|
1071
906
|
errors,
|
|
1072
907
|
"shipping",
|
|
@@ -1075,9 +910,6 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
1075
910
|
MSG_EMAIL_TOO_LONG
|
|
1076
911
|
);
|
|
1077
912
|
} else if (!EMAIL_FORMAT_REGEX.test(emailAddress)) {
|
|
1078
|
-
console.log(
|
|
1079
|
-
"[web-apple-pay] shippingContactDetails: email format invalid"
|
|
1080
|
-
);
|
|
1081
913
|
pushFieldError(
|
|
1082
914
|
errors,
|
|
1083
915
|
"shipping",
|
|
@@ -1085,17 +917,11 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
1085
917
|
"format",
|
|
1086
918
|
MSG_EMAIL_WRONG_FORMAT
|
|
1087
919
|
);
|
|
1088
|
-
} else {
|
|
1089
|
-
console.log("[web-apple-pay] shippingContactDetails: email valid");
|
|
1090
920
|
}
|
|
1091
921
|
}
|
|
1092
922
|
if (errors.length > 0) {
|
|
1093
|
-
console.log("[web-apple-pay] shippingContactDetails: throwing validation error", {
|
|
1094
|
-
errorCount: errors.length
|
|
1095
|
-
});
|
|
1096
923
|
throw new ContactValidationError(errors);
|
|
1097
924
|
}
|
|
1098
|
-
console.log("[web-apple-pay] shippingContactDetails: success");
|
|
1099
925
|
return { emailAddress };
|
|
1100
926
|
};
|
|
1101
927
|
|
|
@@ -1157,27 +983,23 @@ function handleStructuredError(ctx) {
|
|
|
1157
983
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
1158
984
|
const { skuId, returnUrl, queryString } = config;
|
|
1159
985
|
let validatedEmail;
|
|
1160
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
|
|
1161
986
|
try {
|
|
1162
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
|
|
1163
987
|
validatedEmail = validateContacts(
|
|
1164
988
|
event,
|
|
1165
989
|
sessionData,
|
|
1166
990
|
config.supportedBillingCountries
|
|
1167
991
|
);
|
|
1168
|
-
console.
|
|
1169
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
|
|
992
|
+
console.debug("[web-apple-pay] performPurchase currency", { skuId, currency: config.currency });
|
|
1170
993
|
const result = await performPurchase({
|
|
1171
994
|
applePayToken: event.payment.token,
|
|
1172
995
|
skuId: config.skuId,
|
|
996
|
+
currency: config.currency,
|
|
1173
997
|
billingContact: event.payment.billingContact,
|
|
1174
998
|
...event.payment.shippingContact && {
|
|
1175
999
|
shippingContact: event.payment.shippingContact
|
|
1176
1000
|
},
|
|
1177
1001
|
recaptchaTokens: config.recaptchaTokens
|
|
1178
1002
|
});
|
|
1179
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: performPurchase succeeded", { basketId: result.basketId });
|
|
1180
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: step 3 \u2014 completing payment and redirecting");
|
|
1181
1003
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1182
1004
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1183
1005
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
@@ -1190,25 +1012,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1190
1012
|
});
|
|
1191
1013
|
} catch (err) {
|
|
1192
1014
|
if (err instanceof ContactValidationError) {
|
|
1193
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
|
|
1194
1015
|
failApplePaySession(session, err.errors);
|
|
1195
1016
|
return;
|
|
1196
1017
|
}
|
|
1197
1018
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1198
1019
|
const walletError = parseWalletApiError(err);
|
|
1199
|
-
console.error("[web-apple-pay] handlePaymentAuthorized: BFF/network error", {
|
|
1200
|
-
skuId,
|
|
1201
|
-
errorType: walletError?.errorType ?? "UNKNOWN",
|
|
1202
|
-
message: walletError?.message
|
|
1203
|
-
});
|
|
1204
1020
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1205
1021
|
failApplePaySession(session);
|
|
1206
1022
|
if (!walletError) {
|
|
1207
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
|
|
1208
1023
|
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1209
1024
|
return;
|
|
1210
1025
|
}
|
|
1211
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
|
|
1212
1026
|
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1213
1027
|
}
|
|
1214
1028
|
}
|
|
@@ -1495,15 +1309,11 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1495
1309
|
* Creates and configures an ApplePayButton if the feature flag is present.
|
|
1496
1310
|
*/
|
|
1497
1311
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1498
|
-
if (!offer)
|
|
1499
|
-
|
|
1500
|
-
}
|
|
1501
|
-
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1312
|
+
if (!offer) return null;
|
|
1313
|
+
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
|
|
1502
1314
|
return null;
|
|
1503
|
-
|
|
1504
|
-
if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
|
|
1315
|
+
if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT))
|
|
1505
1316
|
return null;
|
|
1506
|
-
}
|
|
1507
1317
|
_ApplePayButton.define();
|
|
1508
1318
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1509
1319
|
button.offer = offer;
|
|
@@ -1530,7 +1340,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1530
1340
|
#returnUrl = "";
|
|
1531
1341
|
#supportedBillingCountries = [];
|
|
1532
1342
|
#entryPoint = "";
|
|
1533
|
-
#recaptchaTokens = null;
|
|
1534
1343
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1535
1344
|
get offer() {
|
|
1536
1345
|
return this.#offer;
|
|
@@ -1601,16 +1410,14 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1601
1410
|
async #run() {
|
|
1602
1411
|
try {
|
|
1603
1412
|
if (await this.#checkAvailability()) return;
|
|
1604
|
-
if (this.#checkOffer()) return;
|
|
1605
|
-
this.#renderTemplate();
|
|
1606
1413
|
if (await this.#checkSession()) return;
|
|
1414
|
+
if (this.#checkOffer()) return;
|
|
1607
1415
|
this.#captureReturnUrl();
|
|
1608
1416
|
this.#computeBillingCountries();
|
|
1609
1417
|
if (await this.#fetchAndCacheOptions()) return;
|
|
1610
|
-
this.#
|
|
1418
|
+
this.#renderTemplate();
|
|
1611
1419
|
} catch {
|
|
1612
1420
|
this.style.display = "none";
|
|
1613
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1614
1421
|
} finally {
|
|
1615
1422
|
this.#rendering = false;
|
|
1616
1423
|
}
|
|
@@ -1632,7 +1439,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1632
1439
|
this.#sessionData = await this.#fetchSession();
|
|
1633
1440
|
if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
|
|
1634
1441
|
this.style.display = "none";
|
|
1635
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1636
1442
|
return true;
|
|
1637
1443
|
}
|
|
1638
1444
|
return false;
|
|
@@ -1666,9 +1472,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1666
1472
|
*/
|
|
1667
1473
|
async #fetchAndCacheOptions() {
|
|
1668
1474
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1669
|
-
if (!this.#paymentOptions?.
|
|
1475
|
+
if (!this.#paymentOptions?.apple_pay) {
|
|
1670
1476
|
this.style.display = "none";
|
|
1671
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1672
1477
|
return true;
|
|
1673
1478
|
}
|
|
1674
1479
|
return false;
|
|
@@ -1680,30 +1485,19 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1680
1485
|
const template = document.createElement("template");
|
|
1681
1486
|
template.innerHTML = apple_pay_button_template_default;
|
|
1682
1487
|
this.appendChild(template.content.cloneNode(true));
|
|
1488
|
+
this.#updateDisabledState();
|
|
1489
|
+
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
1490
|
+
entryPoint: this.#entryPoint,
|
|
1491
|
+
country: this.#country
|
|
1492
|
+
});
|
|
1683
1493
|
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");
|
|
1688
1494
|
button.addEventListener("click", () => {
|
|
1689
|
-
if (button.classList.contains("wap-loading")) return;
|
|
1690
1495
|
this.#openModal();
|
|
1691
1496
|
});
|
|
1692
|
-
|
|
1497
|
+
this.addEventListener("apple-pay-confirmed", (event) => {
|
|
1693
1498
|
const { skuId, country } = event.detail;
|
|
1694
1499
|
this.#initiateApplePay(skuId, country);
|
|
1695
|
-
}
|
|
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
|
-
}
|
|
1500
|
+
});
|
|
1707
1501
|
}
|
|
1708
1502
|
// ─── Private helpers ────────────────────────────────────────────────────────
|
|
1709
1503
|
#updateDisabledState() {
|
|
@@ -1712,24 +1506,14 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1712
1506
|
if (this.#offer) {
|
|
1713
1507
|
button.removeAttribute("disabled");
|
|
1714
1508
|
button.removeAttribute("aria-disabled");
|
|
1715
|
-
button.removeAttribute("aria-busy");
|
|
1716
1509
|
return;
|
|
1717
1510
|
}
|
|
1718
1511
|
button.setAttribute("disabled", "");
|
|
1719
1512
|
button.setAttribute("aria-disabled", "true");
|
|
1720
1513
|
}
|
|
1721
1514
|
#openModal() {
|
|
1722
|
-
if (!this.#offer)
|
|
1723
|
-
return;
|
|
1724
|
-
}
|
|
1725
|
-
if (document.querySelector(ApplePayModal.tag)) {
|
|
1726
|
-
return;
|
|
1727
|
-
}
|
|
1515
|
+
if (!this.#offer || document.querySelector(ApplePayModal.tag)) return;
|
|
1728
1516
|
trackExpressWalletClick(this.#offer.sku_id);
|
|
1729
|
-
getPurchaseRecaptchaTokens().then((tokens) => {
|
|
1730
|
-
this.#recaptchaTokens = tokens;
|
|
1731
|
-
}).catch(() => {
|
|
1732
|
-
});
|
|
1733
1517
|
ApplePayModal.define();
|
|
1734
1518
|
const modal = document.createElement(ApplePayModal.tag);
|
|
1735
1519
|
modal.offer = this.#offer;
|
|
@@ -1764,7 +1548,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1764
1548
|
return {
|
|
1765
1549
|
countryCode: country,
|
|
1766
1550
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1767
|
-
supportedNetworks: paymentOptions.
|
|
1551
|
+
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1768
1552
|
totalAmount,
|
|
1769
1553
|
totalLabel: TOTAL_LABEL,
|
|
1770
1554
|
skuId,
|
|
@@ -1773,6 +1557,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1773
1557
|
onPaymentAuthorized: (event, session) => handlePaymentAuthorized(event, session, sessionData, {
|
|
1774
1558
|
skuId,
|
|
1775
1559
|
country,
|
|
1560
|
+
currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1776
1561
|
returnUrl: this.#returnUrl,
|
|
1777
1562
|
queryString: buildQueryString(),
|
|
1778
1563
|
supportedBillingCountries: this.#supportedBillingCountries,
|
|
@@ -1784,7 +1569,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1784
1569
|
try {
|
|
1785
1570
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
1786
1571
|
const paymentOptions = this.#paymentOptions;
|
|
1787
|
-
const recaptchaTokens =
|
|
1572
|
+
const recaptchaTokens = await getPurchaseRecaptchaTokens();
|
|
1788
1573
|
startApplePaySession(
|
|
1789
1574
|
this.#buildSessionParams(
|
|
1790
1575
|
skuId,
|