Last active
July 12, 2021 20:54
-
-
Save simon-saliba/5439878a679dff9b8ef2606532000c9d to your computer and use it in GitHub Desktop.
Checkout form component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useEffect, useState } from "react"; | |
import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js"; | |
import { StripeCardElementChangeEvent, StripeError } from "@stripe/stripe-js"; | |
import "./styles.css"; | |
import CardField from "../CardField/CardField"; | |
import Field from "../Field/Field"; | |
import SubmitButton from "../SubmitButton/SubmitButton"; | |
import ErrorMessage from "../ErrorMessage/ErrorMessage"; | |
const CheckoutForm = () => { | |
const stripe = useStripe(); | |
const elements = useElements(); | |
const [error, setError] = useState<StripeError | null | undefined>(null); | |
const [processing, setProcessing] = useState<boolean>(false); | |
const [succeeded, setSucceeded] = useState<boolean>(false); | |
const [billingDetails, setBillingDetails] = useState<{ | |
email: string; | |
phone: string; | |
name: string; | |
}>({ | |
email: "", | |
phone: "", | |
name: "", | |
}); | |
const [clientSecret, setClientSecret] = useState<string>(""); | |
const [disabled, setDisabled] = useState<boolean>(true); | |
useEffect(() => { | |
// Create PaymentIntent as soon as the page loads | |
fetch("/create-payment-intent", { | |
method: "POST", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify({ | |
items: [{ id: "tshirt" }], | |
amount: 2500, | |
}), | |
}) | |
.then((res) => { | |
return res.json(); | |
}) | |
.then((data) => { | |
setClientSecret(data.clientSecret); | |
}); | |
}, []); | |
const handleChange = async (event: StripeCardElementChangeEvent) => { | |
// Listen for changes in the CardElement | |
// and display any errors as the customer types their card details | |
setDisabled(event.empty); | |
setError(event.error); | |
}; | |
const handleSubmit: React.FormEventHandler<HTMLFormElement> | undefined = | |
async (ev: React.FormEvent<HTMLFormElement>) => { | |
ev.preventDefault(); | |
if (!stripe || !elements) { | |
// Stripe.js has not loaded yet. Make sure to disable | |
// form submission until Stripe.js has loaded. | |
return; | |
} | |
const cardElement = elements.getElement(CardElement); | |
if (cardElement) { | |
setProcessing(true); | |
const payload = await stripe.confirmCardPayment(clientSecret, { | |
payment_method: { | |
card: cardElement, | |
}, | |
}); | |
if (payload.error) { | |
setError(payload.error); | |
setProcessing(false); | |
} else { | |
setError(null); | |
setProcessing(false); | |
setSucceeded(true); | |
} | |
} | |
}; | |
return ( | |
<form className="Form" onSubmit={handleSubmit}> | |
<fieldset className="FormGroup"> | |
<Field | |
label="Name" | |
id="name" | |
type="text" | |
placeholder="Jane Doe" | |
required | |
autoComplete="name" | |
value={billingDetails.name} | |
onChange={(e) => { | |
setBillingDetails({ ...billingDetails, name: e.target.value }); | |
}} | |
/> | |
<Field | |
label="Email" | |
id="email" | |
type="email" | |
placeholder="janedoe@gmail.com" | |
required | |
autoComplete="email" | |
value={billingDetails.email} | |
onChange={(e) => { | |
setBillingDetails({ ...billingDetails, email: e.target.value }); | |
}} | |
/> | |
<Field | |
label="Phone" | |
id="phone" | |
type="tel" | |
placeholder="(941) 555-0123" | |
required | |
autoComplete="tel" | |
value={billingDetails.phone} | |
onChange={(e) => { | |
setBillingDetails({ ...billingDetails, phone: e.target.value }); | |
}} | |
/> | |
</fieldset> | |
<fieldset className="FormGroup"> | |
<CardField onChange={handleChange} /> | |
</fieldset> | |
{error && <ErrorMessage>{error.message}</ErrorMessage>} | |
<SubmitButton | |
processing={processing} | |
error={error} | |
disabled={processing || disabled || succeeded} | |
> | |
Pay 25$ | |
</SubmitButton> | |
{succeeded && ( | |
<p> | |
Payment succeeded, see the result in your | |
<a href={`https://dashboard.stripe.com/test/payments`}> | |
{" "} | |
Stripe dashboard. | |
</a>{" "} | |
Refresh the page to pay again. | |
</p> | |
)} | |
</form> | |
); | |
}; | |
export default CheckoutForm; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment