Merge pull request #1900 from woocommerce/PCP-2177-uniform-smart-button-display-for-pay-pal-google-pay-and-apple-pay

Uniform Smart Button Display for PayPal, Google Pay, and Apple Pay (2177)
This commit is contained in:
Emili Castells 2023-12-14 09:56:11 +01:00 committed by GitHub
commit ea23d09010
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 251 additions and 104 deletions

View file

@ -1,58 +1,44 @@
#applepay-container, .ppcp-button-applepay { .ppcp-button-applepay {
// Should replicate apm-button.scss sizes.
--apple-pay-button-height: 45px; --apple-pay-button-height: 45px;
--apple-pay-button-min-height: 40px; --apple-pay-button-min-height: 35px;
--apple-pay-button-width: 100%; --apple-pay-button-width: 100%;
--apple-pay-button-max-width: 750px; --apple-pay-button-max-width: 750px;
--apple-pay-button-border-radius: 4px; --apple-pay-button-border-radius: 4px;
--apple-pay-button-overflow: hidden; --apple-pay-button-overflow: hidden;
margin:7px 0;
.ppcp-width-min & {
--apple-pay-button-height: 35px;
}
.ppcp-width-300 & {
--apple-pay-button-height: 45px;
}
.ppcp-width-500 & {
--apple-pay-button-height: 55px;
}
&.ppcp-button-pill { &.ppcp-button-pill {
--apple-pay-button-border-radius: 50px; --apple-pay-button-border-radius: 50px;
} }
&.ppcp-button-minicart { &.ppcp-button-minicart {
--apple-pay-button-display: block; --apple-pay-button-display: block;
--apple-pay-button-height: 40px;
} }
} }
.woocommerce-checkout { .wp-block-woocommerce-checkout, .wp-block-woocommerce-cart {
#applepay-container, .ppcp-button-applepay { .ppcp-button-applepay {
margin-top: 0; --apple-pay-button-margin: 0;
--apple-pay-button-border-radius: 4px;
--apple-pay-button-height: 45px;
&.ppcp-button-pill {
--apple-pay-button-border-radius: 50px;
}
}
}
.ppcp-has-applepay-block { apple-pay-button {
min-width: 0;
.wp-block-woocommerce-checkout { width: 100%;
#applepay-container, .ppcp-button-applepay { --apple-pay-button-width-default: 100%;
margin: 0;
--apple-pay-button-margin: 0;
--apple-pay-button-height: 48px;
&.ppcp-button-pill {
--apple-pay-button-border-radius: 50px;
}
}
}
.wp-block-woocommerce-cart {
#applepay-container, .ppcp-button-applepay {
margin: 0;
--apple-pay-button-margin: 0;
--apple-pay-button-height: 48px;
} }
} }
} }
.wp-admin { .wp-admin {
.ppcp-button-applepay {
pointer-events: none;
}
&.ppcp-non-ios-device { &.ppcp-non-ios-device {
.ppcp-button-applepay { .ppcp-button-applepay {
apple-pay-button { apple-pay-button {

View file

@ -5,10 +5,13 @@ import {setEnabled} from '../../../ppcp-button/resources/js/modules/Helper/Butto
import FormValidator from "../../../ppcp-button/resources/js/modules/Helper/FormValidator"; import FormValidator from "../../../ppcp-button/resources/js/modules/Helper/FormValidator";
import ErrorHandler from '../../../ppcp-button/resources/js/modules/ErrorHandler'; import ErrorHandler from '../../../ppcp-button/resources/js/modules/ErrorHandler';
import widgetBuilder from "../../../ppcp-button/resources/js/modules/Renderer/WidgetBuilder"; import widgetBuilder from "../../../ppcp-button/resources/js/modules/Renderer/WidgetBuilder";
import {apmButtonsInit} from "../../../ppcp-button/resources/js/modules/Helper/ApmButtons";
class ApplepayButton { class ApplepayButton {
constructor(context, externalHandler, buttonConfig, ppcpConfig) { constructor(context, externalHandler, buttonConfig, ppcpConfig) {
apmButtonsInit();
this.isInitialized = false; this.isInitialized = false;
this.context = context; this.context = context;
@ -60,7 +63,7 @@ class ApplepayButton {
this.initEventHandlers(); this.initEventHandlers();
this.isInitialized = true; this.isInitialized = true;
this.applePayConfig = config; this.applePayConfig = config;
const isEligible = this.applePayConfig.isEligible; const isEligible = (this.applePayConfig.isEligible && window.ApplePaySession) || this.buttonConfig.is_admin;
if (isEligible) { if (isEligible) {
this.fetchTransactionInfo().then(() => { this.fetchTransactionInfo().then(() => {
@ -84,6 +87,10 @@ class ApplepayButton {
}); });
} }
}); });
} else {
jQuery('#' + this.buttonConfig.button.wrapper).hide();
jQuery('#' + this.buttonConfig.button.mini_cart_wrapper).hide();
jQuery('#express-payment-method-ppcp-applepay').hide();
} }
} }
@ -179,13 +186,13 @@ class ApplepayButton {
appleContainer.innerHTML = `<apple-pay-button id="${id}" buttonstyle="${color}" type="${type}" locale="${language}">`; appleContainer.innerHTML = `<apple-pay-button id="${id}" buttonstyle="${color}" type="${type}" locale="${language}">`;
} }
jQuery('#' + wrapper).addClass('ppcp-button-' + ppcpStyle.shape); const $wrapper = jQuery('#' + wrapper);
$wrapper.addClass('ppcp-button-' + ppcpStyle.shape);
if (ppcpStyle.height) { if (ppcpStyle.height) {
jQuery('#' + wrapper).css('--apple-pay-button-height', `${ppcpStyle.height}px`) $wrapper.css('--apple-pay-button-height', `${ppcpStyle.height}px`)
$wrapper.css('height', `${ppcpStyle.height}px`)
} }
jQuery(wrapper).append(appleContainer);
} }
//------------------------ //------------------------

View file

@ -65,7 +65,7 @@ import widgetBuilder from "../../../ppcp-button/resources/js/modules/Renderer/Wi
buttonConfig.button.wrapper = selector.replace('#', ''); buttonConfig.button.wrapper = selector.replace('#', '');
applyConfigOptions(buttonConfig); applyConfigOptions(buttonConfig);
const wrapperElement = `<div id="${selector.replace('#', '')}" class="ppcp-button-applepay"></div>`; const wrapperElement = `<div id="${selector.replace('#', '')}" class="ppcp-button-apm ppcp-button-applepay"></div>`;
if (!jQuery(selector).length) { if (!jQuery(selector).length) {
jQuery(ppcpConfig.button.wrapper).after(wrapperElement); jQuery(ppcpConfig.button.wrapper).after(wrapperElement);

View file

@ -23,12 +23,6 @@ const ApplePayComponent = () => {
const manager = new ApplepayManager(buttonConfig, ppcpConfig); const manager = new ApplepayManager(buttonConfig, ppcpConfig);
manager.init(); manager.init();
}; };
useEffect(() => {
const bodyClass = 'ppcp-has-applepay-block';
if (!document.body.classList.contains(bodyClass)) {
document.body.classList.add(bodyClass);
}
}, []);
useEffect(() => { useEffect(() => {
// Load ApplePay SDK // Load ApplePay SDK
@ -50,7 +44,7 @@ const ApplePayComponent = () => {
}, [paypalLoaded, applePayLoaded]); }, [paypalLoaded, applePayLoaded]);
return ( return (
<div id={buttonConfig.button.wrapper.replace('#', '')}></div> <div id={buttonConfig.button.wrapper.replace('#', '')} className="ppcp-button-apm ppcp-button-applepay"></div>
); );
} }

View file

@ -968,7 +968,7 @@ class ApplePayButton implements ButtonInterface {
add_action( add_action(
$render_placeholder, $render_placeholder,
function () { function () {
echo '<span id="applepay-container-minicart" class="ppcp-button-applepay ppcp-button-minicart"></span>'; echo '<span id="applepay-container-minicart" class="ppcp-button-apm ppcp-button-applepay ppcp-button-minicart"></span>';
}, },
21 21
); );
@ -981,7 +981,7 @@ class ApplePayButton implements ButtonInterface {
*/ */
protected function applepay_button(): void { protected function applepay_button(): void {
?> ?>
<div id="applepay-container"> <div id="applepay-container" class="ppcp-button-apm ppcp-button-applepay">
<?php wp_nonce_field( 'woocommerce-process_checkout', 'woocommerce-process-checkout-nonce' ); ?> <?php wp_nonce_field( 'woocommerce-process_checkout', 'woocommerce-process-checkout-nonce' ); ?>
</div> </div>
<?php <?php

View file

@ -149,6 +149,7 @@ class DataToAppleButtonScripts {
return array( return array(
'sdk_url' => $this->sdk_url, 'sdk_url' => $this->sdk_url,
'is_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG ? true : false, 'is_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG ? true : false,
'is_admin' => false,
'preferences' => array( 'preferences' => array(
'checkout_data_mode' => $checkout_data_mode, 'checkout_data_mode' => $checkout_data_mode,
), ),
@ -204,6 +205,7 @@ class DataToAppleButtonScripts {
return array( return array(
'sdk_url' => $this->sdk_url, 'sdk_url' => $this->sdk_url,
'is_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG ? true : false, 'is_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG ? true : false,
'is_admin' => false,
'preferences' => array( 'preferences' => array(
'checkout_data_mode' => $checkout_data_mode, 'checkout_data_mode' => $checkout_data_mode,
), ),
@ -252,6 +254,7 @@ class DataToAppleButtonScripts {
return array( return array(
'sdk_url' => $this->sdk_url, 'sdk_url' => $this->sdk_url,
'is_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG ? true : false, 'is_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG ? true : false,
'is_admin' => true,
'preferences' => array( 'preferences' => array(
'checkout_data_mode' => $checkout_data_mode, 'checkout_data_mode' => $checkout_data_mode,
), ),

View file

@ -0,0 +1,15 @@
@use "../../../ppcp-button/resources/css/mixins/apm-button" as apm-button;
li[id^="express-payment-method-ppcp-"] {
line-height: 0;
// Set min-width to 0 as the buttons need to fit in a tight grid.
.paypal-buttons {
min-width: 0 !important;
}
}
.ppcp-button-apm {
@include apm-button.button;
}

View file

@ -88,6 +88,28 @@ class BlocksModule implements ModuleInterface {
$endpoint->handle_request(); $endpoint->handle_request();
} }
); );
// Enqueue frontend scripts.
add_action(
'wp_enqueue_scripts',
static function () use ( $c ) {
if ( ! has_block( 'woocommerce/checkout' ) && ! has_block( 'woocommerce/cart' ) ) {
return;
}
$module_url = $c->get( 'blocks.url' );
$asset_version = $c->get( 'ppcp.asset-version' );
wp_register_style(
'wc-ppcp-blocks',
untrailingslashit( $module_url ) . '/assets/css/gateway.css',
array(),
$asset_version
);
wp_enqueue_style( 'wc-ppcp-blocks' );
}
);
} }
/** /**

View file

@ -9,7 +9,8 @@ module.exports = {
target: 'web', target: 'web',
plugins: [ new DependencyExtractionWebpackPlugin() ], plugins: [ new DependencyExtractionWebpackPlugin() ],
entry: { entry: {
'checkout-block': path.resolve('./resources/js/checkout-block.js') 'checkout-block': path.resolve('./resources/js/checkout-block.js'),
"gateway": path.resolve('./resources/css/gateway.scss')
}, },
output: { output: {
path: path.resolve(__dirname, 'assets/'), path: path.resolve(__dirname, 'assets/'),

View file

@ -1,3 +1,5 @@
@use "mixins/apm-button" as apm-button;
#place_order.ppcp-hidden { #place_order.ppcp-hidden {
display: none !important; display: none !important;
} }
@ -15,3 +17,17 @@
.ppc-button-wrapper #ppcp-messages:first-child { .ppc-button-wrapper #ppcp-messages:first-child {
padding-top: 10px; padding-top: 10px;
} }
// Prevents spacing after button group.
#ppc-button-ppcp-gateway {
line-height: 0;
}
#ppc-button-minicart {
line-height: 0;
display: block;
}
.ppcp-button-apm {
@include apm-button.button;
}

View file

@ -0,0 +1,42 @@
@mixin button {
overflow: hidden;
min-width: 0;
max-width: 750px;
line-height: 0;
border-radius: 4px;
// Defaults
height: 45px;
margin-top: 14px;
&.ppcp-button-pill {
border-radius: 50px;
}
&.ppcp-button-minicart {
display: block;
}
.ppcp-width-min & {
height: 35px;
}
.ppcp-width-300 & {
height: 45px;
}
.ppcp-width-500 & {
height: 55px;
}
// No margin on block layout.
.wp-block-woocommerce-checkout &, .wp-block-woocommerce-cart & {
margin: 0;
min-width: 0;
}
.wp-admin & {
pointer-events: none;
}
}

View file

@ -0,0 +1,94 @@
export const apmButtonsInit = (selector = '.ppcp-button-apm') => {
if (window.ppcpApmButtons) {
return;
}
window.ppcpApmButtons = new ApmButtons(selector);
}
export class ApmButtons {
constructor(selector) {
this.selector = selector;
this.containers = [];
// Reloads button containers.
this.reloadContainers();
// Refresh button layout.
jQuery(window).resize(() => {
this.refresh();
}).resize();
// Observes for new buttons.
(new MutationObserver(this.observeElementsCallback.bind(this)))
.observe(document.body, { childList: true, subtree: true });
}
observeElementsCallback(mutationsList, observer) {
const observeSelector = this.selector + ', .widget_shopping_cart, .widget_shopping_cart_content';
let shouldReload = false;
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.matches && node.matches(observeSelector)) {
shouldReload = true;
}
});
}
}
if (shouldReload) {
this.reloadContainers();
this.refresh();
}
};
reloadContainers() {
jQuery(this.selector).each((index, el) => {
const parent = jQuery(el).parent();
if (!this.containers.some($el => $el.is(parent))) {
this.containers.push(parent);
}
});
console.log('this.containers', this.containers);
}
refresh() {
for (const container of this.containers) {
const $container = jQuery(container);
// Check width and add classes
const width = $container.width();
$container.removeClass('ppcp-width-500 ppcp-width-300 ppcp-width-min');
if (width >= 500) {
$container.addClass('ppcp-width-500');
} else if (width >= 300) {
$container.addClass('ppcp-width-300');
} else {
$container.addClass('ppcp-width-min');
}
// Check first apm button
const $firstElement = $container.children(':visible').first();
// Assign margins to buttons
$container.find(this.selector).each((index, el) => {
const $el = jQuery(el);
if ($el.is($firstElement)) {
$el.css('margin-top', `0px`);
return true;
}
const height = $el.height();
$el.css('margin-top', `${Math.round(height * 0.3)}px`);
});
}
}
}

View file

@ -1,45 +1,9 @@
.ppcp-button-googlepay { .ppcp-button-googlepay {
margin: 7px 0;
overflow: hidden;
min-height: 40px; min-height: 40px;
height: 45px;
&.ppcp-button-pill {
border-radius: 50px;
}
&.ppcp-button-minicart {
display: block;
height: 40px;
}
} }
.woocommerce-checkout { .wp-block-woocommerce-checkout, .wp-block-woocommerce-cart {
.ppcp-button-googlepay { .gpay-button {
margin-top: 0; min-width: 0 !important;
}
}
.ppcp-has-googlepay-block {
.wp-block-woocommerce-checkout {
.ppcp-button-googlepay {
margin: 0;
height: 48px;
}
}
.wp-block-woocommerce-cart {
.ppcp-button-googlepay {
margin: 0;
height: 48px;
}
}
}
.wp-admin {
.ppcp-button-googlepay {
pointer-events: none;
} }
} }

View file

@ -3,10 +3,13 @@ import {setVisible} from '../../../ppcp-button/resources/js/modules/Helper/Hidin
import {setEnabled} from '../../../ppcp-button/resources/js/modules/Helper/ButtonDisabler'; import {setEnabled} from '../../../ppcp-button/resources/js/modules/Helper/ButtonDisabler';
import widgetBuilder from "../../../ppcp-button/resources/js/modules/Renderer/WidgetBuilder"; import widgetBuilder from "../../../ppcp-button/resources/js/modules/Renderer/WidgetBuilder";
import UpdatePaymentData from "./Helper/UpdatePaymentData"; import UpdatePaymentData from "./Helper/UpdatePaymentData";
import {apmButtonsInit} from "../../../ppcp-button/resources/js/modules/Helper/ApmButtons";
class GooglepayButton { class GooglepayButton {
constructor(context, externalHandler, buttonConfig, ppcpConfig) { constructor(context, externalHandler, buttonConfig, ppcpConfig) {
apmButtonsInit();
this.isInitialized = false; this.isInitialized = false;
this.context = context; this.context = context;

View file

@ -67,7 +67,7 @@ import widgetBuilder from "../../../ppcp-button/resources/js/modules/Renderer/Wi
buttonConfig.button.wrapper = selector; buttonConfig.button.wrapper = selector;
applyConfigOptions(buttonConfig); applyConfigOptions(buttonConfig);
const wrapperElement = `<div id="${selector.replace('#', '')}" class="ppcp-button-googlepay"></div>`; const wrapperElement = `<div id="${selector.replace('#', '')}" class="ppcp-button-apm ppcp-button-googlepay"></div>`;
if (!jQuery(selector).length) { if (!jQuery(selector).length) {
jQuery(ppcpConfig.button.wrapper).after(wrapperElement); jQuery(ppcpConfig.button.wrapper).after(wrapperElement);

View file

@ -24,13 +24,6 @@ const GooglePayComponent = () => {
manager.init(); manager.init();
}; };
useEffect(() => {
const bodyClass = 'ppcp-has-googlepay-block';
if (!document.body.classList.contains(bodyClass)) {
document.body.classList.add(bodyClass);
}
}, []);
useEffect(() => { useEffect(() => {
// Load GooglePay SDK // Load GooglePay SDK
loadCustomScript({ url: buttonConfig.sdk_url }).then(() => { loadCustomScript({ url: buttonConfig.sdk_url }).then(() => {
@ -51,7 +44,7 @@ const GooglePayComponent = () => {
}, [paypalLoaded, googlePayLoaded]); }, [paypalLoaded, googlePayLoaded]);
return ( return (
<div id={buttonConfig.button.wrapper.replace('#', '')} className="ppcp-button-googlepay"></div> <div id={buttonConfig.button.wrapper.replace('#', '')} className="ppcp-button-apm ppcp-button-googlepay"></div>
); );
} }

View file

@ -311,7 +311,7 @@ class Button implements ButtonInterface {
add_action( add_action(
$render_placeholder, $render_placeholder,
function () { function () {
echo '<span id="ppc-button-googlepay-container-minicart" class="ppcp-button-googlepay ppcp-button-minicart"></span>'; echo '<span id="ppc-button-googlepay-container-minicart" class="ppcp-button-apm ppcp-button-googlepay ppcp-button-minicart"></span>';
}, },
21 21
); );
@ -325,7 +325,7 @@ class Button implements ButtonInterface {
*/ */
private function googlepay_button(): void { private function googlepay_button(): void {
?> ?>
<div id="ppc-button-googlepay-container" class="ppcp-button-googlepay"> <div id="ppc-button-googlepay-container" class="ppcp-button-apm ppcp-button-googlepay">
<?php wp_nonce_field( 'woocommerce-process_checkout', 'woocommerce-process-checkout-nonce' ); ?> <?php wp_nonce_field( 'woocommerce-process_checkout', 'woocommerce-process-checkout-nonce' ); ?>
</div> </div>
<?php <?php

View file

@ -1,3 +1,4 @@
@use "../../../ppcp-button/resources/css/mixins/apm-button" as apm-button;
.ppcp-field-hidden { .ppcp-field-hidden {
display: none !important; display: none !important;
@ -15,3 +16,12 @@
padding-left: 20px; padding-left: 20px;
} }
} }
// Prevents spacing after button group.
.ppcp-button-preview-inner {
line-height: 0;
}
.ppcp-button-apm {
@include apm-button.button;
}

View file

@ -15,9 +15,6 @@ document.addEventListener(
jQuery( '*[data-ppcp-display]' ).each( (index, el) => { jQuery( '*[data-ppcp-display]' ).each( (index, el) => {
const rules = jQuery(el).data('ppcpDisplay'); const rules = jQuery(el).data('ppcpDisplay');
// console.log('rules', rules);
for (const rule of rules) { for (const rule of rules) {
displayManager.addRule(rule); displayManager.addRule(rule);
} }