- Replaced custom Zod types with imported schemas in stripe router and user router. - Updated payment controller to use new enum imports for order types and payment statuses. - Refactored payment tests to utilize the new enum structure. - Removed deprecated zod_types file and created new zod_chat_types file for chat-related schemas. - Adjusted service files to align with the new order type enums and schemas. - Enhanced the Caratteristiche type definition using Zod for better validation. Co-authored-by: Copilot <copilot@github.com>
179 lines
5.1 KiB
TypeScript
179 lines
5.1 KiB
TypeScript
import { add, formatDuration, intervalToDuration } from "date-fns";
|
|
import { it } from "date-fns/locale";
|
|
import { ArrowRight, CalendarClock, Clock, PackageCheck } from "lucide-react";
|
|
import Link from "next/link";
|
|
import { useRouter } from "next/router";
|
|
import { useState } from "react";
|
|
import toast from "react-hot-toast";
|
|
import { Button } from "~/components/ui/button";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
} from "~/components/ui/dialog";
|
|
import { FormRinnovo } from "~/forms/FormRinnovo";
|
|
import { useRinnovo } from "~/providers/RinnovoProvider";
|
|
import { orderTypeEnum } from "~/schemas/public/OrderTypeEnum";
|
|
import type { UsersId } from "~/schemas/public/Users";
|
|
import { api } from "~/utils/api";
|
|
|
|
export const Rinnovo = () => {
|
|
const { rinnovo, isAdmin } = useRinnovo();
|
|
const hasPaid = rinnovo.ordini
|
|
.filter((o) => o.type === orderTypeEnum.enum.Rinnovo)
|
|
.find((o) => o.isActive);
|
|
return (
|
|
<div className="w-full space-y-8">
|
|
<div className="flex flex-col flex-wrap items-start justify-between gap-4 sm:flex-row">
|
|
<div className="flex flex-col gap-1">
|
|
<h3 className="font-semibold text-2xl">
|
|
Rinnovo permanenza {rinnovo.codice}
|
|
</h3>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<Clock className="size-5" />
|
|
<span>
|
|
Decorrenza: {rinnovo.decorrenza.toLocaleDateString("it-IT")}
|
|
</span>
|
|
</div>
|
|
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<div className="flex items-center gap-2">
|
|
<CalendarClock className="size-5" />
|
|
<span>
|
|
Scadenza: {rinnovo.scadenza.toLocaleDateString("it-IT")}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<p>
|
|
Permanenza:{" "}
|
|
{formatDuration(
|
|
intervalToDuration({
|
|
start: new Date(rinnovo.decorrenza),
|
|
end: add(new Date(rinnovo.scadenza), { days: 1 }),
|
|
}),
|
|
{ locale: it, format: ["years", "months", "days"] },
|
|
)}
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
{isAdmin && <EditRinnovoModal />}
|
|
</div>
|
|
</div>
|
|
<div className="flex w-full justify-center">
|
|
{hasPaid ? (
|
|
<div className="flex w-full max-w-md flex-col items-center justify-center gap-4 text-center">
|
|
<PackageCheck className="size-46 stroke-1" />
|
|
<p className="font-medium text-green-600 text-lg">
|
|
Pagamento ricevuto!
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<div className="flex w-full max-w-md flex-col items-center justify-center gap-4 text-center">
|
|
<PackageCheck className="size-46 stroke-1" />
|
|
|
|
<Link
|
|
aria-label="Attiva Servizio"
|
|
className="w-full"
|
|
href={`/servizio/pagamento?rinnovoId=${rinnovo.id}&type=${orderTypeEnum.enum.Rinnovo}`}
|
|
>
|
|
<Button className="w-full text-lg" variant="info">
|
|
<span>Procedi al pagamento</span>
|
|
<ArrowRight />
|
|
</Button>
|
|
</Link>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
const EditRinnovoModal = () => {
|
|
const { rinnovo, userId } = useRinnovo();
|
|
const utils = api.useUtils();
|
|
const router = useRouter();
|
|
|
|
const { mutate: edit } = api.servizio.updateRinnovo.useMutation({
|
|
onError: (error) => {
|
|
toast.error(error.message);
|
|
},
|
|
onSuccess: async () => {
|
|
toast.success("Rinnovo modificato con successo");
|
|
await utils.servizio.invalidate();
|
|
},
|
|
});
|
|
const { mutate: remove } = api.servizio.removeRinnovo.useMutation({
|
|
onError: (error) => {
|
|
toast.error(error.message);
|
|
},
|
|
onMutate: async () => {
|
|
await router.push(`/area-riservata/admin/user-view/ricerca/${userId}`);
|
|
},
|
|
onSuccess: async () => {
|
|
toast.success("Rinnovo modificato con successo");
|
|
await utils.servizio.invalidate();
|
|
},
|
|
});
|
|
|
|
return (
|
|
<Dialog>
|
|
<DialogTrigger asChild>
|
|
<Button variant="outline">Modifica Rinnovo</Button>
|
|
</DialogTrigger>
|
|
<DialogContent className="w-full px-4 py-10 sm:max-w-5xl">
|
|
<DialogHeader>
|
|
<DialogTitle>Modifica Rinnovo</DialogTitle>
|
|
<DialogDescription className="sr-only">desc</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<FormRinnovo
|
|
initialData={rinnovo}
|
|
onDelete={() => remove({ rinnovoId: rinnovo.id })}
|
|
onSubmit={(v) => edit({ rinnovoId: rinnovo.id, data: v })}
|
|
/>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|
|
|
|
export const NewRinnovoModal = ({ userId }: { userId: UsersId }) => {
|
|
const [open, setOpen] = useState(false);
|
|
const utils = api.useUtils();
|
|
|
|
const { mutate: add } = api.servizio.createRinnovo.useMutation({
|
|
onError: (error) => {
|
|
toast.error(error.message);
|
|
},
|
|
onSuccess: async () => {
|
|
toast.success("Rinnovo creato con successo");
|
|
await utils.servizio.invalidate();
|
|
|
|
setOpen(false);
|
|
},
|
|
});
|
|
|
|
return (
|
|
<Dialog onOpenChange={setOpen} open={open}>
|
|
<DialogTrigger asChild>
|
|
<Button
|
|
onClick={() => {
|
|
setOpen(true);
|
|
}}
|
|
variant="outline"
|
|
>
|
|
Nuovo Rinnovo
|
|
</Button>
|
|
</DialogTrigger>
|
|
<DialogContent className="w-full px-4 py-10 sm:max-w-5xl">
|
|
<DialogHeader>
|
|
<DialogTitle>Creazione Rinnovo</DialogTitle>
|
|
<DialogDescription className="sr-only">desc</DialogDescription>
|
|
</DialogHeader>
|
|
<FormRinnovo onSubmit={(v) => add({ data: { userId, ...v } })} />
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|