From 1f03b29b90309a99d0b782d1520d06c7b9a57256 Mon Sep 17 00:00:00 2001 From: Giovanni de Maria Date: Fri, 13 Dec 2024 19:10:01 +0100 Subject: [PATCH] update of the availability calendar in order to be compliant with project specifications --- .../src/components/AvailabilitiesTable.jsx | 181 +++++------------- frontend/src/pages/AvailabilitiesPage.jsx | 54 ------ package.json | 5 +- pnpm-lock.yaml | 37 +++- 4 files changed, 83 insertions(+), 194 deletions(-) diff --git a/frontend/src/components/AvailabilitiesTable.jsx b/frontend/src/components/AvailabilitiesTable.jsx index 2b31f64..e5d53a9 100644 --- a/frontend/src/components/AvailabilitiesTable.jsx +++ b/frontend/src/components/AvailabilitiesTable.jsx @@ -38,8 +38,8 @@ function AvailabilitiesTable({ authUser }) { startDate: moment("2024-11-18T09:45:00").format(), endDate: moment("2024-11-18T10:30:00").format(), interview: { - status: "published", availabilityId: 0, + howManyInterviewers: 3, interviewers: [ { firstName: "Federico", @@ -60,7 +60,6 @@ function AvailabilitiesTable({ authUser }) { role: "", }, ], - applicant: null, // Slot not taken }, }, { @@ -68,8 +67,8 @@ function AvailabilitiesTable({ authUser }) { startDate: moment("2024-11-20T09:45:00").format(), endDate: moment("2024-11-20T10:30:00").format(), interview: { - status: "booked", availabilityId: 1, + howManyInterviewers: 3, interviewers: [ { firstName: "Federico", @@ -90,11 +89,6 @@ function AvailabilitiesTable({ authUser }) { role: "", }, ], - applicant: { - firstName: "Claudio", - lastName: "Neri", - email: "claudio.neri@hknpolito.org", - }, }, }, { @@ -102,8 +96,8 @@ function AvailabilitiesTable({ authUser }) { startDate: moment("2024-11-21T09:45:00").format(), endDate: moment("2024-11-21T10:30:00").format(), interview: { - status: "draft", availabilityId: 2, + howManyInterviewers: 3, interviewers: [ { firstName: "Federico", @@ -124,7 +118,6 @@ function AvailabilitiesTable({ authUser }) { role: "", }, ], - applicant: null, }, }, { @@ -132,8 +125,8 @@ function AvailabilitiesTable({ authUser }) { startDate: moment("2024-11-22T09:45:00").format(), endDate: moment("2024-11-22T10:30:00").format(), interview: { - status: "draft", availabilityId: 3, + howManyInterviewers: 3, interviewers: [ { firstName: "Federico", @@ -154,12 +147,15 @@ function AvailabilitiesTable({ authUser }) { role: "", }, ], - applicant: null, }, }, ]; const handleAddAvailability = (timeSlotStart, timeSlotEnd) => { + if (timeSlotStart.isBefore(minDate) || timeSlotStart.isAfter(maxDate)) { + console.log("Date out of range. Cannot add availability."); + return; + } console.log( `Adding availability for ${timeSlotStart.format( "dddd D/MM/YYYY" @@ -175,7 +171,7 @@ function AvailabilitiesTable({ authUser }) { endDate: timeSlotEnd.format(), interview: { availabilityId: id, // Unique ID for the availability - status: "draft", + howManyInterviewers: 1, interviewers: [ { firstName: authUser.given_name, @@ -189,7 +185,6 @@ function AvailabilitiesTable({ authUser }) { : "", // Enforce role presence }, ], - applicant: null, // Slot not taken initially }, }; @@ -204,6 +199,7 @@ function AvailabilitiesTable({ authUser }) { ...a, interview: { ...a.interview, + howManyInterviewers: a.interview.howManyInterviewers + 1, interviewers: [ ...a.interview.interviewers, { @@ -220,74 +216,22 @@ function AvailabilitiesTable({ authUser }) { setAvailabilities(updatedAvailabilities); }; - const handleRemoveAvailability = (availabilityId) => { - console.log(`Removing availability with id: ${availabilityId}`); - setAvailabilities( - availabilities.filter((a) => a.availabilityId !== availabilityId) - ); - }; - - const handleUnpublish = (availabilityId) => { - console.log(`Unpublishing availability with ID ${availabilityId}`); - - const updatedAvailabilities = availabilities.map((availability) => - availability.availabilityId === availabilityId - ? { - ...availability, - interview: { - ...availability.interview, - status: "draft", // Change the status to "draft" - }, - } - : availability - ); - - setAvailabilities(updatedAvailabilities); - }; - - const handleRemoveApplicant = (availabilityId) => { - console.log( - `Removing applicant from availability with id: ${availabilityId}` - ); - const updatedAvailabilities = availabilities.map((a) => - a.availabilityId === availabilityId - ? { - ...a, - interview: { - ...a.interview, - applicant: null, // Remove the applicant - status: "published", // Update status to "published" - }, - } - : a - ); - setAvailabilities(updatedAvailabilities); - }; - const renderInterview = (interview) => { const isAuthUserInterviewer = interview.interviewers.some( (interviewer) => interviewer.email === authUser.email ); - const getBackgroundColor = () => { - if (interview.status === "booked") { - return "#f8d7da"; // Red: Applicant present - } else if (interview.status === "published") { - return "#d1e7dd"; // Green: published - } else { - return "#fff3cd"; // Yellow: draft - } - }; return (
- {interview.interviewers && + {isSupervisor && + interview.interviewers && interview.interviewers.map((interviewer) => { if (interviewer.role === "board") { return ( @@ -313,6 +257,12 @@ function AvailabilitiesTable({ authUser }) { } return null; // If the role is unexpected, render nothing })} + {interview.howManyInterviewers && ( +
+ In this slot {`${interview.howManyInterviewers}`} interviewers have + given availability. +
+ )} {interview.applicant && (
@@ -321,25 +271,12 @@ function AvailabilitiesTable({ authUser }) {
)}
- {isAuthUserInterviewer && interview.applicant && ( - - )} - {isSupervisor && ( - - )} {isSupervisor && ( )} - {isAuthUserInterviewer && interview.status === "draft" && ( + {isAuthUserInterviewer && ( )} - {!isAuthUserInterviewer && interview.status === "draft" && ( + {!isAuthUserInterviewer && ( )} - {isSupervisor && interview.applicant && ( - <> - - - )} - - {isSupervisor && interview.status === "published" && ( - - )} - {isSupervisor && interview.status === "draft" && ( - - )}
); }; - const handleMakePublic = (availabilityId) => { - console.log(`Making availability with ID ${availabilityId} public`); - - // Update the status of the selected availability - const updatedAvailabilities = availabilities.map((availability) => - availability.availabilityId === availabilityId - ? { - ...availability, - interview: { - ...availability.interview, - status: "published", // Set the status to "published" - }, - } - : availability - ); - - setAvailabilities(updatedAvailabilities); // Update the state - }; - const handleRemoveInterviewer = (availabilityId, email) => { - console.log(`Removing interviewer with email: ${(authUser, email)}`); + console.log(`Removing interviewer with email: ${email}`); const updatedAvailabilities = availabilities .map((availability) => { @@ -427,11 +318,13 @@ function AvailabilitiesTable({ authUser }) { return null; } - // Otherwise, return the updated availability + // Otherwise, decrement howManyInterviewers and return the updated availability return { ...availability, interview: { ...availability.interview, + howManyInterviewers: + availability.interview.howManyInterviewers - 1, interviewers: updatedInterviewers, }, }; @@ -444,6 +337,9 @@ function AvailabilitiesTable({ authUser }) { setAvailabilities(updatedAvailabilities); }; + const minDate = moment("2024-11-01"); // Earliest date to display + const maxDate = moment("2024-11-30"); // Latest date to display + return ( @@ -467,12 +363,22 @@ function AvailabilitiesTable({ authUser }) { : "Switch to Supervisor View"} + Start of the recruitment session: + {minDate.format("dddd D/MM/YYYY")} +
+ End of the recruitment session: + {maxDate.format("dddd D/MM/YYYY")} +
@@ -483,6 +389,10 @@ function AvailabilitiesTable({ authUser }) { @@ -518,6 +428,13 @@ function AvailabilitiesTable({ authUser }) { )} - ${rowTimeSlotEnd.format("HH:mm")}`} {Array.from({ length: 5 }).map((_, j) => { const day = startDate.clone().add(j, "days"); + + if ( + day.isBefore(minDate, "day") || + day.isAfter(maxDate, "day") + ) { + return ; // Empty cell for out-of-range dates + } const timeSlotStart = day .clone() .startOf("day") diff --git a/frontend/src/pages/AvailabilitiesPage.jsx b/frontend/src/pages/AvailabilitiesPage.jsx index 8831cbc..3258232 100644 --- a/frontend/src/pages/AvailabilitiesPage.jsx +++ b/frontend/src/pages/AvailabilitiesPage.jsx @@ -25,60 +25,6 @@ function AvailabilitiesPage() { Availabilities

This page will be used by members to manage their availabilities.

- {/* Legend */} - - - -
Legend:
-
    -
  • - - Green slots: The slot is visible to the - applicants but it is not taken yet. Applicants can apply for and - interviewers cannot anymore assign themselves to these slots. -
  • -
  • - - Yellow slots: The slot is a draft and is not - visible to the applicants. Interviewers can assign themselves to - these slots. -
  • -
  • - - Red slots: The slot is taken by an applicant. -
  • -
- -
-
- ); diff --git a/package.json b/package.json index 4d14467..11f4bd0 100644 --- a/package.json +++ b/package.json @@ -22,5 +22,8 @@ }, "keywords": [], "author": "", - "license": "ISC" + "license": "ISC", + "dependencies": { + "@mui/icons-material": "^6.1.7" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 35a9a5a..49b88e4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,11 @@ settings: importers: - .: {} + .: + dependencies: + '@mui/icons-material': + specifier: ^6.1.7 + version: 6.1.7(@mui/material@6.1.7(@emotion/react@11.13.3(@types/react@18.3.2)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.2)(react@18.3.1))(@types/react@18.3.2)(react@18.3.1))(@types/react@18.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.2)(react@18.3.1) api: dependencies: @@ -938,6 +942,17 @@ packages: '@mui/core-downloads-tracker@6.1.7': resolution: {integrity: sha512-POuIBi80BZBogQkG4PQKIGwy4QFwB+kOr+OI4k7Znh7LqMAIhwB9OC00l6M+w1GrZJYj3T8R5WX8G6QAIvoVEw==} + '@mui/icons-material@6.1.7': + resolution: {integrity: sha512-RGzkeHNArIVy5ZQ12bq/8VYNeICEyngngsFskTJ/2hYKhIeIII3iRGtaZaSvLpXh7h3Fg3VKTulT+QU0w5K4XQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@mui/material': ^6.1.7 + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@mui/material@6.1.7': resolution: {integrity: sha512-KsjujQL/A2hLd1PV3QboF+W6SSL5QqH6ZlSuQoeYz9r69+TnyBFIevbYLxdjJcJmGBjigL5pfpn7hTGop+vhSg==} engines: {node: '>=14.0.0'} @@ -5013,7 +5028,7 @@ snapshots: '@emotion/babel-plugin@11.12.0': dependencies: '@babel/helper-module-imports': 7.24.3 - '@babel/runtime': 7.24.5 + '@babel/runtime': 7.26.0 '@emotion/hash': 0.9.2 '@emotion/memoize': 0.9.0 '@emotion/serialize': 1.3.2 @@ -5474,6 +5489,14 @@ snapshots: '@mui/core-downloads-tracker@6.1.7': {} + '@mui/icons-material@6.1.7(@mui/material@6.1.7(@emotion/react@11.13.3(@types/react@18.3.2)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.2)(react@18.3.1))(@types/react@18.3.2)(react@18.3.1))(@types/react@18.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.2)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.0 + '@mui/material': 6.1.7(@emotion/react@11.13.3(@types/react@18.3.2)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.2)(react@18.3.1))(@types/react@18.3.2)(react@18.3.1))(@types/react@18.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.2 + '@mui/material@6.1.7(@emotion/react@11.13.3(@types/react@18.3.2)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.2)(react@18.3.1))(@types/react@18.3.2)(react@18.3.1))(@types/react@18.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.26.0 @@ -5738,7 +5761,7 @@ snapshots: '@restart/ui@1.6.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.24.5 + '@babel/runtime': 7.26.0 '@popperjs/core': 2.11.8 '@react-aria/ssr': 3.9.3(react@18.3.1) '@restart/hooks': 0.4.16(react@18.3.1) @@ -6386,7 +6409,7 @@ snapshots: babel-plugin-macros@3.1.0: dependencies: - '@babel/runtime': 7.24.5 + '@babel/runtime': 7.26.0 cosmiconfig: 7.1.0 resolve: 1.22.8 @@ -6774,7 +6797,7 @@ snapshots: date-fns@2.30.0: dependencies: - '@babel/runtime': 7.24.5 + '@babel/runtime': 7.26.0 debug@2.6.9: dependencies: @@ -6846,7 +6869,7 @@ snapshots: dom-helpers@5.2.1: dependencies: - '@babel/runtime': 7.24.5 + '@babel/runtime': 7.26.0 csstype: 3.1.3 dom-serializer@1.4.1: @@ -9560,7 +9583,7 @@ snapshots: uncontrollable@7.2.1(react@18.3.1): dependencies: - '@babel/runtime': 7.24.5 + '@babel/runtime': 7.26.0 '@types/react': 18.3.2 invariant: 2.2.4 react: 18.3.1