I am currently working on adding stripe payments to my Laravel app - I have the system all working with blate templates but I am now attempting to implement it into a react project I have.
I am searching for the best way to send a token I receive in a response to my server this is what I currently have:
const CheckoutForm = ({intent}) => {
const stripe = useStripe();
const elements = useElements();
const handleSubmit = async (event) => {
event.preventDefault();
const { data, setData, transform , post } = useForm({
//Token here maybe?
})
if (!stripe || !elements) {
return;
}
const result = await stripe.confirmCardSetup(intent.client_secret, {
payment_method: {
card: elements.getElement(CardElement),
},
});
if (result.error) {
console.log(result.error.message);
} else {
// maybe add: result.setupIntent.payment_method to data?
// post(route('subscriptions'));
}
};
return (
<form onSubmit={handleSubmit}>
<CardElement/>
<Button disabled={!stripe}>
Pay Now
</Button>
</form>
)
};
I am very new to React so struggling to even google my answer - I am assuming I need an inertia post route as this is how I did it in the blade template application. However, this doesn't work now due to react states not updating in that way?
Basically, I have no idea the best way to get result.setupIntent.payment_method to my server after card setup.
Thanks for your time!
Found a solution using Inertia.visit
...
Inertia.visit(
route('subscriptions.start'),
{
method: 'post',
data: {
token: result.setupIntent.payment_method,
}
}
);
...
Related
How do you implement payments in React Native 0.70. I worked with earlier React Native versions using react-native-credit-card-input and react-native-credit-card-input-plus that are now breaking.
Now it very easy to implement the payment methods in react-native because stripe provide official doc.
They provide a built-in UI for checkout and Card Tokenisation,
Here you can Follow Official Doc
1) Setup
install stripe official react-native sdk
yarn add #stripe/stripe-react-native
To initialise Stripe in your React Native app, either wrap your payment screen with the StripeProvider component, or use the initStripe initialisation method.
<StripeProvider publishableKey={PUBLISHABLE_KEY}>
<Navigation />
</StripeProvider>
How to get PUBLISHABLE_KEY
Now in your component
Either use the Stripe UI or create your own custom UI for getting card details. In this answer, I'm using rn-credit-card for getting a card, which gives me customization options 🙂.
2) Get Card details, create Card Token and save for future use
import CreditCardForm, { FormModel } from "rn-credit-card";
const handleConfirm = (model: FormModel) => {
axios
.post(
"https://api.stripe.com/v1/tokens",
{
"card[name]": model.holderName,
"card[number]": model.cardNumber,
"card[exp_month]": model.expiration.split("/")[0],
"card[exp_year]": model.expiration.split("/")[1],
"card[cvc]": model.cvv,
},
{
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Bearer ${STRIPE_KEY}`,
},
}
)
.then((res) => {
if (res?.data?.id) {
//res?.data?.id It will return the payment method ID sent to your backend
// You can also save it for future use by saving it in the database.
console.log(res?.data?.id)
}
})
.catch((err) => {
Alert.alert("Stripe Error", err.message);
});
};
For setting defaultValues
const formMethods = useForm<FormModel>({
mode: "onBlur",
defaultValues: {
holderName: "",
cardNumber: "",
expiration: "",
cvv: "",
},
});
const { handleSubmit, formState } = formMethods;
Form to get card details
<CreditCardForm
LottieView={LottieView}
horizontalStart={false}
overrides={{
labelText: {
marginTop: 16,
},
}}
/>
{formState.isValid && (
<Button
style={styles.button}
title={'CONFIRM PAYMENT'}
onPress={handleSubmit(handleConfirm)}
/>
)}
Now When you pay or checkout simple do the following step
3) Checkout or Payment Time
Create a PaymentIntent by passing the paymentMethods Id with other params like reservationId etc
The backend will return you clientSecret and also the calculated bill
Send the clientSecret to stripe
import { useStripe } from "#stripe/stripe-react-native";
const { confirmPayment } = useStripe();
const handlePay = async () => {
setStripeLoading(true);
try {
//Step 1
const response = await createPaymentIntent({
variables: {
paymentMethodId: paymentMethodId, // That you stored on the backend
reserveId: id, // In our case reserveId is required
amountToDeduct: 23,
},
});
if (response) {
//Step 2 by getting clientSecret
const { clientSecret } = response?.createPaymentIntent;
//sending clientSecret to deduct amount
const { error, paymentIntent } = await confirmPayment(clientSecret);
if (error) {
setStripeLoading(false);
Alert.alert(`Error code: ${error.code}`, error.message);
}
if (paymentIntent) {
setStripeLoading(false);
// Show Success Alert
}
}
} catch (error) {
setStripeLoading(false);
} finally {
setStripeLoading(false);
}
};
Tada you done 🥰
I have a final form in a react page that i need to show me a global success if all the data have been sotored in their database.
I have two partial forms (variations and generalInfo) that store the data in two tables in sql.
I use this handlesubmit from last step in the form to store this data.
const handleSubmit = (e) => {
e.preventDefault();
dispatch(setDesignResponse(dataResponse));
dispatch(createNewVariations(variations));
dispatch(createNewJsonResponse(newJsonResponse));
};
i have my slices that return me info if the store is succesfully.
export const createNewJsonResponse = createAsyncThunk (
"new-json-response/post",
async (newData) => {
const { accesToken, newDataResponse } = newData;
const res = await FaqsService.createNewResponse(newDataResponse, accesToken);
return res.data;
}
);
export const createNewVariations = createAsyncThunk (
"new-variations/post",
async (variations) => {
try {
console.log(variations);
const { token, variationsData } = variations;
const res = await FaqsService.createNewVariations(variationsData, token);
console.log(res.data);
alert('VARIACIONES CREADAS PERFECTAMENTE');
return res.data;
} catch(error) { console.log(error);}
}
);
If just i have one call to one api i know how to show and alert to inform the user. Like in the above code (createNewVariations).
But i need to check if both are ok, and then show the alert to the user.
I think that i can do something in the component, in the handlesubmit, to send the info to the slices, store the data in the data bases, return de result succesfuly (with an state that return a true or false from slices (with extrarducer like:
extraReducers: {
[createNewJsonResponse.fulfilled]:(state, action) => {
state.isCreated = action.payload.message; // initial state is: isCreated:false
}
}
// (the same for the other slice).
),
and then pop-up the alert.
Is it possible?
thanks
Yes you can have isCreated in both of the state slices and then have if condition on your compoment which show success alert when both of the isCreated Flag is 1
I have create a Github example for this I am using a counter example,
from # Redux + Plain JS template
npx create-react-app my-app --template redux
and modified the code to demo that how you can achieve it.
You would need to look on the src/feature/counter/Counter.js File
There I have below logic, this is the not full code of the component, you can look that in the Github repo. and yes you can have isCreated on multiple slices and have if condition on the component, that will work for which you are looking for.
export function Counter() {
const count = useSelector(selectCount);
const incrementStatus = useSelector(incrementCountStatus);
const incrementStatusNew = useSelector(incrementCountStatusNew);
const dispatch = useDispatch();
const [incrementAmount, setIncrementAmount] = useState('2');
console.log(`Increment Status:`, incrementStatus);
console.log(`Increment Status New:`, incrementStatusNew);
const incrementValue = Number(incrementAmount) || 0;
const handleAsyncSubmit = () => {
dispatch(incrementByAmount(incrementValue))
dispatch(incrementAsyncNew(incrementValue))
}
if (incrementStatus === 'success' && incrementStatusNew === 'success') {
alert('Data have been saved successfully.');
}
GitHub Repo
I am using google Oauth2 client script but in that "requestAccessToken" function geving me 2 error. See on bellow image
Here I am loading the 'https://accounts.google.com/gsi/client' script dynamically and after it been loaded I am createing a tokenClient by using initTokenClient funciton.
When user click on the button I am checking is token is allready avaiable or not if not then I am sending a request for google auth popup
tokenClient.current.requestAccessToken({ prompt: 'consent' });
But this requestAccessToken funciton giveing me a error called c.trim() is not a funciton. As per as I found it's comming form the internal implementation of this funciton
I am also getting another CORS error in the same place.
Reproduce Link: https://codesandbox.io/s/nostalgic-ives-wngw3v?file=/src/Picker.jsx
Error Image
import React, { useEffect, useRef, useState } from 'react';
import loadScript from 'load-script';
const GOOGLE_INDENTITY_URL = 'https://accounts.google.com/gsi/client';
const clientId = '865996907937-t2ca9nu95hv87f204t11gikb2rqm3s4v.apps.googleusercontent.com';
const scope = ['https://www.googleapis.com/auth/drive.readonly'];
let scriptLoadingStarted = false;
export default function TryPicker() {
const tokenClient = useRef();
const isGoogleAuthReady = () => {
return !!window.google?.accounts?.oauth2;
};
const doAuth = () => {
console.log('yea', tokenClient.current, tokenClient.current.requestAccessToken);
// // Use Google Identity Services to request an access token
tokenClient.current.requestAccessToken({ prompt: 'consent' });
};
const onChoose = () => {
if (!isGoogleAuthReady()) {
return null;
}
doAuth();
return undefined;
};
const onAuthLoad = () => {
tokenClient.current = window.google.accounts.oauth2.initTokenClient({
client_id: clientId,
scope,
callback: async response => {
if (response.error !== undefined) {
throw response;
}
console.log(response);
},
});
};
useEffect(() => {
if (isGoogleAuthReady()) {
// google api is already exists
// init immediately
onAuthLoad();
} else if (!scriptLoadingStarted) {
// load google api and the init
scriptLoadingStarted = true;
loadScript(GOOGLE_INDENTITY_URL, onAuthLoad);
} else {
// is loading
}
});
return (
<div>
<button className="text-darker" onClick={onChoose} type="button">
Get access token
</button>
</div>
);
}
As mentioned by yash, it's probably cuz you are using array. This is how used it for multiple scopes.
scope: 'https://www.googleapis.com/auth/user.birthday.read \
https://www.googleapis.com/auth/profile.agerange.read \
https://www.googleapis.com/auth/user.gender.read',
```
I'm using Next.js framework and made a simple web application.
Using Firebase Auth, I tried to manage only authenticiated users to send requests. So basically, I need that user's id token. But as you know as user.getIdToken() doesn't work because user could be null. So I had to write user?.getIdToken().
As this result is Promise, I tried to use useContext hook. And I could get access to id token from all page files.
But here's the question.
Although I could get id token, as I need to get this inside the Component, it renders by Client Side Rendering. And I could see some delays.... and I want it to be rendered on Server Side. Could you guys help me with this? As I cannot use this id token inside getStaticProps() or other methods...
Here's my code:
export default function Boards() {
const BASE_URL = "http://localhost:5000/myproj/asia-northeast3/api";
const { idToken } = useContext(UserContext);
const [boardCategory, setBoardCategory] = useState("free");
const [posts, setPosts] = useState([]);
useEffect(() => {
try {
if (idToken != "") {
const res = axios.get(
BASE_URL + "/post/get", {
headers: { "Authorization": `Bearer ${idToken}`, "Access-Control-Allow-Origin": "*" },
params: { "boardCategory": `${boardCategory}` }
})
.then((response) => {
setPosts(JSON.parse(JSON.stringify(response.data)));
});
}
} catch (err) {
console.log(err);
}
}, [idToken, boardCategory]);
}
And this renders on Client Side Rendering so I see some delays...
Thank you guys in advance !
I try to get a list from the backend in Reactjs component with JWT token but I get an error message {"status":"Token is Invalid"}, please guide me.
My backend API is working fine and my token is saved in the localstore after login.
my frontend used API code
import {API} from "../config";
/**
* to get about pages
* get a single about page
* update a about page
* delete about page
*/
export const getAboutContent = (token) =>{
return fetch(`${API}/about/?token=${token}`, {
method: "GET",
})
.then(response =>{
return response.json();
})
.catch(err =>{
console.log(err);
});
};
about/index.js
const [allAboutContent, setAllAboutContent] = useState([]);
const loadAllAboutContent = () => {
getAboutContent().then(data => {
if(data.error){
console.log(data.error)
} else{
setAllAboutContent(data.data)
}
});
};
useEffect(() =>{
loadAllAboutContent();
}, [])
Please help.
You are invoking getAboutContent in about/index.js file without JWT and hence it not defined. Just update your code to read JWT from localStorage like below
const loadAllAboutContent = () => {
// Read token from local storage
const token = localStorage.getItem('jwt');
// Pass to getAboutContent
getAboutContent(token).then(data => {
if(data.error){
console.log(data.error)
} else{
setAllAboutContent(data.data)
}
});
};
Also, I see you have stored your token as {token: ''}. Maybe, you can directly save it. Otherwise you have to read it like this JSON.parse(localStorage.getItem('jwt')).token