refactor: update email service functions and add delete all user emails functionality

This commit is contained in:
Marco Pedone 2025-12-29 16:00:57 +01:00
parent c1a383bd2d
commit a0d5faf972
5 changed files with 87 additions and 31 deletions

View file

@ -38,7 +38,7 @@ export const EmailAccordion = ({
const iframeHeight = mobile ? 600 : 500; const iframeHeight = mobile ? 600 : 500;
return ( return (
<div className="mx-auto py-4"> <div className="mx-auto w-full py-4">
<Accordion <Accordion
className="space-y-4" className="space-y-4"
collapsible collapsible

View file

@ -1,11 +1,21 @@
import { MoreVertical, Trash2 } from "lucide-react";
import type { GetServerSideProps } from "next"; import type { GetServerSideProps } from "next";
import toast from "react-hot-toast";
import { EmailAccordion } from "~/components/area-riservata/comunicazioni"; import { EmailAccordion } from "~/components/area-riservata/comunicazioni";
import { Confirm } from "~/components/confirm";
import { AreaRiservataLayoutUserView } from "~/components/Layout"; import { AreaRiservataLayoutUserView } from "~/components/Layout";
import { Button } from "~/components/ui/button";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "~/components/ui/popover";
import type { NextPageWithLayout } from "~/pages/_app"; import type { NextPageWithLayout } from "~/pages/_app";
import { useEnforcedSession } from "~/providers/SessionProvider"; import { useEnforcedSession } from "~/providers/SessionProvider";
import type { UsersId } from "~/schemas/public/Users"; import type { UsersId } from "~/schemas/public/Users";
import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper"; import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper";
import { zUserId } from "~/server/utils/zod_types"; import { zUserId } from "~/server/utils/zod_types";
import { api } from "~/utils/api";
type ComunicazioniUserProps = { type ComunicazioniUserProps = {
userId: UsersId; userId: UsersId;
@ -15,17 +25,54 @@ const ComunicazioniUser: NextPageWithLayout<ComunicazioniUserProps> = ({
userId, userId,
}: ComunicazioniUserProps) => { }: ComunicazioniUserProps) => {
const { user } = useEnforcedSession(); const { user } = useEnforcedSession();
return ( const utils = api.useUtils();
<main className="flex flex-1 flex-col items-start gap-4 md:gap-8"> const { mutate } = api.comunicazioni.deleteAllUserEmails.useMutation({
<div className="grid w-full auto-rows-max items-start gap-2 md:gap-4"> onError: (error) => {
<div className="overflow-auto border-none"> console.error(error);
<h3 className="font-bold text-2xl">Comunicazioni</h3> toast.error("Errore durante l'eliminazione delle comunicazioni");
},
onSuccess: async () => {
toast.success("Comunicazioni eliminate");
await utils.comunicazioni.getEmails.invalidate({ userId });
},
});
<div className="w-full py-4"> return (
<EmailAccordion isAdmin={user.isAdmin} userId={userId} /> <main className="flex flex-1 flex-col items-start gap-4">
</div> <div className="flex w-full items-center justify-between">
</div> <h3 className="font-bold text-2xl">Comunicazioni</h3>
<Popover>
<PopoverTrigger asChild>
<Button size="sm">
<MoreVertical />
</Button>
</PopoverTrigger>
<PopoverContent
align="end"
className="flex w-fit flex-col items-center gap-4"
>
<Confirm
description="Sei sicuro di voler eliminare tutte le comunicazioni?"
onConfirm={() => {
mutate({ userId });
}}
title="Elimina tutte le comunicazioni"
>
<Button
aria-label="Delete Comunicazioni"
className="w-full"
size="sm"
variant="destructive"
>
<Trash2 />
<span>Elimina tutto</span>
</Button>
</Confirm>
</PopoverContent>
</Popover>
</div> </div>
<EmailAccordion isAdmin={user.isAdmin} userId={userId} />
</main> </main>
); );
}; };

View file

@ -5,7 +5,11 @@ import {
createTRPCRouter, createTRPCRouter,
protectedProcedure, protectedProcedure,
} from "~/server/api/trpc"; } from "~/server/api/trpc";
import { DeleteEmail, GetEmails } from "~/server/services/email.service"; import {
deleteAllUserEmails,
deleteEmail,
getEmails,
} from "~/server/services/email.service";
import { NewMail } from "~/server/services/mailer"; import { NewMail } from "~/server/services/mailer";
import { zUserId } from "~/server/utils/zod_types"; import { zUserId } from "~/server/utils/zod_types";
@ -24,7 +28,7 @@ export const comunicazioniRouter = createTRPCRouter({
getEmails: protectedProcedure getEmails: protectedProcedure
.input(z.object({ userId: zUserId })) .input(z.object({ userId: zUserId }))
.query(async ({ input }) => { .query(async ({ input }) => {
return await GetEmails({ return await getEmails({
userId: input.userId, userId: input.userId,
}); });
}), }),
@ -35,23 +39,17 @@ export const comunicazioniRouter = createTRPCRouter({
}), }),
) )
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
return await DeleteEmail({ return await deleteEmail({
id_email: input.id_email, id_email: input.id_email,
}); });
}), }),
// storeEmail: publicProcedure deleteAllUserEmails: adminProcedure
// .input( .input(z.object({ userId: zUserId }))
// z.object({ .mutation(async ({ input }) => {
// data: z.custom<MailsTemplates>(), return await deleteAllUserEmails({
// userId: zUserId, userId: input.userId,
// }), });
// ) }),
// .mutation(async ({ input }) => {
// return await StoreEmail({
// data: input.data,
// userId: input.userId,
// });
// }),
sendSchedaAnnuncioEmail: adminProcedure sendSchedaAnnuncioEmail: adminProcedure
.input( .input(
z.object({ z.object({

View file

@ -4,7 +4,7 @@ import type { UsersId } from "~/schemas/public/Users";
import { db } from "~/server/db"; import { db } from "~/server/db";
import { genMail, type MailsTemplates } from "~/server/services/mailer"; import { genMail, type MailsTemplates } from "~/server/services/mailer";
export const StoreEmail = async ({ export const storeEmail = async ({
userId, userId,
data, data,
}: { }: {
@ -28,7 +28,7 @@ export const StoreEmail = async ({
} }
}; };
export const GetEmails = async ({ userId }: { userId: UsersId }) => { export const getEmails = async ({ userId }: { userId: UsersId }) => {
try { try {
const mails = await db const mails = await db
.selectFrom("emails") .selectFrom("emails")
@ -56,7 +56,7 @@ export const GetEmails = async ({ userId }: { userId: UsersId }) => {
} }
}; };
export const DeleteEmail = async ({ export const deleteEmail = async ({
id_email, id_email,
}: { }: {
id_email: EmailsIdEmail; id_email: EmailsIdEmail;
@ -70,3 +70,14 @@ export const DeleteEmail = async ({
}); });
} }
}; };
export const deleteAllUserEmails = async ({ userId }: { userId: UsersId }) => {
try {
await db.deleteFrom("emails").where("user_id", "=", userId).execute();
} catch (e) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Errore durante l'eliminazione delle email dell'utente: ${(e as Error).message}`,
});
}
};

View file

@ -41,7 +41,7 @@ import { env } from "~/env";
import type { UsersId } from "~/schemas/public/Users"; import type { UsersId } from "~/schemas/public/Users";
import { GetFlagValueHandler } from "~/server/controllers/flags.controller"; import { GetFlagValueHandler } from "~/server/controllers/flags.controller";
import { db } from "~/server/db"; import { db } from "~/server/db";
import { StoreEmail } from "~/server/services/email.service"; import { storeEmail } from "~/server/services/email.service";
const mailer = async (options: Options) => { const mailer = async (options: Options) => {
const smtpTransport = createTransport({ const smtpTransport = createTransport({
@ -230,6 +230,6 @@ export const NewMail = async ({ template, userId, mail }: NewMailProps) => {
if (userId && template) { if (userId && template) {
// Store the email in the database if userId is provided // Store the email in the database if userId is provided
await StoreEmail({ data: template, userId }); await storeEmail({ data: template, userId });
} }
}; };