feat: implement user intestazione generation and update related handlers
This commit is contained in:
parent
d4ffc27aed
commit
995eadd9dc
4 changed files with 134 additions and 81 deletions
|
|
@ -1,4 +1,3 @@
|
||||||
import { format } from "date-fns";
|
|
||||||
import {
|
import {
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
CloudSync,
|
CloudSync,
|
||||||
|
|
@ -274,14 +273,22 @@ const OverseerButton = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const VOCALI = ["A", "E", "I", "O", "U"] as const;
|
|
||||||
|
|
||||||
const IntestazioneMaker = () => {
|
const IntestazioneMaker = () => {
|
||||||
const data = useUserViewContext();
|
const data = useUserViewContext();
|
||||||
const { data: comuni = [] } = api.catasto.searchComuniByCatasto.useQuery({
|
const { mutate } = api.users.genIntestazione.useMutation({
|
||||||
catasto: [data?.luogo_nascita || "", data?.comune_residenza || ""].filter(
|
onError: (error) => {
|
||||||
(f) => f !== "",
|
toast.error(error.message);
|
||||||
),
|
},
|
||||||
|
onSuccess: (intestazione) => {
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(intestazione)
|
||||||
|
.then(() => {
|
||||||
|
toast.success("Intestazione copiata negli appunti");
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toast.error("Errore nella copia");
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const isDisabled =
|
const isDisabled =
|
||||||
|
|
@ -293,86 +300,17 @@ const IntestazioneMaker = () => {
|
||||||
!data.comune_residenza ||
|
!data.comune_residenza ||
|
||||||
!data.via_residenza;
|
!data.via_residenza;
|
||||||
|
|
||||||
const copyToClipboard = () => {
|
|
||||||
if (
|
|
||||||
!data.sesso ||
|
|
||||||
!data.cognome ||
|
|
||||||
!data.nome ||
|
|
||||||
!data.data_nascita ||
|
|
||||||
!data.luogo_nascita ||
|
|
||||||
!data.comune_residenza ||
|
|
||||||
!data.via_residenza
|
|
||||||
) {
|
|
||||||
toast.error("Dati mancanti");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const comune_nascita = comuni.find((c) => c.catasto === data.luogo_nascita);
|
|
||||||
const comune_residenza = comuni.find(
|
|
||||||
(c) => c.catasto === data.comune_residenza,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Format names
|
|
||||||
const cognome = data.cognome.toUpperCase();
|
|
||||||
const nome = data.nome.toUpperCase();
|
|
||||||
const viaResidenza = titleCase(data.via_residenza);
|
|
||||||
const comuneNascita = comune_nascita
|
|
||||||
? titleCase(comune_nascita.nome)
|
|
||||||
: data.luogo_nascita;
|
|
||||||
const comuneResidenza = comune_residenza
|
|
||||||
? titleCase(comune_residenza.nome)
|
|
||||||
: data.comune_residenza;
|
|
||||||
|
|
||||||
// Determine article
|
|
||||||
const isMale = data.sesso === "M";
|
|
||||||
const articolo = isMale ? "Al Sig." : "Alla Sig.ra";
|
|
||||||
const natoNata = isMale ? "nato" : "nata";
|
|
||||||
const preposizione = VOCALI.includes(comuneNascita[0]?.toUpperCase() || "")
|
|
||||||
? "ad"
|
|
||||||
: "a";
|
|
||||||
|
|
||||||
// Build phrase
|
|
||||||
const frase = [
|
|
||||||
`${articolo} ${cognome} ${nome}`,
|
|
||||||
`${natoNata} il ${format(data.data_nascita, "dd/MM/yyyy")}`,
|
|
||||||
`${preposizione} ${comuneNascita}${comune_nascita ? ` (${comune_nascita.sigla})` : ""},`,
|
|
||||||
`residente in ${viaResidenza}, ${data.civico_residenza}`,
|
|
||||||
`a ${comuneResidenza} (${data.provincia_residenza})`,
|
|
||||||
`CAP ${data.cap_residenza},`,
|
|
||||||
`con codice fiscale: ${data.codice_fiscale}`,
|
|
||||||
].join(" ");
|
|
||||||
|
|
||||||
navigator.clipboard
|
|
||||||
.writeText(frase)
|
|
||||||
.then(() => {
|
|
||||||
toast.success("Intestazione copiata negli appunti");
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
toast.error("Errore nella copia");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button disabled={isDisabled} onClick={copyToClipboard} size="sm">
|
<Button
|
||||||
|
disabled={isDisabled}
|
||||||
|
onClick={() => mutate({ userId: data.id })}
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
<UserPen /> Intestazione
|
<UserPen /> Intestazione
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function titleCase(str: string | null | undefined): string {
|
|
||||||
if (!str) return "";
|
|
||||||
|
|
||||||
return str
|
|
||||||
.trim()
|
|
||||||
.toLowerCase()
|
|
||||||
.split(/\s+/) // Handle multiple spaces
|
|
||||||
.map((word) => {
|
|
||||||
if (word.length === 0) return word;
|
|
||||||
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
||||||
})
|
|
||||||
.join(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
const NoteUtenteDialog = () => {
|
const NoteUtenteDialog = () => {
|
||||||
const { id, note } = useUserViewContext();
|
const { id, note } = useUserViewContext();
|
||||||
const [newNote, setNewNote] = useState(note || "");
|
const [newNote, setNewNote] = useState(note || "");
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import {
|
||||||
deleteUserHandler,
|
deleteUserHandler,
|
||||||
editAccountHandler,
|
editAccountHandler,
|
||||||
editAnagraficaHandler,
|
editAnagraficaHandler,
|
||||||
|
genUserIntestazione,
|
||||||
getActiveUserWithoutChatHandler,
|
getActiveUserWithoutChatHandler,
|
||||||
getUserHandler,
|
getUserHandler,
|
||||||
getUsersWithChatInfoHandler,
|
getUsersWithChatInfoHandler,
|
||||||
|
|
@ -102,4 +103,13 @@ export const usersRouter = createTRPCRouter({
|
||||||
getUsersWChatInfo: adminProcedure.query(async () => {
|
getUsersWChatInfo: adminProcedure.query(async () => {
|
||||||
return await getUsersWithChatInfoHandler();
|
return await getUsersWithChatInfoHandler();
|
||||||
}),
|
}),
|
||||||
|
genIntestazione: adminProcedure
|
||||||
|
.input(
|
||||||
|
z.object({
|
||||||
|
userId: zUserId,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.mutation(async ({ input }) => {
|
||||||
|
return await genUserIntestazione(input.userId);
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,17 @@
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
|
import { format } from "date-fns";
|
||||||
import { jsonArrayFrom } from "kysely/helpers/postgres";
|
import { jsonArrayFrom } from "kysely/helpers/postgres";
|
||||||
|
import {
|
||||||
|
ITALY_CATASTO_CODE,
|
||||||
|
parseDBComune,
|
||||||
|
parseDBNazione,
|
||||||
|
} from "~/lib/catasto";
|
||||||
import type { Etichette } from "~/schemas/public/Etichette";
|
import type { Etichette } from "~/schemas/public/Etichette";
|
||||||
import type { Users, UsersId, UsersUpdate } from "~/schemas/public/Users";
|
import type { Users, UsersId, UsersUpdate } from "~/schemas/public/Users";
|
||||||
import type { UsersAnagraficaUpdate } from "~/schemas/public/UsersAnagrafica";
|
import type { UsersAnagraficaUpdate } from "~/schemas/public/UsersAnagrafica";
|
||||||
|
import { getComuni, getNazioni } from "~/server/controllers/catasto.controller";
|
||||||
import { db, type Querier } from "~/server/db";
|
import { db, type Querier } from "~/server/db";
|
||||||
|
import { startsWithVowel, titleCase } from "~/utils/utils";
|
||||||
|
|
||||||
export const editAccountHandler = async ({
|
export const editAccountHandler = async ({
|
||||||
id,
|
id,
|
||||||
|
|
@ -214,3 +222,84 @@ export const getUsersWithChatInfoHandler = async (): Promise<
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const genUserIntestazione = async (userId: UsersId) => {
|
||||||
|
try {
|
||||||
|
const data = await db
|
||||||
|
.selectFrom("users")
|
||||||
|
.innerJoin("users_anagrafica", "users_anagrafica.userid", "users.id")
|
||||||
|
.where("id", "=", userId)
|
||||||
|
.select([
|
||||||
|
"users.cognome",
|
||||||
|
"users.nome",
|
||||||
|
"users_anagrafica.data_nascita",
|
||||||
|
"users_anagrafica.luogo_nascita",
|
||||||
|
"users_anagrafica.nazione_nascita",
|
||||||
|
"users_anagrafica.sesso",
|
||||||
|
"users_anagrafica.via_residenza",
|
||||||
|
"users_anagrafica.civico_residenza",
|
||||||
|
"users_anagrafica.comune_residenza",
|
||||||
|
"users_anagrafica.provincia_residenza",
|
||||||
|
"users_anagrafica.cap_residenza",
|
||||||
|
"users_anagrafica.codice_fiscale",
|
||||||
|
])
|
||||||
|
.executeTakeFirstOrThrow(
|
||||||
|
() => new Error(`User not found - userId: ${userId}`),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!data.sesso ||
|
||||||
|
!data.cognome ||
|
||||||
|
!data.nome ||
|
||||||
|
!data.data_nascita ||
|
||||||
|
!data.luogo_nascita ||
|
||||||
|
!data.nazione_nascita ||
|
||||||
|
!data.comune_residenza ||
|
||||||
|
!data.via_residenza ||
|
||||||
|
!data.codice_fiscale
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`Dati anagrafici incompleti per generazione intestazione - userId: ${userId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const comuni = await getComuni();
|
||||||
|
const nazioni = await getNazioni();
|
||||||
|
|
||||||
|
const parsedComuneResidenza = parseDBComune(data.comune_residenza, comuni);
|
||||||
|
const parsedComuneNascita = parseDBComune(data.luogo_nascita, comuni);
|
||||||
|
const parsedNazione = parseDBNazione(data.nazione_nascita, nazioni);
|
||||||
|
|
||||||
|
const comuneNascita = parsedComuneNascita
|
||||||
|
? titleCase(parsedComuneNascita.nome)
|
||||||
|
: data.luogo_nascita;
|
||||||
|
const comuneResidenza = parsedComuneResidenza
|
||||||
|
? titleCase(parsedComuneResidenza.nome)
|
||||||
|
: data.comune_residenza;
|
||||||
|
const nazioneNascita = parsedNazione ? titleCase(parsedNazione.nome) : "";
|
||||||
|
|
||||||
|
// Determine article
|
||||||
|
const isMale = data.sesso === "M";
|
||||||
|
const articolo = isMale ? "Al Sig." : "Alla Sig.ra";
|
||||||
|
const natoNata = isMale ? "nato" : "nata";
|
||||||
|
const preposizione1 = startsWithVowel(comuneNascita) ? "ad" : "a";
|
||||||
|
const preposizione2 = startsWithVowel(comuneResidenza) ? "ad" : "a";
|
||||||
|
|
||||||
|
// Build phrase
|
||||||
|
const frase = [
|
||||||
|
`${articolo} ${data.cognome.toUpperCase()} ${data.nome.toUpperCase()}`,
|
||||||
|
`${natoNata} il ${format(data.data_nascita, "dd/MM/yyyy")}`,
|
||||||
|
`${preposizione1} ${comuneNascita}${parsedNazione?.catasto === ITALY_CATASTO_CODE ? (parsedComuneNascita ? ` (${parsedComuneNascita.sigla})` : "") : ` (${nazioneNascita})`},`,
|
||||||
|
`residente in ${titleCase(data.via_residenza)}, ${data.civico_residenza}`,
|
||||||
|
`${preposizione2} ${comuneResidenza} (${data.provincia_residenza})`,
|
||||||
|
`CAP ${data.cap_residenza},`,
|
||||||
|
`con codice fiscale: ${data.codice_fiscale}`,
|
||||||
|
].join(" ");
|
||||||
|
return frase;
|
||||||
|
} catch (e) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "INTERNAL_SERVER_ERROR",
|
||||||
|
message: `Errore genUserIntestazione - userId: ${userId}: ${(e as Error).message}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,3 +15,19 @@ export const listWithAnd = (list: string[]) => {
|
||||||
}
|
}
|
||||||
return `${list.slice(0, -1).join(", ")}, and ${list.at(-1)}`;
|
return `${list.slice(0, -1).join(", ")}, and ${list.at(-1)}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function titleCase(str: string | null | undefined): string {
|
||||||
|
if (!str) return "";
|
||||||
|
|
||||||
|
return str
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
.split(/\s+/) // Handle multiple spaces
|
||||||
|
.map((word) => {
|
||||||
|
if (word.length === 0) return word;
|
||||||
|
return word.charAt(0).toUpperCase() + word.slice(1);
|
||||||
|
})
|
||||||
|
.join(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
export const startsWithVowel = (s: string) => /^[aeiouàèéìòù]/i.test(s);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue