typos und link zu adminuser in event tabelle

This commit is contained in:
PxlLoewe
2025-07-22 19:31:21 -07:00
parent 414e238216
commit f12db76f48
3 changed files with 106 additions and 68 deletions

View File

@@ -25,6 +25,7 @@ import { AppointmentModal } from "./AppointmentModal";
import { ParticipantModal } from "./ParticipantModal"; import { ParticipantModal } from "./ParticipantModal";
import { ColumnDef } from "@tanstack/react-table"; import { ColumnDef } from "@tanstack/react-table";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import Link from "next/link";
export const Form = ({ event }: { event?: Event }) => { export const Form = ({ event }: { event?: Event }) => {
const { data: session } = useSession(); const { data: session } = useSession();
@@ -72,10 +73,10 @@ export const Form = ({ event }: { event?: Event }) => {
})} })}
className="grid grid-cols-6 gap-3" className="grid grid-cols-6 gap-3"
> >
<div className="card bg-base-200 shadow-xl col-span-3 max-xl:col-span-6"> <div className="card bg-base-200 col-span-3 shadow-xl max-xl:col-span-6">
<div className="card-body"> <div className="card-body">
<h2 className="card-title"> <h2 className="card-title">
<FileText className="w-5 h-5" /> Allgemeines <FileText className="h-5 w-5" /> Allgemeines
</h2> </h2>
<Select <Select
form={form} form={form}
@@ -91,10 +92,10 @@ export const Form = ({ event }: { event?: Event }) => {
<MarkdownEditor form={form} name="descriptionShort" /> <MarkdownEditor form={form} name="descriptionShort" />
</div> </div>
</div> </div>
<div className="card bg-base-200 shadow-xl col-span-3 max-xl:col-span-6"> <div className="card bg-base-200 col-span-3 shadow-xl max-xl:col-span-6">
<div className="card-body"> <div className="card-body">
<h2 className="card-title"> <h2 className="card-title">
<Bot className="w-5 h-5" /> Automation <Bot className="h-5 w-5" /> Automation
</h2> </h2>
<Input <Input
name="finisherMoodleCourseId" name="finisherMoodleCourseId"
@@ -153,7 +154,7 @@ export const Form = ({ event }: { event?: Event }) => {
</div> </div>
</div> </div>
{form.watch("hasPresenceEvents") ? ( {form.watch("hasPresenceEvents") ? (
<div className="card bg-base-200 shadow-xl col-span-6"> <div className="card bg-base-200 col-span-6 shadow-xl">
<div className="card-body"> <div className="card-body">
<PaginatedTable <PaginatedTable
ref={appointmentsTableRef} ref={appointmentsTableRef}
@@ -167,7 +168,7 @@ export const Form = ({ event }: { event?: Event }) => {
}} }}
leftOfSearch={ leftOfSearch={
<h2 className="card-title"> <h2 className="card-title">
<Calendar className="w-5 h-5" /> Termine <Calendar className="h-5 w-5" /> Termine
</h2> </h2>
} }
rightOfSearch={ rightOfSearch={
@@ -210,7 +211,7 @@ export const Form = ({ event }: { event?: Event }) => {
accessorKey: "Participants", accessorKey: "Participants",
cell: ({ row }) => ( cell: ({ row }) => (
<div className="flex items-center"> <div className="flex items-center">
<UserIcon className="w-5 h-5" /> <UserIcon className="h-5 w-5" />
<span className="ml-2">{row.original.Participants.length}</span> <span className="ml-2">{row.original.Participants.length}</span>
</div> </div>
), ),
@@ -247,12 +248,12 @@ export const Form = ({ event }: { event?: Event }) => {
</div> </div>
) : null} ) : null}
{!form.watch("hasPresenceEvents") ? ( {!form.watch("hasPresenceEvents") ? (
<div className="card bg-base-200 shadow-xl col-span-6"> <div className="card bg-base-200 col-span-6 shadow-xl">
<div className="card-body"> <div className="card-body">
<PaginatedTable <PaginatedTable
leftOfSearch={ leftOfSearch={
<h2 className="card-title"> <h2 className="card-title">
<Calendar className="w-5 h-5" /> Teilnehmer <Calendar className="h-5 w-5" /> Teilnehmer
</h2> </h2>
} }
searchFields={["User.firstname", "User.lastname"]} searchFields={["User.firstname", "User.lastname"]}
@@ -264,46 +265,82 @@ export const Form = ({ event }: { event?: Event }) => {
include={{ include={{
User: true, User: true,
}} }}
columns={[ columns={
{ [
header: "Vorname", {
accessorKey: "User.firstname", header: "Vorname",
}, accessorKey: "User.firstname",
{ cell: ({ row }) => {
header: "Nachname", return (
accessorKey: "User.lastname", <Link
}, className="hover:underline"
{ href={`/admin/user/${row.original.User.id}`}
header: "Moodle Kurs abgeschlossen",
accessorKey: "finisherMoodleCurseCompleted",
},
{
header: "Aktionen",
cell: ({ row }) => {
return (
<div className="flex gap-2">
<button
onSubmit={() => false}
type="button"
onClick={() => {
participantForm.reset(row.original);
participantModal.current?.showModal();
}}
className="btn btn-sm btn-outline"
> >
Bearbeiten {row.original.User.firstname}
</button> </Link>
</div> );
); },
}, },
}, {
]} header: "Nachname",
accessorKey: "User.lastname",
cell: ({ row }) => {
return (
<Link
className="hover:underline"
href={`/admin/user/${row.original.User.id}`}
>
{row.original.User.lastname}
</Link>
);
},
},
{
header: "VAR-Nummer",
accessorKey: "User.publicId",
cell: ({ row }) => {
return (
<Link
className="hover:underline"
href={`/admin/user/${row.original.User.id}`}
>
{row.original.User.publicId}
</Link>
);
},
},
{
header: "Moodle Kurs abgeschlossen",
accessorKey: "finisherMoodleCurseCompleted",
},
{
header: "Aktionen",
cell: ({ row }) => {
return (
<div className="flex gap-2">
<button
onSubmit={() => false}
type="button"
onClick={() => {
participantForm.reset(row.original);
participantModal.current?.showModal();
}}
className="btn btn-sm btn-outline"
>
Bearbeiten
</button>
</div>
);
},
},
] as ColumnDef<Participant & { User: User }>[]
}
/> />
</div> </div>
</div> </div>
) : null} ) : null}
<div className="card bg-base-200 shadow-xl col-span-6"> <div className="card bg-base-200 col-span-6 shadow-xl">
<div className="card-body "> <div className="card-body">
<div className="flex w-full gap-4"> <div className="flex w-full gap-4">
<Button <Button
isLoading={form.formState.isSubmitting} isLoading={form.formState.isSubmitting}

View File

@@ -148,13 +148,13 @@ const ModalBtn = ({
<form method="dialog"> <form method="dialog">
<button className="btn btn-sm btn-circle btn-ghost absolute right-3 top-3"></button> <button className="btn btn-sm btn-circle btn-ghost absolute right-3 top-3"></button>
</form> </form>
<h3 className="font-bold text-lg text-left">{title}</h3> <h3 className="text-left text-lg font-bold">{title}</h3>
<div className="flex flex-wrap gap-4 mt-4"> <div className="mt-4 flex flex-wrap gap-4">
<div className="flex flex-col gap-2 flex-1 p-3 bg-base-300 min-w-[300px] shadow rounded-lg"> <div className="bg-base-300 flex min-w-[300px] flex-1 flex-col gap-2 rounded-lg p-3 shadow">
<h2 className="flex gap-2 text-lg font-bold"> <h2 className="flex gap-2 text-lg font-bold">
<Info /> Details <Info /> Details
</h2> </h2>
<div className="text-left text-balance"> <div className="text-balance text-left">
<MDEditor.Markdown <MDEditor.Markdown
source={event.description} source={event.description}
style={{ style={{
@@ -164,14 +164,14 @@ const ModalBtn = ({
</div> </div>
</div> </div>
{event.hasPresenceEvents && ( {event.hasPresenceEvents && (
<div className="flex flex-col gap-2 flex-1 p-3 bg-base-300 min-w-[300px] shadow rounded-lg"> <div className="bg-base-300 flex min-w-[300px] flex-1 flex-col gap-2 rounded-lg p-3 shadow">
<h2 className="flex gap-2 text-lg font-bold"> <h2 className="flex gap-2 text-lg font-bold">
<Calendar /> Termine <Calendar /> Termine
</h2> </h2>
<div className="flex flex-1 flex-col justify-center items-center"> <div className="flex flex-1 flex-col items-center justify-center">
{!!dates.length && !selectedDate && ( {!!dates.length && !selectedDate && (
<> <>
<p className="text-center text-info">Melde dich zu einem Termin an</p> <p className="text-info text-center">Melde dich zu einem Termin an</p>
<Select <Select
form={selectAppointmentForm} form={selectAppointmentForm}
options={dates.map((date) => ({ options={dates.map((date) => ({
@@ -190,7 +190,7 @@ const ModalBtn = ({
<span>Dein ausgewählter Termin (Deutsche Zeit)</span> <span>Dein ausgewählter Termin (Deutsche Zeit)</span>
<div> <div>
<button <button
className="input input-border min-w-[250px] pointer-events-none" className="input input-border pointer-events-none min-w-[250px]"
style={{ anchorName: "--rdp" } as React.CSSProperties} style={{ anchorName: "--rdp" } as React.CSSProperties}
> >
{new Date(selectedAppointment.appointmentDate).toLocaleString("de-DE", { {new Date(selectedAppointment.appointmentDate).toLocaleString("de-DE", {
@@ -203,12 +203,12 @@ const ModalBtn = ({
</button> </button>
</div> </div>
{participant?.attended ? ( {participant?.attended ? (
<p className="py-4 flex items-center gap-2 justify-center"> <p className="flex items-center justify-center gap-2 py-4">
<CheckCircledIcon className="text-success" /> <CheckCircledIcon className="text-success" />
Du hast an dem Presenztermin teilgenommen Du hast an dem Presenztermin teilgenommen
</p> </p>
) : ( ) : (
<p className="py-4 flex items-center gap-2 justify-center"> <p className="flex items-center justify-center gap-2 py-4">
Bitte erscheine ~5 minuten vor dem Termin im Discord Bitte erscheine ~5 minuten vor dem Termin im Discord
</p> </p>
)} )}
@@ -216,7 +216,7 @@ const ModalBtn = ({
)} )}
{!dates.length && ( {!dates.length && (
<p className="text-center text-error">Aktuell sind keine Termine verfügbar</p> <p className="text-error text-center">Aktuell sind keine Termine verfügbar</p>
)} )}
{!!selectedDate && {!!selectedDate &&
@@ -225,7 +225,7 @@ const ModalBtn = ({
!!(ownPlaceInParticipantList > event.maxParticipants) && ( !!(ownPlaceInParticipantList > event.maxParticipants) && (
<p <p
role="alert" role="alert"
className="py-4 my-5 flex items-center gap-2 justify-center border alert alert-error alert-outline" className="alert alert-error alert-outline my-5 flex items-center justify-center gap-2 border py-4"
> >
<TriangleAlert className="h-6 w-6 shrink-0 stroke-current" fill="none" /> <TriangleAlert className="h-6 w-6 shrink-0 stroke-current" fill="none" />
Dieser Termin ist ausgebucht, wahrscheinlich wirst du nicht teilnehmen Dieser Termin ist ausgebucht, wahrscheinlich wirst du nicht teilnehmen
@@ -237,11 +237,11 @@ const ModalBtn = ({
</div> </div>
)} )}
{event.finisherMoodleCourseId && ( {event.finisherMoodleCourseId && (
<div className="flex flex-col gap-2 flex-1 p-3 bg-base-300 min-w-[300px] shadow rounded-lg"> <div className="bg-base-300 flex min-w-[300px] flex-1 flex-col gap-2 rounded-lg p-3 shadow">
<h2 className="flex gap-2 text-lg font-bold"> <h2 className="flex gap-2 text-lg font-bold">
<BookCheck /> Moodle-Kurs <BookCheck /> Moodle-Kurs
</h2> </h2>
<div className="flex flex-col items-center justify-center h-full"> <div className="flex h-full flex-col items-center justify-center">
<MoodleCourseIndicator <MoodleCourseIndicator
participant={participant} participant={participant}
user={user} user={user}
@@ -254,9 +254,9 @@ const ModalBtn = ({
)} )}
</div> </div>
<div className="flex justify-between items-end mt-5"> <div className="mt-5 flex items-end justify-between">
<div> <div>
<p className="text-gray-600 text-left flex items-center gap-2"> <p className="flex items-center gap-2 text-left text-gray-600">
<DrawingPinFilledIcon /> <b>Teilnahmevoraussetzungen: </b> <DrawingPinFilledIcon /> <b>Teilnahmevoraussetzungen: </b>
{!event.requiredBadges.length && "Keine"} {!event.requiredBadges.length && "Keine"}
</p> </p>
@@ -347,23 +347,27 @@ const MoodleCourseIndicator = ({
const courseUrl = `${process.env.NEXT_PUBLIC_MOODLE_URL}/course/view.php?id=${moodleCourseId}`; const courseUrl = `${process.env.NEXT_PUBLIC_MOODLE_URL}/course/view.php?id=${moodleCourseId}`;
if (event.hasPresenceEvents && !participant?.attended) if (event.hasPresenceEvents && !participant?.attended)
return ( return (
<p className="py-4 flex items-center gap-2 justify-center"> <p className="flex items-center justify-center gap-2 py-4">
<Clock10Icon className="text-error" /> <Clock10Icon className="text-error" />
Abschlusstest erst nach Teilnahme verfügbar Abschlusstest erst nach Teilnahme verfügbar
</p> </p>
); );
if (completed) if (completed)
return ( return (
<p className="py-4 flex items-center gap-2 justify-center"> <p className="flex items-center justify-center gap-2 py-4">
<CheckCircledIcon className="text-success" /> <CheckCircledIcon className="text-success" />
Moodle Kurs abgeschlossen Moodle Kurs abgeschlossen
</p> </p>
); );
return ( return (
<div className="flex flex-col items-center justify-center gap-2"> <div className="flex flex-col items-center justify-center gap-2">
<p className="text-sm flex items-center gap-2"> <p className="flex items-center gap-2 text-sm">
<CirclePlay className="text-warning" /> Moodle-Kurs bereit <CirclePlay className="text-warning" /> Moodle-Kurs bereit
</p> </p>
<p className="font-bold text-gray-400">
Wenn du nach dem Anmelden den moodle Kurs nicht siehst, warte ein paar Sekunden und lade die
Seite neu.
</p>
<button <button
className="btn btn-sm btn-outline btn-info ml-2" className="btn btn-sm btn-outline btn-info ml-2"
onClick={async () => { onClick={async () => {
@@ -386,10 +390,6 @@ const MoodleCourseIndicator = ({
<ExternalLink size={16} /> <ExternalLink size={16} />
Zum Moodle Kurs Zum Moodle Kurs
</button> </button>
<p className="text-xs text-gray-400">
Wenn du nach dem Anmelden den moodle Kurs nicht siehst, warte ein paar Sekunden und lade die
Seite neu.
</p>
</div> </div>
); );
}; };

View File

@@ -13,7 +13,8 @@ export default function () {
BtnIcon={<DiscordLogoIcon />} BtnIcon={<DiscordLogoIcon />}
btnHref="https://discord.com/invite/x6FAMY7DW6" btnHref="https://discord.com/invite/x6FAMY7DW6"
btnLabel="Beitreten" btnLabel="Beitreten"
description="Tritt unserem Discord-Server bei, um mit der Community in Kontakt zu bleiben, Unterstützung zu erhalten und über die neuesten Updates informiert zu werden. Wenn du beigetreten bist, kannst du in deinen Einstellungen dein VAR-Konto mit deinem Discord-Konto verknüpfen und eine Rolle erhalten." description="Tritt unserem Discordserver bei, um mit der Community in Kontakt zu bleiben, Unterstützung zu erhalten und über die neuesten Updates informiert zu werden. Wenn du beigetreten bist kannst du in deinen Einstellungen dein VAR-Konto mit deinem Discordkonto verknüpfen und eine Rolle zu erhalten.
"
/> />
<ResourceCard <ResourceCard
image={Desktop} image={Desktop}
@@ -21,7 +22,7 @@ export default function () {
BtnIcon={<Download />} BtnIcon={<Download />}
btnHref="https://cdn.virtualairrescue.com/desktop/setup.exe" btnHref="https://cdn.virtualairrescue.com/desktop/setup.exe"
btnLabel="Herunterladen" btnLabel="Herunterladen"
description="Verwende diesen Client, um dich mit dem VAR-Netzwerk zu verbinden. Wenn du dich verbindest, kannst du einen Push-To-Talk Key setzen, um den Funk zu bedienen. Wenn du als Pilot fliegen möchtest, wird deine Position aus dem Simulator an unser Tracker-System übertragen." description="Verwende diesen Client, um dich mit dem VAR-Netzwerk zu verbinden. Wenn du dich verbindest, kannst du einen Push-To-Talk-Key setzen, um den Funk zu bedienen. Wenn du als Pilot fliegen möchtest, wird deine Position aus dem Simulator an unser Tracker-System übertragen."
/> />
</div> </div>
); );