🔀 Merge branch 'trunk'

This commit is contained in:
Philipp Stracker 2024-06-07 12:32:32 +02:00
commit a01f1ea77f
No known key found for this signature in database
12 changed files with 339 additions and 14 deletions

View file

@ -10,7 +10,7 @@
"Edge >= 14"
],
"dependencies": {
"@paypal/react-paypal-js": "^8.2.0",
"@paypal/react-paypal-js": "^8.3.0",
"core-js": "^3.25.0",
"react": "^17.0.0",
"react-dom": "^17.0.0"

View file

@ -0,0 +1,79 @@
import {useEffect, useState} from '@wordpress/element';
import {
PayPalScriptProvider,
PayPalCardFieldsProvider,
PayPalCardFieldsForm,
} from "@paypal/react-paypal-js";
import {CheckoutHandler} from "./checkout-handler";
import {createOrder, onApprove} from "../card-fields-config";
import {cartHasSubscriptionProducts} from "../Helper/Subscription";
export function CardFields({config, eventRegistration, emitResponse, components}) {
const {onPaymentSetup} = eventRegistration;
const {responseTypes} = emitResponse;
const { PaymentMethodIcons } = components;
const [cardFieldsForm, setCardFieldsForm] = useState();
const getCardFieldsForm = (cardFieldsForm) => {
setCardFieldsForm(cardFieldsForm)
}
const getSavePayment = (savePayment) => {
localStorage.setItem('ppcp-save-card-payment', savePayment);
}
const hasSubscriptionProducts = cartHasSubscriptionProducts(config.scriptData);
useEffect(
() =>
onPaymentSetup(() => {
async function handlePaymentProcessing() {
await cardFieldsForm.submit()
.catch((error) => {
return {
type: responseTypes.ERROR,
}
});
return {
type: responseTypes.SUCCESS,
}
}
return handlePaymentProcessing();
}),
[onPaymentSetup, cardFieldsForm]
);
return (
<>
<PayPalScriptProvider
options={{
clientId: config.scriptData.client_id,
components: "card-fields",
dataNamespace: 'ppcp-block-card-fields',
}}
>
<PayPalCardFieldsProvider
createOrder={createOrder}
onApprove={onApprove}
onError={(err) => {
console.error(err);
}}
>
<PayPalCardFieldsForm/>
<PaymentMethodIcons icons={config.card_icons} align="left" />
<CheckoutHandler
getCardFieldsForm={getCardFieldsForm}
getSavePayment={getSavePayment}
hasSubscriptionProducts={hasSubscriptionProducts}
saveCardText={config.save_card_text}
is_vaulting_enabled={config.is_vaulting_enabled}
/>
</PayPalCardFieldsProvider>
</PayPalScriptProvider>
</>
)
}

View file

@ -0,0 +1,28 @@
import {useEffect} from '@wordpress/element';
import {usePayPalCardFields} from "@paypal/react-paypal-js";
export const CheckoutHandler = ({getCardFieldsForm, getSavePayment, hasSubscriptionProducts, saveCardText, is_vaulting_enabled}) => {
const {cardFieldsForm} = usePayPalCardFields();
useEffect(() => {
getCardFieldsForm(cardFieldsForm)
}, []);
if (!is_vaulting_enabled) {
return null;
}
return (
<>
<input
type="checkbox"
id="save"
name="save"
onChange={(e) => getSavePayment(e.target.checked)}
defaultChecked={hasSubscriptionProducts}
disabled={hasSubscriptionProducts}
/>
<label htmlFor="save">{saveCardText}</label>
</>
)
}

View file

@ -0,0 +1,17 @@
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
import {CardFields} from "./Components/card-fields";
const config = wc.wcSettings.getSetting('ppcp-credit-card-gateway_data');
registerPaymentMethod({
name: config.id,
label: <div dangerouslySetInnerHTML={{__html: config.title}}/>,
content: <CardFields config={config}/>,
edit: <div></div>,
ariaLabel: config.title,
canMakePayment: () => {return true},
supports: {
showSavedCards: true,
features: config.supports
}
})

View file

@ -0,0 +1,44 @@
const config = wc.wcSettings.getSetting('ppcp-credit-card-gateway_data');
export async function createOrder() {
return fetch(config.scriptData.ajax.create_order.endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
nonce: config.scriptData.ajax.create_order.nonce,
context: config.scriptData.context,
payment_method: 'ppcp-credit-card-gateway',
save_payment_method: localStorage.getItem('ppcp-save-card-payment') === 'true',
}),
})
.then((response) => response.json())
.then((order) => {
return order.data.id;
})
.catch((err) => {
console.error(err);
});
}
export async function onApprove(data) {
return fetch(config.scriptData.ajax.approve_order.endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
order_id: data.orderID,
nonce: config.scriptData.ajax.approve_order.nonce,
}),
})
.then((response) => response.json())
.then((data) => {
console.log(data)
localStorage.removeItem('ppcp-save-card-payment');
})
.catch((err) => {
console.error(err);
});
}

