2022-12-20 16:04:11 +02:00
|
|
|
import {useEffect, useState} from '@wordpress/element';
|
2023-04-07 15:58:59 +03:00
|
|
|
import {registerExpressPaymentMethod, registerPaymentMethod} from '@woocommerce/blocks-registry';
|
2023-04-27 09:06:38 +03:00
|
|
|
import {paypalAddressToWc, paypalOrderToWcAddresses} from "./Helper/Address";
|
2023-03-24 10:11:53 +02:00
|
|
|
import {loadPaypalScript} from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading'
|
2023-08-28 17:19:07 +01:00
|
|
|
import buttonModuleWatcher from "../../../ppcp-button/resources/js/modules/ButtonModuleWatcher";
|
2023-10-24 10:22:55 +03:00
|
|
|
import merge from "deepmerge";
|
2022-12-20 16:04:11 +02:00
|
|
|
|
|
|
|
const config = wc.wcSettings.getSetting('ppcp-gateway_data');
|
|
|
|
|
2023-04-21 11:12:32 +03:00
|
|
|
window.ppcpFundingSource = config.fundingSource;
|
|
|
|
|
2022-12-20 16:04:11 +02:00
|
|
|
const PayPalComponent = ({
|
|
|
|
onClick,
|
|
|
|
onClose,
|
|
|
|
onSubmit,
|
2023-03-23 15:54:24 +02:00
|
|
|
onError,
|
2022-12-20 16:04:11 +02:00
|
|
|
eventRegistration,
|
|
|
|
emitResponse,
|
2023-03-27 10:59:08 +03:00
|
|
|
activePaymentMethod,
|
2023-04-25 15:06:24 +03:00
|
|
|
shippingData,
|
2023-07-11 09:15:36 +03:00
|
|
|
isEditing,
|
2022-12-20 16:04:11 +02:00
|
|
|
}) => {
|
2023-10-19 15:55:57 +03:00
|
|
|
const {onPaymentSetup, onCheckoutFail, onCheckoutValidation} = eventRegistration;
|
2022-12-20 16:04:11 +02:00
|
|
|
const {responseTypes} = emitResponse;
|
|
|
|
|
|
|
|
const [paypalOrder, setPaypalOrder] = useState(null);
|
|
|
|
|
2023-10-23 20:59:49 +03:00
|
|
|
useEffect(() => {
|
|
|
|
// fill the form if in continuation (for product or mini-cart buttons)
|
|
|
|
if (!config.scriptData.continuation || !config.scriptData.continuation.order || window.ppcpContinuationFilled) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-24 10:22:55 +03:00
|
|
|
const paypalAddresses = paypalOrderToWcAddresses(config.scriptData.continuation.order);
|
|
|
|
const wcAddresses = wp.data.select('wc/store/cart').getCustomerData();
|
|
|
|
const addresses = merge(wcAddresses, paypalAddresses, {
|
|
|
|
customMerge: key => (a, b) => a ? a : b, // overwrite empty strings
|
|
|
|
});
|
2023-10-23 20:59:49 +03:00
|
|
|
wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress);
|
|
|
|
if (shippingData.needsShipping) {
|
|
|
|
wp.data.dispatch('wc/store/cart').setShippingAddress(addresses.shippingAddress);
|
|
|
|
}
|
|
|
|
// this useEffect should run only once, but adding this in case of some kind of full re-rendering
|
|
|
|
window.ppcpContinuationFilled = true;
|
|
|
|
}, [])
|
|
|
|
|
2023-03-24 10:11:53 +02:00
|
|
|
const [loaded, setLoaded] = useState(false);
|
|
|
|
useEffect(() => {
|
|
|
|
if (!loaded) {
|
|
|
|
loadPaypalScript(config.scriptData, () => {
|
|
|
|
setLoaded(true);
|
2023-09-06 17:54:08 +01:00
|
|
|
|
|
|
|
buttonModuleWatcher.registerContextBootstrap(config.scriptData.context, {
|
|
|
|
createOrder: () => {
|
|
|
|
return createOrder();
|
|
|
|
},
|
|
|
|
onApprove: (data, actions) => {
|
|
|
|
return handleApprove(data, actions);
|
|
|
|
},
|
|
|
|
});
|
2023-03-24 10:11:53 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}, [loaded]);
|
|
|
|
|
2022-12-20 16:04:11 +02:00
|
|
|
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: '',
|
2023-04-22 13:16:42 +03:00
|
|
|
context: config.scriptData.context,
|
2022-12-20 16:04:11 +02:00
|
|
|
payment_method: 'ppcp-gateway',
|
|
|
|
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);
|
|
|
|
|
2023-03-23 15:54:24 +02:00
|
|
|
onError(err.message);
|
2022-12-20 16:04:11 +02:00
|
|
|
|
|
|
|
onClose();
|
|
|
|
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-07-21 10:49:50 +03:00
|
|
|
const getCheckoutRedirectUrl = () => {
|
|
|
|
const checkoutUrl = new URL(config.scriptData.redirect);
|
|
|
|
// sometimes some browsers may load some kind of cached version of the page,
|
|
|
|
// so adding a parameter to avoid that
|
|
|
|
checkoutUrl.searchParams.append('ppcp-continuation-redirect', (new Date()).getTime().toString());
|
|
|
|
return checkoutUrl.toString();
|
|
|
|
}
|
|
|
|
|
2022-12-20 16:04:11 +02:00
|
|
|
const handleApprove = async (data, actions) => {
|
|
|
|
try {
|
2023-09-25 15:31:38 +03:00
|
|
|
const order = await actions.order.get();
|
|
|
|
|
|
|
|
if (order) {
|
|
|
|
const addresses = paypalOrderToWcAddresses(order);
|
|
|
|
|
2023-10-12 10:18:58 +03:00
|
|
|
let promises = [
|
|
|
|
// save address on server
|
|
|
|
wp.data.dispatch('wc/store/cart').updateCustomerData({
|
|
|
|
billing_address: addresses.billingAddress,
|
|
|
|
shipping_address: addresses.shippingAddress,
|
|
|
|
}),
|
|
|
|
];
|
|
|
|
if (!config.finalReviewEnabled) {
|
|
|
|
// set address in UI
|
|
|
|
promises.push(wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress));
|
|
|
|
if (shippingData.needsShipping) {
|
|
|
|
promises.push(wp.data.dispatch('wc/store/cart').setShippingAddress(addresses.shippingAddress))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
await Promise.all(promises);
|
2023-09-25 15:31:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
setPaypalOrder(order);
|
|
|
|
|
2022-12-20 16:04:11 +02:00
|
|
|
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,
|
2023-04-21 11:12:32 +03:00
|
|
|
funding_source: window.ppcpFundingSource ?? 'paypal',
|
2022-12-20 16:04:11 +02:00
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2023-04-24 08:12:48 +03:00
|
|
|
if (config.finalReviewEnabled) {
|
2023-07-21 10:49:50 +03:00
|
|
|
location.href = getCheckoutRedirectUrl();
|
2023-04-24 08:12:48 +03:00
|
|
|
} else {
|
|
|
|
onSubmit();
|
2023-04-17 10:23:52 +03:00
|
|
|
}
|
2022-12-20 16:04:11 +02:00
|
|
|
} catch (err) {
|
|
|
|
console.error(err);
|
|
|
|
|
2023-03-23 15:54:24 +02:00
|
|
|
onError(err.message);
|
2022-12-20 16:04:11 +02:00
|
|
|
|
|
|
|
onClose();
|
|
|
|
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-10-11 10:10:45 +03:00
|
|
|
useEffect(() => {
|
|
|
|
const unsubscribe = onCheckoutValidation(() => {
|
|
|
|
if (config.scriptData.continuation) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (wp.data.select('wc/store/validation').hasValidationErrors()) {
|
|
|
|
location.href = getCheckoutRedirectUrl();
|
2023-10-11 10:43:33 +03:00
|
|
|
return { type: responseTypes.ERROR };
|
2023-10-11 10:10:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
return unsubscribe;
|
|
|
|
}, [onCheckoutValidation] );
|
|
|
|
|
2023-04-21 11:12:32 +03:00
|
|
|
const handleClick = (data, actions) => {
|
2023-07-11 09:15:36 +03:00
|
|
|
if (isEditing) {
|
|
|
|
return actions.reject();
|
|
|
|
}
|
|
|
|
|
2023-04-21 11:12:32 +03:00
|
|
|
window.ppcpFundingSource = data.fundingSource;
|
|
|
|
|
2022-12-20 16:04:11 +02:00
|
|
|
onClick();
|
|
|
|
};
|
|
|
|
|
2023-04-25 15:06:24 +03:00
|
|
|
let handleShippingChange = null;
|
|
|
|
if (shippingData.needsShipping && !config.finalReviewEnabled) {
|
2023-04-27 09:06:38 +03:00
|
|
|
handleShippingChange = async (data, actions) => {
|
|
|
|
try {
|
|
|
|
const shippingOptionId = data.selected_shipping_option?.id;
|
|
|
|
if (shippingOptionId) {
|
|
|
|
await shippingData.setSelectedRates(shippingOptionId);
|
|
|
|
}
|
|
|
|
|
|
|
|
const address = paypalAddressToWc(data.shipping_address);
|
|
|
|
|
|
|
|
await wp.data.dispatch('wc/store/cart').updateCustomerData({
|
|
|
|
shipping_address: address,
|
|
|
|
});
|
|
|
|
|
2023-04-27 09:29:37 +03:00
|
|
|
await shippingData.setShippingAddress(address);
|
|
|
|
|
2023-04-27 09:06:38 +03:00
|
|
|
const res = await fetch(config.ajax.update_shipping.endpoint, {
|
|
|
|
method: 'POST',
|
|
|
|
credentials: 'same-origin',
|
|
|
|
body: JSON.stringify({
|
|
|
|
nonce: config.ajax.update_shipping.nonce,
|
|
|
|
order_id: data.orderID,
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
const json = await res.json();
|
|
|
|
|
|
|
|
if (!json.success) {
|
|
|
|
throw new Error(json.data.message);
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
console.error(e);
|
|
|
|
|
|
|
|
actions.reject();
|
|
|
|
}
|
2023-04-25 15:06:24 +03:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-12-20 16:04:11 +02:00
|
|
|
useEffect(() => {
|
2023-03-27 10:59:08 +03:00
|
|
|
if (activePaymentMethod !== config.id) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-03-23 11:59:15 +02:00
|
|
|
const unsubscribeProcessing = onPaymentSetup(() => {
|
2023-04-07 15:58:59 +03:00
|
|
|
if (config.scriptData.continuation) {
|
|
|
|
return {
|
|
|
|
type: responseTypes.SUCCESS,
|
|
|
|
meta: {
|
|
|
|
paymentMethodData: {
|
|
|
|
'paypal_order_id': config.scriptData.continuation.order_id,
|
2023-04-21 11:12:32 +03:00
|
|
|
'funding_source': window.ppcpFundingSource ?? 'paypal',
|
2023-04-24 08:12:48 +03:00
|
|
|
}
|
2023-04-07 15:58:59 +03:00
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
2023-04-24 08:12:48 +03:00
|
|
|
|
|
|
|
const addresses = paypalOrderToWcAddresses(paypalOrder);
|
|
|
|
|
|
|
|
return {
|
|
|
|
type: responseTypes.SUCCESS,
|
|
|
|
meta: {
|
|
|
|
paymentMethodData: {
|
|
|
|
'paypal_order_id': paypalOrder.id,
|
|
|
|
'funding_source': window.ppcpFundingSource ?? 'paypal',
|
|
|
|
},
|
|
|
|
...addresses,
|
|
|
|
},
|
|
|
|
};
|
2022-12-20 16:04:11 +02:00
|
|
|
});
|
|
|
|
return () => {
|
|
|
|
unsubscribeProcessing();
|
|
|
|
};
|
2023-03-27 10:59:08 +03:00
|
|
|
}, [onPaymentSetup, paypalOrder, activePaymentMethod]);
|
2022-12-20 16:04:11 +02:00
|
|
|
|
2023-05-22 10:38:31 +03:00
|
|
|
useEffect(() => {
|
2023-10-19 16:56:07 +03:00
|
|
|
if (activePaymentMethod !== config.id) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-19 15:55:57 +03:00
|
|
|
const unsubscribe = onCheckoutFail(({ processingResponse }) => {
|
2023-10-19 16:56:07 +03:00
|
|
|
console.error(processingResponse)
|
2023-05-22 10:38:31 +03:00
|
|
|
if (onClose) {
|
|
|
|
onClose();
|
|
|
|
}
|
2023-10-19 16:56:07 +03:00
|
|
|
if (config.scriptData.continuation) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!config.finalReviewEnabled) {
|
|
|
|
location.href = getCheckoutRedirectUrl();
|
2023-05-22 10:38:31 +03:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
return unsubscribe;
|
2023-10-19 16:56:07 +03:00
|
|
|
}, [onCheckoutFail, onClose, activePaymentMethod]);
|
2023-05-22 10:38:31 +03:00
|
|
|
|
2023-04-07 15:58:59 +03:00
|
|
|
if (config.scriptData.continuation) {
|
|
|
|
return (
|
|
|
|
<div dangerouslySetInnerHTML={{__html: config.scriptData.continuation.cancel.html}}>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-03-24 10:11:53 +02:00
|
|
|
if (!loaded) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const PayPalButton = window.paypal.Buttons.driver("react", { React, ReactDOM });
|
|
|
|
|
2022-12-20 16:04:11 +02:00
|
|
|
return (
|
2023-03-24 10:11:53 +02:00
|
|
|
<PayPalButton
|
|
|
|
style={config.scriptData.button.style}
|
|
|
|
onClick={handleClick}
|
|
|
|
onCancel={onClose}
|
|
|
|
onError={onClose}
|
|
|
|
createOrder={createOrder}
|
|
|
|
onApprove={handleApprove}
|
2023-04-25 15:06:24 +03:00
|
|
|
onShippingChange={handleShippingChange}
|
2023-03-24 10:11:53 +02:00
|
|
|
/>
|
2022-12-20 16:04:11 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-04-07 15:58:59 +03:00
|
|
|
const features = ['products'];
|
|
|
|
let registerMethod = registerExpressPaymentMethod;
|
|
|
|
if (config.scriptData.continuation) {
|
|
|
|
features.push('ppcp_continuation');
|
|
|
|
registerMethod = registerPaymentMethod;
|
|
|
|
}
|
|
|
|
|
|
|
|
registerMethod({
|
2022-12-20 16:04:11 +02:00
|
|
|
name: config.id,
|
|
|
|
label: <div dangerouslySetInnerHTML={{__html: config.title}}/>,
|
2023-07-11 09:15:36 +03:00
|
|
|
content: <PayPalComponent isEditing={false}/>,
|
|
|
|
edit: <PayPalComponent isEditing={true}/>,
|
2022-12-20 16:04:11 +02:00
|
|
|
ariaLabel: config.title,
|
2023-03-29 20:15:42 +03:00
|
|
|
canMakePayment: () => config.enabled,
|
2022-12-20 16:04:11 +02:00
|
|
|
supports: {
|
2023-04-07 15:58:59 +03:00
|
|
|
features: features,
|
2022-12-20 16:04:11 +02:00
|
|
|
},
|
|
|
|
});
|