Pfadauswahl hinzugefügt
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { getServerSession } from "../../api/auth/[...nextauth]/auth";
|
import { getServerSession } from "../../api/auth/[...nextauth]/auth";
|
||||||
import { prisma } from "@repo/db";
|
import { prisma } from "@repo/db";
|
||||||
import { KursItem } from "../events/_components/item";
|
import { EventCard } from "../events/_components/item";
|
||||||
import { RocketIcon } from "lucide-react";
|
import { RocketIcon } from "lucide-react";
|
||||||
import { eventCompleted } from "../../../helper/events";
|
import { eventCompleted } from "../../../helper/events";
|
||||||
|
|
||||||
@@ -15,15 +15,15 @@ const page = async () => {
|
|||||||
|
|
||||||
const events = await prisma.event.findMany({
|
const events = await prisma.event.findMany({
|
||||||
where: {
|
where: {
|
||||||
type: "OBLIGATED_COURSE",
|
type: "EVENT",
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
participants: {
|
Participants: {
|
||||||
where: {
|
where: {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
appointments: {
|
Appointments: {
|
||||||
include: {
|
include: {
|
||||||
Participants: {
|
Participants: {
|
||||||
where: {
|
where: {
|
||||||
@@ -36,12 +36,10 @@ const page = async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const filteredEvents = events.filter((event) => {
|
const filteredEvents = events.filter((event) => {
|
||||||
const userParticipant = event.participants.find(
|
const userParticipant = event.Participants.find(
|
||||||
(participant) => participant.userId === user.id,
|
(participant) => participant.userId === user.id,
|
||||||
);
|
);
|
||||||
if (eventCompleted(event, userParticipant)) return false;
|
if (eventCompleted(event, userParticipant)) return false;
|
||||||
if (event.type === "OBLIGATED_COURSE" && !eventCompleted(event, event.participants[0]))
|
|
||||||
return true;
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -56,9 +54,9 @@ const page = async () => {
|
|||||||
<div className="grid grid-cols-6 gap-4">
|
<div className="grid grid-cols-6 gap-4">
|
||||||
{filteredEvents.map((event) => {
|
{filteredEvents.map((event) => {
|
||||||
return (
|
return (
|
||||||
<KursItem
|
<EventCard
|
||||||
appointments={event.appointments}
|
appointments={event.Appointments}
|
||||||
selectedAppointments={event.appointments.filter((a) =>
|
selectedAppointments={event.Appointments.filter((a) =>
|
||||||
a.Participants.find((p) => p.userId == user.id),
|
a.Participants.find((p) => p.userId == user.id),
|
||||||
)}
|
)}
|
||||||
user={user}
|
user={user}
|
||||||
|
|||||||
@@ -1,9 +1,100 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
import { editUser } from "(app)/admin/user/action";
|
||||||
|
import { Button } from "_components/ui/Button";
|
||||||
|
import { Plane, Workflow } from "lucide-react";
|
||||||
|
import { useSession } from "next-auth/react";
|
||||||
import { useRef, useEffect, useState } from "react";
|
import { useRef, useEffect, useState } from "react";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { getEvents } from "../../../helper/events";
|
||||||
|
import { EventCard } from "(app)/events/_components/item";
|
||||||
|
|
||||||
|
const PathsOptions = ({
|
||||||
|
selected,
|
||||||
|
setSelected,
|
||||||
|
}: {
|
||||||
|
selected: "disponent" | "pilot" | null;
|
||||||
|
setSelected: (value: "disponent" | "pilot") => void;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex gap-6">
|
||||||
|
{/* Disponent Card */}
|
||||||
|
<div
|
||||||
|
className={`cursor-pointer border rounded-lg p-6 w-80 transition-colors ${
|
||||||
|
selected === "disponent" ? "border-info ring-2 ring-info" : "border-base-300"
|
||||||
|
}`}
|
||||||
|
onClick={() => setSelected("disponent")}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
aria-pressed={selected === "disponent"}
|
||||||
|
>
|
||||||
|
<h1 className="font-semibold text-lg mb-2 flex gap-2 justify-center items-center">
|
||||||
|
Disponent <Workflow />
|
||||||
|
</h1>
|
||||||
|
<div className="text-sm text-base-content/70">
|
||||||
|
Denkt sich realistische Einsatzszenarien aus, koordiniert deren Ablauf und ist die
|
||||||
|
zentrale Schnittstelle zwischen Piloten und bodengebundenen Rettungsmitteln. Er trägt
|
||||||
|
die Verantwortung für einen reibungslosen Ablauf und der erfolgreichen Durchführung der
|
||||||
|
Einsätze.
|
||||||
|
<div className="badge badge-sm badge-secondary mt-3">
|
||||||
|
Teilnahme an Einführungsevent Nötig
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Pilot Card */}
|
||||||
|
<div
|
||||||
|
className={`cursor-pointer border rounded-lg p-6 w-80 transition-colors ${
|
||||||
|
selected === "pilot" ? "border-info ring-2 ring-info" : "border-base-300"
|
||||||
|
}`}
|
||||||
|
onClick={() => setSelected("pilot")}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
aria-pressed={selected === "pilot"}
|
||||||
|
>
|
||||||
|
<h1 className="font-semibold text-lg mb-2 flex gap-2 justify-center items-center">
|
||||||
|
Pilot <Plane />
|
||||||
|
</h1>
|
||||||
|
<div className="text-sm text-base-content/70">
|
||||||
|
Fliegt die vom Disponenten erstellten Einsätze und transportiert die Med-Crew sicher zum
|
||||||
|
Einsatzort. Er übernimmt die navigatorische Vorbereitung, achtet auf Wetterentwicklungen
|
||||||
|
und sorgt für die Sicherheit seiner Crew im Flug.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const EventSelect = ({ pathSelected }: { pathSelected: "disponent" | "pilot" }) => {
|
||||||
|
const { data: events } = useQuery({
|
||||||
|
queryKey: ["events", "initial", pathSelected],
|
||||||
|
queryFn: () =>
|
||||||
|
getEvents({
|
||||||
|
type: pathSelected === "pilot" ? "PILOT_STARTER" : "DISPATCH_STARTER",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const user = useSession().data?.user;
|
||||||
|
if (!user) return null;
|
||||||
|
return events?.map((event) => {
|
||||||
|
return (
|
||||||
|
<EventCard
|
||||||
|
appointments={event.Appointments}
|
||||||
|
selectedAppointments={event.Appointments.filter((a) =>
|
||||||
|
a.Participants.find((p) => p.userId == user.id),
|
||||||
|
)}
|
||||||
|
user={user}
|
||||||
|
event={event}
|
||||||
|
key={event.id}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const FirstPath = () => {
|
export const FirstPath = () => {
|
||||||
const modalRef = useRef<HTMLDialogElement>(null);
|
const modalRef = useRef<HTMLDialogElement>(null);
|
||||||
|
const { data: session } = useSession();
|
||||||
const [selected, setSelected] = useState<"disponent" | "pilot" | null>(null);
|
const [selected, setSelected] = useState<"disponent" | "pilot" | null>(null);
|
||||||
|
const [page, setPage] = useState<"path" | "event-select">("path");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (modalRef.current && !modalRef.current.open) {
|
if (modalRef.current && !modalRef.current.open) {
|
||||||
@@ -17,59 +108,40 @@ export const FirstPath = () => {
|
|||||||
<h3 className="flex items-center gap-2 text-lg font-bold mb-10">Wähle deinen Einstieg!</h3>
|
<h3 className="flex items-center gap-2 text-lg font-bold mb-10">Wähle deinen Einstieg!</h3>
|
||||||
<p className="mb-8 text-base text-base-content/80 text-center">
|
<p className="mb-8 text-base text-base-content/80 text-center">
|
||||||
Willkommen bei Virtual Air Rescue!
|
Willkommen bei Virtual Air Rescue!
|
||||||
<br /> Wähle deinen ersten Pfad aus. Du kannst später jederzeit auch den anderen Pfad
|
<br /> Wie möchtest du bei uns starten? Du kannst später jederzeit auch den anderen Pfad
|
||||||
ausprobieren, wenn du möchtest.
|
ausprobieren, wenn du möchtest.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-col items-center justify-center m-20">
|
<div className="flex flex-col items-center justify-center m-20">
|
||||||
<div className="flex gap-6">
|
{page === "path" && <PathsOptions selected={selected} setSelected={setSelected} />}
|
||||||
{/* Disponent Card */}
|
{page === "event-select" && (
|
||||||
<div
|
<div className="flex flex-col gap-3 min-w-[800px]">
|
||||||
className={`cursor-pointer border rounded-lg p-6 w-80 transition-colors ${
|
<div>
|
||||||
selected === "disponent" ? "border-info ring-2 ring-info" : "border-base-300"
|
<p className="text-left text-gray-400 text-sm">Wähle dein Einführungs-Event aus:</p>
|
||||||
}`}
|
|
||||||
onClick={() => setSelected("disponent")}
|
|
||||||
role="button"
|
|
||||||
tabIndex={0}
|
|
||||||
aria-pressed={selected === "disponent"}
|
|
||||||
>
|
|
||||||
<div className="font-semibold text-lg mb-2">Disponent</div>
|
|
||||||
<div className="text-sm text-base-content/70">
|
|
||||||
Denkt sich realistische Einsatzszenarien aus, koordiniert deren Ablauf und ist die
|
|
||||||
zentrale Schnittstelle zwischen Piloten und bodengebundenen Rettungsmitteln. Er
|
|
||||||
trägt die Verantwortung für einen reibungslosen Ablauf und der erfolgreichen
|
|
||||||
Durchführung der Einsätze.
|
|
||||||
<div className="badge badge-sm badge-secondary mt-3">
|
|
||||||
Teilnahme an Einführungsevent Nötig
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<EventSelect pathSelected={selected!} />
|
||||||
</div>
|
</div>
|
||||||
{/* Pilot Card */}
|
)}
|
||||||
<div
|
|
||||||
className={`cursor-pointer border rounded-lg p-6 w-80 transition-colors ${
|
|
||||||
selected === "pilot" ? "border-info ring-2 ring-info" : "border-base-300"
|
|
||||||
}`}
|
|
||||||
onClick={() => setSelected("pilot")}
|
|
||||||
role="button"
|
|
||||||
tabIndex={0}
|
|
||||||
aria-pressed={selected === "pilot"}
|
|
||||||
>
|
|
||||||
<div className="font-semibold text-lg mb-2">Pilot</div>
|
|
||||||
<div className="text-sm text-base-content/70">
|
|
||||||
Fliegt die vom Disponenten erstellten Einsätze und transportiert die Med-Crew sicher
|
|
||||||
zum Einsatzort. Er übernimmt die navigatorische Vorbereitung, achtet auf
|
|
||||||
Wetterentwicklungen und sorgt für die Sicherheit seiner Crew im Flug.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="modal-action">
|
<div className="modal-action">
|
||||||
<button
|
<button className="btn" disabled={page === "path"} onClick={() => setPage("path")}>
|
||||||
|
Zurück
|
||||||
|
</button>
|
||||||
|
<Button
|
||||||
className="btn btn-info"
|
className="btn btn-info"
|
||||||
disabled={!selected}
|
disabled={!selected}
|
||||||
onClick={() => modalRef.current?.close()}
|
onClick={async () => {
|
||||||
|
if (page === "path") {
|
||||||
|
setPage("event-select");
|
||||||
|
} else if (session?.user.id) {
|
||||||
|
await editUser(session?.user.id, {
|
||||||
|
pathSelected: true,
|
||||||
|
});
|
||||||
|
modalRef.current?.close();
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Auswahl Bestätigen
|
{page === "path" ? "Weiter" : "Pfad auswählen"}
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import ModalBtn from "./modalBtn";
|
|||||||
import MDEditor from "@uiw/react-md-editor";
|
import MDEditor from "@uiw/react-md-editor";
|
||||||
import { Badge } from "../../../_components/Badge/Badge";
|
import { Badge } from "../../../_components/Badge/Badge";
|
||||||
|
|
||||||
export const KursItem = ({
|
export const EventCard = ({
|
||||||
user,
|
user,
|
||||||
event,
|
event,
|
||||||
selectedAppointments,
|
selectedAppointments,
|
||||||
@@ -13,8 +13,8 @@ export const KursItem = ({
|
|||||||
}: {
|
}: {
|
||||||
user: User;
|
user: User;
|
||||||
event: Event & {
|
event: Event & {
|
||||||
appointments: EventAppointment[];
|
Appointments: EventAppointment[];
|
||||||
participants: Participant[];
|
Participants: Participant[];
|
||||||
};
|
};
|
||||||
selectedAppointments: EventAppointment[];
|
selectedAppointments: EventAppointment[];
|
||||||
appointments: EventAppointment[];
|
appointments: EventAppointment[];
|
||||||
@@ -28,8 +28,8 @@ export const KursItem = ({
|
|||||||
{event.type === "COURSE" && (
|
{event.type === "COURSE" && (
|
||||||
<span className="badge badge-info badge-outline">Zusatzqualifikation</span>
|
<span className="badge badge-info badge-outline">Zusatzqualifikation</span>
|
||||||
)}
|
)}
|
||||||
{event.type === "OBLIGATED_COURSE" && (
|
{event.type === "EVENT" && (
|
||||||
<span className="badge badge-secondary badge-outline">Verpflichtend</span>
|
<span className="badge badge-secondary badge-outline">Event</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-6 gap-4">
|
<div className="grid grid-cols-6 gap-4">
|
||||||
@@ -75,7 +75,7 @@ export const KursItem = ({
|
|||||||
event={event}
|
event={event}
|
||||||
title={event.name}
|
title={event.name}
|
||||||
dates={appointments}
|
dates={appointments}
|
||||||
participant={event.participants[0]}
|
participant={event.Participants[0]}
|
||||||
modalId={`${event.name}_modal.${event.id}`}
|
modalId={`${event.name}_modal.${event.id}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ const ModalBtn = ({
|
|||||||
<button
|
<button
|
||||||
className={cn(
|
className={cn(
|
||||||
"btn btn-outline btn-info btn-wide",
|
"btn btn-outline btn-info btn-wide",
|
||||||
event.type === "OBLIGATED_COURSE" && "btn-secondary",
|
event.type === "COURSE" && "btn-secondary",
|
||||||
eventCompleted(event, participant) && "btn-success",
|
eventCompleted(event, participant) && "btn-success",
|
||||||
)}
|
)}
|
||||||
onClick={openModal}
|
onClick={openModal}
|
||||||
@@ -219,7 +219,7 @@ const ModalBtn = ({
|
|||||||
<button
|
<button
|
||||||
className={cn(
|
className={cn(
|
||||||
"btn btn-info btn-outline btn-wide",
|
"btn btn-info btn-outline btn-wide",
|
||||||
event.type === "OBLIGATED_COURSE" && "btn-secondary",
|
event.type === "COURSE" && "btn-secondary",
|
||||||
)}
|
)}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const data = selectAppointmentForm.getValues();
|
const data = selectAppointmentForm.getValues();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { prisma } from "@repo/db";
|
import { prisma } from "@repo/db";
|
||||||
import { getServerSession } from "../../api/auth/[...nextauth]/auth";
|
import { getServerSession } from "../../api/auth/[...nextauth]/auth";
|
||||||
import { KursItem } from "./_components/item";
|
import { EventCard } from "./_components/item";
|
||||||
import { RocketIcon } from "@radix-ui/react-icons";
|
import { RocketIcon } from "@radix-ui/react-icons";
|
||||||
|
|
||||||
const page = async () => {
|
const page = async () => {
|
||||||
@@ -11,14 +11,14 @@ const page = async () => {
|
|||||||
|
|
||||||
const events = await prisma.event.findMany({
|
const events = await prisma.event.findMany({
|
||||||
include: {
|
include: {
|
||||||
appointments: {
|
Appointments: {
|
||||||
where: {
|
where: {
|
||||||
appointmentDate: {
|
appointmentDate: {
|
||||||
gte: new Date(),
|
gte: new Date(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
participants: {
|
Participants: {
|
||||||
where: {
|
where: {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
},
|
},
|
||||||
@@ -69,7 +69,7 @@ const page = async () => {
|
|||||||
|
|
||||||
{events.map((event) => {
|
{events.map((event) => {
|
||||||
return (
|
return (
|
||||||
<KursItem
|
<EventCard
|
||||||
appointments={appointments}
|
appointments={appointments}
|
||||||
selectedAppointments={userAppointments}
|
selectedAppointments={userAppointments}
|
||||||
user={user}
|
user={user}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export default async function RootLayout({
|
|||||||
<EmailVerification />
|
<EmailVerification />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<FirstPath />
|
{!session.user.pathSelected && <FirstPath />}
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
25
apps/hub/app/_components/QueryClient.tsx
Normal file
25
apps/hub/app/_components/QueryClient.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// components/TanstackProvider.tsx
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { toast } from "react-hot-toast";
|
||||||
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
|
import { ReactNode, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export function QueryProvider({ children }: { children: ReactNode }) {
|
||||||
|
const [queryClient] = useState(
|
||||||
|
() =>
|
||||||
|
new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
mutations: {
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error("An error occurred: " + (error as Error).message, {
|
||||||
|
position: "top-right",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
|
||||||
|
}
|
||||||
46
apps/hub/app/api/event/route.ts
Normal file
46
apps/hub/app/api/event/route.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { Prisma, prisma } from "@repo/db";
|
||||||
|
import { getServerSession } from "api/auth/[...nextauth]/auth";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export async function GET(request: Request): Promise<NextResponse> {
|
||||||
|
try {
|
||||||
|
const session = await getServerSession();
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const filter = JSON.parse(
|
||||||
|
new URL(request.url).searchParams.get("filter") || "{}",
|
||||||
|
) as Prisma.EventWhereInput;
|
||||||
|
|
||||||
|
const connectedAircraft = await prisma.event.findMany({
|
||||||
|
where: {
|
||||||
|
...filter, // Ensure filter is parsed correctly
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
Participants: {
|
||||||
|
where: {
|
||||||
|
userId: session.user.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Appointments: {
|
||||||
|
include: {
|
||||||
|
Participants: {
|
||||||
|
where: {
|
||||||
|
appointmentCancelled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json(connectedAircraft, {
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return NextResponse.json({ error: "Failed to fetch Aircrafts" }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import { getServerSession } from "./api/auth/[...nextauth]/auth";
|
|||||||
import { CustomErrorBoundary } from "_components/ErrorBoundary";
|
import { CustomErrorBoundary } from "_components/ErrorBoundary";
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "react-hot-toast";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
import { QueryProvider } from "_components/QueryClient";
|
||||||
|
|
||||||
const geistSans = Geist({
|
const geistSans = Geist({
|
||||||
variable: "--font-geist-sans",
|
variable: "--font-geist-sans",
|
||||||
@@ -33,7 +34,9 @@ const RootLayout = async ({
|
|||||||
reverseOrder={false}
|
reverseOrder={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<CustomErrorBoundary>{children}</CustomErrorBoundary>
|
<QueryProvider>
|
||||||
|
<CustomErrorBoundary>{children}</CustomErrorBoundary>
|
||||||
|
</QueryProvider>
|
||||||
</body>
|
</body>
|
||||||
</NextAuthSessionProvider>
|
</NextAuthSessionProvider>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
import { Event, Participant } from "@repo/db";
|
import { Event, EventAppointment, Participant, Prisma } from "@repo/db";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { da } from "date-fns/locale";
|
||||||
|
|
||||||
|
export const getEvents = async (filter: Prisma.EventWhereInput) => {
|
||||||
|
const { data } = await axios.get<
|
||||||
|
(Event & {
|
||||||
|
Appointments: (EventAppointment & {
|
||||||
|
Appointments: EventAppointment[];
|
||||||
|
Participants: Participant[];
|
||||||
|
})[];
|
||||||
|
Participants: Participant[];
|
||||||
|
})[]
|
||||||
|
>(`/api/event`, {
|
||||||
|
params: {
|
||||||
|
filter: JSON.stringify(filter),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
export const eventCompleted = (event: Event, participant?: Participant) => {
|
export const eventCompleted = (event: Event, participant?: Participant) => {
|
||||||
if (!participant) return false;
|
if (!participant) return false;
|
||||||
|
|||||||
@@ -10,19 +10,29 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@eslint/eslintrc": "^3",
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.0.1",
|
||||||
"@next-auth/prisma-adapter": "^1.0.7",
|
"@next-auth/prisma-adapter": "^1.0.7",
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@repo/db": "workspace:*",
|
"@repo/db": "workspace:*",
|
||||||
"@repo/eslint-config": "workspace:*",
|
"@repo/eslint-config": "workspace:*",
|
||||||
"@repo/typescript-config": "workspace:*",
|
"@repo/typescript-config": "workspace:*",
|
||||||
"@tanstack/react-query": "^5.79.0",
|
"@tailwindcss/postcss": "^4.1.8",
|
||||||
|
"@tanstack/react-query": "^5.79.2",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
|
"@types/bcryptjs": "^3.0.0",
|
||||||
|
"@types/jsonwebtoken": "^9.0.9",
|
||||||
|
"@types/node": "^22.15.29",
|
||||||
|
"@types/react": "^19.1.6",
|
||||||
|
"@types/react-dom": "^19.1.5",
|
||||||
"@uiw/react-md-editor": "^4.0.7",
|
"@uiw/react-md-editor": "^4.0.7",
|
||||||
"axios": "^1.9.0",
|
"axios": "^1.9.0",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"daisyui": "^5.0.43",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
|
"eslint": "^9.15.0",
|
||||||
|
"eslint-config-next": "^15.3.3",
|
||||||
"i": "^0.3.7",
|
"i": "^0.3.7",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
@@ -31,6 +41,7 @@
|
|||||||
"next-auth": "^4.24.11",
|
"next-auth": "^4.24.11",
|
||||||
"next-remove-imports": "^1.0.12",
|
"next-remove-imports": "^1.0.12",
|
||||||
"npm": "^11.4.1",
|
"npm": "^11.4.1",
|
||||||
|
"postcss": "^8.5.4",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-datepicker": "^8.4.0",
|
"react-datepicker": "^8.4.0",
|
||||||
"react-day-picker": "^9.7.0",
|
"react-day-picker": "^9.7.0",
|
||||||
@@ -40,20 +51,8 @@
|
|||||||
"react-hot-toast": "^2.5.2",
|
"react-hot-toast": "^2.5.2",
|
||||||
"react-select": "^5.10.1",
|
"react-select": "^5.10.1",
|
||||||
"tailwind-merge": "^3.3.0",
|
"tailwind-merge": "^3.3.0",
|
||||||
"zod": "^3.25.46",
|
|
||||||
"@eslint/eslintrc": "^3",
|
|
||||||
"@tailwindcss/postcss": "^4.1.8",
|
|
||||||
"@types/bcryptjs": "^3.0.0",
|
|
||||||
"@types/jsonwebtoken": "^9.0.9",
|
|
||||||
"@types/node": "^22.15.29",
|
|
||||||
"@types/react": "^19.1.6",
|
|
||||||
"@types/react-dom": "^19.1.5",
|
|
||||||
"daisyui": "^5.0.43",
|
|
||||||
"eslint": "^9.15.0",
|
|
||||||
"eslint-config-next": "^15.3.3",
|
|
||||||
"postcss": "^8.5.4",
|
|
||||||
"tailwindcss": "^4.1.8",
|
"tailwindcss": "^4.1.8",
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3",
|
||||||
},
|
"zod": "^3.25.46"
|
||||||
"devDependencies": {}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
enum EVENT_TYPE {
|
enum EVENT_TYPE {
|
||||||
COURSE
|
COURSE
|
||||||
OBLIGATED_COURSE
|
PILOT_STARTER
|
||||||
|
DISPATCH_STARTER
|
||||||
EVENT
|
EVENT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ model EventAppointment {
|
|||||||
// relations:
|
// relations:
|
||||||
Users User[] @relation("EventAppointmentUser")
|
Users User[] @relation("EventAppointmentUser")
|
||||||
Participants Participant[]
|
Participants Participant[]
|
||||||
Event Event @relation(fields: [eventId], references: [id])
|
Event Event @relation(fields: [eventId], references: [id], onDelete: Cascade)
|
||||||
Presenter User @relation(fields: [presenterId], references: [id])
|
Presenter User @relation(fields: [presenterId], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ model Participant {
|
|||||||
eventId Int
|
eventId Int
|
||||||
// relations:
|
// relations:
|
||||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
Event Event @relation(fields: [eventId], references: [id])
|
Event Event @relation(fields: [eventId], references: [id], onDelete: Cascade)
|
||||||
EventAppointment EventAppointment? @relation(fields: [eventAppointmentId], references: [id])
|
EventAppointment EventAppointment? @relation(fields: [eventAppointmentId], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,8 +49,8 @@ model Event {
|
|||||||
hidden Boolean @default(true)
|
hidden Boolean @default(true)
|
||||||
|
|
||||||
// relations:
|
// relations:
|
||||||
participants Participant[]
|
Participants Participant[]
|
||||||
appointments EventAppointment[]
|
Appointments EventAppointment[]
|
||||||
}
|
}
|
||||||
|
|
||||||
model File {
|
model File {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ model User {
|
|||||||
moodleId Int? @map(name: "moodle_id")
|
moodleId Int? @map(name: "moodle_id")
|
||||||
|
|
||||||
// Settings:
|
// Settings:
|
||||||
|
pathSelected Boolean @default(false)
|
||||||
settingsNtfyRoom String? @map(name: "settings_ntfy_room")
|
settingsNtfyRoom String? @map(name: "settings_ntfy_room")
|
||||||
settingsMicDevice String? @map(name: "settings_mic_device")
|
settingsMicDevice String? @map(name: "settings_mic_device")
|
||||||
settingsMicVolume Float? @map(name: "settings_mic_volume")
|
settingsMicVolume Float? @map(name: "settings_mic_volume")
|
||||||
|
|||||||
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
@@ -342,7 +342,7 @@ importers:
|
|||||||
specifier: ^4.1.8
|
specifier: ^4.1.8
|
||||||
version: 4.1.8
|
version: 4.1.8
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: ^5.79.0
|
specifier: ^5.79.2
|
||||||
version: 5.79.2(react@19.1.0)
|
version: 5.79.2(react@19.1.0)
|
||||||
'@tanstack/react-table':
|
'@tanstack/react-table':
|
||||||
specifier: ^8.21.3
|
specifier: ^8.21.3
|
||||||
|
|||||||
Reference in New Issue
Block a user