@economist/web-apple-pay 0.1.2-beta.0 → 0.1.3-beta.1
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 +161 -157
- package/dist/src/apple-pay-button.js +161 -151
- package/dist/src/apple-pay-button.stories.js +161 -158
- package/dist/src/apple-pay-modal.js +1 -9
- package/dist/src/apple-pay-modal.stories.js +161 -151
- package/dist/src/clients/payment-checkout/apple-session.js +40 -67
- 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/payment-handler.js +0 -14
- package/dist/src/clients/payment-checkout/types.d.ts +4 -6
- package/dist/src/index.js +161 -157
- package/dist/src/stories/utils/story-env.js +0 -7
- 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();
|
|
@@ -323,7 +321,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
323
321
|
this.remove();
|
|
324
322
|
return;
|
|
325
323
|
}
|
|
326
|
-
console.log("[web-apple-pay] ApplePayModal: rendering for offer", { skuId: offer.sku_id, country });
|
|
327
324
|
const offerNameElement = this.querySelector(
|
|
328
325
|
"#apple-pay-modal-offer-name"
|
|
329
326
|
);
|
|
@@ -396,14 +393,11 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
396
393
|
});
|
|
397
394
|
}
|
|
398
395
|
cta?.addEventListener("click", () => {
|
|
399
|
-
console.log("[web-apple-pay] ApplePayModal: CTA clicked", { skuId: offer.sku_id, country, isUS });
|
|
400
396
|
if (isUS && checkbox && !checkbox.checked) {
|
|
401
|
-
console.log("[web-apple-pay] ApplePayModal: T&C checkbox not accepted, showing error");
|
|
402
397
|
errorElement?.classList.add("apm__error--visible");
|
|
403
398
|
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
404
399
|
return;
|
|
405
400
|
}
|
|
406
|
-
console.log("[web-apple-pay] ApplePayModal: dispatching apple-pay-confirmed", { skuId: offer.sku_id, country });
|
|
407
401
|
this.dispatchEvent(
|
|
408
402
|
new CustomEvent("apple-pay-confirmed", {
|
|
409
403
|
bubbles: true,
|
|
@@ -411,7 +405,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
411
405
|
detail: { skuId: offer.sku_id, country }
|
|
412
406
|
})
|
|
413
407
|
);
|
|
414
|
-
|
|
408
|
+
this.close();
|
|
415
409
|
});
|
|
416
410
|
this.querySelector("#apple-pay-modal-close")?.addEventListener(
|
|
417
411
|
"click",
|
|
@@ -419,7 +413,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
419
413
|
);
|
|
420
414
|
}
|
|
421
415
|
open() {
|
|
422
|
-
console.log("[web-apple-pay] ApplePayModal: open()");
|
|
423
416
|
this.#triggerElement = document.activeElement;
|
|
424
417
|
document.body.appendChild(this);
|
|
425
418
|
this.#keyHandler = (event) => {
|
|
@@ -434,7 +427,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
434
427
|
this.querySelector("#apple-pay-modal")?.focus();
|
|
435
428
|
}
|
|
436
429
|
close() {
|
|
437
|
-
console.log("[web-apple-pay] ApplePayModal: close()");
|
|
438
430
|
if (this.#keyHandler) {
|
|
439
431
|
document.removeEventListener("keydown", this.#keyHandler, {
|
|
440
432
|
capture: true
|
|
@@ -447,17 +439,95 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
447
439
|
};
|
|
448
440
|
|
|
449
441
|
// src/templates/apple-pay-button.template.html
|
|
450
|
-
var apple_pay_button_template_default =
|
|
442
|
+
var apple_pay_button_template_default = `<style>
|
|
443
|
+
/* Use CSS variables for layout so parent walls can easily override placement and sizing */
|
|
444
|
+
teg-apple-pay-button {
|
|
445
|
+
display: block;
|
|
446
|
+
margin: var(--apple-pay-margin, 0);
|
|
447
|
+
width: 100%;
|
|
448
|
+
height: 100%;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
teg-apple-pay-button .apple-pay-container {
|
|
452
|
+
display: flex;
|
|
453
|
+
flex-direction: column;
|
|
454
|
+
align-items: stretch;
|
|
455
|
+
width: 100%;
|
|
456
|
+
height: 100%;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
teg-apple-pay-button .apple-pay-btn {
|
|
460
|
+
display: flex;
|
|
461
|
+
align-items: center;
|
|
462
|
+
justify-content: center;
|
|
463
|
+
gap: 0.375rem;
|
|
464
|
+
width: 100%;
|
|
465
|
+
min-width: 0;
|
|
466
|
+
height: 100%;
|
|
467
|
+
min-height: var(--apple-pay-height, 2.75rem);
|
|
468
|
+
background-color: #000;
|
|
469
|
+
color: #fff;
|
|
470
|
+
border: none;
|
|
471
|
+
border-radius: var(--apple-pay-border-radius, 1.375rem);
|
|
472
|
+
cursor: pointer;
|
|
473
|
+
font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
|
|
474
|
+
font-size: 1.0625rem;
|
|
475
|
+
font-weight: 500;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
teg-apple-pay-button .apple-pay-btn svg {
|
|
479
|
+
flex-shrink: 0;
|
|
480
|
+
display: block;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading {
|
|
484
|
+
position: relative;
|
|
485
|
+
cursor: default;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading svg {
|
|
489
|
+
visibility: hidden;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
teg-apple-pay-button .apple-pay-btn.wap-loading::after {
|
|
493
|
+
content: '';
|
|
494
|
+
position: absolute;
|
|
495
|
+
left: 50%;
|
|
496
|
+
top: 50%;
|
|
497
|
+
margin-left: -0.625rem;
|
|
498
|
+
margin-top: -0.625rem;
|
|
499
|
+
width: 1.25rem;
|
|
500
|
+
height: 1.25rem;
|
|
501
|
+
border: 2px solid rgba(255, 255, 255, 0.2);
|
|
502
|
+
border-top-color: #fff;
|
|
503
|
+
border-radius: 50%;
|
|
504
|
+
animation: wap-button-spinner 0.8s linear infinite;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
@keyframes wap-button-spinner {
|
|
508
|
+
to {
|
|
509
|
+
transform: rotate(360deg);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
</style>
|
|
513
|
+
|
|
514
|
+
<div class="apple-pay-container" aria-label="Express checkout with Apple Pay">
|
|
515
|
+
<button
|
|
516
|
+
class="apple-pay-btn"
|
|
517
|
+
type="button"
|
|
518
|
+
aria-label="Pay with Apple Pay"
|
|
519
|
+
data-analytics="paywall:apple-pay-checkout"
|
|
520
|
+
>
|
|
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
|
+
`;
|
|
451
527
|
|
|
452
528
|
// src/clients/payment-checkout/config.ts
|
|
453
529
|
var runtimeConfig = null;
|
|
454
530
|
var configureApplePay = (config) => {
|
|
455
|
-
console.log("[web-apple-pay] configureApplePay called", {
|
|
456
|
-
merchantId: config.merchantId,
|
|
457
|
-
walletApiBaseUrl: config.walletApiBaseUrl,
|
|
458
|
-
debugBypassEnabled: config.debugBypassEnabled,
|
|
459
|
-
recaptchaSiteKey: config.recaptchaSiteKey ? "***" : void 0
|
|
460
|
-
});
|
|
461
531
|
runtimeConfig = {
|
|
462
532
|
...config
|
|
463
533
|
};
|
|
@@ -472,27 +542,21 @@ var isAppleDeviceOrSafari = () => {
|
|
|
472
542
|
};
|
|
473
543
|
var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
|
|
474
544
|
var isApplePayAvailable = async () => {
|
|
475
|
-
console.log("[web-apple-pay] isApplePayAvailable: checking availability");
|
|
476
545
|
if (bypassApplePayChecks()) {
|
|
477
|
-
console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
|
|
478
546
|
return true;
|
|
479
547
|
}
|
|
480
548
|
if (!isAppleDeviceOrSafari()) {
|
|
481
|
-
console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
|
|
482
549
|
return false;
|
|
483
550
|
}
|
|
484
551
|
const applePaySession = window.ApplePaySession;
|
|
485
552
|
if (!applePaySession) {
|
|
486
|
-
console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
|
|
487
553
|
return false;
|
|
488
554
|
}
|
|
489
555
|
try {
|
|
490
556
|
if (typeof applePaySession.canMakePayments !== "function") {
|
|
491
|
-
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
|
|
492
557
|
return false;
|
|
493
558
|
}
|
|
494
559
|
if (!applePaySession.canMakePayments()) {
|
|
495
|
-
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
|
|
496
560
|
return false;
|
|
497
561
|
}
|
|
498
562
|
const merchantId = getApplePayConfig()?.merchantId;
|
|
@@ -502,10 +566,7 @@ var isApplePayAvailable = async () => {
|
|
|
502
566
|
);
|
|
503
567
|
return false;
|
|
504
568
|
}
|
|
505
|
-
|
|
506
|
-
const result = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
507
|
-
console.log("[web-apple-pay] isApplePayAvailable: canMakePaymentsWithActiveCard \u2192", result);
|
|
508
|
-
return result;
|
|
569
|
+
return await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
509
570
|
} catch (error) {
|
|
510
571
|
console.error("Error checking Apple Pay active card status:", error);
|
|
511
572
|
return false;
|
|
@@ -767,13 +828,6 @@ var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
|
767
828
|
|
|
768
829
|
// src/clients/payment-checkout/apple-session.ts
|
|
769
830
|
function startApplePaySession(config) {
|
|
770
|
-
console.log("[web-apple-pay] startApplePaySession", {
|
|
771
|
-
skuId: config.skuId,
|
|
772
|
-
countryCode: config.countryCode,
|
|
773
|
-
currencyCode: config.currencyCode,
|
|
774
|
-
totalAmount: config.totalAmount,
|
|
775
|
-
userLoggedIn: config.userLoggedIn
|
|
776
|
-
});
|
|
777
831
|
const paymentRequest = {
|
|
778
832
|
countryCode: config.countryCode,
|
|
779
833
|
currencyCode: config.currencyCode,
|
|
@@ -787,45 +841,26 @@ function startApplePaySession(config) {
|
|
|
787
841
|
// Only request email from Apple Pay sheet if user is NOT logged in
|
|
788
842
|
...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
|
|
789
843
|
};
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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
|
|
844
|
+
const session = new ApplePaySession(3, paymentRequest);
|
|
845
|
+
session.onvalidatemerchant = async (event) => {
|
|
846
|
+
try {
|
|
847
|
+
const validationHost = new URL(event.validationURL).host;
|
|
848
|
+
if (!validationHost.endsWith("apple.com")) {
|
|
849
|
+
trackFallbackCheckout(config.skuId);
|
|
850
|
+
session.abort();
|
|
851
|
+
window.location.href = redirectToCheckoutFallback({
|
|
852
|
+
skuId: config.skuId,
|
|
853
|
+
returnUrl: config.returnUrl,
|
|
854
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
813
855
|
});
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
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);
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
859
|
+
const response = await validateAppleMerchant({
|
|
860
|
+
validationURL: event.validationURL,
|
|
861
|
+
recaptchaToken
|
|
862
|
+
});
|
|
863
|
+
if (!response?.merchantSession) {
|
|
829
864
|
trackFallbackCheckout(config.skuId);
|
|
830
865
|
session.abort();
|
|
831
866
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -833,29 +868,28 @@ function startApplePaySession(config) {
|
|
|
833
868
|
returnUrl: config.returnUrl,
|
|
834
869
|
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
835
870
|
});
|
|
871
|
+
return;
|
|
836
872
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
});
|
|
858
|
-
}
|
|
873
|
+
session.completeMerchantValidation(response.merchantSession);
|
|
874
|
+
} catch {
|
|
875
|
+
trackFallbackCheckout(config.skuId);
|
|
876
|
+
session.abort();
|
|
877
|
+
window.location.href = redirectToCheckoutFallback({
|
|
878
|
+
skuId: config.skuId,
|
|
879
|
+
returnUrl: config.returnUrl,
|
|
880
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
session.onpaymentauthorized = (event) => {
|
|
885
|
+
trackWalletPaymentAuthorised(config.skuId);
|
|
886
|
+
config.onPaymentAuthorized(event, session);
|
|
887
|
+
};
|
|
888
|
+
session.oncancel = () => {
|
|
889
|
+
config.onCancel?.();
|
|
890
|
+
};
|
|
891
|
+
trackWalletPaymentSheetOpen(config.skuId);
|
|
892
|
+
session.begin();
|
|
859
893
|
}
|
|
860
894
|
|
|
861
895
|
// src/clients/payment-checkout/contact-validation.ts
|
|
@@ -1032,16 +1066,12 @@ function handleStructuredError(ctx) {
|
|
|
1032
1066
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
1033
1067
|
const { skuId, returnUrl, queryString } = config;
|
|
1034
1068
|
let validatedEmail;
|
|
1035
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
|
|
1036
1069
|
try {
|
|
1037
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
|
|
1038
1070
|
validatedEmail = validateContacts(
|
|
1039
1071
|
event,
|
|
1040
1072
|
sessionData,
|
|
1041
1073
|
config.supportedBillingCountries
|
|
1042
1074
|
);
|
|
1043
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: contacts valid", { validatedEmail });
|
|
1044
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
|
|
1045
1075
|
const result = await performPurchase({
|
|
1046
1076
|
applePayToken: event.payment.token,
|
|
1047
1077
|
skuId: config.skuId,
|
|
@@ -1051,8 +1081,6 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1051
1081
|
},
|
|
1052
1082
|
recaptchaTokens: config.recaptchaTokens
|
|
1053
1083
|
});
|
|
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
1084
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1057
1085
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1058
1086
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
@@ -1065,25 +1093,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1065
1093
|
});
|
|
1066
1094
|
} catch (err) {
|
|
1067
1095
|
if (err instanceof ContactValidationError) {
|
|
1068
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
|
|
1069
1096
|
failApplePaySession(session, err.errors);
|
|
1070
1097
|
return;
|
|
1071
1098
|
}
|
|
1072
1099
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1073
1100
|
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
1101
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1080
1102
|
failApplePaySession(session);
|
|
1081
1103
|
if (!walletError) {
|
|
1082
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
|
|
1083
1104
|
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1084
1105
|
return;
|
|
1085
1106
|
}
|
|
1086
|
-
console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
|
|
1087
1107
|
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1088
1108
|
}
|
|
1089
1109
|
}
|
|
@@ -1370,19 +1390,11 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1370
1390
|
* Creates and configures an ApplePayButton if the feature flag is present.
|
|
1371
1391
|
*/
|
|
1372
1392
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1373
|
-
if (!offer)
|
|
1374
|
-
|
|
1393
|
+
if (!offer) return null;
|
|
1394
|
+
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
|
|
1375
1395
|
return null;
|
|
1376
|
-
|
|
1377
|
-
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1378
|
-
console.log("[web-apple-pay] createIfEnabled: excluded variant \u2192 null", { variant: offer.product?.variant });
|
|
1396
|
+
if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT))
|
|
1379
1397
|
return null;
|
|
1380
|
-
}
|
|
1381
|
-
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
|
-
return null;
|
|
1384
|
-
}
|
|
1385
|
-
console.log("[web-apple-pay] createIfEnabled: creating button", { skuId: offer.sku_id, country, entryPoint });
|
|
1386
1398
|
_ApplePayButton.define();
|
|
1387
1399
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1388
1400
|
button.offer = offer;
|
|
@@ -1450,9 +1462,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1450
1462
|
}
|
|
1451
1463
|
// ─── Lifecycle ──────────────────────────────────────────────────────────────
|
|
1452
1464
|
async connectedCallback() {
|
|
1453
|
-
console.log("[web-apple-pay] connectedCallback: element connected");
|
|
1454
1465
|
if (this.#rendering || this.querySelector(SEL_CONTAINER)) {
|
|
1455
|
-
console.log("[web-apple-pay] connectedCallback: already rendering or rendered, skipping");
|
|
1456
1466
|
return;
|
|
1457
1467
|
}
|
|
1458
1468
|
this.#rendering = true;
|
|
@@ -1479,17 +1489,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1479
1489
|
}
|
|
1480
1490
|
// ─── Render pipeline ────────────────────────────────────────────────────────
|
|
1481
1491
|
async #run() {
|
|
1482
|
-
console.log("[web-apple-pay] #run: starting render pipeline");
|
|
1483
1492
|
try {
|
|
1484
1493
|
if (await this.#checkAvailability()) return;
|
|
1485
|
-
if (await this.#checkSession()) return;
|
|
1486
1494
|
if (this.#checkOffer()) return;
|
|
1495
|
+
this.#renderTemplate();
|
|
1496
|
+
if (await this.#checkSession()) return;
|
|
1487
1497
|
this.#captureReturnUrl();
|
|
1488
1498
|
this.#computeBillingCountries();
|
|
1489
1499
|
if (await this.#fetchAndCacheOptions()) return;
|
|
1490
|
-
this.#
|
|
1500
|
+
this.#finishLoading();
|
|
1491
1501
|
} catch {
|
|
1492
1502
|
this.style.display = "none";
|
|
1503
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1493
1504
|
} finally {
|
|
1494
1505
|
this.#rendering = false;
|
|
1495
1506
|
}
|
|
@@ -1498,11 +1509,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1498
1509
|
async #checkAvailability() {
|
|
1499
1510
|
const available = await isApplePayAvailable();
|
|
1500
1511
|
if (!available) {
|
|
1501
|
-
console.log("[web-apple-pay] #checkAvailability: Apple Pay unavailable \u2192 hiding");
|
|
1502
1512
|
this.style.display = "none";
|
|
1503
1513
|
return true;
|
|
1504
1514
|
}
|
|
1505
|
-
console.log("[web-apple-pay] #checkAvailability: Apple Pay available");
|
|
1506
1515
|
return false;
|
|
1507
1516
|
}
|
|
1508
1517
|
/**
|
|
@@ -1511,10 +1520,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1511
1520
|
*/
|
|
1512
1521
|
async #checkSession() {
|
|
1513
1522
|
this.#sessionData = await this.#fetchSession();
|
|
1514
|
-
console.log("[web-apple-pay] #checkSession: session fetched", { loggedIn: this.#sessionData?.loggedIn, userType: this.#sessionData?.userType });
|
|
1515
1523
|
if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
|
|
1516
|
-
console.log("[web-apple-pay] #checkSession: ineligible user \u2192 hiding", { userType: this.#sessionData.userType });
|
|
1517
1524
|
this.style.display = "none";
|
|
1525
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1518
1526
|
return true;
|
|
1519
1527
|
}
|
|
1520
1528
|
return false;
|
|
@@ -1522,17 +1530,14 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1522
1530
|
/** Returns `true` (hide) when no offer has been set before mount. */
|
|
1523
1531
|
#checkOffer() {
|
|
1524
1532
|
if (!this.#offer) {
|
|
1525
|
-
console.log("[web-apple-pay] #checkOffer: no offer set \u2192 hiding");
|
|
1526
1533
|
this.style.display = "none";
|
|
1527
1534
|
return true;
|
|
1528
1535
|
}
|
|
1529
|
-
console.log("[web-apple-pay] #checkOffer: offer present", { skuId: this.#offer.sku_id });
|
|
1530
1536
|
return false;
|
|
1531
1537
|
}
|
|
1532
1538
|
/** Captures the current page URL once at mount for reuse across the session lifetime. */
|
|
1533
1539
|
#captureReturnUrl() {
|
|
1534
1540
|
this.#returnUrl = captureOriginUrl();
|
|
1535
|
-
console.log("[web-apple-pay] #captureReturnUrl:", this.#returnUrl);
|
|
1536
1541
|
}
|
|
1537
1542
|
/**
|
|
1538
1543
|
* Computes supported billing countries once at mount.
|
|
@@ -1544,7 +1549,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1544
1549
|
this.#country,
|
|
1545
1550
|
this.#offer.product?.variant ?? ""
|
|
1546
1551
|
);
|
|
1547
|
-
console.log("[web-apple-pay] #computeBillingCountries:", this.#supportedBillingCountries);
|
|
1548
1552
|
}
|
|
1549
1553
|
/**
|
|
1550
1554
|
* Returns `true` (hide) when the wallet BFF reports Apple Pay is unavailable
|
|
@@ -1552,36 +1556,44 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1552
1556
|
*/
|
|
1553
1557
|
async #fetchAndCacheOptions() {
|
|
1554
1558
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1555
|
-
|
|
1556
|
-
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
1557
|
-
console.log("[web-apple-pay] #fetchAndCacheOptions: apple_pay not in options \u2192 hiding");
|
|
1559
|
+
if (!this.#paymentOptions?.apple_pay) {
|
|
1558
1560
|
this.style.display = "none";
|
|
1561
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1559
1562
|
return true;
|
|
1560
1563
|
}
|
|
1561
1564
|
return false;
|
|
1562
1565
|
}
|
|
1563
1566
|
/** Injects the button template and wires click and confirm event listeners. */
|
|
1564
1567
|
#renderTemplate() {
|
|
1565
|
-
console.log("[web-apple-pay] #renderTemplate: rendering Apple Pay button", { skuId: this.#offer?.sku_id, country: this.#country });
|
|
1566
1568
|
this.style.removeProperty("display");
|
|
1567
1569
|
ensureApplePayLogoSymbol();
|
|
1568
1570
|
const template = document.createElement("template");
|
|
1569
1571
|
template.innerHTML = apple_pay_button_template_default;
|
|
1570
1572
|
this.appendChild(template.content.cloneNode(true));
|
|
1571
|
-
this.#updateDisabledState();
|
|
1572
|
-
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
1573
|
-
entryPoint: this.#entryPoint,
|
|
1574
|
-
country: this.#country
|
|
1575
|
-
});
|
|
1576
1573
|
const button = this.querySelector(SEL_BUTTON);
|
|
1574
|
+
button.classList.add("wap-loading");
|
|
1575
|
+
button.setAttribute("disabled", "");
|
|
1576
|
+
button.setAttribute("aria-disabled", "true");
|
|
1577
|
+
button.setAttribute("aria-busy", "true");
|
|
1577
1578
|
button.addEventListener("click", () => {
|
|
1579
|
+
if (button.classList.contains("wap-loading")) return;
|
|
1578
1580
|
this.#openModal();
|
|
1579
1581
|
});
|
|
1580
|
-
|
|
1582
|
+
this.addEventListener("apple-pay-confirmed", (event) => {
|
|
1581
1583
|
const { skuId, country } = event.detail;
|
|
1582
|
-
console.log("[web-apple-pay] apple-pay-confirmed received on document", { skuId, country });
|
|
1583
1584
|
this.#initiateApplePay(skuId, country);
|
|
1584
|
-
}
|
|
1585
|
+
});
|
|
1586
|
+
}
|
|
1587
|
+
#finishLoading() {
|
|
1588
|
+
const button = this.querySelector(SEL_BUTTON);
|
|
1589
|
+
if (button) {
|
|
1590
|
+
button.classList.remove("wap-loading");
|
|
1591
|
+
this.#updateDisabledState();
|
|
1592
|
+
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
1593
|
+
entryPoint: this.#entryPoint,
|
|
1594
|
+
country: this.#country
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1585
1597
|
}
|
|
1586
1598
|
// ─── Private helpers ────────────────────────────────────────────────────────
|
|
1587
1599
|
#updateDisabledState() {
|
|
@@ -1590,13 +1602,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1590
1602
|
if (this.#offer) {
|
|
1591
1603
|
button.removeAttribute("disabled");
|
|
1592
1604
|
button.removeAttribute("aria-disabled");
|
|
1605
|
+
button.removeAttribute("aria-busy");
|
|
1593
1606
|
return;
|
|
1594
1607
|
}
|
|
1595
1608
|
button.setAttribute("disabled", "");
|
|
1596
1609
|
button.setAttribute("aria-disabled", "true");
|
|
1597
1610
|
}
|
|
1598
1611
|
#openModal() {
|
|
1599
|
-
console.log("[web-apple-pay] #openModal: button clicked", { skuId: this.#offer?.sku_id });
|
|
1600
1612
|
if (!this.#offer || document.querySelector(ApplePayModal.tag)) return;
|
|
1601
1613
|
trackExpressWalletClick(this.#offer.sku_id);
|
|
1602
1614
|
ApplePayModal.define();
|
|
@@ -1610,37 +1622,30 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1610
1622
|
}
|
|
1611
1623
|
async #fetchSession() {
|
|
1612
1624
|
try {
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
return session;
|
|
1616
|
-
} catch (err) {
|
|
1617
|
-
console.warn("[web-apple-pay] #fetchSession: failed, falling back to anonymous session", err);
|
|
1625
|
+
return await getExpressCheckoutSession();
|
|
1626
|
+
} catch {
|
|
1618
1627
|
return null;
|
|
1619
1628
|
}
|
|
1620
1629
|
}
|
|
1621
1630
|
async #fetchPaymentOptions() {
|
|
1622
1631
|
try {
|
|
1623
|
-
|
|
1632
|
+
return await getPaymentOptions({
|
|
1624
1633
|
sku: this.#offer.sku_id,
|
|
1625
1634
|
countryCode: this.#country,
|
|
1626
1635
|
currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1627
1636
|
checkoutUrl: this.#returnUrl
|
|
1628
1637
|
});
|
|
1629
|
-
|
|
1630
|
-
return options;
|
|
1631
|
-
} catch (err) {
|
|
1632
|
-
console.warn("[web-apple-pay] #fetchPaymentOptions: failed", err);
|
|
1638
|
+
} catch {
|
|
1633
1639
|
return null;
|
|
1634
1640
|
}
|
|
1635
1641
|
}
|
|
1636
1642
|
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokens) {
|
|
1637
|
-
console.log("[web-apple-pay] #buildSessionParams", { skuId, country, userLoggedIn: sessionData.loggedIn });
|
|
1638
1643
|
const offer = this.#offer;
|
|
1639
1644
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
1640
1645
|
return {
|
|
1641
1646
|
countryCode: country,
|
|
1642
1647
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1643
|
-
supportedNetworks: paymentOptions.
|
|
1648
|
+
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1644
1649
|
totalAmount,
|
|
1645
1650
|
totalLabel: TOTAL_LABEL,
|
|
1646
1651
|
skuId,
|
|
@@ -1657,7 +1662,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1657
1662
|
};
|
|
1658
1663
|
}
|
|
1659
1664
|
async #initiateApplePay(skuId, country) {
|
|
1660
|
-
console.log("[web-apple-pay] #initiateApplePay: starting", { skuId, country });
|
|
1661
1665
|
try {
|
|
1662
1666
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
1663
1667
|
const paymentOptions = this.#paymentOptions;
|