refactor: update servizio handling to include expiration logic and improve pack retrieval process

This commit is contained in:
Marco Pedone 2025-12-18 13:29:39 +01:00
parent e692f9f1cb
commit 6f83ca3c34
4 changed files with 151 additions and 103 deletions

View file

@ -1,3 +1,4 @@
import { add } from "date-fns";
import { ArrowRight, Package, PackageCheck } from "lucide-react"; import { ArrowRight, Package, PackageCheck } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@ -172,6 +173,36 @@ export const ServizioContent = () => {
/> />
); );
} }
if (
new Date() >
add(servizio.decorrenza, {
days: 60,
}) &&
!servizio.isOkSaldo
) {
return (
<ServizioCard
content={
<>
<p className="font-medium text-lg">Servizio Scaduto</p>
<p>
Non è possibile riutilizzare questo servizio, poiché sono passati
più di 60 giorni dalla data di decorrenza senza che sia stato
effettuato il saldo.
</p>
</>
}
header={
<>
<ServizioActions />
</>
}
headerClassName="pb-0"
/>
);
}
const annuncioConfermato = servizio.annunci.filter( const annuncioConfermato = servizio.annunci.filter(
(a) => a.accettato_conferma_at !== null, (a) => a.accettato_conferma_at !== null,
); );

View file

