From 309d17bb6576b11001f71afea38b2f433c043054 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Wed, 27 Aug 2025 16:10:45 -0400 Subject: [PATCH] Added the first page. Signed-off-by: Cliff Hill --- frontend/package.json | 2 + frontend/src/App.tsx | 30 +++---- frontend/src/pages/LandingPage.tsx | 132 +++++++++++++++++++++++++++++ frontend/yarn.lock | 54 ++++++++++++ 4 files changed, 198 insertions(+), 20 deletions(-) create mode 100644 frontend/src/pages/LandingPage.tsx diff --git a/frontend/package.json b/frontend/package.json index e44360ad..081a6d24 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,8 +15,10 @@ "@types/node": "^16.7.13", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", + "@types/react-router-dom": "^5.3.3", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-router-dom": "^7.8.2", "react-scripts": "5.0.1", "typescript": "^4.4.2", "web-vitals": "^2.1.0" diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 9cc63d91..2a6dcd30 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,26 +1,16 @@ import React from "react"; -import logo from "./logo.svg"; -import "./App.css"; +import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; +import LandingPage from "./pages/LandingPage"; -function App() { +const App: React.FC = () => { return ( -
-
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn React - -
-
+ + + } /> + {/* Add more routes here, e.g. for the booking page */} + + ); -} +}; export default App; diff --git a/frontend/src/pages/LandingPage.tsx b/frontend/src/pages/LandingPage.tsx new file mode 100644 index 00000000..2972b27b --- /dev/null +++ b/frontend/src/pages/LandingPage.tsx @@ -0,0 +1,132 @@ +import React, { useEffect, useState } from "react"; +import { + Container, + Typography, + Box, + Button, + Grid, + Card, + CardContent, + CircularProgress, + AppBar, + Toolbar, +} from "@mui/material"; +import { useNavigate } from "react-router-dom"; + +interface Room { + id: number; + name: string; + capacity: number; +} + +interface Booking { + id: number; + room_id: number; + start_time: string; + end_time: string; + user: string; +} + +const LandingPage: React.FC = () => { + const [rooms, setRooms] = useState([]); + const [bookings, setBookings] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const navigate = useNavigate(); + + useEffect(() => { + const fetchData = async () => { + setLoading(true); + setError(null); + try { + const roomsRes = await fetch("/api/rooms"); + const bookingsRes = await fetch("/api/bookings/today"); + if (!roomsRes.ok || !bookingsRes.ok) + throw new Error("Failed to fetch data"); + setRooms(await roomsRes.json()); + setBookings(await bookingsRes.json()); + } catch (err: any) { + setError(err.message || "Unknown error"); + } finally { + setLoading(false); + } + }; + fetchData(); + }, []); + + return ( + + + + + Conference Room Booking + + + + + + + Available Conference Rooms + + {loading ? ( + + ) : error ? ( + {error} + ) : ( + + {rooms.map((room) => ( + + + + {room.name} + + Capacity: {room.capacity} + + + + + ))} + + )} + + + Today's Bookings + + {loading ? ( + + ) : error ? ( + {error} + ) : bookings.length === 0 ? ( + No bookings for today. + ) : ( + + {bookings.map((booking) => ( + + + + + Room:{" "} + {rooms.find((r) => r.id === booking.room_id)?.name || + "Unknown"} + + + {booking.start_time} - {booking.end_time} + + + Booked by: {booking.user} + + + + + ))} + + )} + + + + ); +}; + +export default LandingPage; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 481eddad..20a7a7e6 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2168,6 +2168,11 @@ dependencies: "@types/node" "*" +"@types/history@^4.7.11": + version "4.7.11" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" + integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== + "@types/html-minifier-terser@^6.0.0": version "6.1.0" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" @@ -2281,11 +2286,35 @@ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.7.tgz#2863f2aa89e023592b981204ef92c5221b286410" integrity sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw== +"@types/react-router-dom@^5.3.3": + version "5.3.3" + resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" + integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-router" "*" + +"@types/react-router@*": + version "5.1.20" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.20.tgz#88eccaa122a82405ef3efbcaaa5dcdd9f021387c" + integrity sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-transition-group@^4.4.12": version "4.4.12" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz#b5d76568485b02a307238270bfe96cb51ee2a044" integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== +"@types/react@*": + version "19.1.12" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.12.tgz#7bfaa76aabbb0b4fe0493c21a3a7a93d33e8937b" + integrity sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w== + dependencies: + csstype "^3.0.2" + "@types/react@^19.0.0": version "19.1.10" resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.10.tgz#a05015952ef328e1b85579c839a71304b07d21d9" @@ -3556,6 +3585,11 @@ cookie@0.7.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== +cookie@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610" + integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA== + core-js-compat@^3.43.0: version "3.45.1" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.45.1.tgz#424f3f4af30bf676fd1b67a579465104f64e9c7a" @@ -8059,6 +8093,21 @@ react-refresh@^0.11.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== +react-router-dom@^7.8.2: + version "7.8.2" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-7.8.2.tgz#25a8fc36588189baf3bbb5e360c8ffffbd2beabc" + integrity sha512-Z4VM5mKDipal2jQ385H6UBhiiEDlnJPx6jyWsTYoZQdl5TrjxEV2a9yl3Fi60NBJxYzOTGTTHXPi0pdizvTwow== + dependencies: + react-router "7.8.2" + +react-router@7.8.2: + version "7.8.2" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-7.8.2.tgz#9d2d4147ca72832c550acc60ed688062d18f70b8" + integrity sha512-7M2fR1JbIZ/jFWqelpvSZx+7vd7UlBTfdZqf6OSdF9g6+sfdqJDAWcak6ervbHph200ePlu+7G8LdoiC3ReyAQ== + dependencies: + cookie "^1.0.1" + set-cookie-parser "^2.6.0" + react-scripts@5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.1.tgz#6285dbd65a8ba6e49ca8d651ce30645a6d980003" @@ -8564,6 +8613,11 @@ serve-static@1.16.2: parseurl "~1.3.3" send "0.19.0" +set-cookie-parser@^2.6.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz#3016f150072202dfbe90fadee053573cc89d2943" + integrity sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ== + set-function-length@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"