Skip to content

Commit

Permalink
Adding payment methods logo on checkout pages
Browse files Browse the repository at this point in the history
  • Loading branch information
bbool authored and Matt75 committed Feb 12, 2024
1 parent 3bd431a commit 0ec7109
Show file tree
Hide file tree
Showing 15 changed files with 269 additions and 297 deletions.
128 changes: 128 additions & 0 deletions _dev/js/front/src/components/common/payment-method-logos.component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* @author PrestaShop SA <[email protected]>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
import { BaseComponent } from '../../core/dependency-injection/base.component';

/**
* @typedef PaymentFieldsComponentProps
*
* @param {string} fundingSource.name
* @param {*} fundingSource.mark
*
* @param {HTMLElement} HTMLElement
*/

export class PaymentMethodLogosComponent extends BaseComponent {
static Inject = {
config: 'PsCheckoutConfig',
payPalService: 'PayPalService',
querySelectorService: 'QuerySelectorService',
prestashopService: 'PrestashopService',
$: '$'
};

created() {
this.data.HTMLElement = this.props.HTMLElement;
}

render() {
this.renderMark();

this.prestashopService.onUpdatedCart(() => {
return this.renderMark();
});

this.prestashopService.onUpdatedProduct(() => {
return this.renderMark();
});

return this;
}

renderMark() {
let containerLogoIdentifier = `#ps_checkout-payment-method-logos-container`;
const containerLogoQuerySelector = this.querySelectorService.getPaymentMethodLogoContainer(this.props.placement);
const fundingSources = this.payPalService.getEligibleFundingSources();

if (containerLogoQuerySelector) {
const containerLogo = document.querySelector(containerLogoIdentifier);

if (null === containerLogo) {
let containerLogoElement = this.createContainer(containerLogoIdentifier, containerLogoQuerySelector);

fundingSources.forEach(fundingSource => {
if (this.hasCustomMark(fundingSource.name)) {
this.renderCustomMark(fundingSource.name, containerLogoElement);
} else {
fundingSource.mark.render(containerLogoElement);
}
});
}
}
}

createContainer(containerIdentifier, querySelector) {
const container = document.querySelector(containerIdentifier);

if (null === container) {
let containerParentElement = document.createElement('div');
containerParentElement.id = 'ps_checkout-payment-method-logo-block-container';

let titleImg = document.createElement('img');
titleImg.id = 'ps_checkout-payment-method-logo-block-img';
titleImg.setAttribute('alt', this.$('payment-method-logos.title'));
titleImg.setAttribute('src', this.config.imgTitlePaymentMethodLogos);

let title = document.createElement('div');
title.id = 'ps_checkout-payment-method-logo-block-title';
title.innerText = this.$('payment-method-logos.title');
title.prepend(titleImg);
containerParentElement.append(title);

let containerLogoElement = document.createElement('div');
containerLogoElement.id = containerIdentifier.slice(1);

containerParentElement.append(containerLogoElement);

querySelector.append(containerParentElement);

return containerLogoElement;
}

return container;
}

hasCustomMark(fundingSource) {
return this.config.customMark[fundingSource];
}

renderCustomMark(fundingSource, containerQuerySelector) {
const src = this.config.customMark[fundingSource];

let containerElement = document.createElement('div');
containerElement.classList.add('paypal-mark');

let customMarkImg = document.createElement('img');
customMarkImg.classList.add('cards-logo');
customMarkImg.setAttribute('alt', fundingSource);
customMarkImg.setAttribute('src', src);
containerElement.append(customMarkImg);

containerQuerySelector.append(containerElement);
}
}
4 changes: 3 additions & 1 deletion _dev/js/front/src/config/ps-checkout.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,7 @@ export const PsCheckoutConfig = {

fundingSourcesSorted: window.ps_checkoutFundingSourcesSorted,

orderId: window.ps_checkoutPayPalOrderId
orderId: window.ps_checkoutPayPalOrderId,
imgTitlePaymentMethodLogos: window.ps_checkoutPaymentMethodLogosTitleImg,
renderPaymentMethodLogos: window.ps_checkoutRenderPaymentMethodLogos
};
25 changes: 25 additions & 0 deletions _dev/js/front/src/core/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { PaymentOptionsLoaderComponent } from '../components/common/payment-opti
import { PayLaterMessageComponent } from '../components/ps-checkout-pay-later-message.component';
import { PayLaterBannerComponent } from '../components/ps-checkout-pay-later-banner.component';
import { loadScript } from '@paypal/paypal-js';
import { PaymentMethodLogosComponent } from '../components/common/payment-method-logos.component';

function initService(app) {
return (service) => () => new service(app);
Expand Down Expand Up @@ -120,6 +121,11 @@ export class App {
new PayLaterBannerComponent(this, props).render();
}

async renderPaymentMethodLogos(props) {
await this.initPayPalService();
new PaymentMethodLogosComponent(this, props).render();
}

async render() {
this.exposeAPI();

Expand Down Expand Up @@ -186,6 +192,25 @@ export class App {
});
}

// Funding source logo
if (
this.psCheckoutConfig.renderPaymentMethodLogos &&
this.prestashopService.isProductPage()
) {
await this.renderPaymentMethodLogos({
placement: 'product'
});
}

if (
this.psCheckoutConfig.renderPaymentMethodLogos &&
this.prestashopService.isCartPage()
) {
await this.renderPaymentMethodLogos({
placement: 'cart'
});
}

if (
this.prestashopService.isCartPage() ||
this.prestashopService.isOrderPersonalInformationStepPage() ||
Expand Down
37 changes: 22 additions & 15 deletions _dev/js/front/src/service/paypal.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@
* @property {function} onApply
*/

/**
* @typedef PaypalMarks
* @type {*}
*
* @property {function} isEligible
* @property {function} render
*/

import { BaseClass } from '../core/dependency-injection/base.class';

/**
Expand Down Expand Up @@ -379,11 +387,7 @@ export class PayPalService extends BaseClass {
this.configPrestaShop.hostedFieldsEnabled &&
!this.isCardFieldsEligible()
) {
console.log(
this.configPrestaShop.hostedFieldsEnabled,
this.isCardFieldsEligible()
);
console.error(
console.warn(
'Card Fields (CCF) eligibility is declined. Switching to PayPal branded card fields (SCF)'
);
}
Expand All @@ -397,7 +401,7 @@ export class PayPalService extends BaseClass {
}

isFundingEligible(fundingSource) {
return this.getEligibleFundingSources(true).contains(fundingSource);
return this.getEligibleFundingSources().contains(fundingSource);
}

isHostedFieldsEligible() {
Expand Down Expand Up @@ -465,15 +469,11 @@ export class PayPalService extends BaseClass {
* @param {object} fields
*/
getPaymentFields(fundingSource, fields = {}) {
console.log(this.sdk.PaymentFields);
return (
this.sdk.PaymentFields &&
this.sdk.PaymentFields({
fundingSource: fundingSource,
style: this.getPaymentFieldsCustomizationStyle(fundingSource),
fields: fields
})
);
return this.sdk.PaymentFields && this.sdk.PaymentFields({
fundingSource: fundingSource,
style: this.getPaymentFieldsCustomizationStyle(fundingSource),
fields: fields
});
}

/**
Expand All @@ -487,4 +487,11 @@ export class PayPalService extends BaseClass {
...(window.ps_checkout.paymentFieldsCustomization || {})
};
}

/**
* @returns {PaypalMarks}
*/
getMarks() {
return this.sdk.Marks && this.sdk.Marks();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,8 @@ export const DefaultSelectors1_6 = {
VENDOR_ERROR: '#ps_checkout-card-fields-card-vendor-error',
EXPIRY_ERROR: '#ps_checkout-card-fields-card-expiry-error',
CVV_ERROR: '#ps_checkout-card-fields-card-cvv-error',
}
},

PAYMENT_METHOD_LOGO_PRODUCT_CONTAINER: 'body.product .box-cart-bottom .buttons_bottom_block',
PAYMENT_METHOD_LOGO_CART_CONTAINER: 'body.order .cart_navigation_extra'
};
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,8 @@ export const DefaultSelectors1_7 = {
VENDOR_ERROR: '#ps_checkout-card-fields-vendor-error',
EXPIRY_ERROR: '#ps_checkout-card-fields-expiry-error',
CVV_ERROR: '#ps_checkout-card-fields-cvv-error',
}
},

PAYMENT_METHOD_LOGO_PRODUCT_CONTAINER: '#product .product-add-to-cart',
PAYMENT_METHOD_LOGO_CART_CONTAINER: '#cart .cart-summary .cart-detailed-actions'
};
4 changes: 4 additions & 0 deletions _dev/js/front/src/service/query-selector.service/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,8 @@ export class QuerySelectorService extends BaseClass {
getCardFieldsCvvError() {
return this.instance.getCardFieldsCvvError();
}

getPaymentMethodLogoContainer(placement) {
return this.instance.getPaymentMethodLogoContainer(placement);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,15 @@ export class QuerySelectorPs1_6Service {

return elements;
}

static getPaymentMethodLogoContainer(placement) {
switch (placement) {
case 'product':
return document.querySelector(SELECTORS.PAYMENT_METHOD_LOGO_PRODUCT_CONTAINER);
case 'cart':
return document.querySelector(SELECTORS.PAYMENT_METHOD_LOGO_CART_CONTAINER);
default:
return;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,15 @@ export class QuerySelectorPs1_7Service {

return elements;
}

static getPaymentMethodLogoContainer(placement) {
switch (placement) {
case 'product':
return document.querySelector(SELECTORS.PAYMENT_METHOD_LOGO_PRODUCT_CONTAINER);
case 'cart':
return document.querySelector(SELECTORS.PAYMENT_METHOD_LOGO_CART_CONTAINER);
default:
return;
}
}
}
Loading

0 comments on commit 0ec7109

Please sign in to comment.