feat: add comms_enabled flag to users and update email notification logic
This commit is contained in:
parent
73b1997c15
commit
a11fc1241c
7 changed files with 266 additions and 194 deletions
2
apps/db/migrations/42_comms_bool.up.sql
Normal file
2
apps/db/migrations/42_comms_bool.up.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE IF EXISTS public.users
|
||||
ADD COLUMN IF NOT EXISTS comms_enabled boolean NOT NULL DEFAULT true;
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
TODOS:
|
||||
- Log email fallite e retry
|
||||
|
||||
|
||||
conferma presa visione deve rimandare a servizio giusto non /ricerrca
|
||||
|
||||
|
||||
AFTER MVP:
|
||||
- TODO migrazione app router https://nextjs.org/docs/pages/building-your-application/upgrading/app-router-migration#migrating-from-pages-to-app
|
||||
- Sezione "La mia locazione" con i dati della locazione attuale dell'utente
|
||||
|
|
|
|||
|
|
@ -210,6 +210,19 @@ const ServizioPrezzo = () => {
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
{packs.acconto.success && (
|
||||
<Link
|
||||
aria-label="Leggi le condizioni"
|
||||
className="block w-fit"
|
||||
href={`/servizio/condizioni/${packs.acconto.pack.testo_condizioni}`}
|
||||
target="_blank"
|
||||
>
|
||||
<Button className="w-full text-sm">
|
||||
<span>{t.acquisto.leggi_condizioni}</span>
|
||||
<ExternalLink />
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ import { EmailAccordion } from "~/components/area-riservata/comunicazioni";
|
|||
import { Confirm } from "~/components/confirm";
|
||||
import { AreaRiservataLayoutUserView } from "~/components/Layout";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Label } from "~/components/ui/label";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "~/components/ui/popover";
|
||||
import { Switch } from "~/components/ui/switch";
|
||||
import type { NextPageWithLayout } from "~/pages/_app";
|
||||
import { useEnforcedSession } from "~/providers/SessionProvider";
|
||||
import type { UsersId } from "~/schemas/public/Users";
|
||||
|
|
@ -74,7 +76,7 @@ const ComunicazioniUser: NextPageWithLayout<ComunicazioniUserProps> = ({
|
|||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
<Queue userId={userId} />
|
||||
<CommsSwitch userId={userId} />
|
||||
<EmailAccordion isAdmin={user.isAdmin} userId={userId} />
|
||||
</main>
|
||||
);
|
||||
|
|
@ -120,12 +122,35 @@ ComunicazioniUser.getLayout = function getLayout(page) {
|
|||
return <AreaRiservataLayoutUserView>{page}</AreaRiservataLayoutUserView>;
|
||||
};
|
||||
|
||||
const Queue = ({ userId }: { userId: UsersId }) => {
|
||||
const { data } = api.comunicazioni.getUserQueuedEmails.useQuery({ userId });
|
||||
console.log("Queue data", data);
|
||||
const CommsSwitch = ({ userId }: { userId: UsersId }) => {
|
||||
const { data, isLoading } = api.users.getUser.useQuery({ id: userId });
|
||||
if (isLoading || !data) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
const utils = api.useUtils();
|
||||
const { mutate } = api.users.editUser.useMutation({
|
||||
onSuccess: async () => {
|
||||
toast.success("Impostazione modificata");
|
||||
await utils.users.getUser.invalidate({ id: userId });
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
toast.error("Errore durante la modifica dell'impostazione");
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Eventi email in coda per user {userId}</h2>
|
||||
<div className="flex items-center gap-2">
|
||||
<Label htmlFor="comms">Abilita comunicazioni</Label>
|
||||
<Switch
|
||||
className="data-[state=checked]:bg-neutral-700"
|
||||
defaultChecked={data.comms_enabled}
|
||||
id="comms"
|
||||
onCheckedChange={(checked) => {
|
||||
mutate({ id: userId, data: { comms_enabled: checked } });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ export default interface UsersTable {
|
|||
mustChangePassword: ColumnType<boolean, boolean | undefined, boolean>;
|
||||
|
||||
note: ColumnType<string | null, string | null, string | null>;
|
||||
|
||||
comms_enabled: ColumnType<boolean, boolean | undefined, boolean>;
|
||||
}
|
||||
|
||||
export type Users = Selectable<UsersTable>;
|
||||
|
|
|
|||
|
|
@ -224,6 +224,8 @@ export const attivaServizio_SaltaPagamentoAcconto = async (
|
|||
() => new Error(`Ordine not found - ordineId: ${ordineId}`),
|
||||
);
|
||||
|
||||
const user = await getUser({ db: tx, userId: ordine.userId });
|
||||
|
||||
const servizio = await tx
|
||||
.updateTable("servizio")
|
||||
.set({
|
||||
|
|
@ -239,6 +241,7 @@ export const attivaServizio_SaltaPagamentoAcconto = async (
|
|||
),
|
||||
);
|
||||
|
||||
if (user.comms_enabled) {
|
||||
await NewMail({
|
||||
template: {
|
||||
mailType: "servizioAttivato",
|
||||
|
|
@ -277,8 +280,11 @@ export const attivaServizio_SaltaPagamentoAcconto = async (
|
|||
userId: ordine.userId,
|
||||
},
|
||||
},
|
||||
lock_expires: add(new Date(), { days: servizio.interruzioneDays - 5 }),
|
||||
lock_expires: add(new Date(), {
|
||||
days: servizio.interruzioneDays - 5,
|
||||
}),
|
||||
});
|
||||
}
|
||||
return true;
|
||||
});
|
||||
} catch (e) {
|
||||
|
|
@ -298,7 +304,7 @@ export const AdminAttivaServizio_Ufficio = async (
|
|||
.selectFrom("servizio")
|
||||
.select(["servizio.user_id", "servizio.interruzioneDays"])
|
||||
.innerJoin("users", "users.id", "servizio.user_id")
|
||||
.select("users.email")
|
||||
.select(["users.email", "users.comms_enabled"])
|
||||
.where("servizio_id", "=", servizioId)
|
||||
.executeTakeFirstOrThrow(
|
||||
() => new Error(`Servizio not found - servizioId: ${servizioId}`),
|
||||
|
|
@ -314,6 +320,7 @@ export const AdminAttivaServizio_Ufficio = async (
|
|||
.where("servizio_id", "=", servizioId)
|
||||
.execute();
|
||||
|
||||
if (data.comms_enabled) {
|
||||
await addEventToQueue({
|
||||
data: {
|
||||
tipo: "email",
|
||||
|
|
@ -330,6 +337,7 @@ export const AdminAttivaServizio_Ufficio = async (
|
|||
},
|
||||
lock_expires: add(today, { days: data.interruzioneDays - 5 }), //avviso 5 giorni prima della scadenza del periodo di ripensamento
|
||||
});
|
||||
}
|
||||
return true;
|
||||
});
|
||||
} catch (e) {
|
||||
|
|
@ -779,7 +787,7 @@ export const SbloccaContatti = async ({
|
|||
|
||||
const user = await tx
|
||||
.selectFrom("users")
|
||||
.select(["id", "username", "email", "telefono"])
|
||||
.select(["id", "username", "email", "telefono", "comms_enabled"])
|
||||
.where("id", "=", servizio.user_id)
|
||||
.executeTakeFirstOrThrow(() => new Error("User not found"));
|
||||
|
||||
|
|
@ -812,6 +820,7 @@ export const SbloccaContatti = async ({
|
|||
user,
|
||||
};
|
||||
});
|
||||
if (!data.user.comms_enabled) return true;
|
||||
|
||||
const EmailProprietario: NewMailProps | null = data.annuncio.email
|
||||
? {
|
||||
|
|
@ -928,6 +937,7 @@ export const interruzioneServizio = async (servizioId: ServizioServizioId) => {
|
|||
// NOTIFICHE EMAIL INTERRUZIONE SERVIZIO
|
||||
const utente = await getUser({ db, userId: servizio.user_id });
|
||||
|
||||
if (utente.comms_enabled) {
|
||||
await NewMail({
|
||||
template: {
|
||||
mailType: "interruzione",
|
||||
|
|
@ -938,7 +948,7 @@ export const interruzioneServizio = async (servizioId: ServizioServizioId) => {
|
|||
},
|
||||
userId: utente.id,
|
||||
});
|
||||
|
||||
}
|
||||
await NewMail({
|
||||
template: {
|
||||
mailType: "generic",
|
||||
|
|
@ -1051,6 +1061,9 @@ export const userSendConfermaIntent = async ({
|
|||
// NOTIFICHE EMAIL CONFERMA IMMOBILE
|
||||
|
||||
const utente = await getUser({ db, userId: servizio.user_id });
|
||||
if (!utente.comms_enabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const annuncio_codice = await db
|
||||
.selectFrom("annunci")
|
||||
|
|
@ -1148,6 +1161,9 @@ export const adminUpdateConfermaStatus = async ({
|
|||
}
|
||||
|
||||
//ADMIN CONFERMA LAVORATA EMAIL
|
||||
if (!utente.comms_enabled) {
|
||||
return true;
|
||||
}
|
||||
if (status) {
|
||||
await NewMail({
|
||||
template: {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,8 @@ export const whIntentSucceededHandler = async ({
|
|||
`Payment not found - intent_id: ${pIntentId}, ordineId: ${ordineId}`,
|
||||
);
|
||||
});
|
||||
|
||||
const condizioniFilename = `condizioni_contrattuali_${(ordine.paid_at || ordine.created_at).toISOString()}.pdf`;
|
||||
const ricevutaFilename = `ricevuta_cortesia_${(ordine.paid_at || ordine.created_at).toISOString()}.pdf`;
|
||||
const condizioni = await trx
|
||||
.selectFrom("prezziario")
|
||||
.select("testo_condizioni")
|
||||
|
|
@ -123,7 +124,7 @@ export const whIntentSucceededHandler = async ({
|
|||
`Failed to update servizio - servizioId: ${ordine.servizio_id}`,
|
||||
),
|
||||
);
|
||||
|
||||
if (utente.comms_enabled) {
|
||||
await addEventToQueue({
|
||||
data: {
|
||||
tipo: "email",
|
||||
|
|
@ -136,7 +137,7 @@ export const whIntentSucceededHandler = async ({
|
|||
to: utente.email,
|
||||
attachments: [
|
||||
{
|
||||
filename: `condizioni_contrattuali_${ordine.created_at.toISOString()}.pdf`,
|
||||
filename: condizioniFilename,
|
||||
generate: {
|
||||
type: "condizioni",
|
||||
stringId: (condizioni?.testo_condizioni ||
|
||||
|
|
@ -146,7 +147,7 @@ export const whIntentSucceededHandler = async ({
|
|||
contentType: "application/pdf",
|
||||
},
|
||||
{
|
||||
filename: `ricevuta_cortesia_${ordine.ordine_id}.pdf`,
|
||||
filename: ricevutaFilename,
|
||||
generate: {
|
||||
type: "ricevuta_cortesia",
|
||||
ordineId: ordine.ordine_id,
|
||||
|
|
@ -180,6 +181,7 @@ export const whIntentSucceededHandler = async ({
|
|||
days: servizio.interruzioneDays - 5,
|
||||
}),
|
||||
});
|
||||
}
|
||||
//SERVIZIO ATTIVATO
|
||||
|
||||
break;
|
||||
|
|
@ -210,6 +212,7 @@ export const whIntentSucceededHandler = async ({
|
|||
isOkSaldo: true,
|
||||
})
|
||||
.execute();
|
||||
if (utente.comms_enabled) {
|
||||
await addEventToQueue({
|
||||
data: {
|
||||
tipo: "email",
|
||||
|
|
@ -222,7 +225,7 @@ export const whIntentSucceededHandler = async ({
|
|||
to: utente.email,
|
||||
attachments: [
|
||||
{
|
||||
filename: `ricevuta_cortesia_${ordine.ordine_id}.pdf`,
|
||||
filename: ricevutaFilename,
|
||||
generate: {
|
||||
type: "ricevuta_cortesia",
|
||||
ordineId: ordine.ordine_id,
|
||||
|
|
@ -237,10 +240,12 @@ export const whIntentSucceededHandler = async ({
|
|||
},
|
||||
lock_expires,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OrderTypeEnum.Rinnovo: {
|
||||
// nessuna azione aggiuntiva richiesta
|
||||
if (utente.comms_enabled) {
|
||||
await addEventToQueue({
|
||||
data: {
|
||||
tipo: "email",
|
||||
|
|
@ -253,7 +258,7 @@ export const whIntentSucceededHandler = async ({
|
|||
to: utente.email,
|
||||
attachments: [
|
||||
{
|
||||
filename: `ricevuta_cortesia_${ordine.ordine_id}.pdf`,
|
||||
filename: ricevutaFilename,
|
||||
generate: {
|
||||
type: "ricevuta_cortesia",
|
||||
ordineId: ordine.ordine_id,
|
||||
|
|
@ -268,6 +273,7 @@ export const whIntentSucceededHandler = async ({
|
|||
},
|
||||
lock_expires,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OrderTypeEnum.Consulenza: {
|
||||
|
|
@ -284,6 +290,7 @@ export const whIntentSucceededHandler = async ({
|
|||
isOkConsulenza: true,
|
||||
})
|
||||
.execute();
|
||||
if (utente.comms_enabled) {
|
||||
await addEventToQueue({
|
||||
data: {
|
||||
tipo: "email",
|
||||
|
|
@ -296,7 +303,7 @@ export const whIntentSucceededHandler = async ({
|
|||
to: utente.email,
|
||||
attachments: [
|
||||
{
|
||||
filename: `ricevuta_cortesia_${ordine.ordine_id}.pdf`,
|
||||
filename: ricevutaFilename,
|
||||
generate: {
|
||||
type: "ricevuta_cortesia",
|
||||
ordineId: ordine.ordine_id,
|
||||
|
|
@ -311,6 +318,7 @@ export const whIntentSucceededHandler = async ({
|
|||
},
|
||||
lock_expires,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OrderTypeEnum.Altro:
|
||||
|
|
@ -341,6 +349,16 @@ export const whIntentSucceededHandler = async ({
|
|||
encoding: "base64",
|
||||
contentType: "application/pdf",
|
||||
},
|
||||
{
|
||||
filename: condizioniFilename,
|
||||
generate: {
|
||||
type: "condizioni",
|
||||
stringId: (condizioni?.testo_condizioni ||
|
||||
CONDIZIONI_DEFAULT) as TestiEStringheStingaId,
|
||||
},
|
||||
encoding: "base64",
|
||||
contentType: "application/pdf",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue