infoalloggi-monorepo/apps/infoalloggi/src/pages/servizio/acquisto-processing.tsx
Marco Pedone 699579b432 feat: update environment variable handling and dependencies
- Added @t3-oss/env-nextjs for improved environment variable management.
- Updated zod to version 4.1.12 for enhanced validation capabilities.
- Upgraded jiti to version 2.6.1 for better module loading.
- Refactored environment variable imports from env.mjs to env.ts.
- Removed deprecated env.mjs file and replaced it with a new env.ts file using @t3-oss/env-nextjs.
- Adjusted various components and API routes to utilize the new environment variable structure.
- Updated next.config.js to support the new environment variable management.
- Modified Docker configuration to align with new BASE_URL handling.
2025-10-20 16:22:20 +02:00

208 lines
5.2 KiB
TypeScript

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