Skip to content

Instantly share code, notes, and snippets.

@simon-saliba
Last active July 12, 2021 20:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simon-saliba/5439878a679dff9b8ef2606532000c9d to your computer and use it in GitHub Desktop.
Save simon-saliba/5439878a679dff9b8ef2606532000c9d to your computer and use it in GitHub Desktop.
Checkout form component
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