diff --git a/components/Table.tsx b/components/Table.tsx
index 78039b12..67281dc9 100644
--- a/components/Table.tsx
+++ b/components/Table.tsx
@@ -3,7 +3,7 @@ import { FaTrash } from "react-icons/fa";
import React from "react";
import { useRouter } from "next/router";
-type ColumnType = {
+export type ColumnType = {
label: string;
field: string;
};
@@ -52,9 +52,8 @@ const Table = ({ rows, columns, onDelete }: TableProps) => {
{columns.map((column) => (
{column.field === "delete" && onDelete ? (
diff --git a/components/admin/RoomOverview.tsx b/components/admin/RoomOverview.tsx
new file mode 100644
index 00000000..72cf4f41
--- /dev/null
+++ b/components/admin/RoomOverview.tsx
@@ -0,0 +1,171 @@
+import { useEffect, useState } from "react";
+import { periodType, RoomBooking } from "../../lib/types/types";
+import Button from "../Button";
+import Table, { ColumnType } from "../Table";
+import DateInput from "../form/DateInput";
+import TextInput from "../form/TextInput";
+import TimeRangeInput from "../form/TimeRangeInput";
+
+import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
+import { WithId } from "mongodb";
+import toast from "react-hot-toast";
+import { createRoom, deleteRoom, fetchRoomsByPeriodId } from "../../lib/api/roomApi";
+
+interface Props {
+ period?: periodType;
+}
+
+const RoomInterview = ({
+ period
+}: Props) => {
+
+ const queryClient = useQueryClient();
+
+ // TODO: Fix correct tabbing
+ const [roomBookings, setRoomBookings] = useState []>([])
+
+ const [date, setDate] = useState("");
+ const [startTime, setStartTime] = useState("");
+ const [endTime, setEndTime] = useState("");
+ const [room, setRoom] = useState("");
+
+ const isValidBooking = () => {
+ if (!room) {
+ toast.error("Vennligst fyll inn rom")
+ return false;
+ }
+ if (!date) {
+ toast.error("Vennligst velg dato")
+ return false;
+ }
+ if (!startTime || !endTime) {
+ toast.error("Vennligst velg tidspunkt")
+ return false;
+ }
+ if (Date.parse("2003-07-26T" + startTime) - Date.parse("2003-07-26T" + endTime) > 0) {
+ toast.error("Starttid må være før sluttid")
+ return false;
+ }
+
+ // TODO: Make sure time is within interviewPeriod
+
+ return true;
+ }
+
+ const {
+ data: roomData,
+ } = useQuery({
+ queryKey: ["rooms", period?._id],
+ queryFn: fetchRoomsByPeriodId
+ })
+
+ const createRoomBookingMutation = useMutation({
+ mutationFn: createRoom,
+ onSuccess: () =>
+ queryClient.invalidateQueries({
+ // TODO: try to update cache instead
+ queryKey: ["rooms", period?._id],
+ }),
+ });
+
+ const deleteRoomBookingMutation = useMutation({
+ mutationFn: (roomId: string) => deleteRoom(roomId, String(period!._id)),
+ onSuccess: () =>
+ queryClient.invalidateQueries({
+ // TODO: try to update cache instead
+ queryKey: ["rooms", period?._id],
+ }),
+ });
+
+ useEffect(() => {
+ if (!roomData) return
+ const { rooms } = roomData
+ console.log(rooms)
+ setRoomBookings(rooms)
+ }, [roomData])
+
+ const handleAddBooking = () => {
+ if (!isValidBooking()) return;
+ addBooking()
+ setRoom("")
+ }
+
+ const addBooking = () => {
+ const booking: RoomBooking = {
+ periodId: String(period?._id),
+ room: room,
+ startDate: new Date(date.split("T")[0] + "T" + startTime),
+ endDate: new Date(date.split("T")[0] + "T" + endTime)
+ }
+
+ createRoomBookingMutation.mutate(booking)
+ }
+
+ const handleDeleteBooking = async (booking: WithId) => {
+ if (!period) return;
+ const isConfirmed = window.confirm(
+ `Er det sikker på at du ønsker å fjerne bookingen av ${booking.room} fra ${booking.startDate} til ${booking.endDate}?`
+ );
+ if (!isConfirmed) return;
+
+ setRoomBookings(roomBookings.filter((bookingA) => bookingA._id != booking._id))
+
+ deleteRoomBookingMutation.mutate(String(booking._id))
+ };
+
+ const columns: ColumnType[] = [
+ { label: "Rom", field: "room" },
+ { label: "Dato", field: "date" },
+ { label: "Fra", field: "from" },
+ { label: "Til", field: "to" },
+ { label: "Slett", field: "delete" },
+ ]
+
+ return
+ Legg inn romvalg
+
+
+ {
+ setRoom(input)
+ }}
+ label="Romnavn"
+ className="mx-0"
+ />
+ {
+ setDate(date)
+ }}
+ label="Test"
+ />
+ {
+ setStartTime(times.start)
+ setEndTime(times.end)
+ }}
+ className="mx-0"
+ />
+
+
+
+ Alle tilgjengelige romvalg
+ {roomBookings?.length ? {
+ return {
+ id: String(roomBooking._id),
+ room: roomBooking.room,
+ date: new Date(roomBooking.startDate).toLocaleDateString(),
+ from: new Date(roomBooking.startDate).toLocaleTimeString(),
+ to: new Date(roomBooking.endDate).toLocaleTimeString()
+ }
+ })} onDelete={(id: string, name: string) => {
+ const deletedBooking = roomBookings.find((booking, index, array) => {
+ return String(booking._id) == id
+ })
+ handleDeleteBooking(deletedBooking!)
+ }} />
+ : Legg inn et rom, så dukker det opp her. }
+
+};
+
+export default RoomInterview;
diff --git a/components/form/DateInput.tsx b/components/form/DateInput.tsx
new file mode 100644
index 00000000..eaff3c9b
--- /dev/null
+++ b/components/form/DateInput.tsx
@@ -0,0 +1,29 @@
+import { useEffect, useState } from "react";
+interface Props {
+ label?: string;
+ updateDate: (date: string) => void;
+}
+
+const DateRangeInput = (props: Props) => {
+ const [date, setDate] = useState("");
+
+ useEffect(() => {
+ const dateString = date ? `${date}T00:00` : "";
+ props.updateDate(dateString);
+ }, [date]);
+
+ return (
+
+ setDate(e.target.value)}
+ className="border text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 border-gray-300 text-gray-900 dark:border-gray-600 dark:bg-online-darkBlue dark:text-gray-200"
+ />
+
+ );
+};
+
+export default DateRangeInput;
diff --git a/components/form/DatePickerInput.tsx b/components/form/DateRangeInput.tsx
similarity index 95%
rename from components/form/DatePickerInput.tsx
rename to components/form/DateRangeInput.tsx
index 6ef4474c..e3182dbf 100644
--- a/components/form/DatePickerInput.tsx
+++ b/components/form/DateRangeInput.tsx
@@ -4,7 +4,7 @@ interface Props {
updateDates: (dates: { start: string; end: string }) => void;
}
-const DatePickerInput = (props: Props) => {
+const DateRangeInput = (props: Props) => {
const [fromDate, setFromDate] = useState("");
const [toDate, setToDate] = useState("");
@@ -42,4 +42,4 @@ const DatePickerInput = (props: Props) => {
);
};
-export default DatePickerInput;
+export default DateRangeInput;
diff --git a/components/form/TextInput.tsx b/components/form/TextInput.tsx
index d54d130b..aa4e2d48 100644
--- a/components/form/TextInput.tsx
+++ b/components/form/TextInput.tsx
@@ -4,6 +4,7 @@ interface Props {
disabled?: boolean;
placeholder?: string;
defaultValue?: string;
+ className?: string;
}
const TextInput = (props: Props) => {
@@ -12,7 +13,7 @@ const TextInput = (props: Props) => {
};
return (
-
+
void;
+ className?: string;
+}
+
+const TimeRangeInput = (props: Props) => {
+ const [fromTime, setFromTime] = useState("");
+ const [toTime, setToTime] = useState("");
+ new Date()
+
+ useEffect(() => {
+ const startTime = fromTime ? `${fromTime}` : "";
+ const endTime = toTime ? `${toTime}` : "";
+ props.updateTimes({ start: startTime, end: endTime });
+ }, [fromTime, toTime]);
+
+ return (
+
+ );
+};
+
+export default TimeRangeInput;
diff --git a/lib/api/roomApi.ts b/lib/api/roomApi.ts
new file mode 100644
index 00000000..8fd9bf3c
--- /dev/null
+++ b/lib/api/roomApi.ts
@@ -0,0 +1,41 @@
+import { QueryFunctionContext } from "@tanstack/react-query";
+import { RoomBooking } from "../types/types";
+
+export const fetchRoomByPeriodAndId = async (context: QueryFunctionContext) => {
+ const periodId = context.queryKey[1];
+ const roomId = context.queryKey[2];
+ return fetch(`/api/rooms/${periodId}/${roomId}`).then((res) => res.json());
+};
+
+export const fetchRoomsByPeriodId = async (context: QueryFunctionContext) => {
+ const periodId = context.queryKey[1];
+ return fetch(`/api/rooms/${periodId}`).then((res) => res.json());
+};
+
+export const createRoom = async (room: RoomBooking): Promise => {
+ const response = await fetch(`/api/rooms/`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(room),
+ });
+
+ const { message, data, error } = await response.json();
+ if (!response.ok) {
+ throw new Error(error || "Unknown error occurred");
+ }
+ return data;
+};
+
+export const deleteRoom = async (roomId: string, periodId: string) => {
+ const response = await fetch(`/api/rooms/${periodId}/${roomId}`, {
+ method: "DELETE",
+ });
+
+ if (!response.ok) {
+ throw new Error("Failed to delete the room");
+ }
+
+ return response;
+};
diff --git a/lib/mongo/rooms.ts b/lib/mongo/rooms.ts
new file mode 100644
index 00000000..2a42d923
--- /dev/null
+++ b/lib/mongo/rooms.ts
@@ -0,0 +1,133 @@
+import { Collection, Db, MongoClient, ObjectId } from "mongodb";
+import { RoomBooking } from "../types/types";
+import clientPromise from "./mongodb";
+
+let client: MongoClient;
+let db: Db;
+let rooms: Collection;
+
+async function init() {
+ if (db) return;
+ try {
+ client = await clientPromise;
+ db = client.db();
+ rooms = db.collection("rooms");
+ } catch (error) {
+ console.error(error);
+ throw new Error("Failed to establish connection to database");
+ }
+}
+
+(async () => {
+ await init();
+})();
+
+export const createRoom = async (roomData: RoomBooking) => {
+ try {
+ if (!rooms) await init();
+
+ const existingRoom = await rooms.findOne({
+ room: roomData.room,
+ periodId: roomData.periodId,
+ $or: [
+ /* Tillater ikke overlappende tidspunkt på samme rom. */
+ {
+ $and: [
+ {
+ startDate: { $gte: roomData.startDate },
+ },
+ { startDate: { $lte: roomData.endDate } },
+ ],
+ },
+ {
+ $and: [
+ {
+ endDate: { $gte: roomData.startDate },
+ },
+ { endDate: { $lte: roomData.endDate } },
+ ],
+ },
+ ],
+ });
+
+ if (existingRoom) {
+ return { error: "409 Room booking already exists for this period" };
+ }
+
+ const result = await rooms.insertOne(roomData);
+ if (result.insertedId) {
+ const insertedRoom = await rooms.findOne({
+ _id: result.insertedId,
+ });
+ if (insertedRoom) {
+ return { room: insertedRoom };
+ } else {
+ return { error: "Failed to retrieve the created room" };
+ }
+ } else {
+ return { error: "Failed to create room" };
+ }
+ } catch (error) {
+ console.error(error);
+ return { error: "Failed to create room" };
+ }
+};
+
+export const getRooms = async () => {
+ try {
+ if (!rooms) await init();
+ const result = await rooms.find({}).toArray();
+ return { rooms: result };
+ } catch (error) {
+ return { error: "Failed to fetch rooms" };
+ }
+};
+
+export const getRoom = async (roomId: string) => {
+ try {
+ if (!rooms) await init();
+
+ const result = await rooms.findOne({
+ _id: new ObjectId(roomId),
+ });
+
+ return { room: result, exists: !!result };
+ } catch (error) {
+ console.error(error);
+ return { error: "Failed to fetch room", exists: false };
+ }
+};
+
+export const getRoomsByPeriod = async (periodId: string) => {
+ try {
+ if (!rooms) await init();
+
+ const result = await rooms
+ .find({ periodId: periodId }) // No ObjectId conversion needed
+ .toArray();
+
+ return { rooms: result, exists: result.length > 0 };
+ } catch (error) {
+ console.error(error);
+ return { error: "Failed to fetch rooms" };
+ }
+};
+
+export const deleteRoom = async (id: string) => {
+ try {
+ if (!rooms) await init();
+
+ const result = await rooms.deleteOne({
+ _id: new ObjectId(id),
+ });
+
+ if (result.deletedCount === 1) {
+ return { message: "Room deleted successfully" };
+ } else {
+ return { error: "Room not found or already deleted" };
+ }
+ } catch (error) {
+ console.error(error);
+ return { error: "Failed to delete room" };
+ }
+};
diff --git a/lib/types/types.ts b/lib/types/types.ts
index 26a48323..35f85c86 100644
--- a/lib/types/types.ts
+++ b/lib/types/types.ts
@@ -142,3 +142,11 @@ export type emailApplicantInterviewType = {
};
}[];
};
+
+export interface RoomBooking {
+ periodId: string;
+ room: String;
+ startDate: Date;
+ endDate: Date;
+ committeeId?: String;
+}
diff --git a/lib/utils/validators.ts b/lib/utils/validators.ts
index e4433c4f..52aed83d 100644
--- a/lib/utils/validators.ts
+++ b/lib/utils/validators.ts
@@ -3,6 +3,7 @@ import {
committeeInterviewType,
periodType,
preferencesType,
+ RoomBooking,
} from "../types/types";
export const isApplicantType = (
@@ -151,11 +152,11 @@ export const validateCommittee = (data: any, period: periodType): boolean => {
);
};
-export const isPeriodType = (data: any): data is periodType => {
- const isDateString = (str: any): boolean => {
- return typeof str === "string" && !isNaN(Date.parse(str));
- };
+const isDateString = (str: any): boolean => {
+ return typeof str === "string" && !isNaN(Date.parse(str));
+};
+export const isPeriodType = (data: any): data is periodType => {
const isValidPeriod = (period: any): boolean => {
return (
typeof period === "object" &&
@@ -191,3 +192,21 @@ export const isPeriodType = (data: any): data is periodType => {
return hasBasicFields;
};
+
+export const isRoomBookings = (data: any): data is RoomBooking[] => {
+ if (!Array.isArray(data)) return false;
+ return data.every(isRoomBooking);
+};
+
+export const isRoomBooking = (data: any): data is RoomBooking => {
+ return (
+ typeof data === "object" &&
+ data !== null &&
+ typeof data.periodId === "string" &&
+ typeof data.room === "string" &&
+ isDateString(data.startDate) &&
+ isDateString(data.endDate) &&
+ (typeof data.committeeId === "string" ||
+ typeof data.committeeId === "undefined")
+ );
+};
diff --git a/package-lock.json b/package-lock.json
index c99b5b06..355d0a2d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,6 +21,7 @@
"@vercel/analytics": "^1.1.2",
"lucide-react": "^0.441.0",
"mongodb": "^6.1.0",
+ "online-opptak": "file:",
"next": "^14.2.16",
"next-auth": "^4.24.10",
"react": "18.2.0",
@@ -5133,6 +5134,10 @@
"wrappy": "1"
}
},
+ "node_modules/online-opptak": {
+ "resolved": "",
+ "link": true
+ },
"node_modules/openid-client": {
"version": "5.6.5",
"resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.5.tgz",
diff --git a/package.json b/package.json
index 336c3ed5..843fc93a 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
"@vercel/analytics": "^1.1.2",
"lucide-react": "^0.441.0",
"mongodb": "^6.1.0",
+ "online-opptak": "file:",
"next": "^14.2.16",
"next-auth": "^4.24.10",
"react": "18.2.0",
diff --git a/pages/admin/[period-id]/index.tsx b/pages/admin/[period-id]/index.tsx
index d025954d..081bc142 100644
--- a/pages/admin/[period-id]/index.tsx
+++ b/pages/admin/[period-id]/index.tsx
@@ -4,8 +4,9 @@ import router from "next/router";
import { periodType } from "../../../lib/types/types";
import NotFound from "../../404";
import ApplicantsOverview from "../../../components/applicantoverview/ApplicantsOverview";
+import RoomOverview from "../../../components/admin/RoomOverview";
import { Tabs } from "../../../components/Tabs";
-import { CalendarIcon, InboxIcon } from "@heroicons/react/24/solid";
+import { CalendarIcon, InboxIcon, BuildingOffice2Icon } from "@heroicons/react/24/solid";
import Button from "../../../components/Button";
import { useQuery } from "@tanstack/react-query";
import { fetchPeriodById } from "../../../lib/api/periodApi";
@@ -87,26 +88,35 @@ const Admin = () => {
/>
),
},
+ {
+ title: "Romoppsett",
+ icon: ,
+ content: (
+
+ )
+ },
//Super admin :)
...(session?.user?.email &&
- ["fhansteen@gmail.com", "jotto0214@gmail.com"].includes(
- session.user.email
- )
+ ["fhansteen@gmail.com", "jotto0214@gmail.com"].includes(
+ session.user.email
+ )
? [
- {
- title: "Send ut",
- icon: ,
- content: (
-
-
- ),
- },
- ]
+ {
+ title: "Send ut",
+ icon: ,
+ content: (
+
+
+ ),
+ },
+ ]
: []),
]}
/>
diff --git a/pages/admin/new-period.tsx b/pages/admin/new-period.tsx
index ee9035d1..90a4f935 100644
--- a/pages/admin/new-period.tsx
+++ b/pages/admin/new-period.tsx
@@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import Button from "../../components/Button";
import ApplicationForm from "../../components/form/ApplicationForm";
import CheckboxInput from "../../components/form/CheckboxInput";
-import DatePickerInput from "../../components/form/DatePickerInput";
+import DateRangeInput from "../../components/form/DateRangeInput";
import TextAreaInput from "../../components/form/TextAreaInput";
import TextInput from "../../components/form/TextInput";
import { DeepPartial, periodType } from "../../lib/types/types";
@@ -154,11 +154,11 @@ const NewPeriod = () => {
/>
-
-
@@ -214,7 +214,7 @@ const NewPeriod = () => {
{}}
+ setApplicationData={() => { }}
availableCommittees={
(periodData.committees?.filter(Boolean) as string[]) || []
}
diff --git a/pages/api/periods/[id].ts b/pages/api/periods/[id].ts
index 55e0787b..f026da16 100644
--- a/pages/api/periods/[id].ts
+++ b/pages/api/periods/[id].ts
@@ -1,8 +1,8 @@
import { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth";
-import { authOptions } from "../auth/[...nextauth]";
import { deletePeriodById, getPeriodById } from "../../../lib/mongo/periods";
import { hasSession, isAdmin } from "../../../lib/utils/apiChecks";
+import { authOptions } from "../auth/[...nextauth]";
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getServerSession(req, res, authOptions);
diff --git a/pages/api/rooms/[period-id]/[id].ts b/pages/api/rooms/[period-id]/[id].ts
new file mode 100644
index 00000000..ce2f5f92
--- /dev/null
+++ b/pages/api/rooms/[period-id]/[id].ts
@@ -0,0 +1,61 @@
+import { NextApiRequest, NextApiResponse } from "next";
+import { getServerSession } from "next-auth";
+import { authOptions } from "../../auth/[...nextauth]";
+import { hasSession, isAdmin } from "../../../../lib/utils/apiChecks";
+import { getPeriodById } from "../../../../lib/mongo/periods";
+import { deleteRoom, getRoom } from "../../../../lib/mongo/rooms";
+
+const handler = async (req: NextApiRequest, res: NextApiResponse) => {
+ const session = await getServerSession(req, res, authOptions);
+
+ if (!hasSession(res, session)) return;
+
+ const id = req.query.id;
+ const periodId = req.query["period-id"];
+
+ if (typeof id !== "string" || typeof periodId !== "string") {
+ return res.status(400).json({ error: "Invalid ID format" });
+ }
+
+ const { period } = await getPeriodById(periodId);
+
+ if (!period) {
+ return res.status(404).json({ error: "Period not found" });
+ }
+
+ if (!isAdmin(res, session))
+ return res.status(403).json({ error: "Unauthorized" });
+
+ try {
+ if (req.method === "GET") {
+ const { room, exists, error } = await getRoom(id);
+
+ if (error) {
+ return res.status(500).json({ error });
+ }
+
+ if (!exists) {
+ return res.status(404).json({ message: "Room not found" });
+ }
+
+ return res.status(200).json({ exists, room });
+ } else if (req.method === "DELETE") {
+ const { error } = await deleteRoom(id);
+
+ if (error) throw new Error(error);
+
+ return res.status(204).end();
+ }
+ } catch (error) {
+ if (error instanceof Error) {
+ return res.status(500).json({ error: error.message });
+ }
+
+ return res.status(500).json("Unexpected error occurred");
+ }
+
+ res.setHeader("Allow", ["GET", "DELETE"]);
+ res.status(405).end(`Method ${req.method} Not Allowed`);
+};
+
+export default handler;
diff --git a/pages/api/rooms/[period-id]/index.ts b/pages/api/rooms/[period-id]/index.ts
new file mode 100644
index 00000000..9ff0c5cc
--- /dev/null
+++ b/pages/api/rooms/[period-id]/index.ts
@@ -0,0 +1,33 @@
+import { NextApiRequest, NextApiResponse } from "next";
+import { getServerSession } from "next-auth";
+import { getRoomsByPeriod } from "../../../../lib/mongo/rooms";
+import { hasSession } from "../../../../lib/utils/apiChecks";
+import { authOptions } from "../../auth/[...nextauth]";
+
+const handler = async (req: NextApiRequest, res: NextApiResponse) => {
+ const session = await getServerSession(req, res, authOptions);
+
+ if (!hasSession(res, session)) return;
+
+ const periodId = req.query["period-id"];
+
+ try {
+ if (req.method === "GET") {
+ if (typeof periodId != "string") {
+ throw new Error("Not a valid period id string");
+ }
+ const { rooms, error } = await getRoomsByPeriod(periodId);
+
+ if (error) throw new Error(error);
+
+ return res.status(200).json({ rooms });
+ }
+ } catch {
+ res.status(500).json("An error occurred");
+ }
+
+ res.setHeader("Allow", ["GET", "POST"]);
+ res.status(405).end(`Method ${req.method} is not allowed.`);
+};
+
+export default handler;
diff --git a/pages/api/rooms/index.ts b/pages/api/rooms/index.ts
new file mode 100644
index 00000000..eb6ba759
--- /dev/null
+++ b/pages/api/rooms/index.ts
@@ -0,0 +1,46 @@
+import { NextApiRequest, NextApiResponse } from "next";
+import { getServerSession } from "next-auth";
+import { createRoom, getRooms } from "../../../lib/mongo/rooms";
+import { RoomBooking } from "../../../lib/types/types";
+import { hasSession, isAdmin } from "../../../lib/utils/apiChecks";
+import { isRoomBooking } from "../../../lib/utils/validators";
+import { authOptions } from "../auth/[...nextauth]";
+
+const handler = async (req: NextApiRequest, res: NextApiResponse) => {
+ const session = await getServerSession(req, res, authOptions);
+
+ if (!hasSession(res, session)) return;
+
+ try {
+ if (req.method === "GET") {
+ const { rooms, error } = await getRooms();
+
+ if (error) throw new Error(error);
+
+ return res.status(200).json({ rooms });
+ }
+
+ if (req.method === "POST") {
+ if (!isAdmin(res, session)) return;
+ const room = req.body as RoomBooking;
+
+ if (!isRoomBooking(req.body)) {
+ return res.status(400).json({ error: "Invalid data format" });
+ }
+
+ const { room: createdRoom, error } = await createRoom(room);
+ if (error) throw new Error(error);
+ return res.status(201).json({
+ message: "Period created successfully",
+ data: createdRoom,
+ });
+ }
+ } catch {
+ res.status(500).json("An error occurred");
+ }
+
+ res.setHeader("Allow", ["GET", "POST"]);
+ res.status(405).end(`Method ${req.method} is not allowed.`);
+};
+
+export default handler;
|