From fb330d94a14047146477f1e0b81bbf014e61e059 Mon Sep 17 00:00:00 2001 From: Henry Hiles Date: Sat, 29 Jul 2023 20:24:09 -0400 Subject: [PATCH] Working, now work on responsiveness --- src/App.test.jsx | 17 ++++- src/components/BookingForm.jsx | 101 ++++++++++++++++++++-------- src/components/Footer.jsx | 22 +++--- src/components/Main.jsx | 56 ++++++++++----- src/components/Special.jsx | 2 +- src/routes/BookingPage.jsx | 14 +++- src/routes/ConfirmedBookingPage.jsx | 10 +++ src/styles/BookingForm.css | 7 ++ src/styles/ConfirmedBookingPage.css | 7 ++ 9 files changed, 176 insertions(+), 60 deletions(-) create mode 100644 src/routes/ConfirmedBookingPage.jsx create mode 100644 src/styles/ConfirmedBookingPage.css diff --git a/src/App.test.jsx b/src/App.test.jsx index 76119ee..1fca331 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -1,10 +1,21 @@ import { render, screen } from "@testing-library/react" -import { describe, expect } from "vitest" -import { BookingForm } from "./components/BookingForm.jsx" +import { BookingForm } from "./components/BookingForm" +import "@testing-library/jest-dom" +import { initializeTimes, updateTimes } from "./components/Main" -describe("Renders the BookingForm heading", () => { +test("Renders the BookingForm heading", () => { const availableTimes = ["17:00"] render() const headingElement = screen.getByText("Choose date") expect(headingElement).toBeInTheDocument() }) + +test("Returns a correct array of times", () => { + expect(initializeTimes()).toHaveLength(6) + expect(initializeTimes()[0]).toMatch(/\d{2}:\d{2}/) +}) + +test("Returns the same value provided in the state", () => { + const times = initializeTimes() + expect(updateTimes(times, "2022-02-04")).toBe(times) +}) diff --git a/src/components/BookingForm.jsx b/src/components/BookingForm.jsx index 60eddf3..c6c12d6 100644 --- a/src/components/BookingForm.jsx +++ b/src/components/BookingForm.jsx @@ -1,43 +1,84 @@ import { useState } from "react" import "../styles/BookingForm.css" -export const BookingForm = ({ availableTimes, dispatch }) => { +export const BookingForm = ({ + availableTimes, + dispatch, + submitForm, + reservationError +}) => { const [date, setDate] = useState(new Date().toISOString().slice(0, 10)) const [time, setTime] = useState(availableTimes[0]) const [guests, setGuests] = useState(1) - const [occasion, setOccasion] = useState("None") + const [occasion, setOccasion] = useState("Other") + + const [dateError, setDateError] = useState("") + const [timeError, setTimeError] = useState("") + const [guestsError, setGuestsError] = useState("") + const [occasionError, setOccasionError] = useState("") + + const isFormInvalid = () => + guestsError !== "" || + dateError !== "" || + timeError !== "" || + occasionError !== "" + + const onDateChange = ({ target }) => { + let error = "" + if (target.value === "") error = "Field is required" + setDateError(error) + setDate(target.value) + if (!error) dispatch(target.valueAsDate) + } + + const onTimeChange = ({ target }) => { + let error = "" + if (target.value === "") error = "Field is required" + setTimeError(error) + setTime(target.value) + } + + const onGuestChange = ({ target }) => { + let error = "" + if (target.value === "") error = "Field is required" + else if (target.value < 1 || target.value > 10) + error = "Guests must be between 1 and 10." + setGuestsError(error) + setGuests(target.value) + } + + const onOccasionChange = ({ target }) => { + let error = "" + if (target.value === "") error = "Field is required" + else if ( + target.value !== "Other" && + target.value !== "Birthday" && + target.value !== "Anniversary" + ) + error = "Invalid occasion." + setOccasionError(error) + setOccasion(target.value) + } return ( -
{ - event.preventDefault() - console.log(date, time, guests, occasion) - }} - > - + + { - setDate(event.target.value) - dispatch(event.target.value) - }} + onChange={onDateChange} type="date" - id="res-date" + id="date" /> + {dateError !== "" && {dateError}} - {availableTimes.map((time) => ( ))} + {timeError !== "" && {timeError}} { max="10" id="guests" value={guests} - onChange={(event) => setGuests(event.target.value)} + onChange={onGuestChange} /> + {guestsError !== "" && {guestsError}} - + + {occasionError !== "" && ( + {occasionError} + )} + {reservationError !== "" && ( + {reservationError} + )}
) } diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx index d58ddbf..4df41ba 100644 --- a/src/components/Footer.jsx +++ b/src/components/Footer.jsx @@ -6,24 +6,24 @@ export const Footer = () => ( Little Lemon Logo

Doormat Navigation

- Home - About - Menu + Home + About + Menu Reserve a table - Order Online - Login + Order online + Login

Contact

- Address - Phone number - Email + Address + Phone number + Email

Social Media Links

- Twitter - Instagram - Threads + Twitter + Instagram + Threads
) diff --git a/src/components/Main.jsx b/src/components/Main.jsx index 3277d72..0c0d0d3 100644 --- a/src/components/Main.jsx +++ b/src/components/Main.jsx @@ -2,39 +2,65 @@ import { Route } from "react-router-dom" import { Routes } from "react-router-dom" import { HomePage } from "../routes/HomePage" import { BookingPage } from "../routes/BookingPage" -import { useReducer } from "react" +import { useReducer, useState } from "react" +import { ConfirmedBookingPage } from "../routes/ConfirmedBookingPage" +import { useNavigate } from "react-router-dom" + +export const initializeTimes = () => [ + "17:00", + "18:00", + "19:00", + "20:00", + "21:00", + "22:00" +] + +export const updateTimes = (_, date) => { + // API provided returns 404, so unable to post data. Mocking return instead. + const day = date.getDay() + const initialTimes = initializeTimes() + if (day === 0) return initialTimes.slice(0, 3) + if (day === 1) return initialTimes.slice(2, 5) + if (day === 2) return initialTimes.slice(4, 5) + if (day === 3) return initialTimes.slice(3, 5) + if (day === 4) return initialTimes.slice(1, 5) + if (day === 5) return initialTimes.slice(3, 3) + if (day === 6) return initialTimes.slice(1, 5) +} export const Main = () => { - const initializeTimes = () => [ - "17:00", - "18:00", - "19:00", - "20:00", - "21:00", - "22:00" - ] - - const updateTimes = (times, date) => { - console.log(times, date) - return times - } - + const navigate = useNavigate() const [availableTimes, dispatch] = useReducer( updateTimes, initializeTimes() ) + const [reservationError, setReservationError] = useState("") + + const submitForm = (event) => { + event.preventDefault() + // API provided returns 404, so unable to post data. Mocking return instead. + if (Math.random() > 0.8) + setReservationError("Unable to book reservation. Please try again.") + else navigate("/confirmed") + } return ( <>
} /> + } + /> } /> diff --git a/src/components/Special.jsx b/src/components/Special.jsx index a87fb4f..700b801 100644 --- a/src/components/Special.jsx +++ b/src/components/Special.jsx @@ -3,7 +3,7 @@ import "../styles/Special.css" export const Special = ({ image, title, price, children }) => (
- Picture of Food + Food

{title}

diff --git a/src/routes/BookingPage.jsx b/src/routes/BookingPage.jsx index 2f95efc..515e37f 100644 --- a/src/routes/BookingPage.jsx +++ b/src/routes/BookingPage.jsx @@ -1,10 +1,20 @@ import { BookingForm } from "../components/BookingForm" import "../styles/BookingPage.css" -export const BookingPage = ({ availableTimes, dispatch }) => ( +export const BookingPage = ({ + availableTimes, + dispatch, + submitForm, + reservationError +}) => (

Book a Table


- +
) diff --git a/src/routes/ConfirmedBookingPage.jsx b/src/routes/ConfirmedBookingPage.jsx new file mode 100644 index 0000000..5096a06 --- /dev/null +++ b/src/routes/ConfirmedBookingPage.jsx @@ -0,0 +1,10 @@ +import { Link } from "react-router-dom" +import "../styles/ConfirmedBookingPage.css" + +export const ConfirmedBookingPage = () => ( +
+

Booking Confirmed

+

Your booking has been confirmed.

+ Back to home +
+) diff --git a/src/styles/BookingForm.css b/src/styles/BookingForm.css index 8f194bb..82580f7 100644 --- a/src/styles/BookingForm.css +++ b/src/styles/BookingForm.css @@ -2,6 +2,7 @@ display: flex; flex-direction: column; gap: 0.2rem; + min-width: 20rem; } .booking-form :is(label, .submit) { @@ -19,3 +20,9 @@ .booking-form .submit { background-color: #fbdabb; } + +.booking-form .error { + color: rgb(255, 152, 152); + font-weight: bold; + margin: 0.5rem 0; +} diff --git a/src/styles/ConfirmedBookingPage.css b/src/styles/ConfirmedBookingPage.css new file mode 100644 index 0000000..eb1e3d7 --- /dev/null +++ b/src/styles/ConfirmedBookingPage.css @@ -0,0 +1,7 @@ +.confirmed { + background-color: var(--primary-1); + border-radius: 2rem; + margin: auto; + padding: 2rem 3rem; + text-align: center; +}