How to change stripe CardElement according to the country regulations? - reactjs

I am trying to implememt stripe subscription.
Here is my react code:
const stripe = useStripe();
const elements = useElements();
const onPayClickHandler = async (event: React.MouseEvent<HTMLElement>) => {
event.preventDefault();
try {
const cardElement = elements.getElement(CardElement);
const { paymentMethod, error } = await stripe.createPaymentMethod({
type: "card",
card: cardElement,
});
if (error) {
alert(error.message);
return;
}
const response = await axios.post("/subscriptions", { plan: "price_1LzFhSSAy6HVqYxUjUW7uUd1", payment_method: paymentMethod.id });
//Error handling code...........
} catch (err) {
console.log(err);
}
};
Here is the jsx part:
<div className="SubsCard">
<div className="SubsCardTitle">Enter card details</div>
<CardElement />
<Button variant="primary" onClick={onPayClickHandler}>
Pay
</Button>
</div>
</div>
When I click on the Pay button I can see that my stripe customer id is being generated but then I get an error saying Error: As per Indian regulations, export transactions require a customer name and address.
How do I add the customer name and addressfields in CardElement. Please guide me.

How do I add the customer name and addressfields in CardElement
You generally wouldn't, since the CardElement only collects the basic number/expiry/CVC/postal code fields and nothing else.
The recommendations here would be:
use Checkout as a hosted payment page from Stripe that will collect everything needed instead of directly integrating CardElement: https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=checkout
if building this yourself, you will need to
add your own HTML inputs for collecting the customer's name and address
send those value to the backend server
supply them to the Customer Create or Update API when creating the Customer object on the backend. (https://stripe.com/docs/api/customers/create#create_customer-name // https://stripe.com/docs/api/customers/create#create_customer-address )

Related

Attempting to send uploaded file in React app to backend returning 'undefined'

I'm currently building some functionality in my React web app to upload a picture, display it on the client (this works), but also store the photo details so they can be sent in an axios post to my backend where the image gets stored in the file system.
Here's my code to now:
const SetupDetails = () => {
const [previewPhoto, setPreviewPhoto] = useState(null)
const [photoFile, setPhotoFile] = useState(null)
const uploadPhoto = (e) => {
e.preventDefault()
setPreviewPhoto(URL.createObjectURL(e.target.files[0]))
setPhotoFile(e.target.files[0])
}
const buttonClick = (e) => {
e.preventDefault()
console.log(previewPhoto)
console.log(photoFile)
axios.post("/api/uploadProfilePicture", {
photoFile: photoFile
})
}
const deletePhoto = (e) => {
e.preventDefault()
setPreviewPhoto(null)
setPhotoFile(null)
}
return (
<label for="photo-upload" className="setup-photo-label">Upload</label>
<input className="setup-photo-input" id="photo-upload" type="file" onChange={uploadPhoto} />
{
previewPhoto ?
<div className="preview-photo-container">
<img className="preview-photo" src={previewPhoto} alt="A small thumbnail uploaded by the user." />
<button className="preview-photo-delete" onClick={deletePhoto}>Delete</button>
</div> : null
}
<button className="setup-continue-button" onClick={buttonClick}>Continue</button>
)
}
The basic premise is:
The input calls a function during 'onChange' which updates state to store the details of the photo
The 'photoFile' details are posted to the backend to be stored in the backend
The 'previewPhoto' is used to display a thumbnail of the image to the user
However, the photoFile is returned as undefined, or an empty object, every time.
I'm not 100% sure where I'm going wrong, as the console.log of the 'photoFile' shows the details of the photo, so I'd have thought I could just post that to the backend.
Any advice here would be really appreciated!

Invalid value for stripe.confirmPayment(): elements should have a mounted Payment Element

I'm trying to integrate a Stripe payments page using the React "Elements". I'm following the tutorial from https://stripe.com/docs/payments/accept-a-payment?platform=web&ui=elements#web-submit-payment and I've gotten to step 5, "Submit the payment to Stripe". My code doesn't look much different from the example, but whenever I try to submit a payment this error:
Invalid value for stripe.confirmPayment(): elements should have a mounted Payment Element.
Thrown from stripe.confirmPayment. I've included the <Elements/> and <PaymentElement/> on the page, and passed the return value from useElements() so I'm really not sure what I'm missing.
Here's my checkout form:
function StripeCheckoutForm({paymentIntent,booking}: StripeCheckoutFormProps) {
const stripe = useStripe();
const elements = useElements();
const [confirming,setConfirming] = useState(false)
const handleSubmit = async (ev: FormEvent<HTMLFormElement>) => {
ev.preventDefault();
if (!stripe || !elements) {
notifyWarning("Still loading. Please wait a few seconds and then try again.");
return;
}
setConfirming(true)
try {
const {error} = await stripe.confirmPayment({
//`Elements` instance that was used to create the Payment Element
elements,
confirmParams: {
return_url: resolveRoute('customerPaymentReceived',{key:booking.key}),
},
})
if(error) {
notifyError(error.message)
setConfirming(false)
}
} catch(error) {
setConfirming(false)
if(error?.message) {
notifyError(error.message) // <-- error shown here
} else {
notifyError("Something went wrong");
}
}
}
return (
<form onSubmit={handleSubmit}>
<PaymentElement/>
<BlockSpacer height="1rem"/>
<ActionButton disabled={!stripe || !elements || confirming} type="submit" className="btn-phone btn-fullwidth">Pay {paymentIntent.amountFormatted}</ActionButton>
</form>
)
}
And that form is inside this component, similar to the example shown in step 4:
import {Elements as StripeElements} from '#stripe/react-stripe-js';
import {useStripe, useElements, PaymentElement} from '#stripe/react-stripe-js';
function StripePaymentForm({stripeAccountId,paymentIntent,booking}: StripePaymentFormProps) {
const options = {
clientSecret: paymentIntent.clientSecret,
loader: 'always',
}
return (
<StripeElements stripe={getStripeConnect(stripeAccountId)} options={options}>
<StripeCheckoutForm paymentIntent={paymentIntent} booking={booking}/>
</StripeElements>
)
}
The only thing I can see that's different is that I'm using a Connect account, so I'm passing in account ID in when I load Stripe. getStripeConnect is basically
loadStripe(STRIPE_PUBLIC_KEY, {stripeAccount: CONNECTED_ACCOUNT_ID})
You can see the React component tree here if it helps:
What am I missing?
I'm guessing this stems from useElements() is not finding any elements:
But I still don't know why.
I believe it's a recent bug in react-stripe-js:
https://github.com/stripe/react-stripe-js/issues/296
I believe your loadStripe() promise isn't resolved at the time it is passed to the Elements provider, thus useElements returns null. Either load it earlier or await it and it should resolve your issue.

Passing props to an axios delete request

The objective is to, by pressing a button, delete the object from the database.
To do that, I have to pass the ID of the object I want to delete from the database to the axios query. But I'm stuck trying to do it.
In my opinion the problem is I am not passing the ID to erase to the query, since the query seems right to me.
File: persons.js
import axios from 'axios'
const baseUrl = 'http://localhost:3001/persons'
const deleteContact = (id) =>{
const request = axios.delete('{$baseUrl}/${id}')
request.then(response =>response.data)
}
export default {
deleteContact: deleteContact,
}
The button that should call the function to delete:
File: person.js
import React from 'react'
const Person = ({ person, deleteContact }) => {
return (
<li>
{person.name} {person.number}
<button onClick={deleteContact(person.id)}>Delete {person.id} </button>
</li>
)
}
export default Person
So, by pressing the button I execute the deleteContact funtion and I pass to that function the person.id so it sends the id to delete.
Here is waht's wrong. I don't know how to make the function deleteContact.
I have tried this, but of course I am not sending any props. It's wrong and does nothing. I get the error TypeError: deleteContact is not a function.
const deleteContact = (id) => {
}
The deleteContact funtion I try to implement is on the file App.js
It is something obvious I am missing here. But I can't figure out what is.
Likely something basic, but I have been stuck here for a while, as silly this may seem to be.
File: App.js
import React, { useState, useEffect } from 'react'
import Person from './components/Person'
import Form from './components/Form'
import Filter from './components/Filter'
import FilterResults from './components/FilterResults'
import contactService from './services/persons'
//npm run server
const App = () => {
//Reminder: current state, function that updates it, initial state.
const [ newName, setNewName ] = useState('')
const [ newNumber, setNewNumber ] = useState('')
const [contacts, setContacts] = useState([])
//Filter
const [ filter, setFilter ] = useState('')
//contactService is importer from /services/persons.
//.getAll is like typing: axios.get('http://localhost:3001/persons')
//Effect hooks used to fetch data from the server. The data fetched is saved
//into the contacts state variable
useEffect(() => {
contactService
.getAll()
.then(response => {
setContacts(response.data)
console.log(contacts)
})
}, [])
/*
second parameter of useEffect is used to specify how often the effect
is run. If the second parameter is an empty array [],
then the effect is only run along with the first render of
the component. */
console.log('render', contacts.length, 'contacts')
//adding new persons
const addPerson = (event) => {
event.preventDefault()
/* complete the addPerson function for creating new persons */
const personObject = {
name: newName,
number: newNumber,
//The server will create the id
//id: persons.length + 1,
}
//Adding the data to the server
/*
using separate server comunication module from persons.js
"create" instead of previous code:
axios
.post('http://localhost:3001/persons', personObject)
replaced by:
contactService
.create(personObject)
*/
contactService
//Passing personObject to create
.create(personObject)
.then(response => {
console.log(response)
//After concat, the fiel is set to blank again ('').
//Updating state after creating, to display created contact.
setContacts(contacts.concat(personObject))
setNewName('')
setNewNumber('')
})
}
//Delete contacts
const deleteContact = (personObject) => {
}
const handlePersonChange = (event) => {
console.log(event.target.value)
setNewName(event.target.value)
}
const handleNumberChange = (event) => {
console.log(event.target.value)
setNewNumber(event.target.value)
}
const handleFilterChange = (event) => {
setFilter(event.target.value)
}
const personsToShow = filter === ''
? contacts
: contacts.filter(person =>
person.name.toLowerCase().includes(filter.toLowerCase()))
const row_names = () => personsToShow.map(person =>
<p key={person.name}>{person.name} {person.number} </p>
)
return (
<div>
<Filter value={filter} onChange={handleFilterChange} />
<Form
onSubmit={addPerson}
name={{value: newName, onChange: handlePersonChange}}
number={{value: newNumber, onChange: handleNumberChange}}
deleteContacts={() => deleteContact()}
/>
<h2>Numbers from database</h2>
{/* The contents of the database are stored on the variable contacts.
I map through the array. Person.js component used. */}
<ul>
{contacts.map(person =>
//Pass all the props from person to Person.js
<Person
key={person.id}
person={person}
/>
)}
</ul>
<h2>Filter results</h2>
<FilterResults persons={row_names()} />
</div>
)
}
export default App
The dabatbase is hardcoded json.
file db.json
"persons": [
{
"name": "ss",
"number": "ssssd",
"id": 17
},
{
"name": "ddd",
"number": "6tyhhth",
"id": 18
},
{
"name": "almejas",
"number": "1234",
"id": 19
},
{
"name": "pailo",
"number": "244",
"id": 20
}
]
}
OK. Once again. To handle API requests you have to build API server first. When you send ajax reqests they must go somewhere, and there must be a program listening requests and doing something what depends on request params and body. The repository you show contains only frontend logic and it is OK because server side logic and front-end can be kept separately and run indepentendly. In the same git account you may find some other reps like this one https://github.com/inci-august/fullstackopen/tree/d6680a40d03536e20ee9537cc64e1cb57dd6b74a/part3/phonebook-backend containing back-end implementation. So you build API server, accepting requests, doing something (create/delete posts, users, auth etc) and sending something back, and AFTER you find it working you can send API requests from frontend. Before front part is created you may use apps like Postman to test your API server.
UPDATE:
You mentioned the following link https://fullstackopen.com/en/part2/altering_data_in_server containing the same I have already said - the server side logic does not suppose to be implemented on this step.
In the next part of the course we will learn to implement our own
logic in the backend. We will then take a closer look at tools like
Postman that helps us to debug our server applications
As for you question - the "props" in requests to server can be sent by params in address string like:
axios.delete("api/person/2")
In the example above we say to server that we want the person with id=2 to be deleted. On the server side it will be catched with instruction like:
router.delete("api/person/:id", (req, res) => {
const id = req.params.id
// here you delete the person information and send response back
})
ID here will be handled by server as parameter and you will have an access to its value for further actions.
The exercise expected me to remove objects from the json database just using axios. Perhaps I did not express myself clarly enough, but I finally solved it.
I just wanted to pass the id to delete of each object to the axios request.
On the return sttement of App.js, I pass the person object as props to deleteContactOf
<ul>
{contacts.map(person =>
//Pass all the props from person to Person.js
//Here you pass the props
<Person
key={person.id}
person={person}
deleteContact={() => deleteContctOf(person)}
/>
)}
</ul>
This is how the function deleteContactOf looks like
//Delete contacts
const deleteContctOf = (person) => {
console.log(person)
console.log('delete contact ' + person.id + ' ????')
if (window.confirm("Do you really want to delete this person")) {
contactService
.remove(person.id)
} else {
return
}
}
deleteContactOf passes the id (person.id) to the axios request on file perons.js
Now the id is passed. That's were I was failing.
const remove = (id) => {
const req = axios.delete(`${baseUrl}/${id}`)
return req.then((res) => res.data)
}
Now by clicking the delete button, the contacts that belong to that id are deleted
<button onClick={deleteContact}>Delete</button>
Thanks for your time effort. Of course this is implemented with APIs in real life. This was just an specific exercise I had to solve.
Thanks

