mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 13:44:42 +08:00
Add express checkout block (wip)
This commit is contained in:
parent
0bf18d67c5
commit
ea3e5bbeb6
22 changed files with 3199 additions and 25 deletions
84
modules/ppcp-blocks/resources/js/Helper/Address.js
Normal file
84
modules/ppcp-blocks/resources/js/Helper/Address.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* @param {String} fullName
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const splitFullName = (fullName) => {
|
||||
fullName = fullName.trim()
|
||||
if (!fullName.includes(' ')) {
|
||||
return [fullName, ''];
|
||||
}
|
||||
const parts = fullName.split(' ');
|
||||
const firstName = parts[0];
|
||||
parts.shift();
|
||||
const lastName = parts.join(' ');
|
||||
return [firstName, lastName];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} address
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const paypalAddressToWc = (address) => {
|
||||
const map = {
|
||||
country_code: 'country',
|
||||
address_line_1: 'address_1',
|
||||
address_line_2: 'address_2',
|
||||
admin_area_1: 'state',
|
||||
admin_area_2: 'city',
|
||||
postal_code: 'postcode',
|
||||
};
|
||||
const result = {};
|
||||
Object.entries(map).forEach(([paypalKey, wcKey]) => {
|
||||
if (address[paypalKey]) {
|
||||
result[wcKey] = address[paypalKey];
|
||||
}
|
||||
})
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} shipping
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const paypalShippingToWc = (shipping) => {
|
||||
const [firstName, lastName] = splitFullName(shipping.name.full_name);
|
||||
return {
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
...paypalAddressToWc(shipping.address),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} payer
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const paypalPayerToWc = (payer) => {
|
||||
const firstName = payer.name.given_name;
|
||||
const lastName = payer.name.surname;
|
||||
const address = payer.address ? paypalAddressToWc(payer.address) : {};
|
||||
return {
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
email: payer.email_address,
|
||||
...address,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} order
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const paypalOrderToWcShippingAddress = (order) => {
|
||||
const res = paypalShippingToWc(order.purchase_units[0].shipping);
|
||||
|
||||
// use the name from billing if the same, to avoid possible mistakes when splitting full_name
|
||||
const billingAddress = paypalPayerToWc(order.payer);
|
||||
if (`${res.first_name} ${res.last_name}` === `${billingAddress.first_name} ${billingAddress.last_name}`) {
|
||||
res.first_name = billingAddress.first_name;
|
||||
res.last_name = billingAddress.last_name;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
151
modules/ppcp-blocks/resources/js/checkout-block.js
Normal file
151
modules/ppcp-blocks/resources/js/checkout-block.js
Normal file
|
@ -0,0 +1,151 @@
|
|||
import {useEffect, useState} from '@wordpress/element';
|
||||
import {registerExpressPaymentMethod} from '@woocommerce/blocks-registry';
|
||||
import {PayPalScriptProvider, PayPalButtons} from "@paypal/react-paypal-js";
|
||||
import {paypalOrderToWcShippingAddress, paypalPayerToWc} from "./Helper/Address";
|
||||
|
||||
const config = wc.wcSettings.getSetting('ppcp-gateway_data');
|
||||
|
||||
const PayPalComponent = ({
|
||||
onClick,
|
||||
onClose,
|
||||
onSubmit,
|
||||
eventRegistration,
|
||||
emitResponse,
|
||||
setExpressPaymentError,
|
||||
}) => {
|
||||
const {onPaymentProcessing} = eventRegistration;
|
||||
const {responseTypes} = emitResponse;
|
||||
|
||||
const [paypalOrder, setPaypalOrder] = useState(null);
|
||||
|
||||
const createOrder = async () => {
|
||||
try {
|
||||
const res = await fetch(config.scriptData.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: config.scriptData.ajax.create_order.nonce,
|
||||
bn_code: '',
|
||||
context: 'express',
|
||||
order_id: config.scriptData.order_id,
|
||||
payment_method: 'ppcp-gateway',
|
||||
funding_source: 'paypal',
|
||||
createaccount: false
|
||||
}),
|
||||
});
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if (!json.success) {
|
||||
if (json.data?.details?.length > 0) {
|
||||
throw new Error(json.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'));
|
||||
} else if (json.data?.message) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
|
||||
throw new Error(config.scriptData.labels.error.generic);
|
||||
}
|
||||
return json.data.id;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
setExpressPaymentError(err.message);
|
||||
|
||||
onClose();
|
||||
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const handleApprove = async (data, actions) => {
|
||||
try {
|
||||
const res = await fetch(config.scriptData.ajax.approve_order.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: config.scriptData.ajax.approve_order.nonce,
|
||||
order_id: data.orderID,
|
||||
//funding_source: ,
|
||||
})
|
||||
});
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if (!json.success) {
|
||||
if (typeof actions !== 'undefined' && typeof actions.restart !== 'undefined') {
|
||||
return actions.restart();
|
||||
}
|
||||
if (json.data?.message) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
|
||||
throw new Error(config.scriptData.labels.error.generic)
|
||||
}
|
||||
|
||||
setPaypalOrder(json.data);
|
||||
|
||||
onSubmit();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
setExpressPaymentError(err.message);
|
||||
|
||||
onClose();
|
||||
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
setExpressPaymentError('');
|
||||
|
||||
onClick();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeProcessing = onPaymentProcessing(() => {
|
||||
const shippingAddress = paypalOrderToWcShippingAddress(paypalOrder);
|
||||
const billingAddress = paypalPayerToWc(paypalOrder.payer);
|
||||
|
||||
return {
|
||||
type: responseTypes.SUCCESS,
|
||||
meta: {
|
||||
paymentMethodData: {
|
||||
'paypal_order_id': paypalOrder.id,
|
||||
},
|
||||
shippingData: {address: shippingAddress},
|
||||
billingAddress,
|
||||
billingData: billingAddress,
|
||||
},
|
||||
};
|
||||
});
|
||||
return () => {
|
||||
unsubscribeProcessing();
|
||||
};
|
||||
}, [onPaymentProcessing, paypalOrder]);
|
||||
|
||||
return (
|
||||
<PayPalScriptProvider options={config.scriptData.url_params}>
|
||||
<PayPalButtons
|
||||
style={config.scriptData.button.style}
|
||||
onClick={handleClick}
|
||||
onCancel={onClose}
|
||||
onError={onClose}
|
||||
createOrder={createOrder}
|
||||
onApprove={handleApprove}
|
||||
/>
|
||||
</PayPalScriptProvider>
|
||||
);
|
||||
}
|
||||
|
||||
registerExpressPaymentMethod({
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={{__html: config.title}}/>,
|
||||
content: <PayPalComponent/>,
|
||||
edit: <b>TODO: editing</b>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => true,
|
||||
supports: {
|
||||
features: ['products'],
|
||||
},
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue