From 30af30bd1d673d42e7329bccd73ddfc46e79fa97 Mon Sep 17 00:00:00 2001 From: PxlLoewe <72106766+PxlLoewe@users.noreply.github.com> Date: Mon, 17 Feb 2025 10:39:29 +0100 Subject: [PATCH] continue Event page --- apps/hub/app/(app)/admin/event/[id]/page.tsx | 8 +- .../(app)/admin/event/_components/Form.tsx | 226 ++++-------------- apps/hub/app/(app)/admin/event/action.ts | 22 +- apps/hub/app/(app)/admin/event/new/page.tsx | 4 +- apps/hub/app/(app)/admin/event/page.tsx | 24 +- apps/hub/app/_components/PaginatedTable.tsx | 25 +- .../app/_components/pagiantedTableActions.ts | 12 +- apps/hub/app/_components/ui/Nav.tsx | 7 +- apps/hub/app/_components/ui/Switch.tsx | 33 +++ .../20250217083328_events/migration.sql | 46 ++++ .../migration.sql | 14 ++ packages/database/prisma/schema/event.prisma | 47 ++++ packages/database/prisma/schema/user.prisma | 1 + 13 files changed, 242 insertions(+), 227 deletions(-) create mode 100644 apps/hub/app/_components/ui/Switch.tsx create mode 100644 packages/database/prisma/migrations/20250217083328_events/migration.sql create mode 100644 packages/database/prisma/migrations/20250217093027_event_participants/migration.sql diff --git a/apps/hub/app/(app)/admin/event/[id]/page.tsx b/apps/hub/app/(app)/admin/event/[id]/page.tsx index 399adf90..9188846c 100644 --- a/apps/hub/app/(app)/admin/event/[id]/page.tsx +++ b/apps/hub/app/(app)/admin/event/[id]/page.tsx @@ -1,13 +1,13 @@ import { prisma } from '@repo/db'; -import { StationForm } from '../_components/Form'; +import { Form } from '../_components/Form'; export default async ({ params }: { params: Promise<{ id: string }> }) => { const { id } = await params; - const station = await prisma.station.findUnique({ + const event = await prisma.event.findUnique({ where: { id: parseInt(id), }, }); - if (!station) return
Station not found
; - return ; + if (!event) return
Event not found
; + return
; }; diff --git a/apps/hub/app/(app)/admin/event/_components/Form.tsx b/apps/hub/app/(app)/admin/event/_components/Form.tsx index c8bfe068..47bae6f4 100644 --- a/apps/hub/app/(app)/admin/event/_components/Form.tsx +++ b/apps/hub/app/(app)/admin/event/_components/Form.tsx @@ -1,20 +1,22 @@ 'use client'; import { zodResolver } from '@hookform/resolvers/zod'; -import { StationOptionalDefaultsSchema } from '@repo/db/zod'; +import { EventOptionalDefaultsSchema } from '@repo/db/zod'; import { set, useForm } from 'react-hook-form'; import { z } from 'zod'; -import { BosUse, Country, Station } from '@repo/db'; -import { FileText, LocateIcon, PlaneIcon } from 'lucide-react'; +import { BosUse, Country, Event, prisma } from '@repo/db'; +import { FileText, LocateIcon, PlaneIcon, UserIcon } from 'lucide-react'; import { Input } from '../../../../_components/ui/Input'; import { useState } from 'react'; -import { deleteStation, upsertStation } from '../action'; +import { deleteEvent, upsertEvent } from '../action'; import { Button } from '../../../../_components/ui/Button'; import { redirect } from 'next/navigation'; +import { Switch } from '../../../../_components/ui/Switch'; +import { PaginatedTable } from '../../../../_components/PaginatedTable'; -export const StationForm = ({ station }: { station?: Station }) => { - const form = useForm>({ - resolver: zodResolver(StationOptionalDefaultsSchema), - defaultValues: station, +export const Form = ({ event }: { event?: Event }) => { + const form = useForm>({ + resolver: zodResolver(EventOptionalDefaultsSchema), + defaultValues: event, }); const [loading, setLoading] = useState(false); const [deleteLoading, setDeleteLoading] = useState(false); @@ -24,9 +26,9 @@ export const StationForm = ({ station }: { station?: Station }) => { { setLoading(true); - const createdStation = await upsertStation(values, station?.id); + const createdEvent = await upsertEvent(values, event?.id); setLoading(false); - if (!station) redirect(`/admin/station`); + if (!event) redirect(`/admin/event`); })} className="grid grid-cols-6 gap-3" > @@ -35,182 +37,50 @@ export const StationForm = ({ station }: { station?: Station }) => {

Allgemeines

+ - - - - - - - +

- Standort + Ausrüstung + Teilnehmer

- - - - - Ausgerüstet mit: - -
- - - - -
- - - -
-
-
-
-

- Hubschrauber -

- - -
@@ -224,13 +94,13 @@ export const StationForm = ({ station }: { station?: Station }) => { > Speichern - {station && ( + {event && ( @@ -17,23 +17,15 @@ export default () => {

diff --git a/apps/hub/app/_components/PaginatedTable.tsx b/apps/hub/app/_components/PaginatedTable.tsx index 4e509f62..b4edf55a 100644 --- a/apps/hub/app/_components/PaginatedTable.tsx +++ b/apps/hub/app/_components/PaginatedTable.tsx @@ -1,28 +1,32 @@ -"use client"; -import { useEffect, useState, useCallback } from "react"; -import SortableTable, { Pagination, SortableTableProps } from "./Table"; -import { PrismaClient } from "@repo/db"; -import { getData } from "./pagiantedTableActions"; +'use client'; +import { useEffect, useState, useCallback } from 'react'; +import SortableTable, { Pagination, SortableTableProps } from './Table'; +import { PrismaClient } from '@repo/db'; +import { getData } from './pagiantedTableActions'; interface PaginatedTableProps - extends Omit, "data"> { + extends Omit, 'data'> { prismaModel: keyof PrismaClient; + filter?: Record; rowsPerPage?: number; showEditButton?: boolean; - searchFields: string[]; + searchFields?: string[]; + include?: Record[]; } export function PaginatedTable({ prismaModel, rowsPerPage = 10, showEditButton = false, - searchFields, + searchFields = [], + filter, + include, ...restProps }: PaginatedTableProps) { const [data, setData] = useState([]); const [page, setPage] = useState(0); const [total, setTotal] = useState(0); - const [searchTerm, setSearchTerm] = useState(""); + const [searchTerm, setSearchTerm] = useState(''); const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(searchTerm); const debounce = (func: Function, delay: number) => { @@ -46,7 +50,8 @@ export function PaginatedTable({ rowsPerPage, page * rowsPerPage, debouncedSearchTerm, - searchFields + searchFields, + filter ).then((result) => { if (result) { setData(result.data); diff --git a/apps/hub/app/_components/pagiantedTableActions.ts b/apps/hub/app/_components/pagiantedTableActions.ts index 9845a74d..52940cbc 100644 --- a/apps/hub/app/_components/pagiantedTableActions.ts +++ b/apps/hub/app/_components/pagiantedTableActions.ts @@ -1,5 +1,5 @@ -"use server"; -import { PrismaClient } from "@repo/db"; +'use server'; +import { PrismaClient } from '@repo/db'; const prisma = new PrismaClient(); @@ -8,7 +8,9 @@ export async function getData( limit: number, offset: number, searchTerm: string, - searchFields: string[] + searchFields: string[], + filter?: Record, + include?: Record[] ) { if (!model || !prisma[model]) { return { data: [], total: 0 }; @@ -24,8 +26,9 @@ export async function getData( [field]: { contains: searchTerm }, })), ].filter(Boolean), + ...filter, } - : {}; + : { ...filter }; if (!prisma[model]) { return { data: [], total: 0 }; @@ -35,6 +38,7 @@ export async function getData( where, take: limit, skip: offset, + include, }); const total = await (prisma[model] as any).count({ where }); diff --git a/apps/hub/app/_components/ui/Nav.tsx b/apps/hub/app/_components/ui/Nav.tsx index 47d6475f..ec65321c 100644 --- a/apps/hub/app/_components/ui/Nav.tsx +++ b/apps/hub/app/_components/ui/Nav.tsx @@ -4,8 +4,8 @@ import { GearIcon, ExitIcon, LockClosedIcon, -} from "@radix-ui/react-icons"; -import Link from "next/link"; +} from '@radix-ui/react-icons'; +import Link from 'next/link'; export const VerticalNav = () => { return ( @@ -34,6 +34,9 @@ export const VerticalNav = () => {
  • Stationen
  • +
  • + Events +
  • diff --git a/apps/hub/app/_components/ui/Switch.tsx b/apps/hub/app/_components/ui/Switch.tsx new file mode 100644 index 00000000..23532f33 --- /dev/null +++ b/apps/hub/app/_components/ui/Switch.tsx @@ -0,0 +1,33 @@ +import { + FieldValues, + Path, + RegisterOptions, + UseFormReturn, +} from 'react-hook-form'; +import { cn } from '../../../helper/cn'; + +interface InputProps + extends Omit, 'form'> { + name: Path; + form: UseFormReturn; + formOptions?: RegisterOptions; + label?: string; +} + +export const Switch = ({ + name, + label = name, + form, + formOptions, + className, + ...inputProps +}: InputProps) => { + return ( +
    + +
    + ); +}; diff --git a/packages/database/prisma/migrations/20250217083328_events/migration.sql b/packages/database/prisma/migrations/20250217083328_events/migration.sql new file mode 100644 index 00000000..77918e71 --- /dev/null +++ b/packages/database/prisma/migrations/20250217083328_events/migration.sql @@ -0,0 +1,46 @@ +-- CreateEnum +CREATE TYPE "PARTICIPANT_STATUS" AS ENUM ('WAITING_FOR_ENTRY_TEST', 'ENTRY_TEST_FAILED', 'READY_FOR_EVENT', 'PARTICIPATED', 'WAITING_FOR_EXIT_TEST', 'EXIT_TEST_FAILED', 'WAITING_FOR_PERMISISONS', 'FINISHED', 'WAVED'); + +-- CreateTable +CREATE TABLE "Participant" ( + "id" SERIAL NOT NULL, + "user_id" TEXT NOT NULL, + "status" "PARTICIPANT_STATUS" NOT NULL, + "selectedForParticipatioon" BOOLEAN NOT NULL DEFAULT false, + "statusLog" JSONB[], + "eventId" INTEGER, + + CONSTRAINT "Participant_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Event" ( + "id" SERIAL NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "discordRoleId" TEXT, + "hasPresenceEvents" BOOLEAN NOT NULL DEFAULT false, + "maxParticipants" INTEGER NOT NULL, + "starterMoodleCourseId" INTEGER, + "finisherMoodleCourseId" INTEGER, + "finished" BOOLEAN NOT NULL DEFAULT false, + "finishedBadges" TEXT[], + "requiredBadges" TEXT[], + "finishedPermissions" TEXT[], + "hidden" BOOLEAN NOT NULL DEFAULT true, + + CONSTRAINT "Event_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "File" ( + "id" SERIAL NOT NULL, + + CONSTRAINT "File_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "Participant" ADD CONSTRAINT "Participant_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Participant" ADD CONSTRAINT "Participant_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "Event"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/packages/database/prisma/migrations/20250217093027_event_participants/migration.sql b/packages/database/prisma/migrations/20250217093027_event_participants/migration.sql new file mode 100644 index 00000000..eeb90d68 --- /dev/null +++ b/packages/database/prisma/migrations/20250217093027_event_participants/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - You are about to drop the column `finished` on the `Event` table. All the data in the column will be lost. + - Made the column `description` on table `Event` required. This step will fail if there are existing NULL values in that column. + +*/ +-- AlterTable +ALTER TABLE "Event" DROP COLUMN "finished", +ALTER COLUMN "description" SET NOT NULL, +ALTER COLUMN "maxParticipants" DROP NOT NULL, +ALTER COLUMN "finishedBadges" SET DEFAULT ARRAY[]::TEXT[], +ALTER COLUMN "requiredBadges" SET DEFAULT ARRAY[]::TEXT[], +ALTER COLUMN "finishedPermissions" SET DEFAULT ARRAY[]::TEXT[]; diff --git a/packages/database/prisma/schema/event.prisma b/packages/database/prisma/schema/event.prisma index e69de29b..f89fa620 100644 --- a/packages/database/prisma/schema/event.prisma +++ b/packages/database/prisma/schema/event.prisma @@ -0,0 +1,47 @@ +enum PARTICIPANT_STATUS { + WAITING_FOR_ENTRY_TEST + ENTRY_TEST_FAILED + READY_FOR_EVENT + PARTICIPATED + WAITING_FOR_EXIT_TEST + EXIT_TEST_FAILED + WAITING_FOR_PERMISISONS + FINISHED + WAVED +} + +model Participant { + id Int @id @default(autoincrement()) + userId String @map(name: "user_id") + status PARTICIPANT_STATUS + selectedForParticipatioon Boolean @default(false) + statusLog Json[] + eventId Int + // relations: + user User @relation(fields: [userId], references: [id]) + Event Event? @relation(fields: [eventId], references: [id]) +} + +model Event { + id Int @id @default(autoincrement()) + name String + description String + discordRoleId String? + hasPresenceEvents Boolean @default(false) + maxParticipants Int? @default(0) + starterMoodleCourseId Int? + finisherMoodleCourseId Int? + finishedBadges String[] @default([]) + requiredBadges String[] @default([]) + finishedPermissions String[] @default([]) + hidden Boolean @default(true) + + // relations: + participants Participant[] +} + +model File { + id Int @id @default(autoincrement()) + + // Weitere Felder für das File-Modell +} diff --git a/packages/database/prisma/schema/user.prisma b/packages/database/prisma/schema/user.prisma index bfd4258c..8d70633a 100644 --- a/packages/database/prisma/schema/user.prisma +++ b/packages/database/prisma/schema/user.prisma @@ -14,6 +14,7 @@ model User { // relations: oauthTokens OAuthToken[] discordAccounts DiscordAccount[] + participants Participant[] @@map(name: "users") }