infoalloggi-monorepo/apps/infoalloggi/src/pages/servizio/acquisto-processing.tsx

209 lines
5.2 KiB
TypeScript
Raw Normal View History

2025-08-04 17:45:44 +02:00
import { Elements, useStripe } from "@stripe/react-stripe-js";
import { loadStripe } from "@stripe/stripe-js";
import { ArrowLeft } from "lucide-react";
import type { GetServerSideProps } from "next";
2025-08-28 18:27:07 +02:00
import Link from "next/link";
import { useRouter } from "next/router";
2025-08-04 17:45:44 +02:00
import { useEffect, useState } from "react";
2025-08-28 18:27:07 +02:00
import PaymentStatus from "~/components/payment_status";
2025-08-04 17:45:44 +02:00
import { ProgressRedirect } from "~/components/progress_redirect";
2025-08-28 18:27:07 +02:00
import { Button, buttonVariants } from "~/components/ui/button";
import { env } from "~/env.mjs";
import { cn } from "~/lib/utils";
import { useTranslation } from "~/providers/I18nProvider";
import PaymentStatusEnum from "~/schemas/public/PaymentStatusEnum";
import { api } from "~/utils/api";
2025-08-04 17:45:44 +02:00
type AcquistoProcessingProps = {
2025-08-28 18:27:07 +02:00
client_secret: string;
2025-08-04 17:45:44 +02:00
};
export const getServerSideProps = (async (context) => {
2025-08-28 18:27:07 +02:00
if (
!context.query.payment_intent_client_secret ||
typeof context.query.payment_intent_client_secret !== "string"
) {
return {
redirect: {
destination: "/500",
permanent: false,
2025-08-29 16:18:32 +02:00
statusCode: 500,
2025-08-28 18:27:07 +02:00
},
};
}
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
return {
props: {
client_secret: context.query.payment_intent_client_secret,
},
};
2025-08-04 17:45:44 +02:00
}) satisfies GetServerSideProps<AcquistoProcessingProps>;
export default function AcquistoProcessing({
2025-08-28 18:27:07 +02:00
client_secret,
2025-08-04 17:45:44 +02:00
}: AcquistoProcessingProps) {
2025-08-28 18:27:07 +02:00
const { t } = useTranslation();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const stripePromise = loadStripe(env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY);
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
return (
<div className="mx-auto my-5 w-full max-w-lg space-y-8">
<h3 className="my-8 text-center text-xl font-bold tracking-wide text-neutral-700 uppercase dark:text-white">
{t.acquisto_elaborazione.titolo}
</h3>
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
<div>
<Elements
options={{
appearance: {
theme: "stripe",
},
clientSecret: client_secret,
}}
stripe={stripePromise}
>
<CompletePage secret={client_secret} />
</Elements>
</div>
</div>
);
2025-08-04 17:45:44 +02:00
}
const CompletePage = ({ secret }: { secret: string }) => {
2025-08-28 18:27:07 +02:00
const stripe = useStripe();
const utils = api.useUtils();
const router = useRouter();
const { t } = useTranslation();
const [status, setStatus] = useState<
"success" | "processing" | "failed" | "internal_error" | "not_found"
>("processing");
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
useEffect(() => {
const fetchPaymentIntent = async () => {
if (!stripe) {
return;
}
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
try {
const { paymentIntent } = await stripe.retrievePaymentIntent(secret);
if (!paymentIntent) {
setStatus("internal_error");
return;
}
const payment = await utils.pagamenti.getPaymentFromIntent.fetch({
pIntentId: paymentIntent.id,
});
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
if (!payment) {
setStatus("not_found");
return;
}
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
if (paymentIntent.status === "succeeded") {
if (payment.paymentstatus !== PaymentStatusEnum.success) {
setStatus("internal_error");
}
setStatus("success");
} else if (paymentIntent.status === "processing") {
if (payment.paymentstatus !== PaymentStatusEnum.processing) {
setStatus("internal_error");
}
setStatus("processing");
} else {
setStatus("failed");
}
} catch (error) {
console.error("Error retrieving payment intent:", error);
}
};
void fetchPaymentIntent();
}, [stripe, secret]);
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
if (!status) {
return null;
}
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
return (
<div className="space-y-4 p-4">
{status === "success" && (
<>
<PaymentStatus
message={t.acquisto_elaborazione.success_desc}
2025-08-29 16:18:32 +02:00
status="success"
title={t.acquisto_elaborazione.success_title}
2025-08-28 18:27:07 +02:00
/>
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
<ProgressRedirect href="/area-riservata/dashboard" />
</>
)}
{status === "processing" && (
<>
<PaymentStatus
message={t.acquisto_elaborazione.processing_desc}
2025-08-29 16:18:32 +02:00
status="processing"
title={t.acquisto_elaborazione.processing_title}
2025-08-28 18:27:07 +02:00
/>
<Link
className={cn("w-full", buttonVariants({ variant: "info" }))}
2025-08-29 16:18:32 +02:00
href="/area-riservata/dashboard"
2025-08-28 18:27:07 +02:00
>
{t.acquisto_elaborazione.to_dashboard}
</Link>
</>
)}
{status === "failed" && (
<>
<PaymentStatus
message={t.acquisto_elaborazione.failed_desc}
2025-08-29 16:18:32 +02:00
status="error"
title={t.acquisto_elaborazione.failed_title}
2025-08-28 18:27:07 +02:00
/>
<Link
className={cn("w-full", buttonVariants({ variant: "default" }))}
2025-08-29 16:18:32 +02:00
href="/area-riservata/chat"
2025-08-28 18:27:07 +02:00
>
{t.acquisto_elaborazione.to_chat}
</Link>
</>
)}
{status === "internal_error" && (
<>
<PaymentStatus
message={t.acquisto_elaborazione.internal_error_desc}
2025-08-29 16:18:32 +02:00
status="error"
title={t.acquisto_elaborazione.internal_error_title}
2025-08-28 18:27:07 +02:00
/>
<Link
className={cn("w-full", buttonVariants({ variant: "default" }))}
2025-08-29 16:18:32 +02:00
href="/area-riservata/chat"
2025-08-28 18:27:07 +02:00
>
{t.acquisto_elaborazione.to_chat}
</Link>
</>
)}
{status === "not_found" && (
<>
<PaymentStatus
message={t.acquisto_elaborazione.not_found_desc}
2025-08-29 16:18:32 +02:00
status="error"
title={t.acquisto_elaborazione.not_found_title}
2025-08-28 18:27:07 +02:00
/>
<Button
className="w-full"
2025-08-29 16:18:32 +02:00
onClick={() => router.back()}
2025-08-28 18:27:07 +02:00
variant="secondary"
>
<ArrowLeft />
{t.indietro}
</Button>
<Link
className={cn("w-full", buttonVariants({ variant: "default" }))}
2025-08-29 16:18:32 +02:00
href="/area-riservata/chat"
2025-08-28 18:27:07 +02:00
>
{t.acquisto_elaborazione.to_chat}
</Link>
</>
)}
</div>
);
2025-08-04 17:45:44 +02:00
};