@ -184,39 +184,48 @@ const ServizioPacksInfos = () => {
}); });
if (!packs) return null; if (!packs) return null;
return ( return (
<div className="space-y-2"> <div className="w-full space-y-2">
<h3 className="font-semibold text-lg">Prezzi:</h3> <h3 className="font-semibold text-lg">Prezzi:</h3>
<div className="flex w-full flex-col gap-4 md:flex-row"> <div className="flex w-full flex-col gap-4 md:flex-row">
{packs.acconto && (
<div className="flex flex-1 flex-col gap-2 rounded-md bg-secondary/50 p-2"> <div className="flex flex-1 flex-col gap-2 rounded-md bg-secondary/50 p-2">
<span className="font-medium">{packs.acconto.nome_it}</span> {packs.acconto.success ? (
<>
<span className="font-medium">{packs.acconto.pack.nome_it}</span>
<span className="text-muted-foreground text-sm"> <span className="text-muted-foreground text-sm">
{packs.acconto.desc_it} {packs.acconto.pack.desc_it}
</span> </span>
<span className="font-semibold text-lg"> <span className="font-semibold text-lg">
{formatCurrency(packs.acconto.prezzo_cent / 100)} {formatCurrency(packs.acconto.pack.prezzo_cent / 100)}
</span> </span>
<span className="text-muted-foreground text-sm"> <span className="text-muted-foreground text-sm">
COD: {packs.acconto.idprezziario} COD: {packs.acconto.pack.idprezziario}
</span> </span>
</div> </>
) : (
<span className="font-medium">{packs.acconto.message}</span>
)} )}
{packs.saldo && ( </div>
<div className="flex flex-1 flex-col gap-2 rounded-md bg-secondary/50 p-2"> <div className="flex flex-1 flex-col gap-2 rounded-md bg-secondary/50 p-2">
<span className="font-medium">{packs.saldo.nome_it}</span> {packs.saldo.success ? (
<>
<span className="font-medium">{packs.saldo.pack.nome_it}</span>
<span className="text-muted-foreground text-sm"> <span className="text-muted-foreground text-sm">
{packs.saldo.desc_it} {packs.saldo.pack.desc_it}
</span> </span>
<span className="font-semibold text-lg"> <span className="font-semibold text-lg">
{formatCurrency(packs.saldo.prezzo_cent / 100)} {formatCurrency(packs.saldo.pack.prezzo_cent / 100)}
</span> </span>
<span className="text-muted-foreground text-sm"> <span className="text-muted-foreground text-sm">
COD: {packs.saldo.idprezziario} COD: {packs.saldo.pack.idprezziario}
</span> </span>
</div> </>
) : (
<span className="font-medium">{packs.saldo.message}</span>
)} )}
</div> </div>
</div> </div>
</div>
); );
}; };
export const AddAnnuncio = ({ export const AddAnnuncio = ({

View file

@ -29,7 +29,7 @@ import {
getCompatibileAnnunci, getCompatibileAnnunci,
getDataPerAcquisto, getDataPerAcquisto,
getOrdineRicevutaData, getOrdineRicevutaData,
getPackPerServizio, getPacksPerServizio,
getPreOnboardData, getPreOnboardData,
getServiziByUserId, getServiziByUserId,
getServizioAnnuncio, getServizioAnnuncio,
@ -51,7 +51,6 @@ import {
userAccettaConferma, userAccettaConferma,
userSendConfermaIntent, userSendConfermaIntent,
} from "~/server/controllers/servizio.controller"; } from "~/server/controllers/servizio.controller";
import { getPrezziarioByIdHandler } from "~/server/services/prezziario.service";
import { import {
zAnnuncioId, zAnnuncioId,
zOrdineId, zOrdineId,
@ -349,25 +348,7 @@ export const servizioRouter = createTRPCRouter({
}), }),
) )
.query(async ({ input }) => { .query(async ({ input }) => {
const accontoId = await getPackPerServizio({ return await getPacksPerServizio(input.servizioId);
stage: "acconto",
servizioId: input.servizioId,
});
const saldoId = await getPackPerServizio({
stage: "saldo",
servizioId: input.servizioId,
});
const acconto = accontoId.success
? await getPrezziarioByIdHandler({ id: accontoId.packId })
: null;
const saldo = saldoId.success
? await getPrezziarioByIdHandler({ id: saldoId.packId })
: null;
return {
acconto,
saldo,
};
}), }),
unlockServizioContatti: protectedProcedure unlockServizioContatti: protectedProcedure
.input( .input(

View file

@ -43,6 +43,7 @@ import { NewMail, type NewMailProps } from "~/server/services/mailer";
import { getUser } from "~/server/services/user.service"; import { getUser } from "~/server/services/user.service";
import { withImages, withVideos } from "~/utils/kysely-helper"; import { withImages, withVideos } from "~/utils/kysely-helper";
import { GetUserInterests } from "../services/interests.service"; import { GetUserInterests } from "../services/interests.service";
import { getPrezziarioByIdHandler } from "../services/prezziario.service";
import type { AnnuncioRicerca } from "./annunci.controller"; import type { AnnuncioRicerca } from "./annunci.controller";
export const addServizio = async (data: NewServizio) => { export const addServizio = async (data: NewServizio) => {
@ -507,40 +508,58 @@ const ConsulenzaPriceMapping = {
}; };
type GetPackError = { success: false; message: string }; type GetPackError = { success: false; message: string };
type GetPackResult = { success: true; packId: PrezziarioIdprezziario }; type GetPackResult = { success: true; pack: Prezziario };
export const getPackPerServizio = async ({ type ServizioPacks = {
stage, acconto: GetPackResult | GetPackError;
servizioId, saldo: GetPackResult | GetPackError;
}: { };
stage: "acconto" | "saldo"; export const getPacksPerServizio = async (
servizioId: ServizioServizioId; servizioId: ServizioServizioId,
}): Promise<GetPackResult | GetPackError> => { ): Promise<ServizioPacks> => {
const servizio = await getServizioById(servizioId); const servizio = await getServizioById(servizioId);
if (!servizio) { if (!servizio) {
return { success: false, message: "Servizio not found" }; throw new TRPCError({
code: "NOT_FOUND",
message: "Servizio non trovato",
});
} }
switch (stage) {
case "acconto": { const getAcconto = async (): Promise<GetPackResult | GetPackError> => {
switch (servizio.tipologia) { switch (servizio.tipologia) {
case TipologiaPosizioneEnum.Transitorio: { case TipologiaPosizioneEnum.Transitorio: {
const pack = await getPrezziarioByIdHandler({
id: "ACCONTO_BD" as PrezziarioIdprezziario,
});
if (!pack) {
return { success: false, message: "Pack non trovato" };
}
return { return {
success: true, success: true,
packId: "ACCONTO_BD" as PrezziarioIdprezziario, pack,
}; };
} }
case TipologiaPosizioneEnum.Stabile: { case TipologiaPosizioneEnum.Stabile: {
const pack = await getPrezziarioByIdHandler({
id: "ACCONTO_CA" as PrezziarioIdprezziario,
});
if (!pack) {
return { success: false, message: "Pack non trovato" };
}
return { return {
success: true, success: true,
packId: "ACCONTO_CA" as PrezziarioIdprezziario, pack,
}; };
} }
default: default:
return { success: false, message: "Invalid tipologia" }; return { success: false, message: "Seleziona tipologia" };
} }
} };
case "saldo": {
const getSaldo = async (): Promise<GetPackResult | GetPackError> => {
switch (servizio.tipologia) { switch (servizio.tipologia) {
case TipologiaPosizioneEnum.Transitorio: { case TipologiaPosizioneEnum.Transitorio: {
const mpp = const mpp =
@ -548,31 +567,39 @@ export const getPackPerServizio = async ({
if (!servizio.permanenza || !mpp) { if (!servizio.permanenza || !mpp) {
return { return {
success: false, success: false,
message: "Permanenza not set for transitorio servizio", message: "Permanenza non selezionata",
}; };
} }
return { success: true, packId: mpp }; const pack = await getPrezziarioByIdHandler({ id: mpp });
} if (!pack) {
case TipologiaPosizioneEnum.Stabile: { return { success: false, message: "Pack non trovato" };
if (servizio.budget >= 500) {
return {
success: true,
packId: "SALDOCA500+" as PrezziarioIdprezziario,
};
}
return {
success: true,
packId: "SALDOCA500" as PrezziarioIdprezziario,
};
}
default:
return { success: false, message: "Invalid tipologia" };
}
} }
default: return { success: true, pack };
return { success: false, message: "Invalid stage" };
} }
case TipologiaPosizioneEnum.Stabile: {
const pack = await getPrezziarioByIdHandler({
id: (servizio.budget >= 500
? "SALDOCA500+"
: "SALDOCA500") as PrezziarioIdprezziario,
});
if (!pack) {
return { success: false, message: "Pack non trovato" };
}
return {
success: true,
pack,
};
}
default:
return { success: false, message: "Seleziona tipologia" };
}
};
return {
acconto: await getAcconto(),
saldo: await getSaldo(),
};
}; };
type TipoEnum = keyof typeof ConsulenzaPriceMapping; type TipoEnum = keyof typeof ConsulenzaPriceMapping;
export const setupSaldoConsulenzaServizio = async ({ export const setupSaldoConsulenzaServizio = async ({