Paypal integration Bad request / Order could not be captured - reactjs

I am trying to implement paypal with credit/Debit card in react.js
Here, I am using references for this : enter link description here
& Here is my code references for paypal button:
createOrder = (data, actions) => {
// console.log('action',actions.order);
return actions.order.create({
purchase_units: [
{
description: +"Mercedes G-Wagon",
amount: {
currency_code: "USD",
value: 200,
// intent: 'capture',
},
},
],
});
};
onApprove = (data, actions) => {
actions.order.capture().then(details => {
const paymentData = {
payerID: data.payerID,
orderID: data.orderID
};
console.log("Payment Approved: ", paymentData);
});
};
Here is the code of paypal button:
<PayPalButton
createOrder={(data, actions) => this.createOrder(data, actions)}
onApprove={(data, actions) => this.onApprove(data, actions)}
/>
Also I added PAYPAL SDK Link
src="https://www.paypal.com/sdk/js?client-id=Ae-iRhlCvBlx2WS-YACHU3MAMbbDPTj9Cp-ynyMFi2qautDvNMynnDn1mG3qgqyeiCD6IAFG0MPHfBxj
"
I tried with make payment using credit/Debit card and choose India in county drop-down But everytime I got the same error that "Order could not be captured"
How I can resolve this error ??

Related

TypeError: prevDeps.join is not a function next js

I want to create a search bar in next js and firebase and it works by getting the slug from the url and parse it though my search algorithm. The problem is that if the user uses the search bar 2 times it breaks and shows this error:
this is how I push the data
<Link href={`http://localhost:3000/search/${search}/`} >
<Magnify fontSize='small' />
</Link>
and here is how ii get it
const serachId = router.query.id;
useEffect(() => {
onAuthStateChanged(auth, async (user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
const places = query(collection(getFirestore(app), '/programs'))
const querySnapshot = await getDocs(places)
querySnapshot.docs.forEach(doc => {
if (JSON.stringify(doc.data()).includes(router.query.id)) {
let programObj = {
age: doc.data().price,
icon: doc.data().logo,
status: "software",
date: doc.data().start,
name: doc.data().name,
salary: '$$$',
email: doc.data().website,
designation: 'Human Resources Assistant',
id: doc.id
};
setPrograms(prev => [...prev, programObj]);
}
})
}
else {
console.log("no loggin")
}
});
}, router.query.id)
Your dependency array should be in square brackets [ ]
like this: [router.query.id]

"Request is missing required authentication credential" when sending a request to Google Calendar

