Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
279 changes: 147 additions & 132 deletions assets/shop/controllers/apple-pay_controller.js
Original file line number Diff line number Diff line change
@@ -1,166 +1,181 @@
import { Controller } from '@hotwired/stimulus';
import $ from 'jquery';

/* stimulusFetch: 'lazy' */
export default class extends Controller {
connect() {
this.applePayHandler();
static values = {
paymentInputId: String,
settings: Object,
notice: String,
}
showApplePayButton() {
const applePayButton = $(document).find("apple-pay-button");
if (applePayButton.length) {
applePayButton.addClass('enabled');

connect() {
this.applePayButton = this.element.querySelector('apple-pay-button');
this.onApplePayButtonClick = this.onApplePayButtonClick.bind(this);

if (this.applePayButton) {
this.applePayButton.addEventListener('click', this.onApplePayButtonClick);
}

this.retryCount = 0;
this.initApplePay();
}
hideApplePayButton() {
const applePayButton = $(document).find("apple-pay-button.enabled");
if (applePayButton.length) {
applePayButton.removeClass('enabled');

initApplePay() {
if (typeof window.ApplePaySession !== 'undefined') {
this.checkSupport();
return;
}

if (this.retryCount < 20) { // Try for 2 seconds
this.retryCount++;
setTimeout(() => this.initApplePay(), 100);
} else {
this.disablePaymentMethod();
}
}
applePayHandler() {
const applePayChoice = $(".payment-item .checkbox-applepay input:radio");
if (applePayChoice) {
if (applePayChoice.is(':checked')) {
this.disableNextStepButton();
this.showApplePayButton();

checkSupport() {
try {
const isSupported = window.ApplePaySession.canMakePayments();

if (isSupported && this.applePayButton) {
this.applePayButton.classList.add('enabled');
} else {
this.enableNextStepButton();
this.hideApplePayButton();
this.disablePaymentMethod();
}
} catch (e) {
this.disablePaymentMethod();
}
$(".payment-item .checkbox input:radio").on('change', this.onPaymentMethodChoice);
$(document).find("apple-pay-button").on('click', this.onApplePayButtonClick);
}
onPaymentMethodChoice(event) {
const isApplePay = $(event.currentTarget).closest('.checkbox-applepay').length;
if (isApplePay) {
this.showApplePayButton();
this.disableNextStepButton();
} else {
this.hideApplePayButton();
this.enableNextStepButton();

disablePaymentMethod() {
if (!this.paymentInputIdValue) return;

const input = document.getElementById(this.paymentInputIdValue);
if (!input) return;

const container = input.closest('.card, .item, .form-check, .field');
if (container) {
container.style.opacity = '0.5';
container.style.pointerEvents = 'none';
container.classList.add('apple-pay-ineligible');

// Add a small info message if not already present
if (!container.querySelector('.apple-pay-notice')) {
const notice = document.createElement('div');
notice.className = 'apple-pay-notice small text-muted mt-2';
notice.style.padding = '0 1rem 1rem';
notice.innerText = this.noticeValue || 'Apple Pay is not available on this browser or device.';
container.appendChild(notice);
}

if (input.checked) {
input.checked = false;
input.dispatchEvent(new Event('change', { bubbles: true }));
}
}

input.disabled = true;

if (this.element) {
this.element.style.display = 'none';
}
}
onApplePayButtonClick(event) {
const applePayButton = $(event.currentTarget);

if (applePaySessionRequestSettings === undefined) {
async onApplePayButtonClick(event) {
const applePayButton = event.currentTarget;

if (!this.settingsValue) {
console.error('Invalid Apple Pay settings!');
return false;
return;
}

// Create ApplePaySession
const session = new ApplePaySession(3, applePaySessionRequestSettings);
if (typeof window.ApplePaySession === 'undefined') {
return;
}

session.onvalidatemerchant = async event => {
$.ajax({
url: applePayButton.data('validate-merchant-route'),
method: 'POST',
cache: false,
data: {},
success: (authorization) => {
let result = authorization.merchant_session;
console.log(result);
// Prepare settings
const settings = { ...this.settingsValue };
if (settings.applePayDomain) {
settings.applicationData = btoa(JSON.stringify({
'apple_pay_domain': settings.applePayDomain
}));
delete settings.applePayDomain;
}

try {
const version = window.ApplePaySession.supportsVersion(14) ? 14 : 3;
const session = new window.ApplePaySession(version, settings);

session.onvalidatemerchant = async (event) => {
try {
const response = await fetch(applePayButton.dataset.validateMerchantRoute, {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
});
const authorization = await response.json();

if (authorization.success === true) {
console.log(authorization.merchant_session);
session.completeMerchantValidation(result);
session.completeMerchantValidation(authorization.merchant_session);
} else {
session.abort();
}
},
error: (XHR, status, error) => {
console.log(XHR, status, error);
} catch (error) {
console.error(error);
session.abort();
window.location.reload();
},
});
};

session.onpaymentauthorized = event => {
$.ajax({
url: applePayButton.data('payment-authorized-route'),
method: 'POST',
cache: false,
data: {
token: event.payment.token
},
success: (authorization) => {
try {
var apple_pay_Session_status = ApplePaySession.STATUS_SUCCESS;

console.log(authorization);
console.log(authorization.data.responseToApple.status);
if (authorization.data.responseToApple.status != 1) {
apple_pay_Session_status = ApplePaySession.STATUS_FAILURE;
}

const result = {
"status": apple_pay_Session_status
};

console.log(apple_pay_Session_status);
console.log(result);

session.completePayment(result);

console.log(authorization.data.returnUrl);
window.location.href = authorization.data.returnUrl;
} catch (err) {
console.error(err);
window.location.reload();
}
};

session.onpaymentauthorized = async (event) => {
try {
const response = await fetch(applePayButton.dataset.paymentAuthorizedRoute, {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json',
},
body: JSON.stringify({
token: event.payment.token,
}),
});
const authorization = await response.json();

let applePaySessionStatus = window.ApplePaySession.STATUS_SUCCESS;

if (authorization.data.responseToApple.status !== 1) {
applePaySessionStatus = window.ApplePaySession.STATUS_FAILURE;
}
},
error: (XHR, status, error) => {
console.log(XHR, status, error);
session.abort();

session.completePayment({ "status": applePaySessionStatus });
window.location.href = authorization.data.returnUrl;
} catch (error) {
console.error(error);
window.location.reload();
},
});
};

session.oncancel = event => {
console.log('Cancelling Apple Pay session!');

$.ajax({
url: applePayButton.data('session-cancel-route'),
cache: false,
method: 'POST',
data: {},
success: (authorization) => {
console.log('Cancelled!');
console.log(authorization.data.returnUrl);
}
};

session.oncancel = async (event) => {
try {
const response = await fetch(applePayButton.dataset.sessionCancelRoute, {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
});
const authorization = await response.json();
window.location.href = authorization.data.returnUrl;
},
error: (XHR, status, error) => {
console.log(XHR, status, error);
} catch (error) {
console.error(error);
window.location.reload();
},
});
};
}
};

session.begin();
}
disableNextStepButton() {
const nextStepButton = $('form[name*="checkout_select_payment"] [data-test-next-step]');
nextStepButton.replaceWith(
$("<span/>", {
id: 'next-step',
class: 'btn btn-primary btn-icon',
html: nextStepButton.html()
})
);
}
enableNextStepButton() {
const nextStepButton = $('form[name*="checkout_select_payment"] [data-test-next-step]');
nextStepButton.replaceWith(
$("<button/>", {
type: 'submit',
id: 'next-step',
class: 'btn btn-primary btn-icon',
html: nextStepButton.html()
})
);
session.begin();
} catch (e) {
console.error('Failed to create Apple Pay session:', e);
}
}
}
Loading
Loading