Add educator email invitations and staff notification preferences
This commit is contained in:
@@ -28,6 +28,7 @@ export type StaffNotice = {
|
||||
toAdmins: boolean;
|
||||
};
|
||||
type CommandResult = {
|
||||
emailIds?: string[];
|
||||
notice?: StaffNotice;
|
||||
invite?: { email: string; name: string; token: string; kitaName: string };
|
||||
};
|
||||
@@ -214,6 +215,33 @@ export async function executeStaffCommand(
|
||||
throw new Error(
|
||||
"Dein Konto hat keinen Zugriff auf den Personalbereich.",
|
||||
);
|
||||
if (command === "emailPreference") {
|
||||
if (actor.role !== UserRole.ERZIEHER)
|
||||
throw new Error(
|
||||
"Diese Einstellung ist für Fachkräfte vorgesehen.",
|
||||
);
|
||||
await tx.user.update({
|
||||
where: { id: actor.id },
|
||||
data: {
|
||||
staffDecisionEmails: z.boolean().parse(data.enabled),
|
||||
},
|
||||
});
|
||||
return {};
|
||||
}
|
||||
if (command === "emailRetry") {
|
||||
const jobs = await tx.staffEmail.findMany({
|
||||
where: {
|
||||
profile: { kitaId: actor.kitaId },
|
||||
...(actor.role === UserRole.ADMIN ? {} : { userId: actor.id }),
|
||||
sentAt: null,
|
||||
skippedAt: null,
|
||||
},
|
||||
select: { id: true },
|
||||
orderBy: { createdAt: "asc" },
|
||||
take: 50,
|
||||
});
|
||||
return { emailIds: jobs.map((job) => job.id) };
|
||||
}
|
||||
if (command === "holiday") {
|
||||
requireAdmin(actor);
|
||||
const input = z
|
||||
@@ -356,6 +384,7 @@ export async function executeStaffCommand(
|
||||
const notice = async (
|
||||
text: string,
|
||||
toAdmins: boolean,
|
||||
email?: { message: string; query: string },
|
||||
): Promise<CommandResult> => {
|
||||
const recipients = await tx.user.findMany({
|
||||
where: {
|
||||
@@ -364,7 +393,7 @@ export async function executeStaffCommand(
|
||||
? { role: UserRole.ADMIN }
|
||||
: { id: profile.userId ?? "" }),
|
||||
},
|
||||
select: { id: true },
|
||||
select: { id: true, role: true, staffDecisionEmails: true },
|
||||
});
|
||||
await tx.staffNotification.createMany({
|
||||
data: recipients.map((user) => ({
|
||||
@@ -373,7 +402,28 @@ export async function executeStaffCommand(
|
||||
message: `${profile.educator.firstName} ${profile.educator.lastName}: ${text}`,
|
||||
})),
|
||||
});
|
||||
return { notice: { profileId, text, toAdmins } };
|
||||
const emailIds: string[] = [];
|
||||
if (email) {
|
||||
for (const user of recipients) {
|
||||
if (
|
||||
!toAdmins &&
|
||||
(user.role !== UserRole.ERZIEHER || !user.staffDecisionEmails)
|
||||
)
|
||||
continue;
|
||||
const job = await tx.staffEmail.create({
|
||||
data: {
|
||||
profileId,
|
||||
userId: user.id,
|
||||
toAdmins,
|
||||
subject: "Kita-Planer: Hinweis im Personalbereich",
|
||||
message: `${profile.educator.firstName} ${profile.educator.lastName}: ${email.message}`,
|
||||
path: `/dashboard/personal?educator=${encodeURIComponent(profile.educatorId)}&${email.query}`,
|
||||
},
|
||||
});
|
||||
emailIds.push(job.id);
|
||||
}
|
||||
}
|
||||
return { notice: { profileId, text, toAdmins }, emailIds };
|
||||
};
|
||||
if (command === "noticeRead") {
|
||||
await tx.staffNotification.updateMany({
|
||||
@@ -446,7 +496,18 @@ export async function executeStaffCommand(
|
||||
where: { id: actor.kitaId },
|
||||
select: { name: true },
|
||||
});
|
||||
const job = await tx.staffEmail.create({
|
||||
data: {
|
||||
profileId,
|
||||
userId: user.id,
|
||||
subject: `Einladung zu ${kita.name} im Kita-Planer`,
|
||||
message: "Account aktivieren",
|
||||
path: `/invite/${token}`,
|
||||
inviteToken: token,
|
||||
},
|
||||
});
|
||||
return {
|
||||
emailIds: [job.id],
|
||||
invite: {
|
||||
email,
|
||||
name: `${profile.educator.firstName} ${profile.educator.lastName}`,
|
||||
@@ -845,6 +906,10 @@ export async function executeStaffCommand(
|
||||
return notice(
|
||||
`Arbeitswoche ab ${start} wurde zur Prüfung eingereicht.`,
|
||||
true,
|
||||
{
|
||||
message: `Arbeitswoche ${start}–${end} wurde zur Prüfung eingereicht.`,
|
||||
query: `tab=zeit&week=${start}`,
|
||||
},
|
||||
);
|
||||
}
|
||||
requireAdmin(actor);
|
||||
@@ -901,6 +966,10 @@ export async function executeStaffCommand(
|
||||
return notice(
|
||||
`Arbeitswoche ab ${start}: ${input.approve ? "genehmigt" : "zur Korrektur zurückgegeben"}. ${input.reason}`,
|
||||
false,
|
||||
{
|
||||
message: `Arbeitswoche ${start}–${end}: ${input.approve ? "genehmigt" : "zur Korrektur zurückgegeben"}.`,
|
||||
query: `tab=zeit&week=${start}`,
|
||||
},
|
||||
);
|
||||
}
|
||||
if (
|
||||
@@ -937,6 +1006,12 @@ export async function executeStaffCommand(
|
||||
? "Ein offener Abwesenheitsantrag wurde zurückgezogen."
|
||||
: "Die Stornierung einer genehmigten Abwesenheit wurde beantragt.",
|
||||
true,
|
||||
existing.kind === "SICKNESS"
|
||||
? undefined
|
||||
: {
|
||||
message: `Abwesenheitsantrag ${dateKey(existing.startDate)}–${dateKey(existing.endDate)}: ${status === "CANCELLED" ? "zurückgezogen" : "Stornierung beantragt"}.`,
|
||||
query: `tab=urlaub&year=${existing.startDate.getUTCFullYear()}`,
|
||||
},
|
||||
);
|
||||
}
|
||||
if (command === "leaveReview") {
|
||||
@@ -1032,6 +1107,12 @@ export async function executeStaffCommand(
|
||||
return notice(
|
||||
`${existing.kind === "VACATION" ? "Urlaub" : existing.kind === "TIME_OFF" ? "Freizeitausgleich" : "Krankmeldung"}: ${status === "CANCELLED" ? "storniert" : status === "REJECTED" ? "abgelehnt" : "genehmigt"}. ${input.reason}`,
|
||||
false,
|
||||
existing.kind === "SICKNESS"
|
||||
? undefined
|
||||
: {
|
||||
message: `${existing.kind === "VACATION" ? "Urlaub" : "Freizeitausgleich"} ${dateKey(existing.startDate)}–${dateKey(existing.endDate)}: ${status === "CANCELLED" ? "storniert" : status === "REJECTED" ? "abgelehnt" : existing.status === "CANCEL_REQUESTED" ? "Stornierung abgelehnt; Genehmigung bleibt bestehen" : "genehmigt"}.`,
|
||||
query: `tab=urlaub&year=${existing.startDate.getUTCFullYear()}`,
|
||||
},
|
||||
);
|
||||
}
|
||||
if (!profile.educator.active)
|
||||
@@ -1140,6 +1221,12 @@ export async function executeStaffCommand(
|
||||
return notice(
|
||||
`${input.kind === "SICKNESS" ? "Krankheit wurde hinterlegt" : "Ein Abwesenheitsantrag wurde eingereicht"}: ${input.startDate}–${input.endDate}.`,
|
||||
input.kind !== "SICKNESS",
|
||||
input.kind === "SICKNESS"
|
||||
? undefined
|
||||
: {
|
||||
message: `${input.kind === "VACATION" ? "Urlaubsantrag" : "Antrag auf Freizeitausgleich"} ${input.startDate}–${input.endDate} wurde ${existing ? "geändert" : "eingereicht"}.`,
|
||||
query: `tab=urlaub&year=${input.startDate.slice(0, 4)}`,
|
||||
},
|
||||
);
|
||||
}
|
||||
throw new Error("Unbekannte Aktion.");
|
||||
|
||||
Reference in New Issue
Block a user