PageSourceSearch

https://www.letsroam.com/assets/js/store/source/quickPay.js

js letsroam.com collected 2026-09-24 09:24:58 UTC 66,641 bytes, 2,100 lines download raw bytes

1// These helpers stay dependency-free so the payment timing and amount contract
2// can be executed directly in Playwright without opening a real wallet.
3function calculateQuickPayTotalMinorUnits(
4  cartBaseTotal,
5  processingFee,
6  shippingFeeMinorUnits,
7  usesZeroDecimalMinorUnits,
8  displayedCartTotal
9) {
10  var minorUnitMultiplier = usesZeroDecimalMinorUnits ? 1 : 100;
11  var approvedCartTotal = Number.isFinite(displayedCartTotal)
12    ? displayedCartTotal
13    : Number(cartBaseTotal || 0);
14  var calculatedAmount =
15    Math.round(
16      (approvedCartTotal + Number(processingFee || 0)) *
17        minorUnitMultiplier
18    ) + Math.round(Number(shippingFeeMinorUnits || 0));
19
20  // The preferred DOM total contains promotions already shown to the customer.
21  // Shipping is selected inside the wallet sheet, so compose it on top.
22  return calculatedAmount;
23}
24
25function getQuickPayDisplayedCartTotal(documentRoot) {
26  if (!documentRoot || typeof documentRoot.querySelector != 'function') {
27    return null;
28  }
29
30  var displayedCartTotalElement =
31    documentRoot.querySelector('.quick_pay_approved_total') ||
32    documentRoot.querySelector('.quick_pay_current_total') ||
33    documentRoot.querySelector('.cart_total_price');
34  if (!displayedCartTotalElement || !displayedCartTotalElement.innerText) {
35    return null;
36  }
37
38  var displayedCartTotal = parseFloat(
39    displayedCartTotalElement.innerText.replace(/[^\d.]/g, '')
40  );
41  return Number.isFinite(displayedCartTotal) ? displayedCartTotal : null;
42}
43
44function getQuickPayInputValue(documentRoot, selector) {
45  if (!documentRoot || typeof documentRoot.querySelector != 'function') {
46    return '';
47  }
48
49  var input = documentRoot.querySelector(selector);
50  return input && typeof input.value != 'undefined' ? input.value : '';
51}
52
53function getQuickPayDigitalProductLabel(
54  cartData,
55  bundleLookup,
56  textTranslator
57) {
58  var translate =
59    typeof textTranslator == 'function'
60      ? textTranslator
61      : function (text) {
62          return text;
63        };
64  var ticketQuantity = 0;
65  var annualPassQuantity = 0;
66
67  if (cartData && Array.isArray(cartData.items)) {
68    cartData.items.forEach(function (cartItem) {
69      var quantity = Math.max(1, Number(cartItem.quantity || 1));
70      var bundle =
71        typeof bundleLookup == 'function'
72          ? bundleLookup(cartItem.bundleId || 1) || {}
73          : {};
74
75      var hasAnnualPass =
76        Number(
77          cartItem.season_pass_length_override ||
78            bundle.season_pass_length ||
79            0
80        ) > 0 ||
81        Number(
82          cartItem.season_pass_players_override ||
83            bundle.season_pass_tickets ||
84            0
85        ) > 0;
86
87      if (hasAnnualPass) {
88        annualPassQuantity += quantity;
89      } else {
90        ticketQuantity += quantity;
91      }
92    });
93  }
94
95  var quantityParts = [];
96  if (ticketQuantity > 0) {
97    quantityParts.push(
98      ticketQuantity +
99        ' ' +
100        translate(
101          ticketQuantity == 1
102            ? 'Scavenger Hunt Ticket'
103            : 'Scavenger Hunt Tickets'
104        )
105    );
106  }
107  if (annualPassQuantity > 0) {
108    quantityParts.push(
109      annualPassQuantity +
110        ' ' +
111        translate(annualPassQuantity == 1 ? 'Annual Pass' : 'Annual Passes')
112    );
113  }
114
115  var deliveryLabel = translate('Instant delivery - Digital Product');
116  return quantityParts.length
117    ? deliveryLabel + ': ' + quantityParts.join(' + ') + '.'
118    : deliveryLabel + '.';
119}
120
121function getQuickPayAvailablePaymentMethods(
122  canMakePaymentRequest,
123  shouldForceLink
124) {
125  // forceLink is an explicit end-to-end automation mode. Stripe can briefly
126  // return null for a fresh CI browser even though Link opens and completes a
127  // real test purchase. Keep shopper capability checks unchanged, but make
128  // the requested test wallet deterministic.
129  if (shouldForceLink) {
130    return { link: true };
131  }
132
133  return canMakePaymentRequest || null;
134}
135
136async function submitQuickPayCheckout(
137  checkoutUrl,
138  formData,
139  requestFunction,
140  completeFunction,
141  retryOptions
142) {
143  retryOptions = retryOptions || {};
144  var maxRequestAttempts = retryOptions.maxRequestAttempts || 8;
145  var retryDelayMilliseconds = retryOptions.retryDelayMilliseconds || 300;
146  var delayFunction =
147    retryOptions.delayFunction ||
148    function (delayMilliseconds) {
149      return new Promise(function (resolve) {
150        setTimeout(resolve, delayMilliseconds);
151      });
152    };
153  var lastRequestError = null;
154  for (
155    var requestAttempt = 0;
156    requestAttempt < maxRequestAttempts;
157    requestAttempt++
158  ) {
159    try {
160      var formattedResponse = await requestFunction(checkoutUrl, formData);
161      var responseError = formattedResponse && formattedResponse.error;
162      var responseErrorCode =
163        responseError && typeof responseError == 'object'
164          ? responseError.code
165          : null;
166      var looksLikeNetworkFailure =
167        formattedResponse &&
168        formattedResponse.status === false &&
169        typeof formattedResponse.error == 'string';
170      var checkoutIsStillProcessing =
171        responseErrorCode === 'quick_pay_checkout_in_progress';
172      var responseIsRetryable =
173        responseError &&
174        typeof responseError == 'object' &&
175        responseError.retryable === true;
176      if (
177        looksLikeNetworkFailure ||
178        checkoutIsStillProcessing ||
179        responseIsRetryable
180      ) {
181        lastRequestError = responseError || new Error('Network error occurred.');
182        if (requestAttempt + 1 < maxRequestAttempts) {
183          await delayFunction(retryDelayMilliseconds);
184          continue;
185        }
186        break;
187      }
188
189      if (!formattedResponse) {
190        lastRequestError = new Error('Quickpay checkout returned no response.');
191        if (requestAttempt + 1 < maxRequestAttempts) {
192          await delayFunction(retryDelayMilliseconds);
193          continue;
194        }
195        continue;
196      }
197
198      completeFunction(
199        formattedResponse && formattedResponse.status === true
200          ? 'success'
201          : 'fail'
202      );
203      return formattedResponse;
204    } catch (paymentRequestError) {
205      lastRequestError = paymentRequestError;
206      if (requestAttempt + 1 < maxRequestAttempts) {
207        await delayFunction(retryDelayMilliseconds);
208        continue;
209      }
210    }
211  }
212
213  // Stripe's wallet API has no indeterminate completion state. Closing the
214  // sheet as submitted prevents a second authorization while the original
215  // same-attempt request may still finish and charge.
216  completeFunction('success');
217  return {
218    status: false,
219    result: null,
220    error: {
221      code: 'quick_pay_checkout_status_unknown',
222      message: 'Quickpay checkout could not be confirmed.',
223      retryable: false,
224      cause: lastRequestError,
225    },
226  };
227}
228
229function createQuickPayCheckoutAttemptId() {
230  if (
231    typeof crypto != 'undefined' &&
232    typeof crypto.randomUUID == 'function'
233  ) {
234    return crypto.randomUUID();
235  }
236
237  return (
238    'quickpay_' +
239    Date.now().toString(36) +
240    '_' +
241    Math.random().toString(36).slice(2) +
242    Math.random().toString(36).slice(2)
243  );
244}
245
246function normalizeQuickPayDebugWalletName(walletName) {
247  var normalizedWalletName = String(walletName || '')
248    .replace(/[^a-z]/gi, '')
249    .toLowerCase();
250
251  if (normalizedWalletName == 'applepay') {
252    return 'apple_pay';
253  }
254  if (normalizedWalletName == 'googlepay' || normalizedWalletName == 'gpay') {
255    return 'google_pay';
256  }
257  if (normalizedWalletName == 'link') {
258    return 'link';
259  }
260  return 'unknown';
261}
262
263function redactQuickPayDebugText(value) {
264  return String(value || '')
265    .replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, '[redacted_email]')
266    .replace(
267      /(^|[^A-Za-z0-9])(?:tok|pm|src|pi|seti|cus|ch)_[A-Za-z0-9_-]+/gi,
268      '$1[redacted_payment_id]'
269    );
270}
271
272function getQuickPayDebugErrorDetails(paymentError) {
273  var errorDetails = {
274    name: '',
275    code: '',
276    message: '',
277  };
278  if (!paymentError) {
279    return errorDetails;
280  }
281
282  if (typeof paymentError == 'string') {
283    errorDetails.message = redactQuickPayDebugText(paymentError).slice(0, 300);
284    return errorDetails;
285  }
286
287  errorDetails.name = redactQuickPayDebugText(paymentError.name)
288    .replace(/[^A-Za-z0-9_.:-]/g, '')
289    .slice(0, 80);
290  errorDetails.code = redactQuickPayDebugText(
291    paymentError.code || paymentError.type
292  )
293    .replace(/[^A-Za-z0-9_.:-]/g, '')
294    .slice(0, 100);
295  errorDetails.message = redactQuickPayDebugText(paymentError.message)
296    .slice(0, 300);
297  return errorDetails;
298}
299
300function quickPayCheckoutSupportsRecovery(checkoutUrl) {
301  // Corporate Quickpay has its own transaction flow and does not yet share the
302  // store checkout's attempt lock/idempotency contract.
303  return checkoutUrl !== '/api/payment/do_corporate_transaction';
304}
305
306function quickPayUsesCorporateCheckout(documentRoot, hasEventUuid) {
307  return !!(
308    hasEventUuid ||
309    (documentRoot &&
310      typeof documentRoot.querySelector == 'function' &&
311      documentRoot.querySelector('.eventQuickPayButton'))
312  );
313}
314
315function quickPayRequiresCurrencyQuote(isCorporateCheckout) {
316  return !isCorporateCheckout;
317}
318
319function quickPayHasCheckoutControls(documentRoot) {
320  return !!(
321    documentRoot &&
322    typeof documentRoot.querySelector == 'function' &&
323    documentRoot.querySelector(
324      '.quickPayButton, .eventQuickPayButton, #payment-request-button, [data-test-id="link-pay-btn"], [onclick*="paymentRequest.show"]'
325    )
326  );
327}
328
329function quickPayCartHasItems(cartData) {
330  return !!(
331    cartData &&
332    Array.isArray(cartData.items) &&
333    cartData.items.length
334  );
335}
336
337function quickPayCurrencyQuoteExpiresAt(currencyQuoteToken) {
338  var tokenParts = String(currencyQuoteToken || '').split(':');
339  if (
340    tokenParts.length !== 3 ||
341    tokenParts[0] !== 'v1' ||
342    !/^\d+$/.test(tokenParts[1]) ||
343    !/^[a-f0-9]{64}$/.test(tokenParts[2])
344  ) {
345    return 0;
346  }
347
348  return parseInt(tokenParts[1], 10);
349}
350
351function quickPayCurrencyQuoteIsUsable(
352  currencyQuoteToken,
353  nowSeconds,
354  minimumValiditySeconds
355) {
356  var expiresAt = quickPayCurrencyQuoteExpiresAt(currencyQuoteToken);
357  nowSeconds = Number.isFinite(nowSeconds)
358    ? nowSeconds
359    : Math.floor(Date.now() / 1000);
360  minimumValiditySeconds = Number.isFinite(minimumValiditySeconds)
361    ? Math.max(0, minimumValiditySeconds)
362    : 120;
363  return expiresAt > nowSeconds + minimumValiditySeconds;
364}
365
366var quickPayCurrencyQuoteRefreshPromise = null;
367var quickPayCurrencyQuoteRefreshTimer = null;
368var quickPayCurrencyQuotePageShowBound = false;
369
370function applyQuickPayCurrencyQuoteRefresh(responseData) {
371  var refreshedToken = responseData.currency_quote_token || '';
372  var refreshedRates = responseData.currency_rates || {};
373  var activeCurrency = String(
374    typeof cy != 'undefined' && cy ? cy : 'usd'
375  ).toLowerCase();
376  var activeRate = Number(refreshedRates[activeCurrency]);
377  if (!quickPayCurrencyQuoteIsUsable(refreshedToken)) {
378    throw new Error('Quickpay currency quote refresh was invalid.');
379  }
380  if (!Number.isFinite(activeRate) || activeRate <= 0) {
381    throw new Error('Quickpay currency rate refresh was invalid.');
382  }
383
384  Object.keys(refreshedRates).forEach(function (currencyCode) {
385    var refreshedRate = Number(refreshedRates[currencyCode]);
386    if (
387      !Number.isFinite(refreshedRate) ||
388      refreshedRate <= 0 ||
389      !currencies[currencyCode]
390    ) {
391      return;
392    }
393    currencies[currencyCode].currency_to_usd = refreshedRates[currencyCode];
394  });
395  if (Array.isArray(currenciesArray)) {
396    currenciesArray.forEach(function (currencyDefinition) {
397      var currencyCode = String(currencyDefinition.code || '').toLowerCase();
398      if (currencies[currencyCode]) {
399        currencyDefinition.currency_to_usd =
400          currencies[currencyCode].currency_to_usd;
401      }
402    });
403  }
404  checkoutCurrencyQuoteToken = refreshedToken;
405  return refreshedToken;
406}
407
408function refreshQuickPayCurrencyQuoteToken() {
409  if (quickPayCurrencyQuoteRefreshPromise) {
410    return quickPayCurrencyQuoteRefreshPromise;
411  }
412
413  quickPayCurrencyQuoteRefreshPromise = window
414    .fetch(
415      '/store/api/checkout/currency-quote?currency=' +
416        encodeURIComponent(
417          String(typeof cy != 'undefined' && cy ? cy : 'usd').toLowerCase()
418        ),
419      { credentials: 'same-origin', cache: 'no-store' }
420    )
421    .then(function (response) {
422      if (!response.ok) {
423        throw new Error('Quickpay currency quote refresh failed.');
424      }
425      return response.json();
426    })
427    .then(function (responseData) {
428      var refreshedToken = applyQuickPayCurrencyQuoteRefresh(responseData);
429      if (typeof updateCurrencies == 'function') {
430        updateCurrencies(cy);
431      }
432      armQuickPayCurrencyQuoteExpiration(refreshedToken);
433      if (typeof CartViewRender == 'function') {
434        CartViewRender();
435      }
435 else if (typeof updateQuickPay == 'function') {
436        updateQuickPay();
437      }
438      return refreshedToken;
439    })
440    .finally(function () {
441      quickPayCurrencyQuoteRefreshPromise = null;
442    });
443
444  return quickPayCurrencyQuoteRefreshPromise;
445}
446
447var quickPayPaymentRequestActive = false;
448
449function acquireQuickPayPaymentRequest() {
450  if (quickPayPaymentRequestActive) {
451    return false;
452  }
453
454  quickPayPaymentRequestActive = true;
455  return true;
456}
457
458function releaseQuickPayPaymentRequest() {
459  quickPayPaymentRequestActive = false;
460}
461
462function showQuickPayPaymentRequest() {
463  if (quickPayPaymentRequestActive) {
464    return null;
465  }
466
467  beginQuickPayDebugWalletInteraction();
468  recordQuickPayDebugStage('wallet_show_requested');
469  var isCorporateCheckout = quickPayUsesCorporateCheckout(
470    document,
471    typeof eventUUID != 'undefined'
472  );
473  if (
474    quickPayRequiresCurrencyQuote(isCorporateCheckout) &&
475    !quickPayCurrencyQuoteIsUsable(checkoutCurrencyQuoteToken)
476  ) {
477    var currencyQuoteError = new Error('Quickpay currency quote expired.');
478    var currencyQuoteDebugEvent = markQuickPayUnavailable(
479      currencyQuoteError,
480      'wallet_preflight_failed'
481    );
482    showQuickPayFailureModal(
483      'wallet_preflight_failed',
484      currencyQuoteError,
485      currencyQuoteDebugEvent
486    );
487    return null;
488  }
489
490  if (
491    typeof paymentRequest == 'undefined' ||
492    !paymentRequest ||
493    typeof paymentRequest.show != 'function'
494  ) {
495    var unavailablePaymentRequestError = new Error(
496      'Quickpay payment request is unavailable.'
497    );
498    var unavailablePaymentRequestDebugEvent = sendQuickPayDebugTerminalEvent(
499      'wallet_preflight_failed',
500      'unavailable',
501      unavailablePaymentRequestError
502    );
503    showQuickPayFailureModal(
504      'wallet_preflight_failed',
505      unavailablePaymentRequestError,
506      unavailablePaymentRequestDebugEvent
507    );
508    return null;
509  }
510
511  // Apple Pay rejects a second show() call while its first sheet is still
512  // active. Treat repeated clicks as the same interaction instead of creating
513  // a noisy InvalidAccessError and interrupting checkout recovery.
514  if (!acquireQuickPayPaymentRequest()) {
515    return null;
516  }
517
518  try {
519    var paymentRequestShowResult = paymentRequest.show();
520    if (
521      paymentRequestShowResult &&
522      typeof paymentRequestShowResult.then == 'function'
523    ) {
524      paymentRequestShowResult
525        .then(function () {
526          recordQuickPayDebugStage('wallet_show_resolved');
527        })
528        .catch(function (paymentRequestShowError) {
529          releaseQuickPayPaymentRequest();
530          var errorDetails = getQuickPayDebugErrorDetails(
531            paymentRequestShowError
532          );
533          var walletShowStage =
534            errorDetails.name == 'AbortError'
535              ? 'wallet_cancelled'
536              : 'wallet_show_failed';
537          var walletShowDebugEvent = sendQuickPayDebugTerminalEvent(
538            walletShowStage,
539            errorDetails.name == 'AbortError' ? 'cancelled' : 'failed',
540            paymentRequestShowError
541          );
542          if (walletShowStage == 'wallet_show_failed') {
543            showQuickPayFailureModal(
544              walletShowStage,
545              paymentRequestShowError,
546              walletShowDebugEvent
547            );
548          }
549        });
550    }
551    return paymentRequestShowResult;
552  } catch (paymentRequestShowError) {
553    releaseQuickPayPaymentRequest();
554    var walletShowDebugEvent = sendQuickPayDebugTerminalEvent(
555      'wallet_show_failed',
556      'failed',
557      paymentRequestShowError
558    );
559    showQuickPayFailureModal(
560      'wallet_show_failed',
561      paymentRequestShowError,
562      walletShowDebugEvent
563    );
564    return null;
565  }
566}
567
568function armQuickPayCurrencyQuoteExpiration(currencyQuoteToken) {
569  var expiresAt = quickPayCurrencyQuoteExpiresAt(currencyQuoteToken);
570  if (!quickPayCurrencyQuoteIsUsable(currencyQuoteToken)) {
571    return refreshQuickPayCurrencyQuoteToken();
572  }
573
574  if (typeof setTimeout == 'function') {
575    if (quickPayCurrencyQuoteRefreshTimer) {
576      clearTimeout(quickPayCurrencyQuoteRefreshTimer);
577    }
578    quickPayCurrencyQuoteRefreshTimer = setTimeout(function () {
579      if (!quickPayCurrencyQuoteIsUsable(currencyQuoteToken)) {
580        refreshQuickPayCurrencyQuoteToken().catch(function (refreshError) {
581          markQuickPayUnavailable(refreshError, 'wallet_preflight_failed');
582        });
583      }
584    }, Math.max(0, expiresAt * 1000 - Date.now() - 120000 + 25));
585  }
586  if (
587    !quickPayCurrencyQuotePageShowBound &&
588    typeof window != 'undefined' &&
589    typeof window.addEventListener == 'function'
590  ) {
591    quickPayCurrencyQuotePageShowBound = true;
592    window.addEventListener('pageshow', function () {
593      if (!quickPayCurrencyQuoteIsUsable(checkoutCurrencyQuoteToken)) {
594        refreshQuickPayCurrencyQuoteToken().catch(function (refreshError) {
595          markQuickPayUnavailable(refreshError, 'wallet_preflight_failed');
596        });
597      }
598    });
599  }
600  return Promise.resolve(currencyQuoteToken);
601}
602
603function disableQuickPayControls(documentRoot) {
604  if (!documentRoot || typeof documentRoot.querySelectorAll != 'function') {
605    return;
606  }
607
608  documentRoot
609    .querySelectorAll(
610      '.quickPayButton, .eventQuickPayButton, #payment-request-button, [data-test-id="link-pay-btn"], [onclick*="paymentRequest.show"]'
611    )
612    .forEach(function (quickPayControl) {
613      var paypalContainer = null;
614      if (
615        typeof quickPayControl.matches == 'function' &&
616        quickPayControl.matches('[data-paypal-quick-pay-entry-point]')
617      ) {
618        paypalContainer = quickPayControl;
619      } else if (typeof quickPayControl.querySelector == 'function') {
620        paypalContainer = quickPayControl.querySelector(
621          '[data-paypal-quick-pay-entry-point]'
622        );
623      }
624
625      if (paypalContainer) {
626        // Reason: modern wallet rows can share the legacy quickPayButton
627        // wrapper with PayPal. Stripe wallet unavailability must not hide a
628        // ready PayPal iframe, including after browser Back restores the page.
629        if (typeof quickPayControl.querySelectorAll == 'function') {
630          quickPayControl
631            .querySelectorAll(
632              '.sch-new-cart__wallet, [data-test-id="link-pay-btn"], [onclick*="paymentRequest.show"]'
633            )
634            .forEach(function (stripeWalletControl) {
635              stripeWalletControl.style.display = 'none';
636              stripeWalletControl.setAttribute('aria-disabled', 'true');
637            });
638        }
639        quickPayControl.style.display = '';
640        if (typeof quickPayControl.removeAttribute == 'function') {
641          quickPayControl.removeAttribute('aria-disabled');
642        }
643        return;
644      }
645
646      quickPayControl.style.display = 'none';
647      quickPayControl.setAttribute('aria-disabled', 'true');
648    });
649}
650
651function getQuickPayFailureModalCopy(stage, paymentError) {
652  var walletNames = {
653    apple_pay: 'Apple Pay',
654    google_pay: 'Google Pay',
655    link: 'Link',
656    unknown: 'Quick Pay',
657  };
658  var reasonLabels = {
659    submission_blocked: 'Checkout could not start',
660    lead_creation_failed: 'Event checkout setup failed',
661    checkout_request_failed: 'Checkout connection failed',
662    checkout_response_failed: 'Payment could not be confirmed',
663    post_token_failed: 'Checkout page error',
664    wallet_show_failed: 'Wallet could not open',
665    wallet_preflight_failed: 'Wallet is not ready',
666    setup_failed: 'Secure payment setup failed',
667  };
668  var walletName = walletNames[
669    normalizeQuickPayDebugWalletName(
670      quickPayDebugActiveWallet || window.quickPayMethod
671    )
672  ];
673  var errorDetails = getQuickPayDebugErrorDetails(paymentError);
674  var declineReasonLabels = {
675    insufficient_funds:
676      'This card does not have enough available funds. Please use another payment method.',
677    card_declined:
678      'This card was declined. Please use another payment method or contact your bank.',
679  };
680  var cardDeclineMessage =
681    paymentError &&
682    paymentError.type == 'card_error' &&
683    errorDetails.message
684      ? errorDetails.message
685      : '';
686  var reason = translateQuickPayFailureText(
687    cardDeclineMessage ||
688      declineReasonLabels[errorDetails.code] ||
689      reasonLabels[stage] ||
690      'Payment could not be completed'
691  );
692  if (errorDetails.code) {
693    reason +=
694      ' (' +
695      translateQuickPayFailureText('code') +
696      ' ' +
697      errorDetails.code +
698      ')';
699  }
700
701  if (stage == 'checkout_status_unknown') {
702    return {
703      title: translateQuickPayFailureText(
704        'Your payment is still being confirmed'
705      ),
706      message: translateQuickPayFailureText(
707        'Do not try to pay again. Check your email for a receipt, or contact support if it does not arrive.'
708      ),
709      reason: translateQuickPayFailureText(
710        'Payment status could not be confirmed'
711      ),
712      walletName: walletName,
713      statusUnknown: true,
714    };
715  }
716
717  return {
718    title:
719      walletName +
720      ' ' +
721      translateQuickPayFailureText('could not complete checkout'),
722    message: translateQuickPayFailureText(
723      'Your order was not completed. Try your wallet again, or use regular checkout.'
724    ),
725    reason: reason,
726    walletName: walletName,
727    statusUnknown: false,
728  };
729}
730
731function translateQuickPayFailureText(text) {
732  return typeof translateText == 'function' ? translateText(text) : text;
733}
734
735function ensureQuickPayFailureModalStyles() {
736  if (
737    typeof document == 'undefined' ||
738    document.getElementById('quick-pay-failure-modal-styles')
739  ) {
740    return;
741  }
742
743  var style = document.createElement('style');
744  style.id = 'quick-pay-failure-modal-styles';
745  // Reason: SCH's mobile ticket sheet uses the browser's maximum z-index.
746  // Matching it lets this later body child render above the checkout sheet.
747  style.textContent =
748    '.quick-pay-failure-modal{align-items:center;background:rgba(15,23,42,.58);display:flex;inset:0;justify-content:center;padding:20px;position:fixed;z-index:2147483647}' +
749    '.quick-pay-failure-modal__dialog{background:#fff;border-radius:18px;box-shadow:0 24px 64px rgba(15,23,42,.3);box-sizing:border-box;color:#172033;font-family:Arial,sans-serif;max-width:440px;padding:28px;text-align:center;width:100%}' +
750    '.quick-pay-failure-modal__icon{align-items:center;background:#fff2e8;border-radius:50%;color:#c45100;display:flex;font-size:28px;font-weight:800;height:56px;justify-content:center;margin:0 auto 16px;width:56px}' +
751    '.quick-pay-failure-modal__title{font-size:24px;line-height:1.25;margin:0 0 10px}' +
752    '.quick-pay-failure-modal__message{color:#475569;font-size:16px;line-height:1.5;margin:0 0 14px}' +
753    '.quick-pay-failure-modal__reason{background:#f8fafc;border:1px solid #e2e8f0;border-radius:9px;color:#475569;font-size:13px;line-height:1.45;margin:0 0 20px;padding:10px 12px;word-break:break-word}' +
754    '.quick-pay-failure-modal__actions{display:flex;flex-wrap:wrap;gap:10px}' +
755    '.quick-pay-failure-modal__button{border:0;border-radius:10px;cursor:pointer;flex:1 1 150px;font-size:16px;font-weight:700;min-height:48px;padding:12px 16px}' +
756    '.quick-pay-failure-modal__button--retry{background:#eef2f7;color:#172033}' +
757    '.quick-pay-failure-modal__button--checkout{background:#e87722;color:#fff}';
758  (document.head || document.body).appendChild(style);
759}
760
761function showQuickPayFailureModal(stage, paymentError, debugEvent) {
762  if (
763    typeof document == 'undefined' ||
764    !document.body ||
765    typeof document.createElement != 'function'
766  ) {
767    console.warn('Unable to show Quick Pay failure modal', { stage: stage });
768    return;
769  }
770
771  if (
772    stage != 'checkout_status_unknown' &&
773    typeof window.schNewTicketFlowSetQuickPayLoading == 'function'
774  ) {
775    window.schNewTicketFlowSetQuickPayLoading(false);
776  }
777
778  ensureQuickPayFailureModalStyles();
779  var existingModal = document.getElementById('quick-pay-failure-modal');
780  if (existingModal) {
781    existingModal.remove();
782  }
783
784  var copy = getQuickPayFailureModalCopy(stage, paymentError);
785  var referenceParts = [stage];
786  if (debugEvent && debugEvent.event_id) {
787    referenceParts.push(String(debugEvent.event_id).slice(0, 8));
788  }
789
790  var overlay = document.createElement('div');
791  overlay.id = 'quick-pay-failure-modal';
792  overlay.className = 'quick-pay-failure-modal';
793  overlay.setAttribute('data-test-id', 'quick-pay-failure-modal');
794
795  var dialog = document.createElement('section');
796  dialog.className = 'quick-pay-failure-modal__dialog';
797  dialog.setAttribute('role', 'dialog');
798  dialog.setAttribute('aria-modal', 'true');
799  dialog.setAttribute('aria-labelledby', 'quick-pay-failure-modal-title');
800
801  var icon = document.createElement('div');
802  icon.className = 'quick-pay-failure-modal__icon';
803  icon.setAttribute('aria-hidden', 'true');
804  icon.textContent = '!';
805
806  var title = document.createElement('h2');
807  title.id = 'quick-pay-failure-modal-title';
808  title.className = 'quick-pay-failure-modal__title';
809  title.textContent = copy.title;
810
811  var message = document.createElement('p');
812  message.className = 'quick-pay-failure-modal__message';
813  message.textContent = copy.message;
814
815  var reason = document.createElement('p');
816  reason.className = 'quick-pay-failure-modal__reason';
817  reason.textContent =
818    copy.reason +
819    ' · ' +
820    translateQuickPayFailureText('Reference') +
821    ': ' +
822    referenceParts.join(' / ');
823
824  var actions = document.createElement('div');
825  actions.className = 'quick-pay-failure-modal__actions';
826
827  function closeModal() {
828    overlay.remove();
829  }
830
831  var retryButton = document.createElement('button');
832  retryButton.type = 'button';
833  retryButton.className =
834    'quick-pay-failure-modal__button quick-pay-failure-modal__button--retry';
835  retryButton.textContent = translateQuickPayFailureText(
836    copy.statusUnknown ? 'Close' : 'Try wallet again'
837  );
838  retryButton.onclick = closeModal;
839  actions.appendChild(retryButton);
840
841  if (!copy.statusUnknown && typeof goToCheckout == 'function') {
842    var checkoutButton = document.createElement('button');
843    checkoutButton.type = 'button';
844    checkoutButton.className =
845      'quick-pay-failure-modal__button quick-pay-failure-modal__button--checkout';
846    checkoutButton.textContent = translateQuickPayFailureText(
847      'Use regular checkout'
848    );
849    checkoutButton.onclick = function () {
850      closeModal();
851      goToCheckout();
852    };
853    actions.appendChild(checkoutButton);
854  }
855
856  dialog.appendChild(icon);
857  dialog.appendChild(title);
858  dialog.appendChild(message);
859  dialog.appendChild(reason);
860  dialog.appendChild(actions);
861  overlay.appendChild(dialog);
862  overlay.onclick = function (event) {
863    if (event.target === overlay) {
864      closeModal();
865    }
866  };
867  document.body.appendChild(overlay);
868  retryButton.focus();
869}
870
871// handling chrome and apple pay
872window.__quickPayScriptInitialized = true;
873
874var quickPayDebugQueueKey = 'lr_wallet_debug_queue_v1';
875var quickPayDebugFeedbackKey = 'lr_wallet_debug_last_terminal_v1';
876var quickPayDebugStartedAt = Date.now();
877var quickPayDebugSessionId = createQuickPayCheckoutAttemptId();
878var quickPayDebugWalletInteractionId = '';
879var quickPayDebugCheckoutAttemptId = '';
880var quickPayDebugActiveWallet = '';
881var quickPayDebugTrail = [];
882var quickPayDebugMemoryQueue = [];
883var quickPayDebugFlushInProgress = false;
884var quickPayDebugInteractionTerminalLogged = false;
885var quickPayDebugWalletCompletionStatus = null;
886var quickPayDebugLoggedFallbackEvents = {};
887
888function quickPayDebugLoggingEnabled() {
889  return window.STORE_QUICK_PAY_DIAGNOSTICS_ENABLED !== false;
890}
891
892function recordQuickPayDebugStage(stage, code) {
893  quickPayDebugTrail.push({
894    stage: stage,
895    elapsed_ms: Math.max(0, Date.now() - quickPayDebugStartedAt),
896    code: String(code || '')
897      .replace(/[^A-Za-z0-9_.:-]/g, '')
898      .slice(0, 100),
899  });
900  quickPayDebugTrail = quickPayDebugTrail.slice(-12);
901}
902
903function beginQuickPayDebugWalletInteraction() {
904  quickPayDebugWalletInteractionId = createQuickPayCheckoutAttemptId();
905  quickPayDebugCheckoutAttemptId = '';
906  quickPayDebugInteractionTerminalLogged = false;
907  quickPayDebugWalletCompletionStatus = null;
908  clearQuickPayDebugEventForFeedback();
909}
910
911function getQuickPayDebugTimezone() {
912  try {
913    return Intl.DateTimeFormat().resolvedOptions().timeZone || '';
914  } catch (timezoneError) {
915    return '';
916  }
917}
918
919function getQuickPayDebugContext() {
920  var availablePaymentMethods = window.quickPayAvailablePaymentMethods || {};
921  var pagePath = window.location.pathname || '/';
922  try {
923    pagePath = decodeURIComponent(pagePath);
924  } catch (pagePathDecodeError) {
925    // Keep the encoded path and redact any recognizable identifiers below.
926  }
927  pagePath = redactQuickPayDebugText(pagePath).slice(0, 300);
928  var browserLanguage =
929    typeof getCookie == 'function'
930      ? getCookie('language') || navigator.language || ''
931      : navigator.language || '';
932  browserLanguage = /^[A-Za-z]{2,3}(?:[-_][A-Za-z0-9]{2,8})?$/.test(
933    browserLanguage
934  )
935    ? browserLanguage
936    : '';
937  return {
938    page_path: pagePath,
939    website_domain:
940      typeof WEBSITE_DOMAIN != 'undefined' ? WEBSITE_DOMAIN : 'unknown',
941    currency: typeof cy != 'undefined' ? cy : 'unknown',
942    language: browserLanguage,
943    timezone: getQuickPayDebugTimezone(),
944    online: navigator.onLine !== false,
945    viewport_width: window.innerWidth || 0,
946    viewport_height: window.innerHeight || 0,
947    apple_pay_available: !!availablePaymentMethods.applePay,
948    google_pay_available: !!availablePaymentMethods.googlePay,
949    link_available: !!availablePaymentMethods.link,
950  };
951}
952
953function readQuickPayDebugQueue() {
954  try {
955    var storedQueue = JSON.parse(
956      window.localStorage.getItem(quickPayDebugQueueKey) || '[]'
957    );
958    var combinedQueue = quickPayDebugMemoryQueue.concat(
959      Array.isArray(storedQueue) ? storedQueue : []
960    );
961    var seenEventIds = {};
962    quickPayDebugMemoryQueue = combinedQueue
963      .filter(function (queuedEvent) {
964        if (
965          !queuedEvent ||
966          !queuedEvent.event_id ||
967          seenEventIds[queuedEvent.event_id]
968        ) {
969          return false;
970        }
971        seenEventIds[queuedEvent.event_id] = true;
972        return true;
973      })
974      .slice(-10);
975    return quickPayDebugMemoryQueue.slice();
976  } catch (queueReadError) {
977    return quickPayDebugMemoryQueue.slice();
978  }
979}
980
981function writeQuickPayDebugQueue(queue) {
982  quickPayDebugMemoryQueue = queue.slice(-10);
983  try {
984    window.localStorage.setItem(
985      quickPayDebugQueueKey,
986      JSON.stringify(quickPayDebugMemoryQueue)
987    );
988  } catch (queueWriteError) {
989    // Wallet checkout must remain usable when storage is unavailable.
990  }
991}
992
993function enqueueQuickPayDebugEvent(debugEvent) {
994  var queue = readQuickPayDebugQueue().filter(function (queuedEvent) {
995    return queuedEvent && queuedEvent.event_id != debugEvent.event_id;
996  });
997  queue.push(debugEvent);
998  writeQuickPayDebugQueue(queue);
999}
1000
1001function rememberQuickPayDebugEventForFeedback(debugEvent) {
1002  try {
1003    window.sessionStorage.setItem(
1004      quickPayDebugFeedbackKey,
1005      JSON.stringify({
1006        event_id: debugEvent.event_id,
1007        stage: debugEvent.stage,
1008        wallet: debugEvent.wallet,
1009        occurred_at: Math.floor(Date.now() / 1000),
1010      })
1011    );
1012  } catch (feedbackStorageError) {
1013    // The diagnostic endpoint remains the source of truth when storage is blocked.
1014  }
1015}
1016
1017function clearQuickPayDebugEventForFeedback() {
1018  try {
1019    window.sessionStorage.removeItem(quickPayDebugFeedbackKey);
1020  } catch (feedbackStorageError) {
1021    // Session storage is optional diagnostic context.
1022  }
1023}
1024
1025function flushQuickPayDebugQueue() {
1026  if (
1027    !quickPayDebugLoggingEnabled() ||
1028    quickPayDebugFlushInProgress ||
1029    typeof window.fetch != 'function'
1030  ) {
1031    return;
1032  }
1033
1034  var queue = readQuickPayDebugQueue();
1035  if (!queue.length) {
1036    return;
1037  }
1038
1039  var debugEvent = queue[0];
1040  quickPayDebugFlushInProgress = true;
1041  window
1042    .fetch('/store/api/checkout/wallet-debug-log', {
1043      method: 'POST',
1044      headers: { 'Content-Type': 'application/json' },
1045      credentials: 'same-origin',
1046      keepalive: true,
1047      body: JSON.stringify(debugEvent),
1048    })
1049    .then(function (response) {
1050      if (!response.ok) {
1051        throw new Error('Wallet diagnostic request failed.');
1052      }
1053      var updatedQueue = readQuickPayDebugQueue().filter(function (
1054        queuedEvent
1055      ) {
1056        return queuedEvent && queuedEvent.event_id != debugEvent.event_id;
1057      });
1058      writeQuickPayDebugQueue(updatedQueue);
1059      quickPayDebugFlushInProgress = false;
1060      flushQuickPayDebugQueue();
1061    })
1062    .catch(function () {
1063      quickPayDebugFlushInProgress = false;
1064    });
1065}
1066
1067function sendQuickPayDebugTerminalEvent(stage, outcome, paymentError) {
1068  if (!quickPayDebugLoggingEnabled()) {
1069    return null;
1070  }
1071
1072  var errorDetails = getQuickPayDebugErrorDetails(paymentError);
1073  recordQuickPayDebugStage(stage, errorDetails.code || errorDetails.name);
1074
1075  if (quickPayDebugWalletInteractionId) {
1076    if (quickPayDebugInteractionTerminalLogged) {
1077      return;
1078    }
1079    quickPayDebugInteractionTerminalLogged = true;
1080  } else {
1081    var fallbackEventKey = stage + ':' + outcome;
1082    if (quickPayDebugLoggedFallbackEvents[fallbackEventKey]) {
1083      return;
1084    }
1085    quickPayDebugLoggedFallbackEvents[fallbackEventKey] = true;
1086  }
1087
1088  var debugEvent = {
1089    event_id: createQuickPayCheckoutAttemptId(),
1090    debug_session_id: quickPayDebugSessionId,
1091    wallet_interaction_id: quickPayDebugWalletInteractionId,
1092    checkout_attempt_id: quickPayDebugCheckoutAttemptId,
1093    stage: stage,
1094    outcome: outcome,
1095    wallet: normalizeQuickPayDebugWalletName(
1096      quickPayDebugActiveWallet || window.quickPayMethod
1097    ),
1098    error: errorDetails,
1099    context: getQuickPayDebugContext(),
1100    trail: quickPayDebugTrail.slice(-12),
1101  };
1102
1103  rememberQuickPayDebugEventForFeedback(debugEvent);
1104  enqueueQuickPayDebugEvent(debugEvent);
1105  flushQuickPayDebugQueue();
1106  console.warn('quickPay diagnostic queued', {
1107    eventId: debugEvent.event_id,
1108    stage: stage,
1109    wallet: debugEvent.wallet,
1110    code: errorDetails.code || errorDetails.name,
1111  });
1112  return debugEvent;
1113}
1114
1115if (quickPayDebugLoggingEnabled()) {
1116  recordQuickPayDebugStage('script_initialized');
1117  flushQuickPayDebugQueue();
1118  if (typeof window.addEventListener == 'function') {
1119    window.addEventListener('online', flushQuickPayDebugQueue);
1120  }
1121}
1122
1123// Reason: js.stripe.com is a third-party script that ad blockers, privacy
1124// extensions, scrapers, and flaky networks routinely block. When it never
1125// loads, wallet checkout is legitimately unavailable and the shopper still
1126// gets standard checkout, so it is an expected environment condition rather
1127// than a wallet failure. main.js already reloads this script once Stripe.js
1128// becomes available, so logging every blocked load as a terminal wallet error
1129// only floods dev_error_logs and hides real wallet regressions.
1130var quickPayStripeScriptUnavailable =
1131  typeof window.stripe == 'undefined' && typeof Stripe == 'undefined';
1132var stripe;
1133var elements;
1134window.__quickPayStripeSetupReady = false;
1135if (quickPayStripeScriptUnavailable) {
1136  // Keep the local diagnostic trail so a later real failure still shows that
1137  // Stripe.js never loaded, without calling an undefined global or sending a
1138  // terminal event. Standard card checkout remains available.
1139  recordQuickPayDebugStage('stripe_script_unavailable', 'ReferenceError');
1140  console.warn('quickPay unavailable: Stripe.js did not load');
1141} else {
1142  try {
1143    stripe =
1144      typeof window.stripe != 'undefined'
1145        ? window.stripe
1146        : Stripe(strpk, { locale: getCookie('language') || 'en' });
1147    elements = stripe.elements();
1148    window.__quickPayStripeSetupReady = true;
1149  } catch (quickPayStripeSetupError) {
1150    sendQuickPayDebugTerminalEvent(
1151      'setup_failed',
1152      'unavailable',
1153      quickPayStripeSetupError
1154    );
1155  }
1156}
1157
1158window.canMakePaymentRequest = false;
1159window.canNotMakePaymentRequest = false;
1160window.quickPayAvailablePaymentMethods = null;
1161window.quickPayCapabilityPending = false;
1162window.quickPayCapabilitySettled = false;
1163
1164function settleQuickPayCapability() {
1165  window.quickPayCapabilityPending = false;
1166  window.quickPayCapabilitySettled = true;
1167  window.dispatchEvent(new CustomEvent('quickpaycapabilitysettled'));
1168}
1169
1170function markQuickPayUnavailable(paymentError, diagnosticStage) {
1171  var diagnosticEvent = null;
1172  if (paymentError) {
1173    console.warn('quickPay unavailable', { paymentError });
1174  }
1175
1176  if (diagnosticStage) {
1177    diagnosticEvent = sendQuickPayDebugTerminalEvent(
1178      diagnosticStage,
1179      'unavailable',
1180      paymentError
1181    );
1182  }
1183
1184  window.quickPayReady = false;
1185  window.quickPayMethod = 'none';
1186  window.canMakePaymentRequest = false;
1187  window.canNotMakePaymentRequest = true;
1188  window.quickPayAvailablePaymentMethods = null;
1189
1190  if (typeof setCookie == 'function') {
1191    setCookie('canNotMakePaymentRequest', 'true');
1192  }
1193
1194  disableQuickPayControls(document);
1195  return diagnosticEvent;
1196}
1197
1198var cartTotalAmount;
1199var quickPayApprovedAmount = null;
1200
1201var lastPages = getCookie('last_pages') || '';
1202
1203if (!cart.shippingOptions && typeof shippingOptions != 'undefined') {
1204  cart.shippingOptions = shippingOptions;
1205}
1206var processingFee = 0;
1207function calculateProcessingFee() {
1208  // only charges processing fee on checkout
1209  processingFee = 0;
1210  if (WEBSITE_DOMAIN != 'afs' && window.location.href.includes('/checkout')) {
1211    processingFee = money_round(cart.total * 0.1);
1212  }
1213
1214  if (
1215    WEBSITE_DOMAIN == 'sch' &&
1216    window.location.href.includes('/checkout') &&
1217    !lastPages.includes('products')
1218  ) {
1219    processingFee = money_round(cart.total * 0.08);
1220  }
1221  // processing fee is 2 cents less than 10 percent
1222  if (processingFee > 0.02) {
1223    processingFee = processingFee - 0.02;
1224  }
1225}
1226calculateProcessingFee();
1227
1228function money_round(num) {
1229  return (Math.round(num * 100) / 100).toFixed(2);
1230}
1231
1232// https://stripe.com/docs/currencies
1233function fixStripeZeroPointCorrection(total_in_cents) {
1234  let fixedTotal = total_in_cents;
1235  if (
1236    currencies &&
1237    currencies[cy] &&
1238    parseInt(currencies[cy].non_zero_point_currency, 10)
1239  ) {
1240    // won and yen
1241    fixedTotal = Math.round(total_in_cents / 100);
1242  } else {
1243    // usd and cad and most dollar curreincies
1244    fixedTotal = parseFloat((total_in_cents / 100).toFixed(2));
1245  }
1246  return fixedTotal;
1247}
1248
1249console.log('quickPay: calculating pricing', {
1250  processingFee,
1251  total: cart.total,
1252  initialShippingFee,
1253  processingFee,
1254});
1255
1256var getCartTotalAmount = function () {
1257  cartBaseTotal = cart.total;
1258  var eventTotal = getQuickPayInputValue(document, '#eventTotal');
1259  var quickPayTotalOverride = getQuickPayInputValue(
1260    document,
1261    '#quickPayTotalOverride'
1262  );
1263
1264  if (eventTotal || quickPayTotalOverride) {
1265    return Math.ceil(
1266      getLocalPrice(eventTotal || quickPayTotalOverride || 0, cy, false),
1267      cy,
1268      false
1269    );
1270  }
1271
1272  if (typeof cartBaseTotalOverride != 'undefined') {
1273    cartBaseTotal = cartBaseTotalOverride;
1274  }
1275
1276  var usesZeroDecimalMinorUnits =
1277    currencies &&
1278    currencies[cy] &&
1279    parseInt(currencies[cy].non_zero_point_currency, 10);
1280  var displayedCartTotal = getQuickPayDisplayedCartTotal(document);
1281
1282  cartTotalAmount = calculateQuickPayTotalMinorUnits(
1283    cartBaseTotal,
1284    processingFee,
1285    initialShippingFee,
1286    usesZeroDecimalMinorUnits,
1287    displayedCartTotal
1288  );
1289
1290  console.log('quickPay: calculated price 1', { cartTotalAmount });
1291
1292  console.log('quickPay: calculated price 1', {
1293    cartTotalAmount,
1294  });
1295
1296  return cartTotalAmount;
1297};
1298
1299function rememberQuickPayApprovedAmount(amount) {
1300  quickPayApprovedAmount = parseInt(amount, 10);
1301  return quickPayApprovedAmount;
1302}
1303
1304var handleEventQuickPay = function () {
1305  var quickPayButtonContent = getQuickPayButton();
1306  console.log('handleEventQuickPay', { quickPayButtonContent });
1307  document
1308    .querySelectorAll('.eventQuickPayButton')
1309    .forEach(function (quickPayEventBuuton) {
1310      quickPayEventBuuton.innerHTML = quickPayButtonContent;
1311    });
1312
1313  if (typeof paymentRequest != 'undefined') {
1314    const approvedAmount = rememberQuickPayApprovedAmount(getCartTotalAmount());
1315    const updatedQuickPayOptions = {
1316      total: {
1317        label: translateText('Scavenger Hunt Party Tickets'),
1318        displayItems: !!(processingFee || useAddressFields)
1319          ? [
1320              {
1321                amount: approvedAmount,
1322                label: translateText('Scavenger Hunt Party Tickets'),
1323              },
1324            ]
1325          : undefined,
1326        amount: approvedAmount,
1327      },
1328    };
1329    //If LinkBtn exists then set data-amount for our quickpay E2E test
1330    const linkBtn = document.querySelector('[data-test-id="link-pay-btn"]');
1331    if (linkBtn) {
1332      //set data-amount of linkBtn to be getCartTotalAmount()
1333      linkBtn.setAttribute('data-amount', approvedAmount);
1334    }
1335
1336    console.log({
1337      updatedQuickPayOptions,
1338      initialShippingFee,
1339      processingFee,
1340    });
1341    paymentRequest.update(updatedQuickPayOptions);
1342  }
1343};
1344
1345var updateQuickPay = function () {
1346  console.log('updateQuickPay');
1347  if (document.querySelector('.eventQuickPayButton')) {
1348    return handleEventQuickPay();
1349  }
1350
1351  if (
1352    quickPayRequiresCurrencyQuote(
1353      quickPayUsesCorporateCheckout(
1354        document,
1355        typeof eventUUID != 'undefined'
1356      )
1357    ) &&
1358    quickPayHasCheckoutControls(document)
1359  ) {
1360    var quickPayRenderedQuoteWasUsable = quickPayCurrencyQuoteIsUsable(
1361      checkoutCurrencyQuoteToken
1362    );
1363    var quickPayRenderedQuoteReady = armQuickPayCurrencyQuoteExpiration(
1364      checkoutCurrencyQuoteToken
1365    );
1366    if (!quickPayRenderedQuoteWasUsable) {
1367      disableQuickPayControls(document);
1368      quickPayRenderedQuoteReady
1369        .then(function () {
1370          if (typeof CartViewRender == 'function') {
1371            CartViewRender();
1372          }
1373        })
1374        .catch(function (refreshError) {
1375          markQuickPayUnavailable(refreshError, 'wallet_preflight_failed');
1376        });
1377      return;
1378    }
1379  }
1380
1381  try {
1382    initialShippingFee = cart.shippingOptions
1383      ? cart.shippingOptions[0].amount
1384      : 0;
1385    calculateProcessingFee();
1386    if (typeof paymentRequest != 'undefined') {
1387      const approvedAmount = rememberQuickPayApprovedAmount(getCartTotalAmount());
1388      const updatedQuickPayOptions = {
1389        currency: cy,
1390        total: {
1391          label: getQuickPayDigitalProductLabel(cart, getBundleInfo, translateText),
1392          displayItems: !!(processingFee || useAddressFields)
1393            ? [
1394                {
1395                  amount: fixStripeZeroPointCorrection(
1396                    parseInt(getValue('#schTotal') || 0)
1397                  ),
1398                  label: translateText('Free Instant Digital Gift Card'),
1399                },
1400              ]
1401            : undefined,
1402          amount: approvedAmount,
1403        },
1404      };
1405      //If LinkBtn exists then set data-amount for our quickpay E2E test
1406      const linkBtn = document.querySelector('[data-test-id="link-pay-btn"]');
1407      if (linkBtn) {
1408        //set data-amount of linkBtn to be getCartTotalAmount()
1409        linkBtn.setAttribute('data-amount', approvedAmount);
1410      }
1411
1412      if (WEBSITE_DOMAIN == 'sch') {
1413        cartBaseTotal = cart.total;
1414        if (typeof cartBaseTotalOverride != 'undefined') {
1415          cartBaseTotal = cartBaseTotalOverride;
1416        }
1417        googlePayShippingInfo['displayItems'] = [
1418          {
1419            amount: fixStripeZeroPointCorrection(
1420              100 * parseInt(Math.round(100 * cartBaseTotal))
1421            ),
1422            label: translateText('Cart Items'),
1423          },
1424          {
1425            amount: fixStripeZeroPointCorrection(
1426              100 * parseInt(parseInt(Math.round(processingFee * 100)))
1427            ),
1428            label: translateText('Duties & Fees'), // Display the label for the fee
1429          },
1430        ];
1431      }
1432
1433      console.log({
1434        updatedQuickPayOptions,
1435        initialShippingFee,
1436        processingFee,
1437      });
1438      paymentRequest.update(updatedQuickPayOptions);
1439    }
1440  } catch (updateQuickPayError) {
1441    console.error({ updateQuickPayError });
1442  }
1443};
1444
1445useAddressFields =
1446  typeof useAddressFields != 'undefined'
1447    ? useAddressFields
1448    : cart.hasPhysicalProduct;
1449
1450var initialShippingFee = cart.shippingOptions
1451  ? cart.shippingOptions[0].amount
1452  : 0;
1453
1454var disableWallets = window.location.href.includes('disableWallets')
1455  ? ['googlePay', 'link', 'applePay']
1456  : ['link'];
1457
1458console.log({ disableWallets });
1459
1460var initialQuickPayApprovedAmount = rememberQuickPayApprovedAmount(
1461  getCartTotalAmount()
1462);
1463
1464// https://stripe.com/docs/js#stripe-payment-request
1465var googlePayShippingInfo = {
1466  country: 'US',
1467  currency: cy,
1468  disableWallets: disableWallets,
1469
1470  total: {
1471    label: getQuickPayDigitalProductLabel(cart, getBundleInfo, translateText),
1472    amount: initialQuickPayApprovedAmount,
1473  },
1474
1475  requestPayerName: true,
1476  requestPayerEmail: true,
1477  requestShipping: false,
1478};
1479
1480if (WEBSITE_DOMAIN == 'sch') {
1481  cartBaseTotal = cart.total;
1482  if (typeof cartBaseTotalOverride != 'undefined') {
1483    cartBaseTotal = cartBaseTotalOverride;
1484  }
1485
1486  googlePayShippingInfo['displayItems'] = [
1487    {
1488      amount: fixStripeZeroPointCorrection(
1489        100 * parseInt(Math.round(100 * cartBaseTotal))
1490      ),
1491      label: 'Cart Items',
1492    },
1493    {
1494      amount: fixStripeZeroPointCorrection(
1495        100 * parseInt(parseInt(Math.round(processingFee * 100)))
1496      ),
1497      label: 'Duties & Fees', // Display the label for the fee
1498    },
1499  ];
1500}
1501
1502console.log({ googlePayShippingInfo });
1503
1504var paymentRequest;
1505var prButton;
1506var skipLegacyPaymentRequestButtonElement = !!window.isTest;
1507// Reason: a blocked Stripe.js load is already handled above as an expected
1508// environment condition, so the follow-on setup failure must not be logged as
1509// a wallet regression either.
1510var quickPaySetupDiagnosticStage = quickPayStripeScriptUnavailable
1511  ? ''
1512  : 'setup_failed';
1513var quickPayCurrencyQuoteReady = Promise.resolve(checkoutCurrencyQuoteToken);
1514
1515try {
1516  var quickPayIsCorporateCheckout = quickPayUsesCorporateCheckout(
1517    document,
1518    typeof eventUUID != 'undefined'
1519  );
1520  if (
1521    quickPayRequiresCurrencyQuote(quickPayIsCorporateCheckout) &&
1522    cart &&
1523    cart.hasSubscription
1524  ) {
1525    // Subscriptions intentionally use the standard checkout, so this is not a
1526    // wallet failure and should not dilute the diagnostic signal.
1527    quickPaySetupDiagnosticStage = '';
1528    throw new Error('Quickpay is unavailable for subscription carts.');
1529  }
1530  if (
1531    quickPayRequiresCurrencyQuote(quickPayIsCorporateCheckout) &&
1532    (quickPayHasCheckoutControls(document) || quickPayCartHasItems(cart))
1533  ) {
1534    quickPayCurrencyQuoteReady = armQuickPayCurrencyQuoteExpiration(
1535      checkoutCurrencyQuoteToken
1536    );
1537  }
1538  paymentRequest = stripe.paymentRequest(googlePayShippingInfo);
1539  if (!skipLegacyPaymentRequestButtonElement) {
1540    prButton = elements.create('paymentRequestButton', {
1541      paymentRequest: paymentRequest,
1542    });
1543  }
1544} catch (quickPaySetupError) {
1545  console.error('quickPay setup error', { quickPaySetupError });
1546  markQuickPayUnavailable(quickPaySetupError, quickPaySetupDiagnosticStage);
1547}
1548
1549if (typeof paymentRequest != 'undefined') {
1550  function getQuickPaySelectedShippingOption(tokenEvent) {
1551    var selectedShippingOption = tokenEvent && tokenEvent.shippingOption;
1552    if (
1553      (!selectedShippingOption || selectedShippingOption.amount == null) &&
1554      cart &&
1555      Array.isArray(cart.shippingOptions) &&
1556      cart.shippingOptions.length
1557    ) {
1558      selectedShippingOption = cart.shippingOptions[0];
1559    }
1560
1561    return selectedShippingOption || null;
1562  }
1563
1564  function getQuickPayPostedShippingAmount(tokenEvent) {
1565    var selectedShippingOption = getQuickPaySelectedShippingOption(tokenEvent);
1566
1567    if (!selectedShippingOption || selectedShippingOption.amount == null) {
1568      return 0;
1569    }
1570
1571    var usesZeroDecimalMinorUnits =
1572      currencies &&
1573      currencies[cy] &&
1574      parseInt(currencies[cy].non_zero_point_currency, 10);
1575    return usesZeroDecimalMinorUnits
1576      ? selectedShippingOption.amount
1577      : selectedShippingOption.amount / 100;
1578  }
1579
1580  function getQuickPayPostedShippingService(tokenEvent) {
1581    var selectedShippingOption = getQuickPaySelectedShippingOption(tokenEvent);
1582    return selectedShippingOption && selectedShippingOption.id != null
1583      ? String(selectedShippingOption.id).trim()
1584      : '';
1585  }
1586
1587  // check availability and mount the button when the promise resolves
1588  console.log('seeing if quickPay: canMakePayment');
1589  recordQuickPayDebugStage('capability_check_started');
1590  // PayPal uses this signal to hold one continuous loading skeleton while the
1591  // floating row learns whether Apple Pay / Google Pay needs another column.
1592  window.quickPayCapabilityPending = true;
1593  Promise.all([paymentRequest.canMakePayment(), quickPayCurrencyQuoteReady])
1594    .then(function (quickPaySetupResults) {
1595      var canMakePaymentRequest = quickPaySetupResults[0];
1596      console.log({ canMakePaymentRequest });
1597      var availablePaymentMethods = getQuickPayAvailablePaymentMethods(
1598        canMakePaymentRequest,
1599        false
1600      );
1601      window.quickPayAvailablePaymentMethods = availablePaymentMethods;
1602
1603      if (availablePaymentMethods) {
1604        recordQuickPayDebugStage('capability_available');
1605        if (availablePaymentMethods.applePay) {
1606          window.quickPayReady = true;
1607          window.quickPayMethod = 'applePay';
1608          setCookie('quickPayMethod', 'applePay');
1609        } else if (availablePaymentMethods.googlePay) {
1610          window.quickPayReady = true;
1611          window.quickPayMethod = 'googlePay';
1612          setCookie('quickPayMethod', 'googlePay');
1613          // no on uses link
1614          // so disabling
1615        } else {
1616          markQuickPayUnavailable();
1617          if (typeof CartViewRender != 'undefined') {
1618            CartViewRender();
1619          }
1620          return console.warn('no quick pay methods', {
1621            availablePaymentMethods,
1622          });
1623        }
1624
1625        quickPayDebugActiveWallet = window.quickPayMethod;
1626
1627        window.canMakePaymentRequest = 1;
1628        setCookie('canNotMakePaymentRequest', 'false');
1629
1630        const usingCustomQuickPayButton =
1631          !!document.querySelector('.quickPayButton') ||
1632          !!document.querySelector('.eventQuickPayButton');
1633
1634        if (document.querySelector('#quick-pay')) {
1635          document.querySelector('#quick-pay').style.display = 'block';
1636
1637          // When we render our own quick-pay button, Stripe recommends using
1638          // paymentRequest.show() directly instead of also mounting the
1639          // paymentRequestButton Element for the same PaymentRequest instance.
1640          if (prButton && !usingCustomQuickPayButton) {
1641            prButton.mount('#payment-request-button');
1642          }
1643        }
1644
1645        // PayPal owns a cross-origin iframe inside the integrated wallet row.
1646        // Replacing quickPayButton.innerHTML here destroys a ready PayPal
1647        // button and causes a second skeleton. The cart render immediately
1648        // below consumes the settled wallet capability and builds the final
1649        // Apple/Google Pay + PayPal columns without mutating a mounted iframe.
1650        if (
1651          document.querySelector('.quickPayButton') &&
1652          window.PAYPAL_QUICK_PAY_VARIANT_ENABLED !== true
1653        ) {
1654          document
1655            .querySelectorAll('.quickPayButton')
1656            .forEach(function (quickPayEventBuuton) {
1657              var quickPayButtonContent = getQuickPayButton();
1658              quickPayEventBuuton.innerHTML = quickPayButtonContent;
1659            });
1660        }
1661
1662        if (document.querySelector('.eventQuickPayButton')) {
1663          handleEventQuickPay();
1664        } else if (typeof CartViewRender != 'undefined') {
1665          CartViewRender();
1666        }
1667      } else {
1668        markQuickPayUnavailable();
1669      }
1670    })
1671    .catch(function (paymentCapabilityError) {
1672      paymentRequest = undefined;
1673      prButton = undefined;
1674      markQuickPayUnavailable(
1675        paymentCapabilityError,
1676        'capability_check_failed'
1677      );
1678    })
1679    .then(function () {
1680      settleQuickPayCapability();
1681    });
1682
1683  paymentRequest.on('shippingoptionchange', function (event) {
1684  console.log({ event });
1685  window.event = event;
1686  var updateWith = event.updateWith;
1687  var shippingOption = event.shippingOption;
1688  // handle shippingoptionchange event
1689  if (shippingOption && shippingOption.amount != null) {
1690    initialShippingFee = shippingOption.amount;
1691  }
1692
1693  const shippingOptionApprovedAmount = rememberQuickPayApprovedAmount(
1694    getCartTotalAmount()
1695  );
1696  const shippingOptionChangeUpdateData = {
1697    status: 'success',
1698    total: {
1699      amount: shippingOptionApprovedAmount,
1700      label: translateText('Free Instant Digital Gift Card'),
1701    },
1702  };
1703
1704  console.log({ shippingOptionChangeUpdateData });
1705
1706  // call event.updateWith within 30 seconds
1707  updateWith(shippingOptionChangeUpdateData);
1708  console.log('update called');
1709  });
1710
1711  paymentRequest.on('token', async function (tokenEvent) {
1712    // A new wallet authorization gets a new attempt. Any network retry below
1713    // reuses this same ID, token, and payload so Stripe can safely deduplicate it.
1714    var quickPayCheckoutAttemptId = createQuickPayCheckoutAttemptId();
1715    if (!quickPayDebugWalletInteractionId) {
1716      beginQuickPayDebugWalletInteraction();
1717    }
1718    quickPayDebugCheckoutAttemptId = quickPayCheckoutAttemptId;
1719    quickPayDebugActiveWallet = tokenEvent.walletName || window.quickPayMethod;
1720    recordQuickPayDebugStage('token_received');
1721    var quickPayCompletionStatus = null;
1722    function completeQuickPay(status) {
1723      if (quickPayCompletionStatus !== null) {
1724        return;
1725      }
1726
1727      quickPayCompletionStatus = status;
1728      quickPayDebugWalletCompletionStatus = status;
1729      releaseQuickPayPaymentRequest();
1730      if (typeof tokenEvent.complete == 'function') {
1731        tokenEvent.complete(status);
1732      }
1733    }
1734
1735  try {
1736    // Send the token to your server to charge it
1737    if (
1738      typeof window.schNewTicketFlowMarkQuickPaySubmitting == 'function' &&
1739      !window.schNewTicketFlowMarkQuickPaySubmitting()
1740    ) {
1741      completeQuickPay('fail');
1742      var submissionBlockedError = new Error(
1743        'Quickpay submission was blocked before checkout.'
1744      );
1745      var submissionBlockedDebugEvent = sendQuickPayDebugTerminalEvent(
1746        'submission_blocked',
1747        'failed',
1748        submissionBlockedError
1749      );
1750      if (typeof window.schNewTicketFlowSetQuickPayLoading == 'function') {
1751        window.schNewTicketFlowSetQuickPayLoading(false);
1752      }
1753      showQuickPayFailureModal(
1754        'submission_blocked',
1755        submissionBlockedError,
1756        submissionBlockedDebugEvent
1757      );
1758      return;
1759    }
1760
1761    const firstName = (tokenEvent.payerName || '').split(' ')[0];
1762    const lastName = (tokenEvent.payerName || '').split(' ')[0];
1763    const payerEmail = tokenEvent.payerEmail || '';
1764
1765    if (typeof quickPayOverride == 'function') {
1766      return quickPayOverride(tokenEvent);
1767    }
1768
1769    var formData = {
1770      bchName: firstName,
1771      bchLastname: lastName,
1772      bchEmail: payerEmail,
1773      bchSource: getValue('#bchSource'),
1774      bchHostalPromo: getValue('#bchHostalPromo'),
1775      cart_fees: processingFee,
1776      bchTransactionType: 'cart',
1777      bchSubscribe: 'yes',
1778      stripeToken: tokenEvent.token.id,
1779      shippingAmount: getQuickPayPostedShippingAmount(tokenEvent),
1780      shippingService: getQuickPayPostedShippingService(tokenEvent),
1781      is_quick_pay: true,
1782      submission_url: window.location.href,
1783      quick_pay_type: (tokenEvent.walletName ?? '') + '_store_page',
1784      quick_pay_approved_amount: quickPayApprovedAmount,
1785      checkout_attempt_id: quickPayCheckoutAttemptId,
1786      currency_quote_token:
1787        typeof checkoutCurrencyQuoteToken != 'undefined'
1788          ? checkoutCurrencyQuoteToken
1789          : '',
1790      quick_pay_contract_version: 'currency_quote_v1',
1791    };
1792
1793    if (typeof cart != 'undefined') {
1794      cart.cy = cy;
1795      cart.currency = cy;
1796      if (typeof priceCart == 'function') {
1797        cart.total = priceCart('discounted');
1798        cart.regularTotal = priceCart('regular');
1799        cart.fullTotal = priceCart('full');
1800      }
1801      formData.cartOverride = JSON.stringify(cart);
1802    }
1803
1804    formData.chargeShipping = getValue('#shippingCheck1');
1805
1806    if (tokenEvent.shippingAddress) {
1807      // submit form w/address fields
1808
1809      formData.includes_address = true;
1810      formData.address_first_name = firstName;
1811      formData.address_last_name = lastName;
1812      if (tokenEvent.shippingAddress.addressLine) {
1813        formData.address = tokenEvent.shippingAddress.addressLine[0];
1814        formData.address2 = tokenEvent.shippingAddress.addressLine[1];
1815      }
1816      formData.address_city = tokenEvent.shippingAddress.city;
1817      formData.address_state = tokenEvent.shippingAddress.region;
1818      formData.address_zip = tokenEvent.shippingAddress.postalCode;
1819    }
1820    var checkout_url = `/store/api/checkout/send`;
1821
1822    if (window.location.href.includes('app/checkout')) {
1823      checkout_url = `/store/api/app/purchase?testing_website_domain=letsroam`;
1824    }
1825
1826    // birth bach quick pay
1827    if (
1828      document.querySelector('.eventQuickPayButton') ||
1829      typeof eventUUID != 'undefined'
1830    ) {
1831      if (typeof eventUUID != 'undefined') {
1832        formData.uuid = eventUUID;
1833      } else {
1834        const modalForm = document.querySelector('#bday-booking-modal');
1835        const rightForm = document.querySelector('#bday-booking');
1836
1837        const formRoot = isHidden(modalForm) ? rightForm : modalForm;
1838
1839        const locationInput = formRoot.querySelector('#clead_GE');
1840        // if on the city page we want to use that city if they don't change it
1841        const fallbackLocation =
1842          formRoot.querySelector('#fallbackLocation').innerText;
1843
1844        let date_of_event_text = formRoot.querySelector('#date_of_event_text');
1845
1846        if (date_of_event_text) {
1847          date_of_event_text = date_of_event_text.value;
1848        }
1849
1850        groupSize = formRoot.querySelector('#group_size').value || 20;
1851
1852        var eventLocation = locationInput.value || fallbackLocation.trim();
1853        if (eventLocation) {
1854          eventLocation = eventLocation.replace('Search a city', '');
1855        }
1856
1857        const leadData = {
1858          email: payerEmail,
1859          full_name: firstName + ' ' + lastName,
1860          company: firstName + ' Custom Event',
1861          location: eventLocation,
1862          package_type: 'scavenger_hunt',
1863          group_size: groupSize,
1864          city: eventLocation,
1865          category: window.location.href.includes('bach')
1866            ? 'bachelorette'
1867            : 'birthday',
1868          event_date:
1869            date_of_event_text || new Date().toISOString().split('T')[0],
1870          currency: cy,
1871	          cookies: typeof getTrackingCookies === 'function' ? getTrackingCookies() : {},
1872          form_page: 'quick_pay_event_page',
1873          submitting_url: window.location.href,
1874        };
1875
1876        console.log({
1877          leadData,
1878          formRoot,
1879          fallbackLocation,
1880          eventLocation,
1881          groupSize,
1882        });
1883
1884        const newLead = await fetchWithParams(
1885          '/api/your_event/create_lead_endpoint',
1886          leadData,
1887          {},
1888          'POST',
1889          function (error) {
1890            console.log('error', error);
1891          }
1892        );
1893
1894        console.log({ newLead });
1895
1896        if (!newLead || !newLead.company || !newLead.company.UUID) {
1897          completeQuickPay('fail');
1898          var leadCreationError = new Error(
1899            'Quickpay event lead creation failed.'
1900          );
1901          var leadCreationDebugEvent = sendQuickPayDebugTerminalEvent(
1902            'lead_creation_failed',
1903            'failed',
1904            leadCreationError
1905          );
1906          showQuickPayFailureModal(
1907            'lead_creation_failed',
1908            leadCreationError,
1909            leadCreationDebugEvent
1910          );
1911          return;
1912        }
1913
1914        formData.uuid = newLead.company.UUID;
1915      }
1916
1917      checkout_url = '/api/payment/do_corporate_transaction';
1918    }
1919    recordQuickPayDebugStage('checkout_request_started');
1920    console.log('quickPay: submitting checkout', {
1921      checkoutAttemptId: quickPayCheckoutAttemptId,
1922      checkoutUrl: checkout_url,
1923      wallet: normalizeQuickPayDebugWalletName(quickPayDebugActiveWallet),
1924    });
1925    var formattedResponse;
1926    try {
1927      if (!quickPayCheckoutSupportsRecovery(checkout_url)) {
1928        // Preserve the established corporate flow; this card only hardens the
1929        // idempotent store checkout path.
1930        completeQuickPay('success');
1931        formattedResponse = await fetchWithParams(checkout_url, formData);
1932      } else {
1933        formattedResponse = await submitQuickPayCheckout(
1934          checkout_url,
1935          formData,
1936          function (requestUrl, requestData) {
1937            return fetchWithParams(
1938              requestUrl,
1939              requestData,
1940              {},
1941              'POST',
1942              null,
1943              true
1944            );
1945          },
1946          completeQuickPay
1947        );
1948      }
1949    } catch (paymentFetchError) {
1950      console.error('no response', { paymentFetchError });
1951      var checkoutRequestDebugEvent = sendQuickPayDebugTerminalEvent(
1952        'checkout_request_failed',
1953        'failed',
1954        paymentFetchError
1955      );
1956      if (typeof window.schNewTicketFlowSetQuickPayLoading == 'function') {
1957        window.schNewTicketFlowSetQuickPayLoading(false);
1958      }
1959      showQuickPayFailureModal(
1960        'checkout_request_failed',
1961        paymentFetchError,
1962        checkoutRequestDebugEvent
1963      );
1964      return;
1965    }
1966
1967    recordQuickPayDebugStage(
1968      'checkout_response_received',
1969      formattedResponse && formattedResponse.error
1970        ? formattedResponse.error.code || formattedResponse.error.type
1971        : ''
1972    );
1973    if (formattedResponse && formattedResponse.status === true) {
1974      recordQuickPayDebugStage('checkout_succeeded');
1975      clearQuickPayDebugEventForFeedback();
1976      fb_track_safe('CartQuickPay');
1977      setTimeout(function () {
1978        if (formattedResponse.redirect_url) {
1979          window.location.href = base_url(formattedResponse.redirect_url);
1980          return;
1981        }
1982
1983        var tid = formattedResponse.result.tid;
1984        console.log('successful payment');
1985        window.location.href = base_url(`/store/receipt/${tid}?firstLoad=1`);
1986      }, 500);
1987      return;
1988    }
1989
1990    if (
1991      formattedResponse &&
1992      formattedResponse.error &&
1993      formattedResponse.error.code === 'quick_pay_checkout_status_unknown'
1994    ) {
1995      var checkoutStatusUnknownDebugEvent = sendQuickPayDebugTerminalEvent(
1996        'checkout_status_unknown',
1997        'failed',
1998        formattedResponse.error
1999      );
2000      markQuickPayUnavailable(formattedResponse.error);
2001      showQuickPayFailureModal(
2002        'checkout_status_unknown',
2003        formattedResponse.error,
2004        checkoutStatusUnknownDebugEvent
2005      );
2006      return;
2007    }
2008
2009    console.error('no response', { formattedResponse });
2010    var checkoutResponseError =
2011      formattedResponse && formattedResponse.error
2012        ? formattedResponse.error
2013        : new Error('Quickpay checkout returned no usable response.');
2014    var checkoutResponseDebugEvent = sendQuickPayDebugTerminalEvent(
2015      'checkout_response_failed',
2016      'failed',
2017      checkoutResponseError
2018    );
2019    if (typeof window.schNewTicketFlowSetQuickPayLoading == 'function') {
2020      window.schNewTicketFlowSetQuickPayLoading(false);
2021    }
2022    showQuickPayFailureModal(
2023      'checkout_response_failed',
2024      checkoutResponseError,
2025      checkoutResponseDebugEvent
2026    );
2027  } catch (quickPayPostTokenError) {
2028    completeQuickPay('fail');
2029    console.error({ quickPayPostTokenError });
2030    var postTokenDebugEvent = sendQuickPayDebugTerminalEvent(
2031      'post_token_failed',
2032      'failed',
2033      quickPayPostTokenError
2034    );
2035    if (typeof window.schNewTicketFlowSetQuickPayLoading == 'function') {
2036      window.schNewTicketFlowSetQuickPayLoading(false);
2037    }
2038    showQuickPayFailureModal(
2039      'post_token_failed',
2040      quickPayPostTokenError,
2041      postTokenDebugEvent
2042    );
2043  }
2044  });
2045
2046  paymentRequest.on('cancel', function () {
2047    releaseQuickPayPaymentRequest();
2048    if (quickPayDebugWalletCompletionStatus !== null) {
2049      return;
2050    }
2051    if (!quickPayDebugWalletInteractionId) {
2052      beginQuickPayDebugWalletInteraction();
2053    }
2054    var walletCancelledError = new Error('Wallet sheet was cancelled.');
2055    walletCancelledError.name = 'AbortError';
2056    sendQuickPayDebugTerminalEvent(
2057      'wallet_cancelled',
2058      'cancelled',
2059      walletCancelledError
2060    );
2061    if (typeof window.schNewTicketFlowHandleQuickPayCancel == 'function') {
2062      window.schNewTicketFlowHandleQuickPayCancel();
2063    } else if (typeof window.schNewTicketFlowSetQuickPayLoading == 'function') {
2064      window.schNewTicketFlowSetQuickPayLoading(false);
2065    }
2066  });
2067} else {
2068  // PayPal must not remain behind a loading skeleton when Stripe could not
2069  // initialize a PaymentRequest at all.
2070  settleQuickPayCapability();
2071}
2072
2073ready(function () {
2074  console.log('quickPay: ready');
2075  updateQuickPay();
2076});
2077
2078function isHidden(el) {
2079  return el.offsetParent === null;
2080}
2081
2082if (
2083  typeof cart !== 'undefined' &&
2084  cart &&
2085  Array.isArray(cart.items) &&
2086  cart.items.length > 0
2087) {
2088  var quickPayAttempts = 0;
2089  var quickPayInterval = setInterval(function () {
2090    if (typeof updateQuickPay === 'function') {
2091      updateQuickPay();
2092    }
2093
2094    quickPayAttempts++;
2095
2096    if (quickPayAttempts === 3) {
2097      clearInterval(quickPayInterval);
2098    }
2099  }, 3000);
2100}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.