react-paypal-js: [BUG]: React skipped hostedField
Is there an existing issue for this?
- I have searched the existing issues.
π Describe the Bug
Referring to my other bug report on #304 , I tried another way using code example as a base. I did not get any error but it seems like React skipped hostedfield.cardFields.submit()
I was unable to find any solutions for this issue but I found a few recent posts on stackoverflow to address the same issue.
My code:
App.js
import { useState, useEffect, useRef } from "react";
import {
PayPalScriptProvider,
PayPalHostedFieldsProvider,
PayPalHostedField,
usePayPalHostedFields,
} from "@paypal/react-paypal-js";
const CUSTOM_FIELD_STYLE = {"border":"1px solid #606060","boxShadow":"2px 2px 10px 2px rgba(0,0,0,0.1)"};
const INVALID_COLOR = {
color: "#dc3545",
};
// Example of custom component to handle form submit
const SubmitPayment = ({ customStyle, mr, sh }) => {
const [paying, setPaying] = useState(false);
const cardHolderName = useRef(null);
const hostedField = usePayPalHostedFields();
const baseUrl = "http://local.payment.web"
const handleClick = () => {
if (!hostedField?.cardFields) {
const childErrorMessage = 'Unable to find any child components in the <PayPalHostedFieldsProvider />';
// eslint-disable-next-line no-undef
action(ERROR)(childErrorMessage);
throw new Error(childErrorMessage);
}
const isFormInvalid =
Object.values(hostedField.cardFields.getState().fields).some(
(field) => !field.isValid
) || !cardHolderName?.current?.value;
if (isFormInvalid) {
return alert(
"The payment form is invalid"
);
}
setPaying(true);
hostedField.cardFields
.submit({
cardholderName: cardHolderName?.current?.value,
})
.then(async () => {
return await fetch(`${baseUrl}/api/Ppal/ReactApi/CaptureOrder`, {
mode: "cors",
method: "post",
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
merchantRef: mr,
sessionHash: sh
})
})
.then(res => res.json())
.then((data) => {
console.log("data from pay button : ", data);
if(data.isApproved) alert("Payment successful")
if(!data.isApproved) alert("Payment declined")
if(data.isExpired) alert("Payment expired")
})
.catch(err => console.log("err : ", err))
.finally(() => setPaying(false))
})
.catch(err => console.log("Error catch : ", err))
};
return (
<>
<label title="This represents the full name as shown in the card">
Card Holder Name
<input
id="card-holder"
ref={cardHolderName}
className="card-field"
style={{ ...customStyle, outline: "none" }}
type="text"
placeholder="Full name"
/>
</label>
<button
className={`btn${paying ? "" : " btn-primary"}`}
style={{ float: "right" }}
onClick={handleClick}
>
{paying ? <div className="spinner tiny" /> : "Pay"}
</button>
</>
);
};
export default function App() {
const [clientId, setClientId] = useState(null)
const [clientToken, setClientToken] = useState(null)
const [merchantRef, setMerchantRef] = useState(null)
const [sessionHash, setSessionHash] = useState(null)
const [orderId, setOrderId] = useState(null)
const baseUrl = "http://local.payment.web"
useEffect(() => {
(async () => {
return await fetch(`${baseUrl}/api/Ppal/ReactApi/PrepareForPayment`, {
mode: "cors",
method: "post",
headers: {
'content-type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify({
"curCode": "USD",
"orderAmount": 500
})
}).then(res => {
console.log("fetch Data : ", res);
return res.json()
}).then(data => {
console.log("fetch Data : ", data);
setClientId(data.ClientId)
setClientToken(data.ClientToken)
if (data.prepareForPayment) {
setMerchantRef(data.merchantRef)
setSessionHash(data.sessionHash)
}
}).catch(err => console.log(err))
})();
}, []);
return (
<>
{clientToken ? (
<PayPalScriptProvider
options={{
"client-id": clientId,
components: "buttons,hosted-fields",
"data-client-token": clientToken,
intent: "capture",
vault: false,
}}
>
<PayPalHostedFieldsProvider
styles={{".valid":{"color":"#28a745"},".invalid":{"color":"#dc3545"},"input":{"font-family":"monospace","font-size":"16px"}}}
createOrder={async() => {
return await fetch(`${baseUrl}/api/Ppal/ReactApi/CreateOrder2`, {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
merchantRef: merchantRef,
sessionHash: sessionHash
})
}).then(res => {
console.log("res from createOrder", res);
return res.json()
}).then(data => {
console.log("orderId from button : ", data?.orderId);
if (data?.createOrder) return setOrderId(data?.orderId)
})
}}
>
<label htmlFor="card-number">
Card Number
<span style={INVALID_COLOR}>*</span>
</label>
<PayPalHostedField
id="card-number"
className="card-field"
style={CUSTOM_FIELD_STYLE}
hostedFieldType="number"
options={{
selector: "#card-number",
placeholder: "4111 1111 1111 1111",
}}
/>
<label htmlFor="cvv">
CVV<span style={INVALID_COLOR}>*</span>
</label>
<PayPalHostedField
id="cvv"
className="card-field"
style={CUSTOM_FIELD_STYLE}
hostedFieldType="cvv"
options={{
selector: "#cvv",
placeholder: "123",
maskInput: true,
}}
/>
<label htmlFor="expiration-date">
Expiration Date
<span style={INVALID_COLOR}>*</span>
</label>
<PayPalHostedField
id="expiration-date"
className="card-field"
style={CUSTOM_FIELD_STYLE}
hostedFieldType="expirationDate"
options={{
selector: "#expiration-date",
placeholder: "MM/YYYY",
}}
/>
<SubmitPayment customStyle={{"border":"1px solid #606060","boxShadow":"2px 2px 10px 2px rgba(0,0,0,0.1)"}} />
</PayPalHostedFieldsProvider>
</PayPalScriptProvider>
) : (
<h1>Loading token...</h1>
)}
</>
);
}
π Current Behavior
No error and Alert tag render but on Network tab, it did not fetch capture api as screenshot below
π€ Expected Behavior
It should call capture api and render alert tag whether the payment was successful or declined or log any errors
π¬ Minimal Reproduction
No response
π Environment
| Software | Version(s) |
| ---------------- | ---------- |
| react-paypal-js | ^7.8.1 |
| Browser | Chrome |
| Operating System | Window10 |
Relevant log output
No log or output, React skipped `Hostedfield.cardfield.submit()`
Code of Conduct
- I agree to follow this projectβs Code of Conduct
β Anything else?
No response
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 39 (8 by maintainers)
Hey @gregjopa Thank you for your input. It didnβt even cross my mind to use useRef. I will try and get back to you soon if it works