2025-08-28 18:27:07 +02:00
|
|
|
import { add } from "date-fns";
|
2025-12-04 17:16:49 +01:00
|
|
|
import {
|
|
|
|
|
Bug,
|
|
|
|
|
ChevronDown,
|
|
|
|
|
ClockAlert,
|
|
|
|
|
Cog,
|
2026-02-25 15:30:53 +01:00
|
|
|
Euro,
|
2026-01-16 17:11:53 +01:00
|
|
|
ExternalLink,
|
2025-12-04 17:16:49 +01:00
|
|
|
Plus,
|
2026-02-24 10:40:32 +01:00
|
|
|
Search,
|
2025-12-18 12:18:24 +01:00
|
|
|
SlidersHorizontal,
|
2025-12-18 15:12:05 +01:00
|
|
|
Trash2,
|
2025-12-04 17:16:49 +01:00
|
|
|
} from "lucide-react";
|
2026-01-16 17:11:53 +01:00
|
|
|
import Link from "next/link";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { useState } from "react";
|
2025-08-04 17:45:44 +02:00
|
|
|
import toast from "react-hot-toast";
|
|
|
|
|
import {
|
2025-08-28 18:27:07 +02:00
|
|
|
Credenza,
|
|
|
|
|
CredenzaBody,
|
|
|
|
|
CredenzaContent,
|
|
|
|
|
CredenzaDescription,
|
|
|
|
|
CredenzaHeader,
|
|
|
|
|
CredenzaTitle,
|
|
|
|
|
CredenzaTrigger,
|
|
|
|
|
} from "~/components/custom_ui/credenza";
|
2025-08-04 17:45:44 +02:00
|
|
|
import { MultiSelect } from "~/components/custom_ui/multiselect";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { LoadingPage } from "~/components/loading";
|
2025-08-04 17:45:44 +02:00
|
|
|
import {
|
2025-08-28 18:27:07 +02:00
|
|
|
AlertDialog,
|
|
|
|
|
AlertDialogAction,
|
|
|
|
|
AlertDialogCancel,
|
|
|
|
|
AlertDialogContent,
|
|
|
|
|
AlertDialogDescription,
|
|
|
|
|
AlertDialogFooter,
|
|
|
|
|
AlertDialogHeader,
|
|
|
|
|
AlertDialogTitle,
|
|
|
|
|
AlertDialogTrigger,
|
2025-08-04 17:45:44 +02:00
|
|
|
} from "~/components/ui/alert-dialog";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { Button } from "~/components/ui/button";
|
2025-08-04 17:45:44 +02:00
|
|
|
import {
|
2025-08-28 18:27:07 +02:00
|
|
|
Collapsible,
|
|
|
|
|
CollapsibleContent,
|
|
|
|
|
CollapsibleTrigger,
|
|
|
|
|
} from "~/components/ui/collapsible";
|
|
|
|
|
import {
|
|
|
|
|
Dialog,
|
|
|
|
|
DialogContent,
|
|
|
|
|
DialogDescription,
|
|
|
|
|
DialogFooter,
|
|
|
|
|
DialogHeader,
|
|
|
|
|
DialogTitle,
|
|
|
|
|
DialogTrigger,
|
|
|
|
|
} from "~/components/ui/dialog";
|
|
|
|
|
import {
|
|
|
|
|
type FormValues as EditFormValues,
|
|
|
|
|
FormEditServizio,
|
|
|
|
|
} from "~/forms/FormEditServizioAdmin";
|
|
|
|
|
import { FormNewServizio, type FormValues } from "~/forms/FormNewServizio";
|
2025-12-17 14:14:30 +01:00
|
|
|
import { cn, formatCurrency } from "~/lib/utils";
|
2026-02-25 15:30:53 +01:00
|
|
|
import { useTranslation } from "~/providers/I18nProvider";
|
2025-08-04 17:45:44 +02:00
|
|
|
import { useServizio } from "~/providers/ServizioProvider";
|
2025-08-28 18:27:07 +02:00
|
|
|
import type { AnnunciId } from "~/schemas/public/Annunci";
|
2025-08-19 16:44:38 +02:00
|
|
|
import type { ServizioServizioId } from "~/schemas/public/Servizio";
|
2026-01-16 17:11:53 +01:00
|
|
|
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
|
2025-08-19 16:44:38 +02:00
|
|
|
import type { UsersId } from "~/schemas/public/Users";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { api } from "~/utils/api";
|
2025-12-18 15:12:05 +01:00
|
|
|
import { Confirm } from "../confirm";
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2026-02-25 15:30:53 +01:00
|
|
|
export const AdminActions = () => {
|
2025-08-28 18:27:07 +02:00
|
|
|
const { servizio, isAdmin, userId } = useServizio();
|
2026-02-25 15:30:53 +01:00
|
|
|
if (!isAdmin) return null;
|
2025-08-28 18:27:07 +02:00
|
|
|
return (
|
2026-02-25 15:30:53 +01:00
|
|
|
<div className="flex flex-wrap items-center gap-3">
|
|
|
|
|
<AddAnnuncio servizioId={servizio.servizio_id} userId={userId} />
|
|
|
|
|
<EditServizioAdmin />
|
|
|
|
|
<Link
|
|
|
|
|
href={`/area-riservata/admin/user-view/ordini/${userId}?servizioId=${servizio.servizio_id}`}
|
|
|
|
|
>
|
|
|
|
|
<Button variant="warning">
|
|
|
|
|
<Search />
|
|
|
|
|
<span>Ordini</span>
|
|
|
|
|
</Button>
|
|
|
|
|
</Link>
|
2025-08-28 18:27:07 +02:00
|
|
|
</div>
|
|
|
|
|
);
|
2025-08-24 15:47:08 +02:00
|
|
|
};
|
2025-12-04 17:16:49 +01:00
|
|
|
|
2026-02-25 15:30:53 +01:00
|
|
|
export const ServizioBasicActions = ({ className }: { className?: string }) => {
|
2025-12-04 17:16:49 +01:00
|
|
|
const { servizio, isAdmin } = useServizio();
|
|
|
|
|
|
2026-02-25 15:30:53 +01:00
|
|
|
const canUserEdit = servizio.isOkAcconto && servizio.decorrenza !== null;
|
|
|
|
|
/*&&
|
2025-12-18 14:12:16 +01:00
|
|
|
new Date() <= add(new Date(servizio.decorrenza), { days: 60 }) &&
|
2025-12-18 15:12:25 +01:00
|
|
|
!servizio.annunci.some((a) => a.user_confirmed_at !== null) &&
|
|
|
|
|
!servizio.isInterrotto &&
|
2026-02-25 15:30:53 +01:00
|
|
|
!servizio.annunci.some((a) => a.user_confirmed_at !== null);*/
|
2025-12-04 17:16:49 +01:00
|
|
|
|
|
|
|
|
if (isAdmin || canUserEdit) {
|
|
|
|
|
return (
|
2026-01-16 17:11:53 +01:00
|
|
|
<div className={cn("flex flex-wrap items-center gap-2", className)}>
|
2025-12-18 12:11:08 +01:00
|
|
|
<EditParametri />
|
2025-12-04 17:16:49 +01:00
|
|
|
<InterruzioneServizio />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
};
|
2025-12-17 14:14:30 +01:00
|
|
|
|
2026-01-16 15:47:38 +01:00
|
|
|
export const ServizioPacksInfos = () => {
|
2025-12-17 14:14:30 +01:00
|
|
|
const { servizio } = useServizio();
|
2026-02-25 15:30:53 +01:00
|
|
|
const { t } = useTranslation();
|
2025-12-17 14:14:30 +01:00
|
|
|
const { data: packs } = api.servizio.getPacksSolution.useQuery({
|
|
|
|
|
servizioId: servizio.servizio_id,
|
|
|
|
|
});
|
|
|
|
|
if (!packs) return null;
|
2026-02-25 15:30:53 +01:00
|
|
|
|
2025-12-17 14:14:30 +01:00
|
|
|
return (
|
2026-02-25 15:30:53 +01:00
|
|
|
<Collapsible className="flex flex-col gap-2">
|
|
|
|
|
<CollapsibleTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
className="h-fit w-fit flex-wrap items-center py-1"
|
|
|
|
|
variant="outline"
|
|
|
|
|
>
|
|
|
|
|
<Euro className="size-5" />
|
2025-12-18 13:29:39 +01:00
|
|
|
|
2026-02-25 15:30:53 +01:00
|
|
|
<h3 className="font-semibold text-lg">{t.servizio.prezzi.title}</h3>
|
|
|
|
|
|
|
|
|
|
<ChevronDown className="size-4" />
|
|
|
|
|
</Button>
|
|
|
|
|
</CollapsibleTrigger>
|
|
|
|
|
<CollapsibleContent className="flex flex-col gap-2">
|
|
|
|
|
<span className="text-muted-foreground text-sm">
|
|
|
|
|
{t.servizio.prezzi.sub}
|
|
|
|
|
</span>
|
|
|
|
|
<div className="flex w-full flex-col gap-4 md:flex-row">
|
2026-01-16 17:11:53 +01:00
|
|
|
<div className="flex flex-1 flex-col gap-2 rounded-md bg-secondary/50 p-2">
|
2026-02-25 15:30:53 +01:00
|
|
|
{packs.acconto.success ? (
|
|
|
|
|
<>
|
|
|
|
|
<span className="font-medium">
|
|
|
|
|
{packs.acconto.pack.nome_it}
|
|
|
|
|
</span>
|
|
|
|
|
<span className="text-muted-foreground text-sm">
|
|
|
|
|
{packs.acconto.pack.desc_it}
|
|
|
|
|
</span>
|
|
|
|
|
<span className="font-semibold text-lg">
|
|
|
|
|
{formatCurrency(packs.acconto.pack.prezzo_cent / 100)}
|
|
|
|
|
</span>
|
|
|
|
|
<span className="text-muted-foreground text-sm">
|
|
|
|
|
COD: {packs.acconto.pack.idprezziario}
|
|
|
|
|
</span>
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<span className="font-medium">{packs.acconto.message}</span>
|
|
|
|
|
)}
|
2026-01-16 17:11:53 +01:00
|
|
|
</div>
|
2026-02-25 15:30:53 +01:00
|
|
|
|
|
|
|
|
<div className="flex flex-1 flex-col gap-2 rounded-md bg-secondary/50 p-2">
|
|
|
|
|
{packs.saldo.success ? (
|
|
|
|
|
<>
|
|
|
|
|
<span className="font-medium">{packs.saldo.pack.nome_it}</span>
|
|
|
|
|
<span className="text-muted-foreground text-sm">
|
|
|
|
|
{packs.saldo.pack.desc_it}
|
|
|
|
|
</span>
|
|
|
|
|
<span className="font-semibold text-lg">
|
|
|
|
|
{formatCurrency(packs.saldo.pack.prezzo_cent / 100)}
|
|
|
|
|
</span>
|
|
|
|
|
<span className="text-muted-foreground text-sm">
|
|
|
|
|
COD: {packs.saldo.pack.idprezziario}
|
|
|
|
|
</span>
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<span className="font-medium">{packs.saldo.message}</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
{servizio.tipologia === TipologiaPosizioneEnum.Stabile && (
|
|
|
|
|
<div className="flex flex-1 flex-col gap-2 rounded-md bg-secondary/50 p-2">
|
|
|
|
|
<>
|
|
|
|
|
<span className="font-medium">
|
|
|
|
|
{t.servizio.prezzi.consulenza}
|
|
|
|
|
</span>
|
|
|
|
|
<span className="text-muted-foreground text-sm">
|
|
|
|
|
{t.servizio.prezzi.consulenza_desc}
|
|
|
|
|
</span>
|
|
|
|
|
<span className="font-semibold">
|
|
|
|
|
<Link
|
|
|
|
|
className="flex items-center gap-2 underline underline-offset-2"
|
|
|
|
|
href={"/prezzi#contratti"}
|
|
|
|
|
target="_blank"
|
|
|
|
|
>
|
|
|
|
|
<span>{t.servizio.prezzi.gotoprezzi}</span>
|
|
|
|
|
<ExternalLink className="size-4 stroke-foreground" />
|
|
|
|
|
</Link>
|
|
|
|
|
</span>
|
|
|
|
|
</>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</CollapsibleContent>
|
|
|
|
|
</Collapsible>
|
2025-12-17 14:14:30 +01:00
|
|
|
);
|
|
|
|
|
};
|
2025-12-18 15:12:05 +01:00
|
|
|
|
|
|
|
|
const AddAnnuncio = ({
|
2025-08-28 18:27:07 +02:00
|
|
|
servizioId,
|
|
|
|
|
userId,
|
2025-08-19 16:44:38 +02:00
|
|
|
}: {
|
2025-08-28 18:27:07 +02:00
|
|
|
servizioId: ServizioServizioId;
|
|
|
|
|
userId: UsersId;
|
2025-08-19 16:44:38 +02:00
|
|
|
}) => {
|
2025-08-28 18:27:07 +02:00
|
|
|
const { data: codici, isLoading: loading } =
|
|
|
|
|
api.servizio.getAnnunciAvailableToAdd.useQuery({
|
|
|
|
|
servizioId,
|
|
|
|
|
});
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const [selectedAnnunci, setSelectedAnnunci] = useState<
|
|
|
|
|
{ value: AnnunciId; label: string }[]
|
|
|
|
|
>([]);
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const [openModal, setOpenModal] = useState(false);
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const utils = api.useUtils();
|
|
|
|
|
const { mutate } = api.servizio.addServizioAnnunci.useMutation({
|
2025-08-29 16:18:32 +02:00
|
|
|
onError: (error) => {
|
|
|
|
|
console.error(error);
|
|
|
|
|
toast.error("Errore durante l'aggiunta dell'annuncio");
|
|
|
|
|
},
|
2025-08-28 18:27:07 +02:00
|
|
|
onSuccess: async () => {
|
|
|
|
|
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
|
|
|
|
await utils.servizio.getAnnunciAvailableToAdd.invalidate({
|
|
|
|
|
servizioId,
|
|
|
|
|
});
|
|
|
|
|
await utils.servizio.getCompatibileAnnunci.invalidate({
|
|
|
|
|
servizioId,
|
|
|
|
|
});
|
|
|
|
|
await utils.servizio.getUserServizi.invalidate({ userId });
|
|
|
|
|
toast.success("Annuncio aggiunto");
|
|
|
|
|
setOpenModal(false);
|
|
|
|
|
setSelectedAnnunci([]);
|
|
|
|
|
},
|
|
|
|
|
});
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
return (
|
2025-08-29 16:18:32 +02:00
|
|
|
<Dialog onOpenChange={setOpenModal} open={openModal}>
|
2025-08-28 18:27:07 +02:00
|
|
|
<DialogTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
aria-label="Add Annuncio"
|
2025-11-03 10:59:45 +01:00
|
|
|
className=""
|
2025-08-28 18:27:07 +02:00
|
|
|
onClick={() => {
|
|
|
|
|
setSelectedAnnunci([]);
|
|
|
|
|
}}
|
2025-08-29 16:18:32 +02:00
|
|
|
variant="outline"
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
|
|
|
|
<Plus />
|
|
|
|
|
Annuncio
|
|
|
|
|
</Button>
|
|
|
|
|
</DialogTrigger>
|
|
|
|
|
<DialogContent
|
2026-01-14 14:21:57 +01:00
|
|
|
className="sm:max-w-106.25"
|
2025-08-28 18:27:07 +02:00
|
|
|
onInteractOutside={(e) => {
|
|
|
|
|
if (selectedAnnunci.length !== 0) {
|
|
|
|
|
e.preventDefault(); // Prevent closing the dialog if there are selected announcements
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<DialogHeader>
|
|
|
|
|
<DialogTitle>Aggiungi annuncio</DialogTitle>
|
|
|
|
|
<DialogDescription>
|
|
|
|
|
Salva un annuncio nella ricerca dell'utente
|
|
|
|
|
</DialogDescription>
|
|
|
|
|
</DialogHeader>
|
|
|
|
|
<div className="grid gap-4 py-4">
|
|
|
|
|
{loading ? (
|
|
|
|
|
<LoadingPage />
|
|
|
|
|
) : (
|
|
|
|
|
<MultiSelect
|
2025-08-29 16:18:32 +02:00
|
|
|
defaultValue={undefined}
|
2025-08-28 18:27:07 +02:00
|
|
|
elementId="select-annuncio"
|
|
|
|
|
elementName="annuncio"
|
|
|
|
|
isMulti={true}
|
|
|
|
|
onValueChange={(value) => {
|
|
|
|
|
setSelectedAnnunci(
|
|
|
|
|
value.map((v) => ({
|
|
|
|
|
label: v.label,
|
2025-08-29 16:18:32 +02:00
|
|
|
value: parseInt(v.value) as AnnunciId,
|
2025-08-28 18:27:07 +02:00
|
|
|
})),
|
|
|
|
|
);
|
|
|
|
|
}}
|
2025-08-29 16:18:32 +02:00
|
|
|
options={
|
|
|
|
|
codici?.map((cod) => ({
|
|
|
|
|
label: cod.codice,
|
|
|
|
|
value: cod.id.toString(),
|
|
|
|
|
})) || []
|
|
|
|
|
}
|
|
|
|
|
placeholder=""
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<DialogFooter>
|
|
|
|
|
<Button
|
|
|
|
|
aria-label="Cancel Add Annuncio"
|
2025-08-29 16:18:32 +02:00
|
|
|
disabled={!selectedAnnunci.length}
|
2025-08-28 18:27:07 +02:00
|
|
|
onClick={() => {
|
|
|
|
|
if (!selectedAnnunci.length) return;
|
|
|
|
|
mutate({
|
|
|
|
|
annunci: selectedAnnunci.map((annuncio) => annuncio.value),
|
2025-08-29 16:18:32 +02:00
|
|
|
servizioId,
|
2025-08-28 18:27:07 +02:00
|
|
|
});
|
|
|
|
|
}}
|
2025-08-29 16:18:32 +02:00
|
|
|
type="button"
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
|
|
|
|
Aggiungi
|
|
|
|
|
</Button>
|
|
|
|
|
</DialogFooter>
|
|
|
|
|
</DialogContent>
|
|
|
|
|
</Dialog>
|
|
|
|
|
);
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
2025-08-19 16:44:38 +02:00
|
|
|
|
2025-08-04 17:45:44 +02:00
|
|
|
const InterruzioneServizio = () => {
|
2025-11-06 17:03:42 +01:00
|
|
|
const { servizio, userId, isAdmin } = useServizio();
|
2026-02-25 15:30:53 +01:00
|
|
|
const { t } = useTranslation();
|
2025-08-28 18:27:07 +02:00
|
|
|
const beforeInterruzioneLimit =
|
|
|
|
|
servizio.decorrenza != null &&
|
|
|
|
|
new Date() <=
|
|
|
|
|
add(servizio.decorrenza, {
|
|
|
|
|
days: 14,
|
|
|
|
|
});
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const utils = api.useUtils();
|
|
|
|
|
const { mutate } = api.servizio.interruzioneServizio.useMutation({
|
|
|
|
|
onError: (error) => {
|
|
|
|
|
console.error(error);
|
|
|
|
|
toast.error("Errore durante la richiesta di interruzione");
|
|
|
|
|
},
|
2025-08-29 16:18:32 +02:00
|
|
|
onSuccess: async () => {
|
|
|
|
|
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
|
|
|
|
toast.success("Interruzione richiesta");
|
|
|
|
|
},
|
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 (
|
|
|
|
|
<AlertDialog>
|
|
|
|
|
<AlertDialogTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
aria-label="Request Interruzione"
|
2025-11-03 10:59:45 +01:00
|
|
|
className=""
|
2025-11-06 17:03:42 +01:00
|
|
|
disabled={
|
|
|
|
|
!isAdmin &&
|
|
|
|
|
(!beforeInterruzioneLimit ||
|
|
|
|
|
servizio.isInterrotto ||
|
|
|
|
|
servizio.annunci.some((a) => a.user_confirmed_at !== null))
|
|
|
|
|
}
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
2026-02-25 15:30:53 +01:00
|
|
|
<ClockAlert /> <span>{t.servizio.interruzione.btn}</span>
|
2025-08-28 18:27:07 +02:00
|
|
|
</Button>
|
|
|
|
|
</AlertDialogTrigger>
|
|
|
|
|
<AlertDialogContent>
|
|
|
|
|
<AlertDialogHeader>
|
2026-02-25 15:30:53 +01:00
|
|
|
<AlertDialogTitle>{t.servizio.interruzione.title}</AlertDialogTitle>
|
2025-08-28 18:27:07 +02:00
|
|
|
<AlertDialogDescription>
|
2026-02-25 15:30:53 +01:00
|
|
|
{t.servizio.interruzione.description}
|
2025-08-28 18:27:07 +02:00
|
|
|
</AlertDialogDescription>
|
|
|
|
|
</AlertDialogHeader>
|
|
|
|
|
<AlertDialogFooter>
|
2026-02-25 15:30:53 +01:00
|
|
|
<AlertDialogCancel>{t.annulla}</AlertDialogCancel>
|
2025-08-28 18:27:07 +02:00
|
|
|
<AlertDialogAction
|
|
|
|
|
aria-label="Confirm Interruzione"
|
|
|
|
|
onClick={() => mutate({ servizioId: servizio.servizio_id })}
|
|
|
|
|
>
|
2026-02-25 15:30:53 +01:00
|
|
|
{t.conferma}
|
2025-08-28 18:27:07 +02:00
|
|
|
</AlertDialogAction>
|
|
|
|
|
</AlertDialogFooter>
|
|
|
|
|
</AlertDialogContent>
|
|
|
|
|
</AlertDialog>
|
|
|
|
|
);
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
2025-12-18 12:11:08 +01:00
|
|
|
const EditParametri = () => {
|
2025-11-06 17:03:42 +01:00
|
|
|
const { servizioId, userId, isAdmin, servizio } = useServizio();
|
2026-02-25 15:30:53 +01:00
|
|
|
const { t } = useTranslation();
|
2025-12-18 12:11:08 +01:00
|
|
|
const [openEditParametri, setOpenEditParametri] = useState(false);
|
2025-08-28 18:27:07 +02:00
|
|
|
const { data, isLoading } = api.servizio.getServizio.useQuery({ servizioId });
|
|
|
|
|
const utils = api.useUtils();
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const { mutate: update } = api.servizio.updateServizio.useMutation({
|
2025-08-29 16:18:32 +02:00
|
|
|
onError: (error) => {
|
|
|
|
|
toast.error(error.message);
|
|
|
|
|
},
|
2025-08-28 18:27:07 +02:00
|
|
|
onSuccess: async () => {
|
|
|
|
|
toast.success("Servizio modificato con successo");
|
|
|
|
|
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
|
|
|
|
await utils.servizio.getServizio.invalidate({ servizioId });
|
|
|
|
|
await utils.servizio.getCompatibileAnnunci.invalidate({
|
|
|
|
|
servizioId,
|
|
|
|
|
});
|
2025-12-18 12:18:24 +01:00
|
|
|
await utils.servizio.getPacksSolution.invalidate({ servizioId });
|
2025-12-18 12:11:08 +01:00
|
|
|
setOpenEditParametri(false);
|
2025-08-28 18:27:07 +02:00
|
|
|
},
|
|
|
|
|
});
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
function onSubmit(fields: FormValues) {
|
|
|
|
|
update({
|
|
|
|
|
data: {
|
|
|
|
|
...fields,
|
|
|
|
|
},
|
2025-08-29 16:18:32 +02:00
|
|
|
servizioId,
|
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 (
|
2025-12-18 12:11:08 +01:00
|
|
|
<Credenza onOpenChange={setOpenEditParametri} open={openEditParametri}>
|
2025-08-28 18:27:07 +02:00
|
|
|
<CredenzaTrigger asChild>
|
2025-11-06 17:03:42 +01:00
|
|
|
<Button
|
2025-12-18 12:11:08 +01:00
|
|
|
aria-label="Parametri di ricerca"
|
2025-11-06 17:03:42 +01:00
|
|
|
className=""
|
|
|
|
|
disabled={
|
|
|
|
|
!isAdmin &&
|
|
|
|
|
(servizio.isInterrotto ||
|
|
|
|
|
servizio.annunci.some((a) => a.hasConfermaAdmin))
|
|
|
|
|
}
|
2025-12-04 17:16:49 +01:00
|
|
|
variant="secondary"
|
2025-11-06 17:03:42 +01:00
|
|
|
>
|
2025-12-18 12:18:24 +01:00
|
|
|
<SlidersHorizontal />
|
2026-02-25 15:30:53 +01:00
|
|
|
{t.servizio.parametri.btn}
|
2025-08-28 18:27:07 +02:00
|
|
|
</Button>
|
|
|
|
|
</CredenzaTrigger>
|
|
|
|
|
<CredenzaContent className="max-h-[90vh] w-full sm:max-w-5xl">
|
|
|
|
|
<CredenzaHeader>
|
2026-02-25 15:30:53 +01:00
|
|
|
<CredenzaTitle>{t.servizio.parametri.title}</CredenzaTitle>
|
2025-08-28 18:27:07 +02:00
|
|
|
<CredenzaDescription className="sr-only">
|
2026-02-25 15:30:53 +01:00
|
|
|
{t.servizio.parametri.title}
|
2025-08-28 18:27:07 +02:00
|
|
|
</CredenzaDescription>
|
|
|
|
|
</CredenzaHeader>
|
2025-11-04 19:18:13 +01:00
|
|
|
<CredenzaBody className="max-h-[80vh] w-full max-w-3xl overflow-y-auto pb-5 sm:max-w-5xl">
|
2025-08-28 18:27:07 +02:00
|
|
|
{isLoading ? (
|
|
|
|
|
<LoadingPage />
|
|
|
|
|
) : (
|
|
|
|
|
<FormNewServizio
|
|
|
|
|
initialData={data}
|
|
|
|
|
isLimited={!isAdmin}
|
2025-08-29 16:18:32 +02:00
|
|
|
onSubmit={onSubmit}
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</CredenzaBody>
|
|
|
|
|
</CredenzaContent>
|
|
|
|
|
</Credenza>
|
|
|
|
|
);
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
2025-08-23 17:13:43 +02:00
|
|
|
|
|
|
|
|
const EditServizioAdmin = () => {
|
2025-08-28 18:27:07 +02:00
|
|
|
const { servizioId, userId, servizio } = useServizio();
|
|
|
|
|
const [open, setOpen] = useState(false);
|
|
|
|
|
const { data, isLoading } = api.servizio.getServizio.useQuery({ servizioId });
|
|
|
|
|
const utils = api.useUtils();
|
2025-08-23 17:13:43 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const { mutate: update } = api.servizio.updateServizio.useMutation({
|
2025-08-29 16:18:32 +02:00
|
|
|
onError: (error) => {
|
|
|
|
|
toast.error(error.message);
|
|
|
|
|
},
|
2025-08-28 18:27:07 +02:00
|
|
|
onSuccess: async () => {
|
|
|
|
|
toast.success("Servizio modificato con successo");
|
|
|
|
|
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
|
|
|
|
await utils.servizio.getServizio.invalidate({ servizioId });
|
|
|
|
|
await utils.servizio.getCompatibileAnnunci.invalidate({
|
|
|
|
|
servizioId,
|
|
|
|
|
});
|
2025-12-18 12:18:24 +01:00
|
|
|
await utils.servizio.getPacksSolution.invalidate({ servizioId });
|
2025-08-28 18:27:07 +02:00
|
|
|
setOpen(false);
|
|
|
|
|
},
|
|
|
|
|
});
|
2025-12-18 15:12:05 +01:00
|
|
|
const { mutate: remove } = api.servizio.deleteServizio.useMutation({
|
|
|
|
|
onError: (error) => {
|
|
|
|
|
toast.error(error.message);
|
|
|
|
|
},
|
|
|
|
|
onSuccess: async () => {
|
|
|
|
|
toast.success("Servizio rimosso con successo");
|
|
|
|
|
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
|
|
|
|
await utils.servizio.getServizio.invalidate({ servizioId });
|
|
|
|
|
},
|
|
|
|
|
});
|
2025-08-23 17:13:43 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
function onSubmit(fields: EditFormValues) {
|
|
|
|
|
update({
|
|
|
|
|
data: {
|
|
|
|
|
...fields,
|
|
|
|
|
},
|
2025-08-29 16:18:32 +02:00
|
|
|
servizioId,
|
2025-08-28 18:27:07 +02:00
|
|
|
});
|
|
|
|
|
}
|
2025-08-23 17:13:43 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
return (
|
2025-08-29 16:18:32 +02:00
|
|
|
<Credenza onOpenChange={setOpen} open={open}>
|
2025-08-28 18:27:07 +02:00
|
|
|
<CredenzaTrigger asChild>
|
2025-11-03 10:59:45 +01:00
|
|
|
<Button aria-label="Modifica Servizio Admin">
|
2025-12-04 17:16:49 +01:00
|
|
|
<Cog />
|
|
|
|
|
Modifica
|
2025-08-28 18:27:07 +02:00
|
|
|
</Button>
|
|
|
|
|
</CredenzaTrigger>
|
|
|
|
|
<CredenzaContent className="max-h-[90vh] w-full sm:max-w-5xl">
|
|
|
|
|
<CredenzaHeader>
|
|
|
|
|
<CredenzaTitle>Modifica Servizio Admin</CredenzaTitle>
|
|
|
|
|
<CredenzaDescription className="sr-only">
|
|
|
|
|
Modifica
|
|
|
|
|
</CredenzaDescription>
|
|
|
|
|
</CredenzaHeader>
|
|
|
|
|
<CredenzaBody className="max-h-[80vh] w-full space-y-2 overflow-y-auto pb-5">
|
|
|
|
|
{isLoading ? (
|
|
|
|
|
<LoadingPage />
|
|
|
|
|
) : (
|
|
|
|
|
<FormEditServizio initialData={data} onSubmit={onSubmit} />
|
|
|
|
|
)}
|
|
|
|
|
<Collapsible>
|
|
|
|
|
<CollapsibleTrigger asChild>
|
2025-11-03 10:59:45 +01:00
|
|
|
<Button variant="warning">
|
2025-08-28 18:27:07 +02:00
|
|
|
<Bug /> Debug Info Servizio
|
|
|
|
|
</Button>
|
|
|
|
|
</CollapsibleTrigger>
|
|
|
|
|
<CollapsibleContent>
|
|
|
|
|
{(() => {
|
|
|
|
|
const { annunci, ...rest } = servizio;
|
|
|
|
|
return <pre>{JSON.stringify(rest, null, 2)}</pre>;
|
|
|
|
|
})()}
|
|
|
|
|
</CollapsibleContent>
|
|
|
|
|
</Collapsible>
|
2025-12-18 15:12:05 +01:00
|
|
|
<Confirm
|
|
|
|
|
description="Sei sicuro di voler eliminare questo servizio? L'azione è irreversibile."
|
|
|
|
|
onConfirm={() => {
|
|
|
|
|
remove({ servizioId });
|
|
|
|
|
}}
|
|
|
|
|
title="Elimina servizio"
|
|
|
|
|
>
|
|
|
|
|
<Button aria-label="Elimina Servizio" variant="destructive">
|
|
|
|
|
<Trash2 className="size-6" />
|
|
|
|
|
Elimina Servizio
|
|
|
|
|
</Button>
|
|
|
|
|
</Confirm>
|
2025-08-28 18:27:07 +02:00
|
|
|
</CredenzaBody>
|
|
|
|
|
</CredenzaContent>
|
|
|
|
|
</Credenza>
|
|
|
|
|
);
|
2025-08-23 17:13:43 +02:00
|
|
|
};
|