init hosted fields functionality

This commit is contained in:
David Remer 2020-04-30 15:28:48 +03:00
parent 1225ad83c8
commit 23dd407fc8
21 changed files with 212 additions and 45 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,11 +1,13 @@
import MiniCartBootstap from './modules/MiniCartBootstap';
import SingleProductBootstap from './modules/SingleProductBootstap';
import CartBootstrap from './modules/CartBootstap';
import CheckoutBootstap from './modules/CheckoutBootstap';
import Renderer from './modules/Renderer';
import MiniCartBootstap from './modules/ContextBootstrap/MiniCartBootstap';
import SingleProductBootstap from './modules/ContextBootstrap/SingleProductBootstap';
import CartBootstrap from './modules/ContextBootstrap/CartBootstap';
import CheckoutBootstap from './modules/ContextBootstrap/CheckoutBootstap';
import Renderer from './modules/Renderer/Renderer';
import CreditCardRenderer from "./modules/Renderer/CreditCardRenderer";
const bootstrap = () => {
const renderer = new Renderer(PayPalCommerceGateway);
const creditCardRenderer = new CreditCardRenderer(PayPalCommerceGateway);
const renderer = new Renderer(creditCardRenderer, PayPalCommerceGateway);
const context = PayPalCommerceGateway.context;
if (context === 'mini-cart' || context === 'product') {
@ -55,6 +57,11 @@ document.addEventListener(
const script = document.createElement('script');
script.setAttribute('src', PayPalCommerceGateway.button.url);
Object.entries(PayPalCommerceGateway.script_attributes).forEach(
(keyValue) => {
script.setAttribute(keyValue[0], keyValue[1]);
}
);
script.addEventListener('load', (event) => {
bootstrap();
});

View file

@ -1,5 +1,5 @@
import onApprove from './onApproveForContinue.js';
import {payerData} from "./Payer";
import onApprove from '../OnApproveHandler/onApproveForContinue.js';
import {payerData} from "../Helper/PayerData";
class CartActionHandler {

View file

@ -1,5 +1,5 @@
import onApprove from './onApproveForPayNow.js';
import {payerData} from "./Payer";
import onApprove from '../OnApproveHandler/onApproveForPayNow.js';
import {payerData} from "../Helper/PayerData";
class CheckoutActionHandler {

View file

@ -1,7 +1,7 @@
import ButtonsToggleListener from './ButtonsToggleListener';
import Product from './Product';
import onApprove from './onApproveForContinue';
import {payerData} from "./Payer";
import ButtonsToggleListener from '../Helper/ButtonsToggleListener';
import Product from '../Entity/Product';
import onApprove from '../OnApproveHandler/onApproveForContinue';
import {payerData} from "../Helper/PayerData";
class SingleProductActionHandler {

View file

@ -1,5 +1,5 @@
import CartActionHandler from './CartActionHandler';
import ErrorHandler from './ErrorHandler';
import CartActionHandler from '../ActionHandler/CartActionHandler';
import ErrorHandler from '../ErrorHandler';
class CartBootstrap {
constructor(gateway, renderer) {
@ -31,6 +31,7 @@ class CartBootstrap {
this.renderer.render(
this.gateway.button.wrapper,
this.gateway.hosted_fields.wrapper,
actionHandler.configuration(),
);
}

View file

@ -1,5 +1,5 @@
import ErrorHandler from './ErrorHandler';
import CheckoutActionHandler from './CheckoutActionHandler';
import ErrorHandler from '../ErrorHandler';
import CheckoutActionHandler from '../ActionHandler/CheckoutActionHandler';
class CheckoutBootstap {
constructor(gateway, renderer) {
@ -22,6 +22,7 @@ class CheckoutBootstap {
on('updated_checkout payment_method_selected', () => {
this.switchBetweenPayPalandOrderButton();
});
this.switchBetweenPayPalandOrderButton();
}
shouldRender() {
@ -40,6 +41,7 @@ class CheckoutBootstap {
this.renderer.render(
this.gateway.button.wrapper,
this.gateway.hosted_fields.wrapper,
actionHandler.configuration(),
);
}
@ -50,10 +52,12 @@ class CheckoutBootstap {
if (currentPaymentMethod !== 'ppcp-gateway') {
this.renderer.hideButtons(this.gateway.button.wrapper);
this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
jQuery('#place_order').show();
}
else {
this.renderer.showButtons(this.gateway.button.wrapper);
this.renderer.showButtons(this.gateway.hosted_fields.wrapper);
jQuery('#place_order').hide();
}
}

View file

@ -1,5 +1,5 @@
import ErrorHandler from './ErrorHandler';
import CartActionHandler from './CartActionHandler';
import ErrorHandler from '../ErrorHandler';
import CartActionHandler from '../ActionHandler/CartActionHandler';
class MiniCartBootstap {
constructor(gateway, renderer) {
@ -32,6 +32,7 @@ class MiniCartBootstap {
this.renderer.render(
this.gateway.button.mini_cart_wrapper,
null,
actionHandler.configuration()
);
}

View file

@ -1,6 +1,6 @@
import ErrorHandler from './ErrorHandler';
import UpdateCart from './UpdateCart';
import SingleProductActionHandler from './SingleProductActionHandler';
import ErrorHandler from '../ErrorHandler';
import UpdateCart from "../Helper/UpdateCart";
import SingleProductActionHandler from "../ActionHandler/SingleProductActionHandler";
class SingleProductBootstap {
constructor(gateway, renderer) {
@ -43,6 +43,7 @@ class SingleProductBootstap {
this.renderer.render(
this.gateway.button.wrapper,
this.gateway.hosted_fields.wrapper,
actionHandler.configuration(),
);
}

View file

@ -1,4 +1,4 @@
import Product from "./Product";
import Product from "../Entity/Product";
class UpdateCart {
constructor(endpoint, nonce)

View file

@ -0,0 +1,49 @@
class CreditCardRenderer {
constructor(defaultConfig) {
this.defaultConfig = defaultConfig;
}
render(wrapper, contextConfig) {
if (
wrapper === null
|| typeof paypal.HostedFields === 'undefined'
|| ! paypal.HostedFields.isEligible()
|| document.querySelector(wrapper) === null
) {
return;
}
//ToDo: Styles
paypal.HostedFields.render({
createOrder: contextConfig.createOrder,
fields: {
number: {
selector: '#ppcp-credit-card',
placeholder: this.defaultConfig.hosted_fields.labels.credit_card_number,
},
cvv: {
selector: '#ppcp-cvv',
placeholder: this.defaultConfig.hosted_fields.labels.cvv,
},
expirationDate: {
selector: '#ppcp-expiration-date',
placeholder: this.defaultConfig.hosted_fields.labels.mm_yyyy,
}
}
}).then(hostedFields => {
document.querySelector(wrapper).addEventListener(
'submit',
event => {
event.preventDefault();
hostedFields.submit().then(payload => {
payload.orderID = payload.orderId;
return contextConfig.onApprove(payload);
});
}
);
});
}
}
export default CreditCardRenderer;

View file

@ -1,9 +1,10 @@
class Renderer {
constructor(defaultConfig) {
constructor(creditCardRenderer, defaultConfig) {
this.defaultConfig = defaultConfig;
this.creditCardRenderer = creditCardRenderer;
}
render(wrapper, contextConfig) {
render(wrapper, hostedFieldsWrapper, contextConfig) {
if (this.isAlreadyRendered(wrapper)) {
return;
}
@ -13,7 +14,9 @@ class Renderer {
style,
...contextConfig,
}).render(wrapper);
}
this.creditCardRenderer.render(hostedFieldsWrapper, contextConfig);
}
isAlreadyRendered(wrapper) {
return document.querySelector(wrapper).hasChildNodes();

View file

@ -16,17 +16,21 @@ use Inpsyde\PayPalCommerce\Button\Exception\RuntimeException;
return [
'button.smart-button' => static function (ContainerInterface $container): SmartButtonInterface {
$settings = $container->get('wcgateway.settings');
$payeeRepository = $container->get('api.repository.payee');
if (wc_string_to_bool($settings->get('enabled'))) {
return new SmartButton(
$container->get('button.url'),
$container->get('session.handler'),
$settings,
$payeeRepository
);
if (! wc_string_to_bool($settings->get('enabled'))) {
return new DisabledSmartButton();
}
return new DisabledSmartButton();
$payeeRepository = $container->get('api.repository.payee');
$identityToken = $container->get('api.endpoint.identity-token');
return new SmartButton(
$container->get('button.url'),
$container->get('session.handler'),
$settings,
$payeeRepository,
$identityToken
);
},
'button.url' => static function (ContainerInterface $container): string {
return plugins_url(

View file

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\Button\Assets;
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\IdentityToken;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Repository\PayeeRepository;
use Inpsyde\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
@ -17,24 +19,39 @@ class SmartButton implements SmartButtonInterface
private $sessionHandler;
private $settings;
private $payeeRepository;
private $identityToken;
public function __construct(
string $moduleUrl,
SessionHandler $sessionHandler,
Settings $settings,
PayeeRepository $payeeRepository
PayeeRepository $payeeRepository,
IdentityToken $identityToken
) {
$this->moduleUrl = $moduleUrl;
$this->sessionHandler = $sessionHandler;
$this->settings = $settings;
$this->payeeRepository = $payeeRepository;
$this->identityToken = $identityToken;
}
public function renderWrapper(): bool
{
$renderer = static function () {
$hostedFieldsEnabled = $this->dccIsEnabled();
$renderer = static function () use ($hostedFieldsEnabled) {
echo '<div id="ppc-button"></div>';
if (! $hostedFieldsEnabled) {
return;
}
printf(
'<form id="ppc-hosted-fields"><label for="ppcp-credit-card">%s</label><div id="ppcp-credit-card"></div><label for="ppcp-expiration-date">%s</label><div id="ppcp-expiration-date"></div><label for="ppcp-cvv">%s</label><div id="ppcp-cvv"></div><button>%s</button></form>',
__('Card number', 'woocommerce-paypal-commerce-gateway'),
__('Expiration Date', 'woocommerce-paypal-commerce-gateway'),
__('CVV', 'woocommerce-paypal-commerce-gateway'),
__('Pay with Card', 'woocommerce-paypal-commerce-gateway')
);
};
if (is_cart() && wc_string_to_bool($this->settings->get('button_cart_enabled'))) {
add_action(
@ -88,6 +105,7 @@ class SmartButton implements SmartButtonInterface
private function localizeScript(): array
{
$localize = [
'script_attributes' => $this->attributes(),
'redirect' => wc_get_checkout_url(),
'context' => $this->context(),
'ajax' => [
@ -117,6 +135,14 @@ class SmartButton implements SmartButtonInterface
'label' => 'paypal',
],
],
'hosted_fields' => [
'wrapper' => '#ppc-hosted-fields',
'labels' => [
'credit_card_number' => __('Credit Card Number', 'woocommerce-paypal-commerce-gateway'),
'cvv' => __('CVV', 'woocommerce-paypal-commerce-gateway'),
'mm_yyyy' => __('MM/YYYY', 'woocommerce-paypal-commerce-gateway'),
],
],
];
return $localize;
}
@ -155,18 +181,21 @@ class SmartButton implements SmartButtonInterface
{
$params = [
//ToDo: Add the correct client id, toggle when settings is set to sandbox
'client-id' => 'AcVzowpNCpTxFzLG7onQI4JD0sVcA0BkZv-D42qRZPv_gZ8cNfX9zGL_8bXmSu7cbJ5B2DH7sot8vDpw',
'client-id' => 'AQB97CzMsd58-It1vxbcDAGvMuXNCXRD9le_XUaMlHB_U7XsU9IiItBwGQOtZv9sEeD6xs2vlIrL4NiD',
'currency' => get_woocommerce_currency(),
'locale' => get_user_locale(),
//'debug' => (defined('WP_DEBUG') && WP_DEBUG) ? 'true' : 'false',
//ToDo: Update date on releases.
'integration-date' => date('Y-m-d'),
'components' => 'marks,buttons',
'components' => implode(',', $this->components()),
//ToDo: Probably only needed, when DCC
'vault' => 'false',
'vault' => $this->dccIsEnabled() ? 'false' : 'false',
'commit' => is_checkout() ? 'true' : 'false',
'intent' => $this->settings->get('intent'),
];
if (defined('WP_DEBUG') && \WP_DEBUG && WC()->customer) {
$params['buyer-country'] = WC()->customer->get_billing_country();
}
$payee = $this->payeeRepository->payee();
if ($payee->merchantId()) {
$params['merchant-id'] = $payee->merchantId();
@ -179,6 +208,28 @@ class SmartButton implements SmartButtonInterface
return $smartButtonUrl;
}
private function attributes() : array {
$attributes = [
//'data-partner-attribution-id' => '',
];
try {
$clientToken = $this->identityToken->generate();
$attributes['data-client-token'] = $clientToken->token();
return $attributes;
} catch (RuntimeException $exception) {
return $attributes;
}
}
private function components() : array
{
$components = ['buttons'];
if ($this->dccIsEnabled()) {
$components[] = 'hosted-fields';
}
return $components;
}
private function context(): string
{
$context = 'mini-cart';
@ -193,4 +244,9 @@ class SmartButton implements SmartButtonInterface
}
return $context;
}
private function dccIsEnabled() : bool
{
return wc_string_to_bool($this->settings->get('enable_dcc'));
}
}

View file

@ -14,10 +14,11 @@ class SettingsFields
$this->gateway(),
$this->account(),
$this->buttons(),
$this->creditCards(),
);
}
protected function gateway(): array
private function gateway(): array
{
return [
'enabled' => [
@ -91,7 +92,7 @@ class SettingsFields
{
return [
'button_settings' => [
'title' => __('Button Settings', 'woocommerce-paypal-gateway'),
'title' => __('SmartButton Settings', 'woocommerce-paypal-gateway'),
'type' => 'title',
'description' => __(
'Customize the appearance of PayPal Payments on your site.',
@ -174,4 +175,44 @@ class SettingsFields
],
];
}
private function creditCards() : array {
return [
'credit_card_settings' => [
'title' => __('Credit Card Settings', 'woocommerce-paypal-gateway'),
'type' => 'title',
'description' => __(
'Customize the appearance of Credit Card Payments on your site.',
'woocommerce-paypal-gateway'
),
],
'enable_dcc' => [
'title' => __('Enable credit card payment', 'woocommerce-paypal-gateway'),
'type' => 'checkbox',
'label' => __('Enable credit card payments.', 'woocommerce-paypal-gateway'),
'default' => 'yes',
],
'disable_cards' => [
'title' => __('Disable specific credid cards', 'woocommerce-paypal-gateway'),
'type' => 'multiselect',
'class' => 'wc-enhanced-select',
'default' => [],
'desc_tip' => true,
'description' => __(
'By default all possible credit cards will be shown. You can disable some cards, if you wish.',
'woocommerce-paypal-gateway'
),
'options' => [
'visa' => _x('Visa', 'Name of credit card', 'woocommerce-paypal-gateway'),
'mastercard' => _x('Mastercard', 'Name of credit card', 'woocommerce-paypal-gateway'),
'amex' => _x('American Express', 'Name of credit card', 'woocommerce-paypal-gateway'),
'discover' => _x('Discover', 'Name of credit card', 'woocommerce-paypal-gateway'),
'jcb' => _x('JCB', 'Name of credit card', 'woocommerce-paypal-gateway'),
'elo' => _x('Elo', 'Name of credit card', 'woocommerce-paypal-gateway'),
'hiper' => _x('Hiper', 'Name of credit card', 'woocommerce-paypal-gateway'),
],
],
];
}
}