Stripe payment button for ReactJs with a simple Snippet Code

I have found a lot of repositories and examples about installing an Stripe complete checkout, but I cannot just use the simple Snippet code that Stripe offers for a product. How can I use that code on a page in my React Project? Here is the code. I just want to redirect the user to the Stripe checkout page for that product, I don't want to use my own formulary and I don't want either to collect data in my app. Thanks a lot.
<!-- Load Stripe.js on your website. -->
<script src="https://js.stripe.com/v3"></script>
<!-- Create a button that your customers click to complete their purchase. Customize the styling to suit your branding. -->
<button
style="background-color:#6772E5;color:#FFF;padding:8px 12px;border:0;border-radius:4px;font-size:1em"
id="checkout-button-price_1Heree568gerg54rtretrt"
role="link"
type="button"
>
Checkout
</button>
<div id="error-message"></div>
<script>
(function() {
var stripe = Stripe('pk_live_t5tyutrytutruytyutyufake....');
var checkoutButton = document.getElementById('checkout-button-price_1Heree568gerg54rtretrt');
checkoutButton.addEventListener('click', function () {
// When the customer clicks on the button, redirect
// them to Checkout.
stripe.redirectToCheckout({
lineItems: [{price: 'price_1Heree568gerg54rtretrt', quantity: 1}],
mode: 'subscription',
// Do not rely on the redirect to the successUrl for fulfilling
// purchases, customers may not always reach the success_url after
// a successful payment.
// Instead use one of the strategies described in
// https://stripe.com/docs/payments/checkout/fulfill-orders
successUrl: 'https://myweb.com/success',
cancelUrl: 'https://myweb.com/canceled',
})
.then(function (result) {
if (result.error) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer.
var displayError = document.getElementById('error-message');
displayError.textContent = result.error.message;
}
});
});
})();
</script>
You can create a dedicated component for that. As stated in the documentation, I am using StripeJS to import it as a module.
// npm install #stripe/stripe-js
import React from 'react';
import {loadStripe} from '#stripe/stripe-js';
const StripeButton = (props) => {
const [stripeError, setStripeError] = React.useState(null);
const [stripe, setStripe] = React.useState(null);
useEffect( async () => {
if (!stripe) {
// Here, you can use some `props` instead of hardcoding the API key
const stripeTmp = await loadStripe('pk_live_t5tyutrytutruytyutyufake....');
setStripe(stripeTmp);
}
});
const handleClick = () => {
// Reset error holder
setStripeError(null);
// When the customer clicks on the button, redirect
// them to Checkout.
stripe.redirectToCheckout({
// Here you can use another `prop` instead of hard coding it
lineItems: [{price: 'price_1Heree568gerg54rtretrt', quantity: 1}],
mode: 'subscription',
// Do not rely on the redirect to the successUrl for fulfilling
// purchases, customers may not always reach the success_url after
// a successful payment.
// Instead use one of the strategies described in
// https://stripe.com/docs/payments/checkout/fulfill-orders
successUrl: 'https://myweb.com/success',
cancelUrl: 'https://myweb.com/canceled',
})
.then(function (result) {
if (result.error) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer.
setStripeError(result.error.message);
}
});
}
return (
<>
{ stripe ? (
<button
style="background-color:#6772E5;color:#FFF;padding:8px 12px ;border:0;border-radius:4px;font-size:1em"
id="checkout-button-price_1Heree568gerg54rtretrt"
role="link"
type="button"
onClick={ handleClick }
>
Checkout
</button>
) : "Loading..."
}
{ stripeError ? <div id="error-message">{ stripeError }</div> : null }
</>
)
}
export default StripeButton;

