isDisabled bool

This commit is contained in:
Marco Pedone 2026-05-08 14:16:29 +02:00
parent 91a650079d
commit d0f146b99e
15 changed files with 212 additions and 57 deletions

View file

@ -0,0 +1,3 @@
-- nulla_fatto_flag.up.sql
ALTER TABLE IF EXISTS public.servizio
ADD COLUMN IF NOT EXISTS "isDisabled" boolean NOT NULL DEFAULT false;

View file

@ -70,8 +70,6 @@ ARG EXP_API_USER
ENV EXP_API_USER=$EXP_API_USER ENV EXP_API_USER=$EXP_API_USER
ARG EXP_API_PASS ARG EXP_API_PASS
ENV EXP_API_PASS=$EXP_API_PASS ENV EXP_API_PASS=$EXP_API_PASS
ARG TILES_URL
ENV TILES_URL=$TILES_URL
ARG SKEBBY_USER ARG SKEBBY_USER
ENV SKEBBY_USER=$SKEBBY_USER ENV SKEBBY_USER=$SKEBBY_USER
ARG SKEBBY_PASS ARG SKEBBY_PASS

View file

@ -798,6 +798,7 @@ export const EditServizioModal = () => {
disabled={ disabled={
!isAdmin && !isAdmin &&
(servizio.isInterrotto || (servizio.isInterrotto ||
servizio.isDisabled ||
servizio.annunci.some((a) => a.status_conferma !== null)) servizio.annunci.some((a) => a.status_conferma !== null))
} }
variant="secondary" variant="secondary"

View file

@ -11,6 +11,7 @@ import {
ExternalLink, ExternalLink,
type LucideIcon, type LucideIcon,
PackageCheck, PackageCheck,
SearchSlash,
SearchX, SearchX,
Timer, Timer,
Trash2, Trash2,
@ -161,6 +162,9 @@ const ServizioLinkCard = ({
if (servizio.isInterrotto) { if (servizio.isInterrotto) {
status = "interrotto"; status = "interrotto";
StatusIcon = SearchX; StatusIcon = SearchX;
} else if (servizio.isDisabled) {
status = "disabled";
StatusIcon = SearchSlash;
} else if (!servizio.isOkAcconto) { } else if (!servizio.isOkAcconto) {
status = "in_attesa"; status = "in_attesa";
StatusIcon = ClockFading; StatusIcon = ClockFading;
@ -223,6 +227,7 @@ const ServizioLinkCard = ({
className={cn( className={cn(
status === "attivo" && "border-green-500", status === "attivo" && "border-green-500",
status === "interrotto" && "border-red-500", status === "interrotto" && "border-red-500",
status === "disabled" && "border-gray-500",
status === "scaduto" && "border-gray-500", status === "scaduto" && "border-gray-500",
status === "completato" && "border-blue-500", status === "completato" && "border-blue-500",
"transition-shadow", "transition-shadow",
@ -243,6 +248,7 @@ const ServizioLinkCard = ({
"flex items-center gap-2", "flex items-center gap-2",
status === "attivo" && "text-green-500", status === "attivo" && "text-green-500",
status === "interrotto" && "text-red-500", status === "interrotto" && "text-red-500",
status === "disabled" && "text-gray-500",
status === "scaduto" && "text-gray-500", status === "scaduto" && "text-gray-500",
status === "completato" && "text-blue-500", status === "completato" && "text-blue-500",
)} )}
@ -436,6 +442,61 @@ const Main = () => {
</div> </div>
); );
} }
if (servizio.isDisabled) {
if (isAdmin) {
return (
<>
<div className="flex w-full items-center justify-center rounded-md bg-gray-300 p-2">
<div className="flex items-center gap-2">
<SearchSlash className="size-5" />
<span>Servizio Disattivato</span>
</div>
</div>
<div className="@container grid grid-flow-row @sm:grid-cols-2 grid-cols-1 gap-4">
{servizio.annunci.map((data) => {
return (
<ServizioAnnuncioProvider
data={data}
key={data.id}
servizioId={servizio.servizio_id}
>
<AnnuncioCard />
</ServizioAnnuncioProvider>
);
})}
{servizio.annunci.length > 1 &&
servizio.annunci.length % 2 === 1 && (
<div className="@sm:block hidden size-full rounded-md border border-(--pattern-fg) bg-[repeating-linear-gradient(45deg,var(--pattern-fg)_0,var(--pattern-fg)_1px,transparent_0,transparent_50%)] bg-size-[10px_10px] bg-fixed opacity-10 [--pattern-fg:#696969] dark:[--pattern-fg:#e1e1e1]" />
)}
</div>
</>
);
}
return (
<div className="flex w-full flex-col items-center justify-center gap-4 py-10 text-center">
<div className="flex size-14 items-center justify-center rounded-full bg-gray-100 dark:bg-gray-500/10">
<SearchSlash className="size-7" />
</div>
<div className="flex flex-col gap-1">
<p className="font-semibold text-xl">
{t.servizio.servizio_disattivato}
</p>
<p className="max-w-sm text-muted-foreground text-sm">
{t.servizio.servizio_disattivato_desc}
</p>
</div>
<Link
href={
isAdmin
? `/area-riservata/admin/user-view/ricerca/${userId}`
: "/area-riservata/dashboard"
}
>
<Button variant="secondary">Torna alla lista dei servizi</Button>
</Link>
</div>
);
}
// mostra onboarding // mostra onboarding
if (!servizio.onboardOk) { if (!servizio.onboardOk) {
return ( return (

View file

@ -1,5 +1,4 @@
import { import {
Bug,
Check, Check,
Cog, Cog,
Euro, Euro,
@ -7,7 +6,6 @@ import {
Logs, Logs,
Plus, Plus,
Search, Search,
Trash2,
} from "lucide-react"; } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@ -27,11 +25,6 @@ import { LoadingPage } from "~/components/loading";
import { InterruzioneServizio } from "~/components/servizio/interruzione"; import { InterruzioneServizio } from "~/components/servizio/interruzione";
import { EditServizioModal } from "~/components/servizio/parametri_ricerca"; import { EditServizioModal } from "~/components/servizio/parametri_ricerca";
import { Button } from "~/components/ui/button"; import { Button } from "~/components/ui/button";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "~/components/ui/collapsible";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -568,33 +561,11 @@ const EditServizioAdmin = () => {
</CredenzaDescription> </CredenzaDescription>
</CredenzaHeader> </CredenzaHeader>
<CredenzaBody className="max-h-[80vh] w-full space-y-2 overflow-y-auto pb-5"> <CredenzaBody className="max-h-[80vh] w-full space-y-2 overflow-y-auto pb-5">
<FormEditServizio initialData={servizio} onSubmit={onSubmit} /> <FormEditServizio
handleRemove={() => remove({ servizioId })}
<Collapsible> initialData={servizio}
<CollapsibleTrigger asChild> onSubmit={onSubmit}
<Button variant="warning"> />
<Bug /> Debug Info Servizio
</Button>
</CollapsibleTrigger>
<CollapsibleContent>
{(() => {
const { annunci, ...rest } = servizio;
return <pre>{JSON.stringify(rest, null, 2)}</pre>;
})()}
</CollapsibleContent>
</Collapsible>
<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>
</CredenzaBody> </CredenzaBody>
</CredenzaContent> </CredenzaContent>
</Credenza> </Credenza>

View file

@ -17,6 +17,7 @@ import {
ExternalLink, ExternalLink,
Logs, Logs,
ReceiptEuro, ReceiptEuro,
SearchSlash,
SearchX, SearchX,
UserCog, UserCog,
} from "lucide-react"; } from "lucide-react";
@ -75,6 +76,7 @@ type RichiesteTableProps = {
const StatusMapping = { const StatusMapping = {
attesa_attivazione: "Attesa di attivazione", attesa_attivazione: "Attesa di attivazione",
interrotto: "Interrotto", interrotto: "Interrotto",
disabled: "Disattivato",
onboarding: "Onboarding", onboarding: "Onboarding",
scaduto: "Scaduto", scaduto: "Scaduto",
consulenza_da_pagare: "Consulenza da pagare", consulenza_da_pagare: "Consulenza da pagare",
@ -93,6 +95,9 @@ function statusParser(data: RichiesteData): keyof typeof StatusMapping {
if (data.isInterrotto) { if (data.isInterrotto) {
return "interrotto"; return "interrotto";
} }
if (data.isDisabled) {
return "disabled";
}
if (!data.onboardOk) { if (!data.onboardOk) {
return "onboarding"; return "onboarding";
} }
@ -380,6 +385,9 @@ export const RichiesteTable = ({ data }: RichiesteTableProps) => {
} else if (row.original.isInterrotto) { } else if (row.original.isInterrotto) {
decorrenzaColor = "text-destructive"; decorrenzaColor = "text-destructive";
decorrenzaTooltip = "Servizio interrotto"; decorrenzaTooltip = "Servizio interrotto";
} else if (row.original.isDisabled) {
decorrenzaColor = "text-muted-foreground";
decorrenzaTooltip = "Servizio disattivato";
} else if (row.original.isOkAcconto && !row.original.isOkSaldo) { } else if (row.original.isOkAcconto && !row.original.isOkSaldo) {
decorrenzaColor = "text-warning"; decorrenzaColor = "text-warning";
decorrenzaTooltip = "Attesa di saldo"; decorrenzaTooltip = "Attesa di saldo";
@ -452,6 +460,10 @@ export const RichiesteTable = ({ data }: RichiesteTableProps) => {
"border-destructive bg-destructive/10 text-destructive"; "border-destructive bg-destructive/10 text-destructive";
icon = <SearchX className="stroke-red-500 dark:stroke-red-400" />; icon = <SearchX className="stroke-red-500 dark:stroke-red-400" />;
break; break;
case "disabled":
badgeClass = "border-gray-500 bg-muted/10 text-muted-foreground";
icon = <SearchSlash className="" />;
break;
case "onboarding": case "onboarding":
badgeClass = "border-pink-500 bg-pink-500/10 text-pink-600"; badgeClass = "border-pink-500 bg-pink-500/10 text-pink-600";
icon = ( icon = (
@ -543,6 +555,7 @@ export const RichiesteTable = ({ data }: RichiesteTableProps) => {
accessorKey: "interruzione_expires_at", accessorKey: "interruzione_expires_at",
cell: ({ row }) => { cell: ({ row }) => {
if (row.original.isInterrotto) return "---"; if (row.original.isInterrotto) return "---";
if (row.original.isDisabled) return "---";
if (!row.original.decorrenza) return "---"; if (!row.original.decorrenza) return "---";
const expiresAt = add(row.original.decorrenza, { const expiresAt = add(row.original.decorrenza, {
days: row.original.interruzioneDays, days: row.original.interruzioneDays,

View file

@ -22,7 +22,6 @@ export const env = createEnv({
POSTGRES_USER: z.string(), POSTGRES_USER: z.string(),
STRIPE_SECRET_KEY: z.string(), STRIPE_SECRET_KEY: z.string(),
STRIPE_WEBHOOK_SECRET: z.string(), STRIPE_WEBHOOK_SECRET: z.string(),
TILES_URL: z.string(),
SKEBBY_USER: z.string(), SKEBBY_USER: z.string(),
SKEBBY_PASS: z.string(), SKEBBY_PASS: z.string(),
REVALIDATION_SECRET: z.string(), REVALIDATION_SECRET: z.string(),

View file

@ -1,5 +1,6 @@
import { X } from "lucide-react"; import { Bug, Trash2, X } from "lucide-react";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { Confirm } from "~/components/confirm";
import { Counter } from "~/components/counter"; import { Counter } from "~/components/counter";
import { import {
Form, Form,
@ -12,26 +13,33 @@ import {
} from "~/components/custom_ui/form"; } from "~/components/custom_ui/form";
import { DateInput } from "~/components/custom_ui/inputDate"; import { DateInput } from "~/components/custom_ui/inputDate";
import { Button } from "~/components/ui/button"; import { Button } from "~/components/ui/button";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "~/components/ui/collapsible";
import { Label } from "~/components/ui/label"; import { Label } from "~/components/ui/label";
import { Switch } from "~/components/ui/switch"; import { Switch } from "~/components/ui/switch";
import { cn } from "~/lib/utils"; import { cn } from "~/lib/utils";
import { useZodForm } from "~/lib/zodForm"; import { useZodForm } from "~/lib/zodForm";
import { useTranslation } from "~/providers/I18nProvider"; import { useTranslation } from "~/providers/I18nProvider";
import type { Servizio } from "~/schemas/public/Servizio"; import { ServizioSchema } from "~/schemas/public/Servizio";
import type { ServizioData } from "~/server/controllers/servizio.controller";
import { DEFAULT_SERVIZIO_INTERRUZIONE_DURATION_DAYS } from "~/utils/config"; import { DEFAULT_SERVIZIO_INTERRUZIONE_DURATION_DAYS } from "~/utils/config";
const Schema = z.object({ const Schema = ServizioSchema.pick({
decorrenza: z.date().nullable(), decorrenza: true,
isInterrotto: z.boolean(), isInterrotto: true,
isOkAcconto: z.boolean(), isOkAcconto: true,
isOkConsulenza: z.boolean(), isOkConsulenza: true,
isOkSaldo: z.boolean(), isOkSaldo: true,
skipPayment: z.boolean(), skipPayment: true,
skipControlloDoc: z.boolean(), skipControlloDoc: true,
skipDocMotivazione: z.boolean(), skipDocMotivazione: true,
onboardOk: z.boolean(), onboardOk: true,
interruzioneDays: z.number(), interruzioneDays: true,
acceptedInterr: z.boolean(), acceptedInterr: true,
isDisabled: true,
}); });
export type FormValues = z.infer<typeof Schema>; export type FormValues = z.infer<typeof Schema>;
@ -39,16 +47,29 @@ export type FormValues = z.infer<typeof Schema>;
export const FormEditServizio = ({ export const FormEditServizio = ({
initialData, initialData,
onSubmit, onSubmit,
handleRemove,
}: { }: {
initialData: Servizio | undefined; initialData: ServizioData | undefined;
onSubmit: (fields: FormValues) => void; onSubmit: (fields: FormValues) => void;
handleRemove: () => void;
}) => { }) => {
// This can come from your database or API. // This can come from your database or API.
let defaultValues: FormValues; let defaultValues: FormValues;
if (initialData) { if (initialData) {
defaultValues = { defaultValues = {
...initialData, decorrenza: initialData.decorrenza,
isInterrotto: initialData.isInterrotto,
isOkAcconto: initialData.isOkAcconto,
isOkConsulenza: initialData.isOkConsulenza,
isOkSaldo: initialData.isOkSaldo,
skipPayment: initialData.skipPayment,
skipControlloDoc: initialData.skipControlloDoc,
skipDocMotivazione: initialData.skipDocMotivazione,
onboardOk: initialData.onboardOk,
interruzioneDays: initialData.interruzioneDays,
acceptedInterr: initialData.acceptedInterr,
isDisabled: initialData.isDisabled,
}; };
} else { } else {
defaultValues = { defaultValues = {
@ -63,6 +84,7 @@ export const FormEditServizio = ({
onboardOk: false, onboardOk: false,
interruzioneDays: DEFAULT_SERVIZIO_INTERRUZIONE_DURATION_DAYS, interruzioneDays: DEFAULT_SERVIZIO_INTERRUZIONE_DURATION_DAYS,
acceptedInterr: false, acceptedInterr: false,
isDisabled: false,
}; };
} }
const { locale, t } = useTranslation(); const { locale, t } = useTranslation();
@ -147,6 +169,7 @@ export const FormEditServizio = ({
)} )}
/> />
</div> </div>
<hr />
<div className="flex w-full flex-col items-start justify-between gap-4 sm:flex-row"> <div className="flex w-full flex-col items-start justify-between gap-4 sm:flex-row">
<FormField <FormField
control={form.control} control={form.control}
@ -280,6 +303,7 @@ export const FormEditServizio = ({
)} )}
/> />
</div> </div>
<hr />
<div className="flex w-full flex-col items-start justify-between gap-4 sm:flex-row"> <div className="flex w-full flex-col items-start justify-between gap-4 sm:flex-row">
<FormField <FormField
control={form.control} control={form.control}
@ -359,7 +383,62 @@ export const FormEditServizio = ({
)} )}
/> />
</div> </div>
<hr />
<FormField
control={form.control}
name="isDisabled"
render={({ field }) => (
<FormItem className="w-full">
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="isDisabled">DISABILITATO</FormLabel>
<FormControl>
<Switch
className="data-[state=checked]:bg-neutral-700"
defaultChecked={field.value}
id="isDisabled"
onCheckedChange={field.onChange}
/>
</FormControl>
<FormMessage />
</div>
<FormDescription>
Disabilita il servizio, chiude la posizione senza eliminare.
</FormDescription>
</FormItem>
)}
/>
<Collapsible className="space-y-2">
<div className="flex items-center gap-4">
<Button type="submit">Salva</Button> <Button type="submit">Salva</Button>
<CollapsibleTrigger asChild>
<Button variant="warning">
<Bug /> Debug Info Servizio
</Button>
</CollapsibleTrigger>
<Confirm
description="Sei sicuro di voler eliminare questo servizio? L'azione è irreversibile."
onConfirm={() => {
handleRemove();
}}
title="Elimina servizio"
>
<Button aria-label="Elimina Servizio" variant="destructive">
<Trash2 className="size-6" />
Elimina Servizio
</Button>
</Confirm>
</div>
<CollapsibleContent>
{(() => {
if (!initialData) return null;
const { annunci, ...rest } = initialData;
return <pre>{JSON.stringify(rest, null, 2)}</pre>;
})()}
</CollapsibleContent>
</Collapsible>
</form> </form>
</Form> </Form>
); );

View file

@ -1320,6 +1320,7 @@ The Stable Rent service, ideal for those with demonstrable work references and f
interrotto: "Interrupted", interrotto: "Interrupted",
scaduto: "Expired", scaduto: "Expired",
completato: "Completed", completato: "Completed",
disabled: "Disabled",
}, },
torna_alla_dashboard: "Dashboard", torna_alla_dashboard: "Dashboard",
dettaglio_servizio: "Service Details", dettaglio_servizio: "Service Details",
@ -1330,7 +1331,9 @@ The Stable Rent service, ideal for those with demonstrable work references and f
durata_servizio: "Service Duration:", durata_servizio: "Service Duration:",
servizio_interrotto: "Service Interrupted", servizio_interrotto: "Service Interrupted",
servizio_interrotto_desc: servizio_interrotto_desc:
"This service cannot be reused as it has been interrupted.", "This service cannot be used as it has been interrupted.",
servizio_disattivato: "Service Disabled",
servizio_disattivato_desc: "This service cannot be used.",
non_attivo: "Service not yet activated", non_attivo: "Service not yet activated",
attiva_cta: "Activate the Service Now!", attiva_cta: "Activate the Service Now!",
per_te_1: "Already selected", per_te_1: "Already selected",

View file

@ -1319,6 +1319,7 @@ export const it: LangDict = {
in_attesa: "In Attesa di Attivazione", in_attesa: "In Attesa di Attivazione",
scaduto: "Scaduto", scaduto: "Scaduto",
completato: "Completato", completato: "Completato",
disabled: "Disattivato",
}, },
torna_alla_dashboard: "Dashboard", torna_alla_dashboard: "Dashboard",
dettaglio_servizio: "Dettaglio Servizio", dettaglio_servizio: "Dettaglio Servizio",
@ -1329,7 +1330,9 @@ export const it: LangDict = {
durata_servizio: "Durata servizio:", durata_servizio: "Durata servizio:",
servizio_interrotto: "Servizio interrotto", servizio_interrotto: "Servizio interrotto",
servizio_interrotto_desc: servizio_interrotto_desc:
"Non è possibile riutilizzare questo servizio, poichè è stato interrotto.", "Non è possibile utilizzare questo servizio, poichè è stato interrotto.",
servizio_disattivato: "Servizio disattivato",
servizio_disattivato_desc: "Non è possibile utilizzare questo servizio.",
non_attivo: "Servizio non ancora attivato", non_attivo: "Servizio non ancora attivato",
attiva_cta: "Attiva il Servizio Ora!", attiva_cta: "Attiva il Servizio Ora!",
per_te_1: "Sono già stati selezionati", per_te_1: "Sono già stati selezionati",

View file

@ -779,6 +779,7 @@ export type LangDict = {
in_attesa: string; in_attesa: string;
scaduto: string; scaduto: string;
completato: string; completato: string;
disabled: string;
}; };
torna_alla_dashboard: string; torna_alla_dashboard: string;
dettaglio_servizio: string; dettaglio_servizio: string;
@ -789,6 +790,8 @@ export type LangDict = {
durata_servizio: string; durata_servizio: string;
servizio_interrotto: string; servizio_interrotto: string;
servizio_interrotto_desc: string; servizio_interrotto_desc: string;
servizio_disattivato: string;
servizio_disattivato_desc: string;
non_attivo: string; non_attivo: string;
attiva_cta: string; attiva_cta: string;
per_te_1: string; per_te_1: string;

View file

@ -72,6 +72,8 @@ export default interface ServizioTable {
interruzioneDays: ColumnType<number, number | undefined, number>; interruzioneDays: ColumnType<number, number | undefined, number>;
acceptedInterr: ColumnType<boolean, boolean | undefined, boolean>; acceptedInterr: ColumnType<boolean, boolean | undefined, boolean>;
isDisabled: ColumnType<boolean, boolean | undefined, boolean>;
} }
export type Servizio = Selectable<ServizioTable>; export type Servizio = Selectable<ServizioTable>;
@ -115,6 +117,7 @@ export const ServizioSchema = z.object({
onboardOk: z.boolean(), onboardOk: z.boolean(),
interruzioneDays: z.number(), interruzioneDays: z.number(),
acceptedInterr: z.boolean(), acceptedInterr: z.boolean(),
isDisabled: z.boolean(),
}); });
export const NewServizioSchema = z.object({ export const NewServizioSchema = z.object({
@ -150,6 +153,7 @@ export const NewServizioSchema = z.object({
onboardOk: z.boolean().optional(), onboardOk: z.boolean().optional(),
interruzioneDays: z.number().optional(), interruzioneDays: z.number().optional(),
acceptedInterr: z.boolean().optional(), acceptedInterr: z.boolean().optional(),
isDisabled: z.boolean().optional(),
}); });
export const ServizioUpdateSchema = z.object({ export const ServizioUpdateSchema = z.object({
@ -185,4 +189,5 @@ export const ServizioUpdateSchema = z.object({
onboardOk: z.boolean().optional(), onboardOk: z.boolean().optional(),
interruzioneDays: z.number().optional(), interruzioneDays: z.number().optional(),
acceptedInterr: z.boolean().optional(), acceptedInterr: z.boolean().optional(),
isDisabled: z.boolean().optional(),
}); });

View file

@ -198,6 +198,7 @@ export const servizioRouter = createTRPCRouter({
!servizio || !servizio ||
servizio.isOkAcconto || servizio.isOkAcconto ||
servizio.isInterrotto || servizio.isInterrotto ||
servizio.isDisabled ||
servizio.decorrenza !== null servizio.decorrenza !== null
) { ) {
return { available: false, userId: null }; return { available: false, userId: null };

View file

@ -1143,6 +1143,7 @@ export type RichiesteData = Pick<
| "servizio_id" | "servizio_id"
| "user_id" | "user_id"
| "isInterrotto" | "isInterrotto"
| "isDisabled"
| "isOkAcconto" | "isOkAcconto"
| "isOkSaldo" | "isOkSaldo"
| "decorrenza" | "decorrenza"
@ -1184,6 +1185,7 @@ export const getRichieste = async (): Promise<RichiesteData[]> => {
"servizio.created_at", "servizio.created_at",
"servizio.user_id", "servizio.user_id",
"servizio.isInterrotto", "servizio.isInterrotto",
"servizio.isDisabled",
"servizio.isOkAcconto", "servizio.isOkAcconto",
"servizio.isOkSaldo", "servizio.isOkSaldo",
"servizio.decorrenza", "servizio.decorrenza",

View file

@ -7,6 +7,7 @@ import type {
ServizioUpdate, ServizioUpdate,
} from "~/schemas/public/Servizio"; } from "~/schemas/public/Servizio";
import type { ServizioAnnunciUpdate } from "~/schemas/public/ServizioAnnunci"; import type { ServizioAnnunciUpdate } from "~/schemas/public/ServizioAnnunci";
import { clearUserEmailQueue } from "~/server/controllers/event_queue.controller";
import { db } from "../db"; import { db } from "../db";
export const addServizio = async (data: NewServizio) => { export const addServizio = async (data: NewServizio) => {
@ -78,7 +79,14 @@ export const updateServizio = async ({
data: ServizioUpdate; data: ServizioUpdate;
}) => { }) => {
try { try {
return await db const isDisabledPrev = await db
.selectFrom("servizio")
.select("isDisabled")
.where("servizio_id", "=", servizioId)
.executeTakeFirstOrThrow(
() => new Error(`Servizio not found - servizioId: ${servizioId}`),
);
const updated = await db
.updateTable("servizio") .updateTable("servizio")
.set(data) .set(data)
.where("servizio_id", "=", servizioId) .where("servizio_id", "=", servizioId)
@ -87,6 +95,11 @@ export const updateServizio = async ({
() => () =>
new Error(`Failed to update servizio - servizioId: ${servizioId}`), new Error(`Failed to update servizio - servizioId: ${servizioId}`),
); );
if (!isDisabledPrev.isDisabled && updated.isDisabled) {
// Only the on isDisabled false->true change
await clearUserEmailQueue(updated.user_id);
}
return updated;
} catch (e) { } catch (e) {
throw new TRPCError({ throw new TRPCError({
code: "INTERNAL_SERVER_ERROR", code: "INTERNAL_SERVER_ERROR",