-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Vitalij Mik
committed
Oct 22, 2024
1 parent
8fa9706
commit 8afe095
Showing
16 changed files
with
132 additions
and
247 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
217 changes: 34 additions & 183 deletions
217
src/Resources/app/storefront/src/mollie-payments/plugins/apple-pay-direct.plugin.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,230 +1,81 @@ | ||
import HttpClient from '../services/HttpClient'; | ||
import Plugin from '../Plugin'; | ||
import ApplePaySessionFactory from '../services/ApplePaySessionFactory'; | ||
import ExpressButtonsRepository from '../repository/ExpressButtonsRepository'; | ||
import BuyElementRepository from '../repository/BuyElementRepository'; | ||
import {MOLLIE_BIND_EXPRESS_EVENTS} from './mollie-express-actions.plugin'; | ||
|
||
export default class MollieApplePayDirect extends Plugin { | ||
|
||
/** | ||
* | ||
* @type {number} | ||
*/ | ||
APPLE_PAY_VERSION = 3; | ||
|
||
|
||
/** | ||
* | ||
*/ | ||
init() { | ||
const me = this; | ||
|
||
me.client = new HttpClient(); | ||
|
||
// register our off-canvas listener | ||
// we need to re-init all apple pay button | ||
// once the offcanvas is loaded (lazy) into the DOM | ||
|
||
const pluginOffCanvasInstances = window.PluginManager.getPluginList().OffCanvasCart.get('instances'); | ||
if (pluginOffCanvasInstances.length > 0) { | ||
const pluginOffCanvas = pluginOffCanvasInstances[0]; | ||
pluginOffCanvas.$emitter.subscribe('offCanvasOpened', me.initCurrentPage.bind(me)); | ||
} | ||
|
||
|
||
const submitForm = document.querySelector('#productDetailPageBuyProductForm'); | ||
|
||
if (submitForm !== null) { | ||
this.checkSubmitButton(submitForm); | ||
submitForm.addEventListener('change', (event) => { | ||
this.checkSubmitButton(event.target.closest('form#productDetailPageBuyProductForm')); | ||
this.initCurrentPage(); | ||
pluginOffCanvasInstances.forEach((pluginOffCanvas) => { | ||
pluginOffCanvas.$emitter.subscribe('offCanvasOpened', this.bindEvents.bind(this)); | ||
}); | ||
} | ||
|
||
// now update our current page | ||
this.initCurrentPage(); | ||
|
||
this.bindEvents(); | ||
} | ||
|
||
|
||
/** | ||
* | ||
*/ | ||
initCurrentPage() { | ||
|
||
const me = this; | ||
|
||
// we might have wrapping containers | ||
// that also need to be hidden -> they might have different margins or other things | ||
const applePayContainers = document.querySelectorAll('.js-apple-pay-container'); | ||
// of course, also grab our real buttons | ||
const applePayButtons = document.querySelectorAll('.js-apple-pay'); | ||
|
||
bindEvents() { | ||
|
||
if (!window.ApplePaySession || !window.ApplePaySession.canMakePayments()) { | ||
// hide our wrapping Apple Pay containers | ||
// to avoid any wrong margins being displayed | ||
|
||
if (applePayContainers) { | ||
applePayContainers.forEach(function (container) { | ||
container.style.display = 'none'; | ||
container.classList.add('d-none'); | ||
}); | ||
} | ||
return; | ||
} | ||
const expressButtonsRepository = new ExpressButtonsRepository(); | ||
const expressButtons = expressButtonsRepository.findAll('.js-apple-pay'); | ||
const applePayContainers = document.querySelectorAll('.js-apple-pay-container'); | ||
|
||
|
||
if (applePayButtons.length <= 0) { | ||
if (expressButtons.length === 0 && applePayContainers.length === 0) { | ||
return; | ||
} | ||
|
||
// we start by fetching the shop url from the data attribute. | ||
// we need this as prefix for our ajax calls, so that we always | ||
// call the correct sales channel and its controllers. | ||
|
||
const shopUrl = me.getShopUrl(applePayButtons[0]); | ||
|
||
|
||
// verify if apple pay is even allowed | ||
// in our current sales channel | ||
me.client.get( | ||
shopUrl + '/mollie/apple-pay/available', | ||
data => { | ||
if (data.available === undefined || data.available === false) { | ||
return; | ||
} | ||
|
||
applePayContainers.forEach(function (container) { | ||
container.classList.remove('d-none'); | ||
}); | ||
|
||
applePayButtons.forEach(function (button) { | ||
|
||
if (button.hasAttribute('disabled')) { | ||
button.classList.add('d-none'); | ||
button.removeEventListener('click', me.onButtonClick); | ||
return; | ||
} | ||
// Remove display none | ||
button.classList.remove('d-none'); | ||
// remove previous handlers (just in case) | ||
button.removeEventListener('click', me.onButtonClick); | ||
// add click event handlers | ||
button.addEventListener('click', me.onButtonClick); | ||
}); | ||
} | ||
); | ||
} | ||
document.dispatchEvent(new CustomEvent(MOLLIE_BIND_EXPRESS_EVENTS, {detail: expressButtons})); | ||
|
||
checkSubmitButton(form) { | ||
const buyButton = form.querySelector('.btn-buy'); | ||
applePayContainers.forEach((container) => { | ||
container.classList.remove('d-none'); | ||
}) | ||
|
||
if (buyButton === null) { | ||
return; | ||
} | ||
expressButtons.forEach((button) => { | ||
button.classList.remove('d-none'); | ||
button.addEventListener('click', this.onExpressCheckout) | ||
}); | ||
} | ||
|
||
const expressButtons = form.querySelectorAll('.mollie-express-button'); | ||
onExpressCheckout(event) { | ||
const clickedButton = event.target; | ||
|
||
if (expressButtons.length === 0) { | ||
if (!clickedButton.classList.contains('processed')) { | ||
return; | ||
} | ||
|
||
expressButtons.each(function(expressButton){ | ||
if (expressButton.hasAttribute('disabled')) { | ||
expressButton.removeAttribute('disabled'); | ||
} | ||
if (buyButton.hasAttribute('disabled')) { | ||
expressButton.setAttribute('disabled', 'disabled'); | ||
} | ||
}) | ||
} | ||
|
||
/** | ||
* | ||
* @param event | ||
*/ | ||
onButtonClick(event) { | ||
|
||
event.preventDefault(); | ||
const buyElementRepository = new BuyElementRepository(); | ||
const buyElement = buyElementRepository.find(clickedButton); | ||
|
||
const button = event.target; | ||
const form = button.parentNode; | ||
|
||
// get sales channel base URL | ||
// so that our shop slug is correctly | ||
let shopSlug = button.getAttribute('data-shop-url'); | ||
|
||
// remove trailing slash if existing | ||
if (shopSlug.substr(-1) === '/') { | ||
shopSlug = shopSlug.substr(0, shopSlug.length - 1); | ||
} | ||
|
||
const countryCode = form.querySelector('input[name="countryCode"]').value; | ||
const currency = form.querySelector('input[name="currency"]').value; | ||
const mode = form.querySelector('input[name="mode"]').value; | ||
const withPhone = parseInt(form.querySelector('input[name="withPhone"]').value); | ||
const dataProtection = form.querySelector('input[name="acceptedDataProtection"]'); | ||
const countryCode = buyElement.querySelector('input[name="countryCode"]').value; | ||
const currency = buyElement.querySelector('input[name="currency"]').value; | ||
const mode = buyElement.querySelector('input[name="mode"]').value; | ||
const withPhone = parseInt(buyElement.querySelector('input[name="withPhone"]').value); | ||
const dataProtection = buyElement.querySelector('input[name="acceptedDataProtection"]'); | ||
const isProductMode = mode === 'productMode'; | ||
|
||
form.classList.remove('was-validated'); | ||
let shopSlug = clickedButton.getAttribute('data-shop-url'); | ||
|
||
if (dataProtection !== null) { | ||
const dataProtectionValue = dataProtection.checked ? 1: 0; | ||
form.classList.add('was-validated'); | ||
|
||
dataProtection.classList.remove('is-invalid'); | ||
if (dataProtectionValue === 0) { | ||
dataProtection.classList.add('is-invalid'); | ||
return; | ||
} | ||
if (shopSlug.slice(-1) === '/') { | ||
shopSlug = shopSlug.slice(0, -1); | ||
} | ||
|
||
// this helps us to figure out if we are in | ||
// "product" mode to purchase a single product, or in "cart" mode | ||
// to just purchase the current cart with Apple Pay Direct. | ||
const isProductMode = (mode === 'productMode'); | ||
|
||
if (isProductMode) { | ||
|
||
let productForm = document.querySelector('#productDetailPageBuyProductForm'); | ||
if (productForm === null) { | ||
productForm = button.closest('.product-box').querySelector('form'); | ||
} | ||
|
||
|
||
const formData = new FormData(productForm); | ||
formData.delete('redirectTo'); | ||
formData.append('isExpressCheckout', '1'); | ||
|
||
|
||
fetch(productForm.action, { | ||
method: productForm.method, | ||
body: formData, | ||
}); | ||
|
||
|
||
} | ||
const applePaySessionFactory = new ApplePaySessionFactory(); | ||
const session = applePaySessionFactory.create(isProductMode, countryCode, currency, withPhone, shopSlug, dataProtection); | ||
session.begin(); | ||
|
||
} | ||
|
||
/** | ||
* | ||
* @param button | ||
* @returns string | ||
*/ | ||
getShopUrl(button) { | ||
// get sales channel base URL | ||
// so that our shop slug is correctly | ||
let shopSlug = button.getAttribute('data-shop-url'); | ||
|
||
// remove trailing slash if existing | ||
if (shopSlug.substr(-1) === '/') { | ||
shopSlug = shopSlug.substr(0, shopSlug.length - 1); | ||
} | ||
|
||
return shopSlug; | ||
} | ||
|
||
} |
Oops, something went wrong.