| 1 |
import { decodeEntities } from '@wordpress/html-entities'; |
| 2 |
import { __ } from '@wordpress/i18n'; |
| 3 |
import { useEffect, useState } from '@wordpress/element'; |
| 4 |
|
| 5 |
const { registerPaymentMethod } = window.wc.wcBlocksRegistry |
| 6 |
const { getSetting } = window.wc.wcSettings |
| 7 |
|
| 8 |
const settings = getSetting('sequra_data', {}) |
| 9 |
const label = decodeEntities(settings.title) |
| 10 |
|
| 11 |
const Content = (props) => { |
| 12 |
const { eventRegistration, emitResponse } = props; |
| 13 |
const { onPaymentSetup } = eventRegistration; |
| 14 |
|
| 15 |
const [content, setContent] = useState(settings.description || ''); |
| 16 |
|
| 17 |
useEffect(() => { |
| 18 |
const unsubscribe = onPaymentSetup(async () => { |
| 19 |
const checkedInput = document.querySelector('[name="sequra_payment_method_data"]:checked') |
| 20 |
const data = checkedInput ? checkedInput.value : null; |
| 21 |
|
| 22 |
if (!data) { |
| 23 |
return { |
| 24 |
type: emitResponse.responseTypes.ERROR, |
| 25 |
message: __('Please select a payment method.', 'sequra'), |
| 26 |
}; |
| 27 |
} |
| 28 |
return { |
| 29 |
type: emitResponse.responseTypes.SUCCESS, |
| 30 |
meta: { |
| 31 |
paymentMethodData: { "sequra_payment_method_data": data }, |
| 32 |
}, |
| 33 |
}; |
| 34 |
}); |
| 35 |
return () => unsubscribe(); |
| 36 |
}, [ |
| 37 |
emitResponse.responseTypes.ERROR, |
| 38 |
emitResponse.responseTypes.SUCCESS, |
| 39 |
onPaymentSetup, |
| 40 |
]); |
| 41 |
|
| 42 |
useEffect(() => { |
| 43 |
document.addEventListener('canMakePaymentLoading', (event) => { |
| 44 |
setContent('<div class="sq-loader" style="margin-top:1rem;margin-bottom:1rem;"><span class="sqp-spinner"></span></div>'); |
| 45 |
}); |
| 46 |
document.addEventListener('canMakePaymentReady', (event) => { |
| 47 |
setContent(event.detail.content); |
| 48 |
setTimeout(() => { |
| 49 |
if ('undefined' !== typeof Sequra && 'function' === typeof Sequra.refreshComponents) { |
| 50 |
Sequra.refreshComponents(); |
| 51 |
} |
| 52 |
}, 0); |
| 53 |
}); |
| 54 |
if ('undefined' !== typeof Sequra && 'function' === typeof Sequra.refreshComponents && 'function' === typeof Sequra.onLoad) { |
| 55 |
Sequra.onLoad(Sequra.refreshComponents()); |
| 56 |
} |
| 57 |
}, []); |
| 58 |
|
| 59 |
return <div dangerouslySetInnerHTML={{ __html: decodeEntities(content) }} /> |
| 60 |
} |
| 61 |
|
| 62 |
const Label = () => { |
| 63 |
return ( |
| 64 |
<span style={{ width: '100%' }}> |
| 65 |
{label} |
| 66 |
</span> |
| 67 |
) |
| 68 |
} |
| 69 |
|
| 70 |
registerPaymentMethod({ |
| 71 |
// A unique string to identify the payment method client side. |
| 72 |
name: "sequra", |
| 73 |
// A react node that will be used as a label for the payment method in the checkout. |
| 74 |
label: <Label />, |
| 75 |
// A react node for your payment method UI. |
| 76 |
content: <Content />, |
| 77 |
// A react node to display a preview of your payment method in the editor. |
| 78 |
edit: <Content />, |
| 79 |
// A callback to determine whether the payment method should be shown in the checkout. |
| 80 |
canMakePayment: ({ shippingAddress, billingAddress, cart }) => { |
| 81 |
const isSolicitationAllowed = () => 'undefined' !== typeof SeQuraBlockIntegration && SeQuraBlockIntegration.isSolicitationAllowed; |
| 82 |
|
| 83 |
const initCache = () => { |
| 84 |
if ('undefined' === typeof SeQuraBlockIntegration.cache) { |
| 85 |
SeQuraBlockIntegration.cache = {}; |
| 86 |
} |
| 87 |
}; |
| 88 |
|
| 89 |
const readFromCache = (key) => { |
| 90 |
initCache(); |
| 91 |
return SeQuraBlockIntegration.cache[key]; |
| 92 |
}; |
| 93 |
|
| 94 |
const writeToCache = (key, value) => { |
| 95 |
initCache(); |
| 96 |
SeQuraBlockIntegration.cache[key] = value; |
| 97 |
}; |
| 98 |
|
| 99 |
return new Promise((resolve) => { |
| 100 |
const onResolved = (canMakePayment, detail) => { |
| 101 |
settings.description = detail.content; |
| 102 |
document.dispatchEvent(new CustomEvent('canMakePaymentReady', { detail })); |
| 103 |
resolve(canMakePayment); |
| 104 |
} |
| 105 |
|
| 106 |
if (!isSolicitationAllowed()) { |
| 107 |
// Prevent unnecessary requests. |
| 108 |
onResolved(false, { content: '' }); |
| 109 |
return; |
| 110 |
} |
| 111 |
|
| 112 |
// Hash the data to prevent unnecessary requests. |
| 113 |
const requestId = btoa(encodeURIComponent(JSON.stringify({ shippingAddress, billingAddress, cart }))); |
| 114 |
|
| 115 |
document.dispatchEvent(new CustomEvent('canMakePaymentLoading', { detail: { requestId } })); |
| 116 |
|
| 117 |
// TODO: Implement check if requestId is pending. When page loads, this code is executed three times for the same requestId what can be avoided. |
| 118 |
const cachedContent = readFromCache(requestId); |
| 119 |
if (cachedContent) { |
| 120 |
onResolved('' !== cachedContent, { content: cachedContent }); |
| 121 |
return; |
| 122 |
} |
| 123 |
|
| 124 |
settings.description = ''; |
| 125 |
const data = new FormData(); |
| 126 |
data.append('action', settings.blockContentAjaxAction); |
| 127 |
data.append('shippingAddress', JSON.stringify(shippingAddress)); |
| 128 |
data.append('billingAddress', JSON.stringify(billingAddress)); |
| 129 |
data.append('requestId', requestId); |
| 130 |
|
| 131 |
fetch(settings.blockContentUrl, { |
| 132 |
method: 'POST', |
| 133 |
credentials: 'same-origin', // Allow including cookies in the request. |
| 134 |
body: data |
| 135 |
}).then(response => { |
| 136 |
if (!response.ok) { |
| 137 |
throw new Error('Network response was not ok'); |
| 138 |
} |
| 139 |
|
| 140 |
response.json().then(json => { |
| 141 |
if (!json.requestId) { |
| 142 |
// invalidate the request. |
| 143 |
throw new Error('Request ID is missing'); |
| 144 |
} |
| 145 |
|
| 146 |
writeToCache(json.requestId, json.content); |
| 147 |
onResolved('' !== json.content, { content: json.content }); |
| 148 |
}).catch(() => { |
| 149 |
onResolved(false, { content: '' }); |
| 150 |
}); |
| 151 |
}).catch(() => { |
| 152 |
onResolved(false, { content: '' }); |
| 153 |
}); |
| 154 |
}); |
| 155 |
}, |
| 156 |
ariaLabel: label, |
| 157 |
// SupportsConfiguration Object that describes various features provided by the payment method. |
| 158 |
supports: { |
| 159 |
features: settings.supports, |
| 160 |
} |
| 161 |
}) |