feat: add email sending functionality for receipt and conditions in AdminOrdiniModal
This commit is contained in:
parent
a09fa0597d
commit
0619ca0c34
4 changed files with 116 additions and 16 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import { CircleCheck, CircleSlash, ReceiptText } from "lucide-react";
|
import { CircleCheck, CircleSlash, ReceiptText } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import type { Dispatch, SetStateAction } from "react";
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
import {
|
import {
|
||||||
Credenza,
|
Credenza,
|
||||||
CredenzaBody,
|
CredenzaBody,
|
||||||
|
|
@ -48,6 +49,16 @@ const AdminOrdiniModal = ({
|
||||||
ordineId,
|
ordineId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { mutate: sendReceipt } =
|
||||||
|
api.comunicazioni.sendRicevutaECondizioniEmail.useMutation({
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success("Email inviata con successo!");
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(`Errore durante l'invio dell'email: ${error.message}`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -66,18 +77,27 @@ const AdminOrdiniModal = ({
|
||||||
</CredenzaHeader>
|
</CredenzaHeader>
|
||||||
<CredenzaBody className="max-h-[80vh] space-y-2 overflow-auto pb-5">
|
<CredenzaBody className="max-h-[80vh] space-y-2 overflow-auto pb-5">
|
||||||
<p>Id Ordine: {data.ordine_id}</p>
|
<p>Id Ordine: {data.ordine_id}</p>
|
||||||
{data.isActive && (
|
<div className="flex items-center gap-2">
|
||||||
<div>
|
{data.isActive && (
|
||||||
<Link
|
<div>
|
||||||
href={`/servizio/ricevuta-cortesia/${data.ordine_id}`}
|
<Link
|
||||||
target="_blank"
|
href={`/servizio/ricevuta-cortesia/${data.ordine_id}`}
|
||||||
>
|
target="_blank"
|
||||||
<Button variant="outline">
|
>
|
||||||
Ricevuta di cortesia <ReceiptText />
|
<Button variant="outline">
|
||||||
</Button>
|
Ricevuta di cortesia <ReceiptText />
|
||||||
</Link>
|
</Button>
|
||||||
</div>
|
</Link>
|
||||||
)}
|
</div>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
disabled={!data.isActive}
|
||||||
|
onClick={() => sendReceipt({ ordineId: data.ordine_id })}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
Invia Ricevuta e Condizioni
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
<FormEditOrder
|
<FormEditOrder
|
||||||
close={() => setSelected(null)}
|
close={() => setSelected(null)}
|
||||||
data={data}
|
data={data}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import type { EmailsIdEmail } from "~/schemas/public/Emails";
|
import type { EmailsIdEmail } from "~/schemas/public/Emails";
|
||||||
|
import type { TestiEStringheStingaId } from "~/schemas/public/TestiEStringhe";
|
||||||
import {
|
import {
|
||||||
adminProcedure,
|
adminProcedure,
|
||||||
createTRPCRouter,
|
createTRPCRouter,
|
||||||
protectedProcedure,
|
protectedProcedure,
|
||||||
publicProcedure,
|
publicProcedure,
|
||||||
} from "~/server/api/trpc";
|
} from "~/server/api/trpc";
|
||||||
|
import { addEventToQueue } from "~/server/controllers/event_queue.controller";
|
||||||
import { SendContattoAnnuncioEmail } from "~/server/controllers/servizio.controller";
|
import { SendContattoAnnuncioEmail } from "~/server/controllers/servizio.controller";
|
||||||
import { db } from "~/server/db";
|
import { db } from "~/server/db";
|
||||||
import {
|
import {
|
||||||
|
|
@ -15,7 +17,7 @@ import {
|
||||||
} from "~/server/services/email.service";
|
} from "~/server/services/email.service";
|
||||||
import { NewMail } from "~/server/services/mailer";
|
import { NewMail } from "~/server/services/mailer";
|
||||||
import { genPdfSchedaAnnuncioBase64 } from "~/server/services/puppeteer.service";
|
import { genPdfSchedaAnnuncioBase64 } from "~/server/services/puppeteer.service";
|
||||||
import { zAnnuncioId, zUserId } from "~/server/utils/zod_types";
|
import { zAnnuncioId, zOrdineId, zUserId } from "~/server/utils/zod_types";
|
||||||
|
|
||||||
export const comunicazioniRouter = createTRPCRouter({
|
export const comunicazioniRouter = createTRPCRouter({
|
||||||
getEmails: protectedProcedure
|
getEmails: protectedProcedure
|
||||||
|
|
@ -208,4 +210,68 @@ export const comunicazioniRouter = createTRPCRouter({
|
||||||
...input,
|
...input,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
sendRicevutaECondizioniEmail: adminProcedure
|
||||||
|
.input(
|
||||||
|
z.object({
|
||||||
|
ordineId: zOrdineId,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.mutation(async ({ input }) => {
|
||||||
|
try {
|
||||||
|
const ordine = await db
|
||||||
|
.selectFrom("ordini")
|
||||||
|
.selectAll()
|
||||||
|
.innerJoin("users", "users.id", "ordini.userid")
|
||||||
|
.select(["users.email"])
|
||||||
|
.innerJoin("prezziario", "prezziario.idprezziario", "ordini.packid")
|
||||||
|
.select(["prezziario.testo_condizioni"])
|
||||||
|
.where("ordine_id", "=", input.ordineId)
|
||||||
|
.executeTakeFirstOrThrow(() => {
|
||||||
|
throw new Error(`Ordine not found - ordineId: ${input.ordineId}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
await addEventToQueue({
|
||||||
|
data: {
|
||||||
|
tipo: "email",
|
||||||
|
data: {
|
||||||
|
template: {
|
||||||
|
mailType: "servizioAttivato",
|
||||||
|
},
|
||||||
|
mail: {
|
||||||
|
subject: "Pagamento Confermato - Acconto Infoalloggi.it",
|
||||||
|
to: ordine.email,
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
filename: `condizioni_contrattuali_${ordine.created_at.toISOString()}.pdf`,
|
||||||
|
generate: {
|
||||||
|
type: "condizioni",
|
||||||
|
stringId: (ordine.testo_condizioni ||
|
||||||
|
"CONDIZIONI_CERCHI") as TestiEStringheStingaId,
|
||||||
|
},
|
||||||
|
encoding: "base64",
|
||||||
|
contentType: "application/pdf",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filename: `ricevuta_cortesia_${ordine.ordine_id}.pdf`,
|
||||||
|
|
||||||
|
generate: {
|
||||||
|
type: "ricevuta_cortesia",
|
||||||
|
ordineId: ordine.ordine_id,
|
||||||
|
},
|
||||||
|
encoding: "base64",
|
||||||
|
contentType: "application/pdf",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
userId: ordine.userid,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lock_expires: new Date(), // Lock expires in 1
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(
|
||||||
|
`Errore nell'invio dell'email: ${(e as Error).message}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,14 @@ export const whIntentSucceededHandler = async ({
|
||||||
})
|
})
|
||||||
.where("intent_id", "=", pIntentId)
|
.where("intent_id", "=", pIntentId)
|
||||||
.where("ordine_id", "=", ordineId)
|
.where("ordine_id", "=", ordineId)
|
||||||
.returning(["servizio_id", "ordine_id", "userid", "type", "created_at"])
|
.returning([
|
||||||
|
"servizio_id",
|
||||||
|
"ordine_id",
|
||||||
|
"userid",
|
||||||
|
"type",
|
||||||
|
"created_at",
|
||||||
|
"packid",
|
||||||
|
])
|
||||||
.executeTakeFirstOrThrow(() => {
|
.executeTakeFirstOrThrow(() => {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Payment not found - intent_id: ${pIntentId}, ordineId: ${ordineId}`,
|
`Payment not found - intent_id: ${pIntentId}, ordineId: ${ordineId}`,
|
||||||
|
|
@ -97,6 +104,12 @@ export const whIntentSucceededHandler = async ({
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const condizioni = await trx
|
||||||
|
.selectFrom("prezziario")
|
||||||
|
.select("testo_condizioni")
|
||||||
|
.where("idprezziario", "=", ordine.packid)
|
||||||
|
.executeTakeFirst();
|
||||||
|
|
||||||
const utente = await getUser({
|
const utente = await getUser({
|
||||||
db: trx,
|
db: trx,
|
||||||
userId: ordine.userid,
|
userId: ordine.userid,
|
||||||
|
|
@ -131,7 +144,8 @@ export const whIntentSucceededHandler = async ({
|
||||||
|
|
||||||
generate: {
|
generate: {
|
||||||
type: "condizioni",
|
type: "condizioni",
|
||||||
stringId: "CONDIZIONI_CERCHI" as TestiEStringheStingaId,
|
stringId: (condizioni?.testo_condizioni ||
|
||||||
|
"CONDIZIONI_CERCHI") as TestiEStringheStingaId,
|
||||||
},
|
},
|
||||||
encoding: "base64",
|
encoding: "base64",
|
||||||
contentType: "application/pdf",
|
contentType: "application/pdf",
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ const puppeteerGenPdf = async ({
|
||||||
|
|
||||||
try {
|
try {
|
||||||
browser = await puppeteer.connect({
|
browser = await puppeteer.connect({
|
||||||
browserWSEndpoint: `${env.BROWSER_WS_URL}?--user-data-dir=/tmp/session-0`,
|
browserWSEndpoint: `${env.BROWSER_WS_URL}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue