infoalloggi-monorepo/apps/infoalloggi/src/components/checkout.tsx

123 lines
2.8 KiB
TypeScript
Raw Normal View History

import {
Elements,
PaymentElement,
useElements,
useStripe,
} from "@stripe/react-stripe-js";
import { loadStripe } from "@stripe/stripe-js";
import { type FormEvent, useState } from "react";
import { env } from "~/env";
import { formatCurrency } from "~/lib/utils";
import { useTranslation } from "~/providers/I18nProvider";
import LoadingButton from "./custom_ui/loading-button";
import { Card, CardContent, CardHeader, CardTitle } from "./ui/card";
const stripePromise = loadStripe(env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY);
export default function CheckoutForm({
clientSecret,
titolo,
prezzo,
descrizione,
}: {
clientSecret: string;
titolo: string;
prezzo: number;
descrizione: string;
}) {
return (
<Elements
options={{
appearance: {
theme: "stripe",
variables: {
colorPrimary: "#18181b",
colorText: "#18181b",
},
},
clientSecret,
}}
stripe={stripePromise}
>
<PaymentForm descrizione={descrizione} prezzo={prezzo} titolo={titolo} />
</Elements>
);
}
const PaymentForm = ({
titolo,
prezzo,
descrizione,
}: {
titolo: string;
prezzo: number;
descrizione: string;
}) => {
const stripe = useStripe();
const elements = useElements();
const [message, setMessage] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const { t } = useTranslation();
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!stripe || !elements) {
return;
}
setIsLoading(true);
const { error } = await stripe.confirmPayment({
confirmParams: {
return_url: `${env.NEXT_PUBLIC_BASE_URL}/servizio/pagamento-status`,
},
elements,
});
if (error.type === "card_error" || error.type === "validation_error") {
setMessage(error.message || "An unexpected error occurred.");
} else {
setMessage("An unexpected error occurred.");
}
setIsLoading(false);
};
return (
<Card className="flex w-full flex-col justify-between text-left">
<CardHeader>
<CardTitle>
<p className="text-2xl">{titolo}</p>
</CardTitle>
<p>{descrizione}</p>
<span>
<span className="font-bold text-3xl">
{formatCurrency(prezzo / 100)}
</span>{" "}
<span className="font-normal text-base sm:text-sm">
{t.pricing_cmp.risultati_iva}
</span>
</span>
</CardHeader>
<CardContent>
<form className="space-y-5" id="payment-form" onSubmit={handleSubmit}>
<PaymentElement
id="payment-element"
options={{ layout: "accordion" }}
/>
<LoadingButton
aria-label="Procedi al pagamento"
className="w-full"
disabled={isLoading || !stripe || !elements}
loading={isLoading || !stripe || !elements}
type="submit"
>
{t.procedi}
</LoadingButton>
{message && <div id="payment-message">{message}</div>}
</form>
</CardContent>
</Card>
);
};