From 507251e4d59cb5fe7fcd52e3f3ecdd50d0db480c Mon Sep 17 00:00:00 2001 From: Nola Dodd Date: Thu, 30 May 2024 10:43:49 -0700 Subject: [PATCH] tests 1, 2, 3 pass --- back-end/package-lock.json | 20 ++++ back-end/package.json | 1 + back-end/src/db/seeds/00-reservations.json | 50 +++++++++ .../reservations/reservations.controller.js | 104 ++++++++---------- .../src/reservations/reservations.service.js | 12 +- front-end/src/layout/CreateEditReservation.js | 27 +++-- front-end/src/utils/api.js | 30 +++-- package-lock.json | 14 +++ package.json | 1 + 9 files changed, 178 insertions(+), 81 deletions(-) diff --git a/back-end/package-lock.json b/back-end/package-lock.json index 3a69b0b..96519cf 100644 --- a/back-end/package-lock.json +++ b/back-end/package-lock.json @@ -14,6 +14,7 @@ "express": "^4.17.1", "knex": "^0.21.12", "moment": "^2.30.1", + "moment-timezone": "^0.5.45", "nanoid": "^3.1.20", "npm-run-all": "^4.1.5", "pg": "^8.5.1", @@ -7301,6 +7302,17 @@ "node": "*" } }, + "node_modules/moment-timezone": { + "version": "0.5.45", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz", + "integrity": "sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, "node_modules/mri": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", @@ -16205,6 +16217,14 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" }, + "moment-timezone": { + "version": "0.5.45", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz", + "integrity": "sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==", + "requires": { + "moment": "^2.29.4" + } + }, "mri": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", diff --git a/back-end/package.json b/back-end/package.json index a6fcce8..1ab39d2 100644 --- a/back-end/package.json +++ b/back-end/package.json @@ -33,6 +33,7 @@ "express": "^4.17.1", "knex": "^0.21.12", "moment": "^2.30.1", + "moment-timezone": "^0.5.45", "nanoid": "^3.1.20", "npm-run-all": "^4.1.5", "pg": "^8.5.1", diff --git a/back-end/src/db/seeds/00-reservations.json b/back-end/src/db/seeds/00-reservations.json index 60c5ad3..5d69c1f 100644 --- a/back-end/src/db/seeds/00-reservations.json +++ b/back-end/src/db/seeds/00-reservations.json @@ -48,5 +48,55 @@ "people": 2, "created_at": "2020-12-10T08:31:32.326Z", "updated_at": "2020-12-10T08:31:32.326Z" + }, + { + "first_name": "Clark", + "last_name": "Kent", + "mobile_number": "620-346-4852", + "reservation_date": "2024-05-30", + "reservation_time": "18:00", + "people": 2, + "created_at": "2024-05-29T08:31:32.326Z", + "updated_at": "2024-05-29T08:31:32.326Z" + }, + { + "first_name": "Bruce", + "last_name": "Wayne", + "mobile_number": "212-453-4792", + "reservation_date": "2024-05-31", + "reservation_time": "13:00", + "people": 1, + "created_at": "2024-05-29T08:31:32.326Z", + "updated_at": "2024-05-29T08:31:32.326Z" + }, + { + "first_name": "Peter", + "last_name": "Parker", + "mobile_number": "215-147-9053", + "reservation_date": "2024-06-01", + "reservation_time": "10:40", + "people": 4, + "created_at": "2024-05-29T08:31:32.326Z", + "updated_at": "2024-05-29T08:31:32.326Z" + }, + { + "first_name": "Diana", + "last_name": "Prince", + "mobile_number": "808-333-4819", + "reservation_date": "2024-06-02", + "reservation_time": "14:00", + "people": 3, + "created_at": "2024-05-29T08:31:32.326Z", + "updated_at": "2024-05-29T08:31:32.326Z" + }, + { + "first_name": "Mickey", + "last_name": "Mouse", + "mobile_number": "714-222-2468", + "reservation_date": "2024-06-03", + "reservation_time": "12:00", + "people": 6, + "created_at": "2024-05-29T08:31:32.326Z", + "updated_at": "2024-05-29T08:31:32.326Z" } ] diff --git a/back-end/src/reservations/reservations.controller.js b/back-end/src/reservations/reservations.controller.js index acf77d5..638248c 100644 --- a/back-end/src/reservations/reservations.controller.js +++ b/back-end/src/reservations/reservations.controller.js @@ -3,33 +3,26 @@ */ const asyncErrorBoundary = require("../errors/asyncErrorBoundary"); const service = require("./reservations.service") -const moment = require("moment") +const moment = require("moment-timezone") -async function list(req, res) { - res.json({ - data: await service.list(), - }); -} - -function filterByDate(req, res, next) { - const { date } = req.query; - const { reservation_date } = req.body.data; - if (date !== reservation_date) { - return next({status: 400, message: "No reservations found for the given date"}); +async function list(req, res, next) { + const {date} = req.query + console.log("list date", date) + let reservations + + if (date){ + reservations = await service.listByDate(date) + } else { + reservations = await service.list() } - next(); -} - -function getReservations(req, res, next) { - let reservations = []; // Fetch reservations from your database - - reservations.sort((a, b) => { - return new Date(`1970/01/01 ${a.reservation_time}`) - new Date(`1970/01/01 ${b.reservation_time}`); - }); + if (reservations.length <= 0){ + return next({status: 400, message: "No reservations found for the given date"}) + } else { + res.json({ data: reservations }); + } - res.json({ data: reservations }); } async function create (req, res){ @@ -37,22 +30,41 @@ async function create (req, res){ res.status(201).json({data}) } +function correctTimesOnly(req, res, next){ + const {data} = req.body // Define 'data' here + + // Parse the reservation date and time in the server's time zone + const reservationDateTime = moment.tz(`${data.reservation_date}T${data.reservation_time}`, 'America/Los_Angeles'); + const today = moment.tz('America/Los_Angeles'); + + // Check if the reservation date is a Tuesday + if (reservationDateTime.day() === 2) { + return next({ status: 400, message: "The restaurant is closed on Tuesdays." }); + } + + // Check if the reservation time is before 10:30 AM or after 9:30 PM + const reservationHour = reservationDateTime.hour(); + const reservationMinutes = reservationDateTime.minutes(); + if (reservationHour < 10 || (reservationHour === 10 && reservationMinutes < 30) || reservationHour > 21 || (reservationHour === 21 && reservationMinutes > 30)) { + return next({ status: 400, message: "Reservations are only allowed between 10:30 AM and 9:30 PM." }); + } + + //Check if the reservation date and time is in the past + if (reservationDateTime.isBefore(today)) { + return next({ status: 400, message: "Only future reservations are allowed." }); + } + + next() +} + + + + async function read(req, res){ const data = res.locals.reservation_id res.json({data}) } -async function listReservationsByDate(req, res, next){ - console.log("listReservationsByDate") - let {date} = req.query - if (!date) { - date = moment().format('YYYY-MM-DD') // use 'YYYY-MM-DD' format - } - console.log("date", date) - const data = await service.listReservationsByDate(date); - res.json({data}); -} - function reservationExists(req, res, next){ service.read(req.params.reservation_id) .then((reservation) => { @@ -65,26 +77,6 @@ function reservationExists(req, res, next){ .catch(next) } -function correctTimesOnly(req, res, next){ - const {data: {}} = req.body - console.log(data) - - // Extract the reservation date from the data - const reservationDate = new Date(data.reservation_date); - const today = new Date(); - - // Check if the reservation date is a Tuesday - if (reservationDate.getUTCDay() === 2) { - return next({ status: 400, message: "The restaurant is closed on Tuesdays." }); - } - - //Check if the reservation date is in the past - if (reservationDate.setHours(0,0,0,0) < today.setHours(0,0,0,0)) { - return next({ status: 400, message: "Only future reservations are allowed." }); - } - next() -} - function isValidTime(time) { const timeFormat = /^([01]\d|2[0-3]):([0-5]\d)$/; return timeFormat.test(time) @@ -130,12 +122,8 @@ function propertiesExist(req, res, next){ - - - - module.exports = { list: [asyncErrorBoundary(list)], - create: [propertiesExist, asyncErrorBoundary(create)], + create: [propertiesExist, correctTimesOnly, asyncErrorBoundary(create)], read: [asyncErrorBoundary(read)] }; diff --git a/back-end/src/reservations/reservations.service.js b/back-end/src/reservations/reservations.service.js index 95761bf..f8b62fd 100644 --- a/back-end/src/reservations/reservations.service.js +++ b/back-end/src/reservations/reservations.service.js @@ -1,7 +1,16 @@ const knex = require("../db/connection") function list (){ - return knex("reservations").select("*") + return knex("reservations") + .select("*") + .orderBy("reservation_time", "asc") +} + +function listByDate(date){ +return knex("reservations") + .select("*") + .where({reservation_date: date}) + .orderBy("reservation_time", "asc") } function create(newReservation){ @@ -19,6 +28,7 @@ function list (){ module.exports = { list, + listByDate, create, read } \ No newline at end of file diff --git a/front-end/src/layout/CreateEditReservation.js b/front-end/src/layout/CreateEditReservation.js index eec7381..35b83c4 100644 --- a/front-end/src/layout/CreateEditReservation.js +++ b/front-end/src/layout/CreateEditReservation.js @@ -1,6 +1,7 @@ import React, {useState } from "react"; import {Link, useNavigate} from "react-router-dom" import { createReservation } from "../utils/api"; +import ErrorAlert from "./ErrorAlert"; function CreateEditReservation(){ const initialFormState ={ @@ -13,7 +14,7 @@ function CreateEditReservation(){ } const [formData, setFormData] = useState({...initialFormState}) - console.log(formData) + const [formError, setFormError] = useState(null); const handleChange = ({target}) => { setFormData({...formData, [target.name]: target.value}) @@ -24,10 +25,16 @@ function CreateEditReservation(){ const handleSubmit = async (event) => { console.log("handleSubmit") event.preventDefault() - setFormData(initialFormState) - createReservation(formData) - navigate(`/dashboard`) - } + + try { + await createReservation(formData); + setFormData(initialFormState); + navigate(`/dashboard`); + } catch (error) { + setFormError(error) + } + } + const handleEdit = async (event) => { console.log("handleEdit") @@ -121,7 +128,7 @@ function CreateEditReservation(){ type="number" name="people" min="1" - onChange={handleChange} + onChange={handleChange} value={formData.people} required /> @@ -130,13 +137,13 @@ function CreateEditReservation(){ Cancel - - + + ) -return ( - createReservationForm +return ( + createReservationForm ) diff --git a/front-end/src/utils/api.js b/front-end/src/utils/api.js index bd4c549..646fc7c 100644 --- a/front-end/src/utils/api.js +++ b/front-end/src/utils/api.js @@ -59,13 +59,14 @@ async function fetchJson(url, options, onCancel) { */ export async function listReservations(params, signal) { - const url = new URL(`${API_BASE_URL}/reservations`); - Object.entries(params).forEach(([key, value]) => + const url = new URL(`${API_BASE_URL}/reservations`); + Object.entries(params).forEach(([key, value]) => url.searchParams.append(key, value.toString()) - ); + ) return await fetchJson(url, { headers, signal }, []) .then(formatReservationDate) .then(formatReservationTime); + } @@ -75,13 +76,18 @@ export async function listReservations(params, signal) { * a promise that resolves to the saved reservation, which will now have an 'id' property. */ export async function createReservation(reservation, signal) { - const url = `${API_BASE_URL}/reservations`; - reservation.people = Number(reservation.people); - const options = { - method: "POST", - headers, - body: JSON.stringify({ data: reservation }), - signal, - }; - return await fetchJson(url, options, reservation); + try{ + const url = `${API_BASE_URL}/reservations`; + reservation.people = Number(reservation.people); + const options = { + method: "POST", + headers, + body: JSON.stringify({ data: reservation }), + signal, + }; + return await fetchJson(url, options, reservation); + } catch (error){ + throw error + } + } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 024618a..b29cb4e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "hasInstallScript": true, "license": "UNLICENSED", "dependencies": { + "moment": "^2.30.1", "react-router-dom": "^6.23.1" } }, @@ -39,6 +40,14 @@ "loose-envify": "cli.js" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -125,6 +134,11 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" + }, "react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", diff --git a/package.json b/package.json index 71add39..b88fb45 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "author": "Thinkful, Inc.", "license": "UNLICENSED", "dependencies": { + "moment": "^2.30.1", "react-router-dom": "^6.23.1" } }