Skip to content

Commit

Permalink
Feat: continue implementing UI for booking
Browse files Browse the repository at this point in the history
  • Loading branch information
Mauritzskog committed Aug 31, 2024
1 parent e5cd3c8 commit 35beb38
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 50 deletions.
18 changes: 12 additions & 6 deletions frontend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,16 @@ model Arrangement {
}

model Booking {
id String @id @default(cuid())
id String @id @default(cuid())
userID String
komiteID String?
item BookedItem
bookedAt DateTime
duration Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
komite komite? @relation(fields: [komiteID], references: [id])
user User @relation(fields: [userID], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
status BookingStatus @default(PENDING)
komite komite? @relation(fields: [komiteID], references: [id])
user User @relation(fields: [userID], references: [id])
}

model ArrangementPaamelding {
Expand Down Expand Up @@ -157,3 +157,9 @@ enum UserRole {
USER
SUPER_USER
}

enum BookingStatus {
PENDING
CONFIRMED
REJECTED
}
2 changes: 1 addition & 1 deletion frontend/src/app/for_studenten/arrangement/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ const ForStudentenPage = () => {
<p>
Påmelding til arrangementer skjer både gjennom nettsiden og gjennom
emils
<span className="text-[#9DDBAD]"> Facebookgruppe</span>. Ved
<span className="text-[#9DDBAD] text-underscore"><a href="https://www.facebook.com/groups/emilntnu/?locale=nb_NO"> Facebookgruppe</a></span>. Ved
spørsmål angående arrangementer kan man henvende seg til arrangør
eller hovedstyret.
</p>
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/app/for_studenten/booking/bookings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
"use client";

import BookingView from "@/components/ForStudenten/booking/booking-view";
import { ArrowLeft } from "lucide-react";
import Link from "next/link";

const MineBookingerPage = () => {
return (
<div className="w-4/5 flex flex-col items-center justify-center p-12 gap-y-6">
<div className="flex flex-col items-center justify-center bg-[#225654] rounded-b-md gap-y-4 px-4">
<div className="flex justify-start w-full">
<Link href="/for_studenten/booking" className="flex px-4 font-light text-md items-center text-underscore"><ArrowLeft/>Tilbake</Link>
</div>
<div className="flex flex-col space-y-4">
<h1 className=" text-white text-center font-semibold text-4xl w-full">
Soundbox
Expand Down
127 changes: 94 additions & 33 deletions frontend/src/app/for_studenten/booking/soundbox/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,67 +6,128 @@ import { Booking } from "@/schemas/booking";
import { useEffect, useState } from "react";
import Calendar from "react-calendar";
import { getBookingList } from "@/utils/booking/booking";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import { ArrowLeft } from "lucide-react";
import router from "next/router";

const SoundboxPage = () => {
const [bookings, setBookings] = useState<Booking[]>();
const [bookings, setBookings] = useState<Booking[]>([]);

useEffect(() => {
fetchBookings();
console.log(bookings);
}, [])
}, []);

const fetchBookings = async () => {
try {
const bookings = await getBookingList();
console.log(bookings);
if (bookings){
// setBookings(bookings);
if (bookings) {
const transformedBookings = bookings.map((booking) => ({
...booking,
}));
setBookings(transformedBookings);
}
} catch (err) {
console.error("Could not fetch bookings:", err);
}
};
const handleStatusChange = (status: string) => {
if (status === "Booking successful!") {
fetchBookings();
}
};

return (
<div className="flex flex-col items-center justify-center bg-[#225654] rounded-b-md gap-y-4 px-4">
<div className="flex justify-start w-full">
<Link href="/for_studenten/booking" className="flex px-4 font-light text-md items-center text-underscore"><ArrowLeft/>Tilbake</Link>
</div>
<div className="max-w-[512px]">
<h1 className=" text-white text-center font-semibold text-2xl w-full">
Soundbox
</h1>
<p className="text-white text-sm text-center">
Emil har 2 soundboxer som kan bookes. Se oversikten nedenfor og finn
en dato.{" "}
Emil har 2 soundboxer som kan bookes. Se oversikt over tilgjengelige datoer nedenfor og legg inn en booking.
Når du har lagt inn en booking vil styret godkjenne bookingen din og den kommer opp i oversikten
under<span className="text-[#9DDBAD] text-underscore"><Link href="/for_studenten/booking/bookings"> dine bookinger</Link></span>
</p>
</div>
<div className="flex flex-col lg:flex-row justify-center items-center gap-y-4 py-4">
<div className="flex justify-start items-start">
<BookingWindow />
</div>
<div className="flex flex-col lg:flex-row justify-center items-center lg:gap-y-4 pb-4">
<div className="w-full max-w-[800px]">
<div className="text-2xl font-bold flex h-[500px] flex-col justify- items-start ">
<div className="text-2xl font-bold flex h-[550px] flex-col items-center ">
<p className="w-full flex justify-center">Bookinger</p>
{/* RENDER COLOURS FOR BOOKED INSTANCES */}
<Calendar
locale="nb"
className="text-white p-4 font-normal text-sm rounded-md flex items-center justify-center flex-col gap-y-4 lg:px-12"
tileClassName={({ date, view }) => {
const dateString = date.toDateString();
const isToday = dateString === new Date().toDateString();

return view === "month" && isToday
? "bg-[#579783] text-white font-bold border border-white lg:h-[4rem] p-2 flex flex-col justify-center items-center relative"
: "p-2 border border-white h-[4rem] flex flex-col justify-center items-center relative";
}}
navigationLabel={({ date, label, locale, view }) => (
<div className="text-md w-[150px] flex justify-center flex-shrink-0 font-semibold text-white icon-hover">
{label.charAt(0).toUpperCase() + label.slice(1)}
<div className="flex justify-start font-normal">
<div className="flex gap-x-2 items-center px-4">
<div className="w-2 h-2 bg-yellow-500 rounded-full"></div>
<span className="text-sm lg:text-base">En ledig soundbox</span>
<div className="w-2 h-2 bg-red-500 rounded-full"></div>
<span className="text-sm lg:text-base">
Ingen ledige soundboxer
</span>
</div>
)}
next2Label={null}
prev2Label={null}
nextLabel={<span className="text-white font-bold text-xl"></span>}
prevLabel={<span className="text-white font-bold text-xl"></span>}
/>
</div>
<Calendar
locale="nb"
className="text-white p-4 font-normal text-sm rounded-md flex items-center justify-center flex-col gap-y-4 lg:px-12"
tileClassName={({ date, view }) => {
const dateString = date.toDateString();
const isToday = dateString === new Date().toDateString();

return view === "month" && isToday
? "bg-[#579783] text-white font-bold border border-white lg:h-[4rem] p-2 flex flex-col justify-center items-center relative cursor-default"
: "p-2 border border-white h-[4rem] flex flex-col justify-center items-center relative cursor-default";
}}
tileContent={({ date, view }) => {
if (view === "month") {
const matchingBookings = bookings.filter((booking) => {
const bookingDate = new Date(
booking.bookedAt,
).toDateString();
return bookingDate === date.toDateString();
});

// Count the number of "ONE_SOUNDBOX" bookings
const oneSoundboxCount = matchingBookings.filter(
(booking) => booking.item === "ONE_SOUNDBOX",
).length;

// Check if there is a "TWO_SOUNDBOXES" booking
const hasTwoSoundboxes = matchingBookings.some(
(booking) => booking.item === "TWO_SOUNDBOXES",
);

// Determine the dot color: red if there is a "TWO_SOUNDBOXES" booking or more than one "ONE_SOUNDBOX" booking
const dotColor =
hasTwoSoundboxes || oneSoundboxCount > 1
? "bg-red-500"
: "bg-yellow-500";

return matchingBookings.length > 0 ? (
<div className="flex items-center justify-center">
<div className={`w-2 h-2 ${dotColor} rounded-full`}></div>
</div>
) : null;
}
}}
navigationLabel={({ date, label, locale, view }) => (
<div className="text-md w-[150px] flex justify-center flex-shrink-0 font-semibold text-white icon-hover">
{label.charAt(0).toUpperCase() + label.slice(1)}
</div>
)}
next2Label={null}
prev2Label={null}
nextLabel={
<span className="text-white font-bold text-xl"></span>
}
prevLabel={
<span className="text-white font-bold text-xl"></span>
}
/>
</div>
</div>
<div className="flex justify-start items-start">
<BookingWindow onStatusChange={handleStatusChange} />
</div>
</div>
</div>
Expand Down
18 changes: 13 additions & 5 deletions frontend/src/components/ForStudenten/booking/booking-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { useCurrentUser } from "@/hooks/use-current-user";
import { checkBooking } from "@/utils/actions/checkBooking";
import { bookingFormSchema } from "@/schemas/booking";

export const BookingCard = () => {
export const BookingCard = ({ onStatusChange }: { onStatusChange: (status: string) => void }) => {
const user = useCurrentUser();
const [error, setError] = useState<string | undefined>("");
const [success, setSuccess] = useState<string | undefined>("");
Expand All @@ -62,8 +62,16 @@ export const BookingCard = () => {

startTransition(() => {
checkBooking(values, user?.id || "").then((data) => {
setError(data?.error);
setSuccess(data?.success);
const { error, success } = data || {};

if (error) {
setError(error);
onStatusChange(error); // Send the error to the parent component
} else if (success) {
setSuccess(success);
onStatusChange(success); // Send the success message to the parent component
}

toast({
title: "Booking gjennomført!:",
description: (
Expand All @@ -82,8 +90,8 @@ export const BookingCard = () => {
<CardWrapper
headerTitle="Book soundbox"
headerLabel="Enkelt å booke"
backButtonLabel="Tilbake til booking"
backButtonHref="/for_studenten/booking"
backButtonLabel="Se mine bookinger"
backButtonHref="/for_studenten/booking/bookings"
>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@

import { Label } from "@radix-ui/react-label";
import { DatePickerForm } from "../ui/date-picker-form";
import { ReactNode } from "react";
import { ReactNode, useState } from "react";
import BookingForm from "@/components/ForStudenten/booking/booking-form";
import { BookingCard } from "./booking-card";

const BookingWindow = () => {
const BookingWindow = ({ onStatusChange }: { onStatusChange: (status: string) => void }) => {
const handleChange = (status: string) => {
onStatusChange(status);
}
return (
<div className="sm:p-0 text-white min-h-[320px] w-full rounded-md flex flex-col gap-y-2 items-center justify-center">
{/* <BookingForm /> */}
<BookingCard />
<BookingCard onStatusChange={handleChange}/>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/schemas/booking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { nb } from "date-fns/locale";
export const BookingSchema = z.object({
id: z.string(),
userID: z.string(),
komiteID: z.string().optional(),
komiteID: z.string().nullable().optional(),
item: z.enum(["KONTOR", "ONE_SOUNDBOX", "TWO_SOUNDBOXES"]),
bookedAt: z.string().transform((str) => new Date(str)),
duration: z.number().optional(),
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/utils/booking/booking.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use server'

import { db } from "@/lib/db";
import { format } from "date-fns";
import { nb } from "date-fns/locale";
Expand Down

0 comments on commit 35beb38

Please sign in to comment.