added suer to p-log, HUB_URL in hub-server, dynamic badges in email
This commit is contained in:
@@ -3,4 +3,5 @@ MOODLE_URL=
|
||||
MAIL_SERVER=
|
||||
MAIL_USER=
|
||||
MAIL_PASSWORD=
|
||||
MAIL_PORT=
|
||||
MAIL_PORT=
|
||||
HUB_URL=http://localhost:3000
|
||||
21
apps/hub-server/modules/mail-templates/Badge.tsx
Normal file
21
apps/hub-server/modules/mail-templates/Badge.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { BADGES } from "@repo/db";
|
||||
import React from "react";
|
||||
|
||||
const badgeImageMapping = {
|
||||
[BADGES.P1]: "p-1.png",
|
||||
[BADGES.P2]: "p-2.png",
|
||||
[BADGES.P3]: "p-3.png",
|
||||
[BADGES.D1]: "d-1.png",
|
||||
[BADGES.D2]: "d-2.png",
|
||||
[BADGES.D3]: "d-3.png",
|
||||
[BADGES.DAY1]: "day-1-member.png",
|
||||
};
|
||||
|
||||
export const Badge = ({ badge }: { badge: BADGES }) => (
|
||||
<img
|
||||
src={`${process.env.HUB_URL}/badges/${badgeImageMapping[badge]}`}
|
||||
alt="Badge"
|
||||
width="80"
|
||||
style={{ display: "block", margin: "0 auto" }}
|
||||
/>
|
||||
);
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from "react";
|
||||
import { Event, User } from "@repo/db";
|
||||
import { Html, Button, render } from "@react-email/components";
|
||||
import { Badge } from "./Badge";
|
||||
|
||||
const styles = `
|
||||
* {
|
||||
@@ -87,7 +88,7 @@ const Template = ({ event, user }: { user: User; event: Event }) => (
|
||||
<tr>
|
||||
<td style={{ textAlign: "center", paddingTop: "30px" }}>
|
||||
<img
|
||||
src="http://localhost:3000/mail/var_logo.png"
|
||||
src={`${process.env.HUB_URL}/mail/var_logo.png`}
|
||||
alt="Logo"
|
||||
width="80"
|
||||
style={{ display: "block", margin: "0 auto" }}
|
||||
@@ -119,12 +120,9 @@ const Template = ({ event, user }: { user: User; event: Event }) => (
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={{ textAlign: "center", padding: "20px" }}>
|
||||
<img
|
||||
src="http://localhost:3000/badges/p-1.png"
|
||||
alt="Badge"
|
||||
width="80"
|
||||
style={{ display: "block", margin: "0 auto" }}
|
||||
/>
|
||||
{event.finishedBadges.map((badge) => (
|
||||
<Badge badge={badge} />
|
||||
))}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -123,7 +123,7 @@ export const AppointmentModal = ({
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return <span>Abwarten</span>;
|
||||
return <span>?</span>;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -149,7 +149,7 @@ export const AppointmentModal = ({
|
||||
onClick={async () => {
|
||||
await upsertParticipant({
|
||||
eventId: event!.id,
|
||||
userId: participantForm.watch("userId"),
|
||||
userId: row.original.userId,
|
||||
attended: true,
|
||||
appointmentCancelled: false,
|
||||
});
|
||||
@@ -160,32 +160,33 @@ export const AppointmentModal = ({
|
||||
Anwesend
|
||||
</button>
|
||||
)}
|
||||
{!row.original.attended && event?.hasPresenceEvents && (
|
||||
<button
|
||||
type="button"
|
||||
onSubmit={() => {}}
|
||||
onClick={async () => {
|
||||
await upsertParticipant({
|
||||
eventId: event!.id,
|
||||
userId: participantForm.watch("userId"),
|
||||
attended: false,
|
||||
appointmentCancelled: true,
|
||||
statusLog: [
|
||||
...(row.original.statusLog as any),
|
||||
{
|
||||
event: "Gefehlt",
|
||||
timestamp: new Date().toISOString(),
|
||||
user: `${session?.user?.firstname} (${session?.user?.lastname} - ${session?.user?.publicId})`,
|
||||
},
|
||||
],
|
||||
});
|
||||
participantTableRef.current?.refresh();
|
||||
}}
|
||||
className="btn btn-outline btn-error btn-sm"
|
||||
>
|
||||
nicht da
|
||||
</button>
|
||||
)}
|
||||
{!row.original.appointmentCancelled &&
|
||||
event?.hasPresenceEvents && (
|
||||
<button
|
||||
type="button"
|
||||
onSubmit={() => {}}
|
||||
onClick={async () => {
|
||||
await upsertParticipant({
|
||||
eventId: event!.id,
|
||||
userId: row.original.userId,
|
||||
attended: false,
|
||||
appointmentCancelled: true,
|
||||
statusLog: [
|
||||
...(row.original.statusLog as any),
|
||||
{
|
||||
event: "Gefehlt an Event",
|
||||
timestamp: new Date().toISOString(),
|
||||
user: `${session?.user?.firstname} ${session?.user?.lastname} - ${session?.user?.publicId}`,
|
||||
},
|
||||
],
|
||||
});
|
||||
participantTableRef.current?.refresh();
|
||||
}}
|
||||
className="btn btn-outline btn-error btn-sm"
|
||||
>
|
||||
abwesend
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Switch } from "../../../../_components/ui/Switch";
|
||||
import { Button } from "../../../../_components/ui/Button";
|
||||
import { Participant, Prisma } from "@repo/db";
|
||||
import { Participant, ParticipantLog, Prisma } from "@repo/db";
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
import { upsertParticipant } from "../../../events/actions";
|
||||
import { RefObject } from "react";
|
||||
@@ -59,7 +59,7 @@ export const ParticipantModal = ({
|
||||
<h3 className="text-xl">Termine</h3>
|
||||
|
||||
<p className="w-full flex justify-between">
|
||||
<span>Termin ausgewählt</span>
|
||||
<span>Termin ausgewählt am</span>
|
||||
<span>
|
||||
{new Date(
|
||||
participantForm.watch("enscriptionDate"),
|
||||
@@ -69,9 +69,12 @@ export const ParticipantModal = ({
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<h3 className="text-xl">Verlauf</h3>
|
||||
{participantForm.watch("statusLog")?.map((s) => (
|
||||
{(
|
||||
participantForm.watch("statusLog") as unknown as ParticipantLog[]
|
||||
)?.map((s) => (
|
||||
<div className="flex justify-between" key={(s as any).timestamp}>
|
||||
<p>{(s as any).event}</p>
|
||||
<p>{s.event}</p>
|
||||
<p>{s.user}</p>
|
||||
<p>{new Date((s as any).timestamp).toLocaleString()}</p>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -214,6 +214,7 @@ const ModalBtn = ({
|
||||
appointmentDate:
|
||||
selectedAppointment.appointmentDate,
|
||||
},
|
||||
user: `${user?.firstname} ${user?.lastname} - ${user?.publicId}`,
|
||||
event: "Termin abgesagt",
|
||||
timestamp: new Date(),
|
||||
},
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
"**/*.tsx",
|
||||
"next-env.d.ts",
|
||||
"next.config.js",
|
||||
".next/types/**/*.ts"
|
||||
".next/types/**/*.ts",
|
||||
"types/.d.ts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
3
apps/hub/types/prisma.d.ts
vendored
3
apps/hub/types/prisma.d.ts
vendored
@@ -1,4 +1,5 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { JsonArray, JsonObject } from "@prisma/client/runtime/library";
|
||||
|
||||
declare module "@prisma/client" {
|
||||
export type InputJsonValue =
|
||||
@@ -8,4 +9,6 @@ declare module "@prisma/client" {
|
||||
| null
|
||||
| JsonObject
|
||||
| JsonArray;
|
||||
|
||||
export type JsonValue = any; // Erzwingt Flexibilität
|
||||
}
|
||||
|
||||
@@ -4,3 +4,4 @@ export * from "./generated/client"; // exports generated types from prisma
|
||||
import * as zodTypes from "./generated/zod";
|
||||
|
||||
export const zod = zodTypes;
|
||||
export * from "./prisma/json";
|
||||
|
||||
7
packages/database/prisma/json/ParticipantLog.ts
Normal file
7
packages/database/prisma/json/ParticipantLog.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { JsonValue } from "@prisma/client/runtime/library";
|
||||
|
||||
export interface ParticipantLog {
|
||||
event: string;
|
||||
timestamp: Date;
|
||||
user: string;
|
||||
}
|
||||
1
packages/database/prisma/json/index.ts
Normal file
1
packages/database/prisma/json/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type { ParticipantLog } from "./ParticipantLog";
|
||||
Reference in New Issue
Block a user