From ebeb2cf93aae3f12e06af0efe4c0bb339a97b88f Mon Sep 17 00:00:00 2001 From: PxlLoewe <72106766+PxlLoewe@users.noreply.github.com> Date: Sat, 27 Sep 2025 22:25:31 +0200 Subject: [PATCH] Booking Panel auf Dashboard --- apps/hub/app/(app)/_components/Badges.tsx | 32 +++++---- apps/hub/app/(app)/_components/Bookings.tsx | 67 +++++++++++++++++++ apps/hub/app/(app)/page.tsx | 10 ++- .../app/_components/BookingTimelineModal.tsx | 13 +--- apps/hub/app/_components/NewBookingModal.tsx | 15 ++--- apps/hub/helper/timerange.ts | 11 +++ 6 files changed, 110 insertions(+), 38 deletions(-) create mode 100644 apps/hub/app/(app)/_components/Bookings.tsx create mode 100644 apps/hub/helper/timerange.ts diff --git a/apps/hub/app/(app)/_components/Badges.tsx b/apps/hub/app/(app)/_components/Badges.tsx index 1d044ece..b35cfe0b 100644 --- a/apps/hub/app/(app)/_components/Badges.tsx +++ b/apps/hub/app/(app)/_components/Badges.tsx @@ -8,24 +8,22 @@ export const Badges: () => Promise = async () => { if (!session) return
; return ( -
-
-

- - Verdiente Abzeichen +
+

+ + Verdiente Abzeichen + +

+
+ {session.user.badges.length === 0 && ( + + Noch ziemlich leer hier. Du kannst dir Abzeichen erarbeiten indem du an Events + teilnimmst. -

-
- {session.user.badges.length === 0 && ( - - Noch ziemlich leer hier. Du kannst dir Abzeichen erarbeiten indem du an Events - teilnimmst. - - )} - {session.user.badges.map((badge, i) => { - return ; - })} -
+ )} + {session.user.badges.map((badge, i) => { + return ; + })}
); diff --git a/apps/hub/app/(app)/_components/Bookings.tsx b/apps/hub/app/(app)/_components/Bookings.tsx new file mode 100644 index 00000000..1cf3f6d7 --- /dev/null +++ b/apps/hub/app/(app)/_components/Bookings.tsx @@ -0,0 +1,67 @@ +import { Calendar } from "lucide-react"; +import { getServerSession } from "../../api/auth/[...nextauth]/auth"; +import { Badge } from "@repo/shared-components"; +import { JSX } from "react"; +import { getPublicUser, prisma } from "@repo/db"; +import { formatTimeRange } from "../../../helper/timerange"; + +export const Bookings: () => Promise = async () => { + const session = await getServerSession(); + const futureBookings = await prisma.booking.findMany({ + where: { + userId: session?.user.id, + startTime: { + gte: new Date(), + }, + }, + orderBy: { + startTime: "asc", + }, + include: { + User: true, + Station: true, + }, + }); + if (!session) return
; + + return ( +
+

+ + Zukünftige Buchungen + +

+
+ {futureBookings.length === 0 && ( + + Keine zukünftigen Buchungen. Du kannst dir welche im Buchungssystem erstellen. + + )} + {futureBookings.map((booking) => { + return ( +
+
+ + {booking.type.startsWith("LST_") + ? "LST" + : booking.Station?.bosCallsignShort || booking.Station?.bosCallsign} + + {getPublicUser(booking.User).fullName} +
+
+
+

+ {formatTimeRange(booking, { includeDate: true })} +

+
+
+
+ ); + })} +
+
+ ); +}; diff --git a/apps/hub/app/(app)/page.tsx b/apps/hub/app/(app)/page.tsx index 85a96c45..8ee3158b 100644 --- a/apps/hub/app/(app)/page.tsx +++ b/apps/hub/app/(app)/page.tsx @@ -2,6 +2,7 @@ import Events from "./_components/FeaturedEvents"; import { Stats } from "./_components/Stats"; import { Badges } from "./_components/Badges"; import { RecentFlights } from "(app)/_components/RecentFlights"; +import { Bookings } from "(app)/_components/Bookings"; export default async function Home({ searchParams, @@ -14,10 +15,15 @@ export default async function Home({
-
+
- +
+ +
+
+ +
diff --git a/apps/hub/app/_components/BookingTimelineModal.tsx b/apps/hub/app/_components/BookingTimelineModal.tsx index d564f8ef..f3205ee1 100644 --- a/apps/hub/app/_components/BookingTimelineModal.tsx +++ b/apps/hub/app/_components/BookingTimelineModal.tsx @@ -2,10 +2,11 @@ import { useState } from "react"; import { CalendarIcon, Plus, X, ChevronLeft, ChevronRight, Trash2 } from "lucide-react"; -import { Booking, getPublicUser, PublicUser, Station, User } from "@repo/db"; +import { Booking, PublicUser, Station, User } from "@repo/db"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { deleteBookingAPI, getBookingsAPI } from "(app)/_querys/bookings"; import { Button } from "@repo/shared-components"; +import { formatTimeRange } from "../../helper/timerange"; interface BookingTimelineModalProps { isOpen: boolean; @@ -227,18 +228,10 @@ export const BookingTimelineModal = ({ return sortedGroups; }; - const formatTimeRange = (booking: Booking) => { - const start = new Date(booking.startTime); - const end = new Date(booking.endTime); - return `${start.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" })} - ${end.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" })}`; - }; - if (!isOpen) return null; const groupedBookings = groupBookingsByResource(); - console.log("Grouped Bookings:", groupedBookings); - return (
@@ -298,7 +291,7 @@ export const BookingTimelineModal = ({
{booking.type.startsWith("LST_") - ? "" + ? "LST" : booking.Station.bosCallsignShort || booking.Station.bosCallsign} {booking.User.fullName} diff --git a/apps/hub/app/_components/NewBookingModal.tsx b/apps/hub/app/_components/NewBookingModal.tsx index 6bac19f5..7b9e7197 100644 --- a/apps/hub/app/_components/NewBookingModal.tsx +++ b/apps/hub/app/_components/NewBookingModal.tsx @@ -7,6 +7,8 @@ import toast from "react-hot-toast"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { getStationsAPI } from "(app)/_querys/stations"; import { createBookingAPI } from "(app)/_querys/bookings"; +import { Button } from "@repo/shared-components"; +import { useRouter } from "next/navigation"; interface Station { id: number; @@ -39,14 +41,12 @@ export const NewBookingModal = ({ onBookingCreated, userPermissions, }: NewBookingModalProps) => { - const [submitting, setSubmitting] = useState(false); - const queryClient = useQueryClient(); const { data: stations, isLoading: isLoadingStations } = useQuery({ queryKey: ["stations"], queryFn: () => getStationsAPI({}), }); - + const router = useRouter(); const { mutate: createBooking, isPending: isCreateBookingLoading } = useMutation({ mutationKey: ["createBooking"], mutationFn: createBookingAPI, @@ -91,7 +91,6 @@ export const NewBookingModal = ({ }, [isOpen, reset, setValue]); const onSubmit = async (data: NewBookingFormData) => { - setSubmitting(true); try { // Validate that end time is after start time if (new Date(data.endTime) <= new Date(data.startTime)) { @@ -106,11 +105,10 @@ export const NewBookingModal = ({ toast.success("Buchung erfolgreich erstellt!"); onBookingCreated(); onClose(); + router.refresh(); } catch (error) { console.error("Error creating booking:", error); toast.error("Fehler beim Erstellen der Buchung"); - } finally { - setSubmitting(false); } }; @@ -231,10 +229,9 @@ export const NewBookingModal = ({ {/* Actions */}
- + diff --git a/apps/hub/helper/timerange.ts b/apps/hub/helper/timerange.ts new file mode 100644 index 00000000..9e2d0fa2 --- /dev/null +++ b/apps/hub/helper/timerange.ts @@ -0,0 +1,11 @@ +import { Booking } from "@repo/db"; + +export const formatTimeRange = (booking: Booking, options?: { includeDate?: boolean }) => { + const start = new Date(booking.startTime); + const end = new Date(booking.endTime); + const timeRange = `${start.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" })} - ${end.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" })}`; + if (options?.includeDate) { + return `${start.toLocaleDateString("de-DE")} ${timeRange}`; + } + return timeRange; +};