fix payment method page element loading

this resolves the race condition issue when loading recurly payment element
and hence sometimes it wasn't showing
This commit is contained in:
Nuwan 2025-08-20 20:31:44 +05:30
parent a84a55f178
commit d424026f17
1 changed files with 36 additions and 106 deletions

View File

@ -16,7 +16,7 @@ import iconPaypalFull from '../../assets/img/icons/icon-paypal-full.png';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { updatePayment } from '../../helpers/rest'; import { updatePayment } from '../../helpers/rest';
import { useAuth } from '../../context/UserAuth'; import { useAuth } from '../../context/UserAuth';
import { getBillingInfo, updateBillingInfo, getUserDetail, getCountries } from '../../helpers/rest'; import { getBillingInfo, getUserDetail, getCountries } from '../../helpers/rest';
import { useForm, Controller } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import Select from 'react-select'; import Select from 'react-select';
import { useResponsive } from '@farfetch/react-context-responsive'; import { useResponsive } from '@farfetch/react-context-responsive';
@ -30,7 +30,6 @@ const JKPaymentMethod = () => {
const [countries, setCountries] = useState([]); const [countries, setCountries] = useState([]);
const labelClassName = 'ls text-600 font-weight-semi-bold mb-0'; const labelClassName = 'ls text-600 font-weight-semi-bold mb-0';
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
const [billingDataLoaded, setBillingDataLoaded] = useState(false);
const [isCardValid, setIsCardValid] = useState(false); const [isCardValid, setIsCardValid] = useState(false);
const { greaterThan } = useResponsive(); const { greaterThan } = useResponsive();
@ -74,7 +73,6 @@ const JKPaymentMethod = () => {
if (userData.has_recurly_account) { if (userData.has_recurly_account) {
setHasStoredCreditCard(userData['has_stored_credit_card?']); setHasStoredCreditCard(userData['has_stored_credit_card?']);
await populateBillingAddress(); await populateBillingAddress();
setBillingDataLoaded(true);
} }
} catch (error) { } catch (error) {
console.error('Failed to get user details:', error); console.error('Failed to get user details:', error);
@ -128,46 +126,36 @@ const JKPaymentMethod = () => {
setValue('country', selectedOption.value); setValue('country', selectedOption.value);
}; };
const recurlyContainerRef = useRef();
useEffect(() => { useEffect(() => {
if (!window.recurly) return; if (!recurlyContainerRef.current || !window.recurly || recurlyConfigured.current) return;
if (recurlyConfigured.current) return; window.recurly.configure({ publicKey: process.env.REACT_APP_RECURLY_PUBLIC_API_KEY });
const elements = window.recurly.Elements();
const cardElement = elements.CardElement();
const interval = setInterval(() => { cardElement.attach(recurlyContainerRef.current);
const container = document.querySelector('#recurly-elements');
console.log('Checking for Recurly Elements container:', container);
if (container && window.recurly) {
console.log('Initializing Recurly Elements...');
window.recurly.configure({ publicKey: process.env.REACT_APP_RECURLY_PUBLIC_API_KEY });
const elements = window.recurly.Elements();
const cardElement = elements.CardElement();
cardElement.attach('#recurly-elements');
cardElement.on('change', (event) => { cardElement.on('change', (event) => {
if (event.complete) { setIsCardValid(event.complete && !event.error);
setIsCardValid(true); });
} else if (event.error) {
setIsCardValid(false);
} else {
setIsCardValid(false);
}
});
//then load paypal: //then load paypal:
const paypalInst = window.recurly.PayPal({ braintree: { clientAuthorization: process.env.REACT_APP_BRAINTREE_TOKEN } }) const paypalInst = window.recurly.PayPal({ braintree: { clientAuthorization: process.env.REACT_APP_BRAINTREE_TOKEN } })
paypal.current = paypalInst; paypal.current = paypalInst;
paypal.current.on('error', onPayPalError); paypal.current.on('error', onPayPalError);
paypal.current.on('token', onPayPalToken); paypal.current.on('token', onPayPalToken);
elementsRef.current = elements; elementsRef.current = elements;
recurlyConfigured.current = true; recurlyConfigured.current = true;
clearInterval(interval);
}
}, 100);
return () => clearInterval(interval); return () => {
}, []); // Optional cleanup if the component unmounts
recurlyContainerRef.current.innerHTML = '';
recurlyConfigured.current = false;
};
}, [recurlyContainerRef.current]);
const onPayPalError = (error) => { const onPayPalError = (error) => {
console.error('PayPal Error:', error); console.error('PayPal Error:', error);
@ -196,67 +184,9 @@ const JKPaymentMethod = () => {
}); });
}; };
// const onSubmit = async (data) => { const onSubmit = async (data) => {
// //first update billing address
// setSubmitting(true);
// const resp = await updateBillingInfo(data)
// if (!resp.ok) {
// setSubmitting(false);
// const errorData = await resp.json();
// console.error('Error updating billing info:', errorData);
// toast.error(errorData.message || t('payment_method.alerts.billing_update_error'));
// return;
// }
// if (paymentMethod === 'paypal') {
// handoverToPaypal();
// return;
// } else {
// if (!elementsRef.current) {
// console.error('Recurly elementsRef.current is not ready');
// setSubmitting(false);
// return;
// }
// if (!formRef.current) {
// console.error('formRef.current is not ready');
// setSubmitting(false);
// return;
// }
// // if (!isCardValid) {
// // console.error('Card is not valid');
// // toast.error(t('payment_method.validations.card.invalid'));
// // setSubmitting(false);
// // return;
// // }
// window.recurly.token(elementsRef.current, formRef.current, (err, token) => {
// if (err) {
// console.error('Recurly token error:', err);
// toast.error(err.message || t('payment_method.alerts.card_processing_error'));
// setSubmitting(false);
// } else {
// console.log('Recurly token:', token.id);
// // send token.id to backend
// handleUpdatePayment(token);
// }
// });
// }
// };
const onSubmit = async (data) => {
//first update billing address
setSubmitting(true); setSubmitting(true);
// const resp = await updateBillingInfo(data) if (paymentMethod === 'paypal') { // PayPal payment method
// if (!resp.ok) {
// setSubmitting(false);
// const errorData = await resp.json();
// console.error('Error updating billing info:', errorData);
// toast.error(errorData.message || t('payment_method.alerts.billing_update_error'));
// return;
// }
if (paymentMethod === 'paypal') {
handoverToPaypal(); handoverToPaypal();
return; return;
} else { // Credit Card payment method } else { // Credit Card payment method
@ -284,7 +214,7 @@ const JKPaymentMethod = () => {
} }
}); });
} }
}; };
const handoverToPaypal = () => { const handoverToPaypal = () => {
@ -319,7 +249,7 @@ const JKPaymentMethod = () => {
<Row className="mb-2"> <Row className="mb-2">
<Col xs={12} md={5} lg={4} className="text-md-right"> <Col xs={12} md={5} lg={4} className="text-md-right">
<Label for="first_name" className={labelClassName}> <Label for="first_name" className={labelClassName}>
{t('payment_method.first_name')} {t('payment_method.first_name')}
</Label> </Label>
</Col> </Col>
<Col> <Col>
@ -334,7 +264,7 @@ const JKPaymentMethod = () => {
<Row className="mb-2"> <Row className="mb-2">
<Col xs={12} md={5} lg={4} className="text-md-right"> <Col xs={12} md={5} lg={4} className="text-md-right">
<Label for="last_name" className={labelClassName}> <Label for="last_name" className={labelClassName}>
{t('payment_method.last_name')} {t('payment_method.last_name')}
</Label> </Label>
</Col> </Col>
<Col> <Col>
@ -349,7 +279,7 @@ const JKPaymentMethod = () => {
<Row className="mb-2"> <Row className="mb-2">
<Col xs={12} md={5} lg={4} className="text-md-right"> <Col xs={12} md={5} lg={4} className="text-md-right">
<Label for="address1" className={labelClassName}> <Label for="address1" className={labelClassName}>
{t('payment_method.address1')} {t('payment_method.address1')}
</Label> </Label>
</Col> </Col>
<Col> <Col>
@ -364,7 +294,7 @@ const JKPaymentMethod = () => {
<Row className="mb-2"> <Row className="mb-2">
<Col xs={12} md={5} lg={4} className="text-md-right"> <Col xs={12} md={5} lg={4} className="text-md-right">
<Label for="address2" className={labelClassName}> <Label for="address2" className={labelClassName}>
{t('payment_method.address2')} {t('payment_method.address2')}
</Label> </Label>
</Col> </Col>
<Col> <Col>
@ -379,7 +309,7 @@ const JKPaymentMethod = () => {
<Row className="mb-2"> <Row className="mb-2">
<Col xs={12} md={5} lg={4} className="text-md-right"> <Col xs={12} md={5} lg={4} className="text-md-right">
<Label for="city" className={labelClassName}> <Label for="city" className={labelClassName}>
{t('payment_method.city')} {t('payment_method.city')}
</Label> </Label>
</Col> </Col>
<Col> <Col>
@ -394,7 +324,7 @@ const JKPaymentMethod = () => {
<Row className="mb-2"> <Row className="mb-2">
<Col xs={12} md={5} lg={4} className="text-md-right"> <Col xs={12} md={5} lg={4} className="text-md-right">
<Label for="state" className={labelClassName}> <Label for="state" className={labelClassName}>
{t('payment_method.state')} {t('payment_method.state')}
</Label> </Label>
</Col> </Col>
<Col> <Col>
@ -409,7 +339,7 @@ const JKPaymentMethod = () => {
<Row className="mb-2"> <Row className="mb-2">
<Col xs={12} md={5} lg={4} className="text-md-right"> <Col xs={12} md={5} lg={4} className="text-md-right">
<Label for="zip" className={labelClassName}> <Label for="zip" className={labelClassName}>
{t('payment_method.zip_code')} {t('payment_method.zip_code')}
</Label> </Label>
</Col> </Col>
<Col> <Col>
@ -427,7 +357,7 @@ const JKPaymentMethod = () => {
<Row className="mb-2"> <Row className="mb-2">
<Col xs={12} md={5} lg={4} className="text-md-right"> <Col xs={12} md={5} lg={4} className="text-md-right">
<Label for="country" className={labelClassName}> <Label for="country" className={labelClassName}>
{t('payment_method.country')} {t('payment_method.country')}
</Label> </Label>
</Col> </Col>
<Col> <Col>
@ -490,7 +420,7 @@ const JKPaymentMethod = () => {
</Row> </Row>
<Row> <Row>
<Col sm={8}> <Col sm={8}>
<div id="recurly-elements"></div> <div id="recurly-elements" ref={recurlyContainerRef}></div>
{!isCardValid && errors.recurly && ( {!isCardValid && errors.recurly && (
<div className="text-danger"> <div className="text-danger">
<small>{errors.recurly.message}</small> <small>{errors.recurly.message}</small>
@ -522,7 +452,7 @@ const JKPaymentMethod = () => {
<Button <Button
color="primary" color="primary"
type="submit" type="submit"
disabled={ submitting } disabled={submitting}
className="mt-3" className="mt-3"
> >
{submitting ? t('payment_method.submitting') : t('payment_method.save_payment_info')} {submitting ? t('payment_method.submitting') : t('payment_method.save_payment_info')}