How do I fix a "IntegrationError: No such sku: "prod_....." error when using Gatsby and Stripe

I'm creating a test site using Gatsby and Stripe.
At the moment, I have 2 products set up in my Stripe account; I can render these successfully in a Gatsby site, created using the standard starter template.
In my gatsby-config.js file, I have this for the Stripe setup:
resolve: `gatsby-source-stripe`,
options: {
objects: ["Product", "Price"],
secretKey: process.env.STRIPE_SECRET_KEY,
downloadFiles: true,
},
The query and rendering code I'm using is this:
const Skus = () => {
return (
<StaticQuery
query={graphql`
query SkusForProduct {
skus: allStripePrice {
edges {
node {
id
currency
unit_amount
unit_amount_decimal
product {
images
unit_label
description
name
id
}
}
}
}
}
`}
render={({ skus }) => (
<div style={containerStyles}>
{skus.edges.map(({ node: sku }) => (
<SkuCard key={sku.product.id} sku={sku} stripePromise={stripePromise} />
))}
</div>
)}
/>
)
}
I have a separate component (SkuCard), which is used to render the details of each product - the core code looks like this:
const formatPrice = (amount, currency) => {
let price = (amount / 100).toFixed(2)
let numberFormat = new Intl.NumberFormat(["en-US"], {
style: "currency",
currency: currency,
currencyDisplay: "symbol",
})
return numberFormat.format(price)
}
const SkuCard = ({ sku, stripePromise }) => {
const redirectToCheckout = async (event, sku, quantity = 1) => {
event.preventDefault()
const stripe = await stripePromise
const { error } = await stripe.redirectToCheckout({
items: [{ sku, quantity }],
successUrl: `${window.location.origin}/page-2/`,
cancelUrl: `${window.location.origin}/advanced`,
})
if (error) {
console.warn("Error:", error)
}
}
return (
<div style={cardStyles}>
<h4>{sku.product.name}</h4>
<img src={sku.product.images} alt={sku.product.name} />
<p>Price: {formatPrice(sku.unit_amount, sku.currency)}</p>
<p>ID: {sku.product.id}</p>
<button
style={buttonStyles}
onClick={event => redirectToCheckout(event, sku.product.id)}
>
BUY ME
</button>
</div>
)
}
export default SkuCard
My Issue:
Each time I click on the Buy Me button, I'm getting this error in console log:
The steps I've taken:
Confirmed that the ID against the "No such sku" error is indeed one of my test products;
Tried altering the GraphQL query to see if I'm picking up the wrong ID entry - I have tried ones under sku.id and sku.product.id (using the GraphiQL browser), but neither work;
Added a tag to the products displayed to confirm what I believe to be the correct product ID (same as the one shown in the screenshot), can be rendered on screen in the product details - this is displayed without issue;
Scoured the internet to see if anyone else has done similar examples - nothing found;
Used the example code from the main Gatsby site to confirm that I can at least put a single "hard-coded" product through the checkout process - that works. (My chosen method though is to render products dynamically, not as hard-coded items on the page)
Checked the Stackoverflow site: questions have been asked about Stripe & Gatsby, but not found anything yet that is close to this issue.
I'm trying to figure out what is causing this error - can anyone help please?

Resources