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 {
|
||||
ChevronDown,
|
||||
CloudSync,
|
||||
|
|
@ -274,14 +273,22 @@ const OverseerButton = () => {
|
|||
);
|
||||
};
|
||||
|
||||
const VOCALI = ["A", "E", "I", "O", "U"] as const;
|
||||
|
||||
const IntestazioneMaker = () => {
|
||||
const data = useUserViewContext();
|
||||
const { data: comuni = [] } = api.catasto.searchComuniByCatasto.useQuery({
|
||||
catasto: [data?.luogo_nascita || "", data?.comune_residenza || ""].filter(
|
||||
(f) => f !== "",
|
||||
),
|
||||
const { mutate } = api.users.genIntestazione.useMutation({
|
||||
onError: (error) => {
|
||||
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 =
|
||||
|
|
@ -293,86 +300,17 @@ const IntestazioneMaker = () => {
|
|||
!data.comune_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 (
|
||||
<Button disabled={isDisabled} onClick={copyToClipboard} size="sm">
|
||||
<Button
|
||||
disabled={isDisabled}
|
||||
onClick={() => mutate({ userId: data.id })}
|
||||
size="sm"
|
||||
>
|
||||
<UserPen /> Intestazione
|
||||
</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 { id, note } = useUserViewContext();
|
||||
const [newNote, setNewNote] = useState(note || "");
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {
|
|||
deleteUserHandler,
|
||||
editAccountHandler,
|
||||
editAnagraficaHandler,
|
||||
genUserIntestazione,
|
||||
getActiveUserWithoutChatHandler,
|
||||
getUserHandler,
|
||||
getUsersWithChatInfoHandler,
|
||||
|
|
@ -102,4 +103,13 @@ export const usersRouter = createTRPCRouter({
|
|||
getUsersWChatInfo: adminProcedure.query(async () => {
|
||||
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 { format } from "date-fns";
|
||||
import { jsonArrayFrom } from "kysely/helpers/postgres";
|
||||
import {
|
||||
ITALY_CATASTO_CODE,
|
||||
parseDBComune,
|
||||
parseDBNazione,
|
||||
} from "~/lib/catasto";
|
||||
import type { Etichette } from "~/schemas/public/Etichette";
|
||||
import type { Users, UsersId, UsersUpdate } from "~/schemas/public/Users";
|
||||
import type { UsersAnagraficaUpdate } from "~/schemas/public/UsersAnagrafica";
|
||||
import { getComuni, getNazioni } from "~/server/controllers/catasto.controller";
|
||||
import { db, type Querier } from "~/server/db";
|
||||
import { startsWithVowel, titleCase } from "~/utils/utils";
|
||||
|
||||
export const editAccountHandler = async ({
|
||||
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)}`;
|
||||
};
|
||||
|
||||
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