I'm developing a react calendar app where a user can see their events retrieved from a Google calendar or add their own ones through the app.
I am using #react-oauth/google to sign in and get credentials.
Here I can get a clientId and credential. How can I use them to add/retrieve events to/from a Google Calendar? Should I add credentials to a request object somehow? (NOTE: instead of "" in CLIENT_ID and API_KEY I inserted some valid values that I got here https://console.cloud.google.com/. Authorized JavaScript origins are http://localhost:3000 and http://localhost)
error: {code: 401, data: Array(1), message: 'Request is missing required authentication credent…ogle.com/identity/sign-in/web/devconsole-project.'}
import React from "react";
import { GoogleOAuthProvider, GoogleLogin } from "#react-oauth/google";
const GoogleCalendar = () => {
var gapi = window.gapi;
var CLIENT_ID =
"";
var DISCOVERY_DOCS = [
"https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest",
];
var SCOPES = "https://www.googleapis.com/auth/calendar.events";
var API_KEY = "";
const AddEvent = (credentialResponse) => {
var event = {
summary: "Google I/O 2015",
location: "800 Howard St., San Francisco, CA 94103",
description: "A chance to hear more about Google's developer products.",
start: {
dateTime: "2022-05-21T09:00:00-07:00",
timeZone: "America/Los_Angeles",
},
end: {
dateTime: "2022-05-21T17:00:00-07:00",
timeZone: "America/Los_Angeles",
},
recurrence: ["RRULE:FREQ=DAILY;COUNT=2"],
attendees: [
{ email: "lpage#example.com" },
{ email: "sbrin#example.com" },
],
reminders: {
useDefault: false,
overrides: [
{ method: "email", minutes: 24 * 60 },
{ method: "popup", minutes: 10 },
],
},
};
gapi.client.load("calendar", "v3", () => console.log("bam!"));
var request = gapi.client.calendar.events.insert({
calendarId: "primary",
resource: event,
});
request.execute((event) => {
console.log(event);
window.open(event.htmlLink);
});
};
return (
<>
<GoogleOAuthProvider clientId={CLIENT_ID}>
<GoogleLogin
onSuccess={(credentialResponse) => {
console.log(credentialResponse);
AddEvent(credentialResponse);
}}
onError={() => {
console.log("Login Failed");
}}
/>
</GoogleOAuthProvider>
</>
);
};
export default GoogleCalendar;
In order to add the events, the client should be loaded and signed in before calling add events. What you did is correct but you have to wait for the response of client load then you can call add events:
gapi.client.setApiKey('YOUR_API_KEY');
gapi.client
.load('https://content.googleapis.com/discovery/v1/apis/calendar/v3/rest')
.then((res) => {
var request = gapi.client.calendar.events.insert({
calendarId: 'primary',
resource: event,
});
request.execute((event) => {
console.log(event);
window.open(event.htmlLink);
});
});
you need your access_token to authorize to google APIs, you can get it from using Authorization flows from #react-oauth/google by using useGoogleLogin

How to call ProcessPayment function in Google Pay react button?

I am integrating google pay in react application. According to documentation, when token is generated it will be pass to gateway for process payment. I am using #google-pay/button-react. How can I pass token to gateway. I didn't find anything in documentation. Is this library send token to gateway by itself?
From google tutorial to send token to gateway
processPayment(paymentDetail) {
const paymentToken = paymentDetail.paymentMethodData.tokenizationData.token;
let paymentData = {
orderId : '12331231232311',
amount : '50.00'
}
axios.post("https://esqa.moneris.com/googlepay/googlepay-api.js", {
body: JSON.stringify({
paymentToken,
paymentData
})
}).then(response => {
if ( response && response.receipt && response.receipt.ResponseCode &&
!isNaN(response.receipt.ResponseCode) )
{
if ( parseInt(response.receipt.ResponseCode) < 50 )
{
alert("Looks like the transaction is approved.");
}
else
{
alert("Looks like the transaction is declined.");
}
}
else
{
throw ("Error processing receipt.");
}
})
}
<GooglePayButton
environment="TEST"
paymentRequest={{
apiVersion: 2,
apiVersionMinor: 0,
allowedPaymentMethods: [
{
type: 'CARD',
parameters: {
allowedAuthMethods: ['PAN_ONLY'],
allowedCardNetworks: ['MASTERCARD', 'VISA', 'DISCOVER', 'AMEX','DISCOVER','JCB','INTERAC'],
},
tokenizationSpecification: {
type: 'PAYMENT_GATEWAY',
parameters: {
gateway: "moneris",
gatewayMerchantId: "monca05217"
},
},
},
],
merchantInfo: {
merchantId: '12345678901234567890',
merchantName: 'Demo Merchant',
},
transactionInfo: {
totalPriceStatus: 'FINAL',
totalPriceLabel: 'Total',
totalPrice: '50.00',
currencyCode: 'USD',
countryCode: 'CA',
},
callbackIntents: ['PAYMENT_AUTHORIZATION'],
emailRequired: true,
}}
onLoadPaymentData={paymentRequest => {
console.log('load payment data', paymentRequest);
this.processPayment(paymentRequest)
}}
onPaymentAuthorized={(paymentData) => ({
transactionState: 'SUCCESS'
})}
onReadyToPayChange={result => {
console.log('ready to pay change', result);
this.setState({isReadyToPay : result.isReadyToPay});
}}
onCancel={() => alert('Cancelled')}
existingPaymentMethodRequired = {true}
/>
You need to call your processPayment method from onLoadPaymentData.
Your processPayment is responsible for calling your backend and passing the payment token to your payment gateway.
Example:
onLoadPaymentData={paymentRequest => {
processPayment();
}}
async function processPayment(paymentData) {
const paymentToken = paymentData.paymentMethodData.tokenizationData.token;
const response = await fetch("/backend/api", {
method: "POST",
body: JSON.stringify({
paymentToken,
orderDetails: {/* details about your order */}
})
});
}

PayPal Buttons don't close (Duplicates after re-rendering)

I'm implementing the PayPal Smart Payment Buttons with React, and every time my component re-renders I receive a duplicate of the buttons (with the one on the bottom holding the correct transaction information).
Clearly I need to close the buttons, if I try so I receive the error that window.paypal.close()is not a function.
I tried to follow this example: Paypal React shows extra buttons after changing amount
Here is my code, I'm using Redux for state management and I need to rerender the component if items in the shopping cart are removed (to update the item information of the transaction):
useEffect(() => {
if (window.myButton) {
window.myButton.close()
}
window.myButton = window.paypal
.Buttons({
createOrder: (data, actions) => {
return actions.order.create({
purchase_units: [
{
description: "test transaction",
amount: {
currency_code: "USD",
value: document.getElementById("totalAmount").innerHTML,
breakdown: {
item_total: {
currency_code: "USD",
value: document.getElementById("totalAmount").innerHTML
}
}
}
,
items: itemsInCart.map(item => {
console.log(item.value)
return {
name: item.name,
unit_amount: {
currency_code: "USD",
value: String(item.price)
},
quantity: "1"
}
})
}
]
});
},
onApprove: async (data, actions) => {
const order = await actions.order.capture();
}
.catch(function(error) {
console.error("Error writing document: ", error);
});
},
onError: err => {
// setError(err);
console.error(err);
}
})
.render(paypalRef.current)
}, [itemsInCart]);
})
.render(paypalRef.current)
The problem is you are setting myButton to the .render() promise result, not the Button itself.
You need to store a reference to the actual Button (before rendereing it), and only then .render() it -- so that later you can call .close() on the reference. Basically:
let myButton = paypal.Buttons(
....
});
myButton.render(paypalRef.current)
// and at some later point in time...
myButton.close();

PayPal React shows extra buttons after changing amount

WITHOUT react-paypal-button-v2 ~~~has an ovehead of 60KB
Similar question here but they suggest react-paypal-button-v2
I'm Trying to make a React PayPal button that changes the billing amount on props change.
I call the following component with props price and every time the price change i would like to re-render the button to update the actual price. WITHOUT react-paypal-button-v2
const PaypalForm = props => {
let paypalRef = useRef();
useEffect(() => {
window.paypal
.Buttons({
createOrder: (data, actions) => {
return actions.order.create({
purchase_units: [
{
description: "test",
amount: {
currency_code: "USD",
value: props.price
}
}
]
});
},
onApprove: async (data, actions) => {
const order = await actions.order.capture();
console.log(order);
},
onError: err => {
setError(err);
console.error(err);
}
})
.render(paypalRef.current);
}, [props.price]);
return (
<Row className="justify-content-center">
{error && <div>Uh oh, an error occurred! {error.message}</div>}
<div ref={paypalRef} />
</Row>
);
};
Everything is working except that a new button is created and added in the bottom of old one at each props change. I would like my new button to replace the old one. Without using react-paypal-button-v2
Something like:
useEffect(() => {
if(window.myButton) window.myButton.close();
window.myButton = window.paypal
.Buttons({
createOrder: (data, actions) => {
return actions.order.create({
purchase_units: [
{
description: "test",
amount: {
currency_code: "USD",
value: props.price
}
}
]
});
},
onApprove: async (data, actions) => {
const order = await actions.order.capture();
console.log(order);
},
onError: err => {
setError(err);
console.error(err);
}
});
window.myButton.render(paypalRef.current);
However, you do not actually need to re-render the button on price change!
You can do value: document.getElementById('...').value or similar (or whatever variable or function call you need)
In your example, if props.price returns the (new/current) desired value when the button is clicked, then that value will be used.
Basically, the createOrder function isn't called until you click a button.

Resources