View file

@ -9,6 +9,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Blocks;
use WooCommerce\PayPalCommerce\Blocks\Endpoint\GetPayPalOrderFromSession;
use WooCommerce\PayPalCommerce\Blocks\Endpoint\UpdateShippingEndpoint;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
@ -45,6 +46,17 @@ return array(
$container->get( 'wcgateway.all-funding-sources' )
);
},
'blocks.advanced-card-method' => static function( ContainerInterface $container ): AdvancedCardPaymentMethod {
return new AdvancedCardPaymentMethod(
$container->get( 'blocks.url' ),
$container->get( 'ppcp.asset-version' ),
$container->get( 'wcgateway.credit-card-gateway' ),
function () use ( $container ): SmartButtonInterface {
return $container->get( 'button.smart-button' );
},
$container->get( 'wcgateway.settings' )
);
},
'blocks.settings.final_review_enabled' => static function ( ContainerInterface $container ): bool {
$settings = $container->get( 'wcgateway.settings' );
assert( $settings instanceof ContainerInterface );

View file

@ -0,0 +1,142 @@
<?php
/**
* Advanced card payment method.
*
* @package WooCommerce\PayPalCommerce\Blocks
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Blocks;
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/**
* Class AdvancedCardPaymentMethod
*/
class AdvancedCardPaymentMethod extends AbstractPaymentMethodType {
/**
* The URL of this module.
*
* @var string
*/
private $module_url;
/**
* The assets version.
*
* @var string
*/
private $version;
/**
* Credit card gateway.
*
* @var CreditCardGateway
*/
private $gateway;
/**
* The smart button script loading handler.
*
* @var SmartButtonInterface|callable
*/
private $smart_button;
/**
* The settings.
*
* @var Settings
*/
protected $settings;
/**
* AdvancedCardPaymentMethod constructor.
*
* @param string $module_url The URL of this module.
* @param string $version The assets version.
* @param CreditCardGateway $gateway Credit card gateway.
* @param SmartButtonInterface|callable $smart_button The smart button script loading handler.
* @param Settings $settings The settings.
*/
public function __construct(
string $module_url,
string $version,
CreditCardGateway $gateway,
$smart_button,
Settings $settings
) {
$this->name = CreditCardGateway::ID;
$this->module_url = $module_url;
$this->version = $version;
$this->gateway = $gateway;
$this->smart_button = $smart_button;
$this->settings = $settings;
}
/**
* {@inheritDoc}
*/
public function initialize() {}
/**
* {@inheritDoc}
*/
public function is_active() {
return true;
}
/**
* {@inheritDoc}
*/
public function get_payment_method_script_handles() {
wp_register_script(
'ppcp-advanced-card-checkout-block',
trailingslashit( $this->module_url ) . 'assets/js/advanced-card-checkout-block.js',
array(),
$this->version,
true
);
return array( 'ppcp-advanced-card-checkout-block' );
}
/**
* {@inheritDoc}
*/
public function get_payment_method_data() {
$script_data = $this->smart_button_instance()->script_data();
return array(
'id' => $this->name,
'title' => $this->gateway->title,
'description' => $this->gateway->description,
'scriptData' => $script_data,
'supports' => $this->gateway->supports,
'save_card_text' => esc_html__( 'Save your card', 'woocommerce-paypal-payments' ),
'is_vaulting_enabled' => $this->settings->has( 'vault_enabled_dcc' ) && $this->settings->get( 'vault_enabled_dcc' ),
'card_icons' => $this->settings->has( 'card_icons' ) ? (array) $this->settings->get( 'card_icons' ) : array(),
);
}
/**
* The smart button.
*
* @return SmartButtonInterface
*/
private function smart_button_instance(): SmartButtonInterface {
if ( $this->smart_button instanceof SmartButtonInterface ) {
return $this->smart_button;
}
if ( is_callable( $this->smart_button ) ) {
$this->smart_button = ( $this->smart_button )();
}
return $this->smart_button;
}
}

View file

@ -61,6 +61,7 @@ class BlocksModule implements ModuleInterface {
'woocommerce_blocks_payment_method_type_registration',
function( PaymentMethodRegistry $payment_method_registry ) use ( $c ): void {
$payment_method_registry->register( $c->get( 'blocks.method' ) );
$payment_method_registry->register( $c->get( 'blocks.advanced-card-method' ) );
}
);

View file

@ -10,6 +10,7 @@ module.exports = {
plugins: [ new DependencyExtractionWebpackPlugin() ],
entry: {
'checkout-block': path.resolve('./resources/js/checkout-block.js'),
'advanced-card-checkout-block': path.resolve('./resources/js/advanced-card-checkout-block.js'),
"gateway": path.resolve('./resources/css/gateway.scss')
},
output: {

View file

@ -1005,19 +1005,19 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"
"@paypal/paypal-js@^8.0.4":
version "8.0.4"
resolved "https://registry.yarnpkg.com/@paypal/paypal-js/-/paypal-js-8.0.4.tgz#abe9f40f519b1d2c306adddfbe733be03eb26ce5"
integrity sha512-91g5fhRBHGEBoikDzQT6uBn3PzlJQ75g0c3MvqVJqN0XRm5kHa9wz+6+Uaq8QQuxRzz5C2x55Zg057CW6EuwpQ==
"@paypal/paypal-js@^8.0.5":
version "8.0.5"
resolved "https://registry.yarnpkg.com/@paypal/paypal-js/-/paypal-js-8.0.5.tgz#77bc461b4d1e5a2c6f081269e3ef0b2e3331a68c"
integrity sha512-yQNV7rOILeaVCNU4aVDRPqEnbIlzfxgQfFsxzsBuZW1ouqRD/4kYBWJDzczCiscSr2xOeA/Pkm7e3a9fRfnuMQ==
dependencies:
promise-polyfill "^8.3.0"
"@paypal/react-paypal-js@^8.2.0":
version "8.2.0"
resolved "https://registry.yarnpkg.com/@paypal/react-paypal-js/-/react-paypal-js-8.2.0.tgz#4b1a142bbb68e62dca4a92da4a6b5568f54901f0"
integrity sha512-SworUfu0BNNcqoh0O53Ke4MFpx2m3qJRu3hayXvlluEEXJpKqGSV5aaSGFhbsZqi8hnbsx/hZR7BQbmqsggiGQ==
"@paypal/react-paypal-js@^8.3.0":
version "8.3.0"
resolved "https://registry.yarnpkg.com/@paypal/react-paypal-js/-/react-paypal-js-8.3.0.tgz#a103080b752766b8ff59b8620887abf802e1a01b"
integrity sha512-SX17d2h1CMNFGI+wtjb329AEDaBR8Ziy2LCV076eDcY1Q0MFKRkfQ/v0HOAvZtk3sJoydRmYez2pq47BRblwqQ==
dependencies:
"@paypal/paypal-js" "^8.0.4"
"@paypal/paypal-js" "^8.0.5"
"@paypal/sdk-constants" "^1.0.122"
"@paypal/sdk-constants@^1.0.122":

View file

@ -1421,7 +1421,7 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
$disable_funding,
array_diff(
array_keys( $this->all_funding_sources ),
array( 'venmo', 'paylater', 'paypal' )
array( 'venmo', 'paylater', 'paypal', 'card' )
)
);
}

View file

@ -105,9 +105,8 @@ class CardFieldsModule implements ModuleInterface {
add_filter(
'ppcp_create_order_request_body_data',
function( array $data ) use ( $c ): array {
function( array $data, string $payment_method ) use ( $c ): array {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$payment_method = wc_clean( wp_unslash( $_POST['payment_method'] ?? '' ) );
if ( $payment_method !== CreditCardGateway::ID ) {
return $data;
}
@ -134,7 +133,9 @@ class CardFieldsModule implements ModuleInterface {
}
return $data;
}
},
10,
2
);
}
}