added basic data for event list, md editor and viewer

This commit is contained in:
PxlLoewe
2025-02-23 23:02:29 +01:00
parent 11d3e71b7a
commit c5b8a7c4cb
9 changed files with 5797 additions and 100 deletions

View File

@@ -22,6 +22,7 @@ import {
} from '../../../../_components/PaginatedTable'; } from '../../../../_components/PaginatedTable';
import { Select } from '../../../../_components/ui/Select'; import { Select } from '../../../../_components/ui/Select';
import { useSession } from 'next-auth/react'; import { useSession } from 'next-auth/react';
import { MarkdownEditor } from '../../../../_components/ui/MDEditor';
export const Form = ({ export const Form = ({
event, event,
@@ -107,12 +108,7 @@ export const Form = ({
<FileText className="w-5 h-5" /> Allgemeines <FileText className="w-5 h-5" /> Allgemeines
</h2> </h2>
<Input form={form} label="Name" name="name" className="input-sm" /> <Input form={form} label="Name" name="name" className="input-sm" />
<Input <MarkdownEditor form={form} name="description" />
form={form}
label="Beschreibung"
name="description"
className="input-sm"
/>
<Input <Input
form={form} form={form}
label="Maximale Teilnehmer (Nur für live Events)" label="Maximale Teilnehmer (Nur für live Events)"
@@ -174,12 +170,14 @@ export const Form = ({
<h2 className="card-title"> <h2 className="card-title">
<Calendar className="w-5 h-5" /> Termine <Calendar className="w-5 h-5" /> Termine
</h2> </h2>
{event && (
<button <button
className="btn btn-primary btn-outline" className="btn btn-primary btn-outline"
onClick={() => addParticipantModal.current?.showModal()} onClick={() => addParticipantModal.current?.showModal()}
> >
Hinzufügen Hinzufügen
</button> </button>
)}
</div> </div>
<PaginatedTable <PaginatedTable
@@ -233,6 +231,7 @@ export const Form = ({
type="button" type="button"
onClick={() => { onClick={() => {
console.log(row.original); console.log(row.original);
// TODO: open modal to edit appointment
}} }}
className="btn btn-sm btn-outline" className="btn btn-sm btn-outline"
> >

View File

@@ -1,28 +1,15 @@
"use client"; 'use client';
import { DrawingPinFilledIcon, EnterIcon } from "@radix-ui/react-icons"; import { DrawingPinFilledIcon, EnterIcon } from '@radix-ui/react-icons';
import { User } from "@repo/db"; import { Event, User } from '@repo/db';
import ModalBtn from "./modalBtn"; import ModalBtn from './modalBtn';
import MDEditor from '@uiw/react-md-editor';
export const KursItem = ({ export const KursItem = ({ user, event }: { user: User; event: Event }) => {
user,
title,
type,
beschreibung,
badge,
moodleReq,
}: {
user: User;
title: string;
type: string;
beschreibung: string;
badge: string;
moodleReq: boolean;
}) => {
return ( return (
<div className="col-span-full"> <div className="col-span-full">
<div className="card bg-base-200 shadow-xl mb-4"> <div className="card bg-base-200 shadow-xl mb-4">
<div className="card-body"> <div className="card-body">
<h2 className="card-title">{title}</h2> <h2 className="card-title">{event.name}</h2>
<div className="absolute top-0 right-0 m-4"> <div className="absolute top-0 right-0 m-4">
<span className="badge badge-info badge-outline"> <span className="badge badge-info badge-outline">
Zusatzqualifikation Zusatzqualifikation
@@ -30,21 +17,48 @@ export const KursItem = ({
</div> </div>
<div className="grid grid-cols-6 gap-4"> <div className="grid grid-cols-6 gap-4">
<div className="col-span-4"> <div className="col-span-4">
<p className="text-left text-balance">{beschreibung}</p> <div className="text-left text-balance">
<MDEditor.Markdown
source={event.description}
className="whitespace-pre-wrap"
style={{
backgroundColor: 'transparent',
}}
/>
</div> </div>
<div className="col-span-2">{badge}</div> </div>
<div className="col-span-2">{event.finishedBadges}</div>
</div> </div>
<div className="card-actions flex justify-between items-center mt-5"> <div className="card-actions flex justify-between items-center mt-5">
<div>
<p className="text-gray-600 text-left flex items-center gap-2"> <p className="text-gray-600 text-left flex items-center gap-2">
<DrawingPinFilledIcon /> <b>Teilnahmevoraussetzungen: </b> <DrawingPinFilledIcon /> <b>Teilnahmevoraussetzungen: </b>
{(!event.starterMoodleCourseId ||
!event.requiredBadges.length) &&
'Keine'}
{event.starterMoodleCourseId && (
<a className="link link-info" href=""> <a className="link link-info" href="">
Moodle Kurs /MOODLEKURSTITLE\ Moodle Kurs {event.starterMoodleCourseId}
</a> </a>
)}
</p> </p>
{!!event.requiredBadges.length && (
<div className="flex ml-6">
<b className="text-gray-600 text-left">Abzeichen:</b>
<div className="flex gap-2">
{event.requiredBadges.map((badge) => (
<div className="badge badge-secondary badge-outline">
{badge}
</div>
))}
</div>
</div>
)}
</div>
<ModalBtn <ModalBtn
title={title} title={event.name}
dates={["Dienstag, 25 Februar 2025", "Mittwoch, 26 Februar 2025"]} dates={['Dienstag, 25 Februar 2025', 'Mittwoch, 26 Februar 2025']}
modalId={title + "_modal" + Math.random()} modalId={`${event.name}_modal.${event.id}`}
/> />
</div> </div>
</div> </div>

View File

@@ -1,22 +1,16 @@
import { getServerSession } from "../../api/auth/[...nextauth]/auth"; import { getServerSession } from '../../api/auth/[...nextauth]/auth';
import { PrismaClient } from "@repo/db"; import { PrismaClient } from '@repo/db';
import { PilotKurs, KursItem } from "./_components/item"; import { PilotKurs, KursItem } from './_components/item';
import { import { RocketIcon } from '@radix-ui/react-icons';
RocketIcon,
DrawingPinFilledIcon,
EnterIcon,
} from "@radix-ui/react-icons";
export default async () => { export default async () => {
const prisma = new PrismaClient(); const prisma = new PrismaClient();
const session = await getServerSession(); const session = await getServerSession();
if (!session) return null; if (!session) return null;
const user = await prisma.user.findFirst({ const user = session.user;
where: { const events = await prisma.event.findMany();
id: session.user.id,
},
});
if (!user) return null; if (!user) return null;
return ( return (
<div className="grid grid-cols-6 gap-4"> <div className="grid grid-cols-6 gap-4">
<div className="col-span-full"> <div className="col-span-full">
@@ -25,21 +19,9 @@ export default async () => {
</p> </p>
</div> </div>
<PilotKurs user={user} /> <PilotKurs user={user} />
<KursItem {events.map((event) => (
user={user} <KursItem user={user} event={event} key={event.id} />
title="Einsteigerkurs für Disponenten" ))}
type="1"
beschreibung="In diesem Kurs lernen Teilnehmer die Aufgaben eines
Disponenten in der Rettungsfliegerei kennen. Dazu gehören die
Koordination von Notfalleinsätzen, die effiziente Planung von
Ressourcen und die Kommunikation mit Piloten sowie
Rettungsdiensten. Der Kurs vermittelt praxisnahe Kenntnisse
für die schnelle und präzise Entscheidungsfindung unter
Zeitdruck, um eine reibungslose Abwicklung von
Rettungseinsätzen zu gewährleisten."
badge="Badge"
moodleReq={true}
/>
</div> </div>
); );
}; };

View File

@@ -90,9 +90,9 @@ export function PaginatedTable<TData>({
return ( return (
<div className="space-y-4 m-4"> <div className="space-y-4 m-4">
{searchFields.length > 0 && (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="flex-1">{leftOfSearch}</div> <div className="flex-1">{leftOfSearch}</div>
{searchFields.length > 0 && (
<input <input
type="text" type="text"
placeholder="Suchen..." placeholder="Suchen..."
@@ -103,9 +103,9 @@ export function PaginatedTable<TData>({
}} }}
className="input input-bordered w-full max-w-xs justify-end" className="input input-bordered w-full max-w-xs justify-end"
/> />
)}
<div className="flex justify-center">{rightOfSearch}</div> <div className="flex justify-center">{rightOfSearch}</div>
</div> </div>
)}
<SortableTable <SortableTable
data={data} data={data}
prismaModel={prismaModel} prismaModel={prismaModel}

View File

@@ -0,0 +1,46 @@
'use client';
import MDEditor from '@uiw/react-md-editor';
import {
FieldValues,
Path,
RegisterOptions,
UseFormReturn,
} from 'react-hook-form';
import { cn } from '../../../helper/cn';
interface MarkdownEditorProps<T extends FieldValues> {
name: Path<T>;
form: UseFormReturn<T>;
formOptions?: RegisterOptions<T>;
label?: string;
placeholder?: string;
className?: string;
}
export const MarkdownEditor = <T extends FieldValues>({
name,
label = name,
placeholder = label,
form,
className,
}: MarkdownEditorProps<T>) => {
return (
<label className="floating-label w-full mt-5">
<span className="text-lg flex items-center gap-2">{label}</span>
<div className={cn('border rounded-lg p-2 w-full', className)}>
<MDEditor
value={form.watch(name)}
onChange={(value) =>
form.setValue(name, value as any, { shouldValidate: true })
}
textareaProps={{ placeholder }}
/>
</div>
{form.formState.errors[name] && (
<p className="text-error">
{form.formState.errors[name].message as string}
</p>
)}
</label>
);
};

View File

@@ -24,8 +24,10 @@ export const Switch = <T extends FieldValues>({
}: InputProps<T>) => { }: InputProps<T>) => {
return ( return (
<div className="form-control "> <div className="form-control ">
<label className="label cursor-pointer"> <label className="label cursor-pointer w-full">
<span className={cn('label-text', className)}>{label}</span> <span className={cn('label-text text-left w-full', className)}>
{label}
</span>
<input type="checkbox" className="toggle" {...form.register(name)} /> <input type="checkbox" className="toggle" {...form.register(name)} />
</label> </label>
</div> </div>

View File

@@ -1,4 +1,5 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = {}; const removeImports = require('next-remove-imports')();
const nextConfig = removeImports({});
export default nextConfig; export default nextConfig;

View File

@@ -14,14 +14,18 @@
"@repo/db": "*", "@repo/db": "*",
"@repo/ui": "*", "@repo/ui": "*",
"@tanstack/react-table": "^8.20.6", "@tanstack/react-table": "^8.20.6",
"@uiw/react-md-editor": "^4.0.5",
"axios": "^1.7.9", "axios": "^1.7.9",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"i": "^0.3.7",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lucide-react": "^0.474.0", "lucide-react": "^0.474.0",
"next": "15.1.4", "next": "15.1.4",
"next-auth": "^4.24.11", "next-auth": "^4.24.11",
"next-remove-imports": "^1.0.12",
"npm": "^11.1.0",
"react": "^19.0.0", "react": "^19.0.0",
"react-day-picker": "^9.5.1", "react-day-picker": "^9.5.1",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",

5687
package-lock.json generated

File diff suppressed because it is too large Load Diff