mirror of
https://github.com/UofCBaja/BajaUofCWebsite.git
synced 2025-06-16 05:44:17 -06:00
feat(InterviewBooking): added error handing, button css and defined select on date
This commit is contained in:
parent
6aade88454
commit
aa8e5c2577
@ -1,84 +1,122 @@
|
|||||||
:root {
|
:root {
|
||||||
--interviewspacing: clamp(5px, 2.5svw, 200px);
|
--interviewspacing: clamp(5px, 2.5svw, 200px);
|
||||||
--interviewwidth: 260px;
|
--interviewwidth: 260px;
|
||||||
}
|
}
|
||||||
#InterviewBooking header {
|
#InterviewBooking header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
background-color: lightslategray;
|
background-color: lightslategray;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
#InterviewForm {
|
#InterviewForm {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
#InterviewForm div {
|
#InterviewForm div {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding-left: var(--interviewspacing);
|
padding-left: var(--interviewspacing);
|
||||||
padding-right: var(--interviewspacing);
|
padding-right: var(--interviewspacing);
|
||||||
text-align: start;
|
text-align: start;
|
||||||
width: var(--interviewwidth);
|
width: var(--interviewwidth);
|
||||||
}
|
}
|
||||||
#InterviewForm div label {
|
#InterviewForm div label {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
#InterviewForm div p {
|
#InterviewForm div p {
|
||||||
font-size: x-small;
|
font-size: x-small;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
#InterviewForm div input {
|
#InterviewForm div input {
|
||||||
margin-top: 1svh;
|
margin-top: 1svh;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
#MainForm {
|
#MainForm {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
#MainForm form {
|
#MainForm form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
}
|
}
|
||||||
#TimeSlotSelector {
|
#TimeSlotSelector {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.TimeSlot {
|
.TimeSlot {
|
||||||
padding-left: var(--interviewspacing);
|
padding-left: var(--interviewspacing);
|
||||||
padding-right: var(--interviewspacing);
|
padding-right: var(--interviewspacing);
|
||||||
width: var(--interviewwidth);
|
width: var(--interviewwidth);
|
||||||
}
|
}
|
||||||
.TimeSlot h4 {
|
.TimeSlot h4 {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
}
|
}
|
||||||
.TimeSlot p {
|
.TimeSlot p {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
#InterviewSubmit {
|
#InterviewSubmit {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: inherit;
|
width: inherit;
|
||||||
}
|
}
|
||||||
#InterviewSubmit button {
|
#InterviewSubmit button {
|
||||||
background-color: lightgreen;
|
background-color: lightgreen;
|
||||||
width: 20%;
|
width: 20%;
|
||||||
height: 5svh;
|
height: 5svh;
|
||||||
margin-bottom: 5svh;
|
margin-bottom: 5svh;
|
||||||
font-size: large;
|
font-size: large;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
#InterviewText {
|
#InterviewText {
|
||||||
padding-left: var(--interviewspacing);
|
padding-left: var(--interviewspacing);
|
||||||
padding-right: var(--interviewspacing);
|
padding-right: var(--interviewspacing);
|
||||||
width: 80%;
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* used for editing time buttons */
|
||||||
|
--TimeSlotSideWidth: 48%;
|
||||||
|
--TimeSlotSidePaddingTopBottom: 1svh 0px;
|
||||||
|
--TimeSlotSideMarginTopBottom: 0.25svh 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TimeSlotSide0 {
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
width: var(--TimeSlotSideWidth);
|
||||||
|
|
||||||
|
padding: var(--TimeSlotSidePaddingTopBottom);
|
||||||
|
margin: var(--TimeSlotSideMarginTopBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
.TimeSlotSide1 {
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
width: var(--TimeSlotSideWidth);
|
||||||
|
|
||||||
|
padding: var(--TimeSlotSidePaddingTopBottom);
|
||||||
|
margin: var(--TimeSlotSideMarginTopBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
#interviewLoading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
height: 334.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#CurrentSelected {
|
||||||
|
background-color: lightseagreen;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useState, useRef } from "react";
|
import { useState, useRef } from "react";
|
||||||
import TimeDateSelector from "./TimeDateSelector"; // Import the TimeSlotSelector component
|
import TimeDateSelector from "./TimeDateSelector";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {null} null - Takes in nothing
|
* @param {null} null - Takes in nothing
|
||||||
@ -10,149 +10,181 @@ import TimeDateSelector from "./TimeDateSelector"; // Import the TimeSlotSelecto
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const InterviewForm = () => {
|
const InterviewForm = () => {
|
||||||
const [isButtonDisabled, setIsButtonDisabled] = useState(false);
|
const [isButtonDisabled, setIsButtonDisabled] = useState(false);
|
||||||
const dialogRef = useRef(null);
|
const dialogRef = useRef(null);
|
||||||
const [selectedTimeSlot, setSelectedTimeSlot] = useState(null);
|
const [selectedTimeSlot, setSelectedTimeSlot] = useState(null);
|
||||||
const [getTimeDates, setGetTimeDates] = useState("");
|
const [getTimeDates, setGetTimeDates] = useState("");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String HTML} event - Takes in form info
|
* @param {String HTML} event - Takes in form info
|
||||||
* @returns {null} null - Returns in nothing
|
* @returns {null} null - Returns in nothing
|
||||||
* @description
|
* @description submits the form with the appropriate information
|
||||||
* @author Ahmad <ahmadmuhammadofficial@gmail.com>
|
* @author Ahmad <ahmadmuhammadofficial@gmail.com>
|
||||||
* @todo CSS
|
* @todo imporper email and other erros from backend
|
||||||
*/
|
*/
|
||||||
const formsubmit = async (event) => {
|
const formsubmit = async (event) => {
|
||||||
event.preventDefault();
|
const errorLine = document.getElementById("InterviewError");
|
||||||
|
|
||||||
if (!selectedTimeSlot) {
|
event.preventDefault();
|
||||||
alert("Please select a time slot!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable button to stop multiple requests
|
if (selectedTimeSlot) {
|
||||||
setIsButtonDisabled(true);
|
console.log(selectedTimeSlot);
|
||||||
|
if (selectedTimeSlot.date !== null && selectedTimeSlot.startTime !== "") {
|
||||||
|
errorLine.innerHTML = " ";
|
||||||
|
// disable button to stop multiple requests
|
||||||
|
setIsButtonDisabled(true);
|
||||||
|
|
||||||
// await new Promise((res) => setTimeout(res, 1000));
|
// await new Promise((res) => setTimeout(res, 1000));
|
||||||
const formData = new FormData(event.target);
|
const formData = new FormData(event.target);
|
||||||
const formObject = Object.fromEntries(formData.entries());
|
const formObject = Object.fromEntries(formData.entries());
|
||||||
formObject.date = selectedTimeSlot["date"]; // Add the selected time slot to form data
|
formObject.date = selectedTimeSlot["date"]; // Add the selected time slot to form data
|
||||||
formObject.startTime = selectedTimeSlot["startTime"];
|
formObject.startTime = selectedTimeSlot["startTime"];
|
||||||
console.log("Form Data:", formObject);
|
console.log("Form Data:", formObject);
|
||||||
const res = await fetch(
|
|
||||||
"https://bajabackend.bajacloud.duckdns.org/SelectInterview",
|
|
||||||
{
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(formObject),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
// const res = await fetch(
|
|
||||||
// "http://127.0.0.1:8000/SelectInterview",
|
|
||||||
// {
|
|
||||||
// method: "POST",
|
|
||||||
// headers: {
|
|
||||||
// "Content-Type": "application/json",
|
|
||||||
// },
|
|
||||||
// body: JSON.stringify(formObject),
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
let data = await res.json();
|
const res = await fetch(
|
||||||
|
"https://bajabackend.bajacloud.duckdns.org/SelectInterview",
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(formObject),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// const res = await fetch(
|
||||||
|
// "http://127.0.0.1:8000/SelectInterview",
|
||||||
|
// {
|
||||||
|
// method: "POST",
|
||||||
|
// headers: {
|
||||||
|
// "Content-Type": "application/json",
|
||||||
|
// },
|
||||||
|
// body: JSON.stringify(formObject),
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
if (data["body"]["Success"] === true) {
|
let data = await res.json();
|
||||||
dialogRef.current.showModal();
|
|
||||||
} else {
|
|
||||||
setGetTimeDates(getTimeDates + "i");
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsButtonDisabled(false);
|
if (data["body"]["Success"] === true) {
|
||||||
};
|
dialogRef.current.showModal();
|
||||||
|
} else {
|
||||||
|
setGetTimeDates(getTimeDates + "i");
|
||||||
|
}
|
||||||
|
x;
|
||||||
|
} else {
|
||||||
|
formSubmitTimeErorrs(selectedTimeSlot, errorLine);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
formSubmitTimeErorrs(selectedTimeSlot, errorLine);
|
||||||
|
}
|
||||||
|
setIsButtonDisabled(false);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
/**
|
||||||
<>
|
* @param {Object} missingError - Takes in object to find what is missing from it
|
||||||
<form onSubmit={formsubmit}>
|
* @param {HTMLSelectElement} - display line on page
|
||||||
<div id="InterviewForm">
|
* @returns {null} null - Returns in nothing
|
||||||
<div>
|
* @description A separated function to handle all timeslot errors possible states and displays the appropriate message on the error line
|
||||||
<label for="name">Name:</label>
|
* @author Brock <darkicewolf50@gmail.com>
|
||||||
<input
|
*/
|
||||||
type="text"
|
const formSubmitTimeErorrs = (missingError, errorLine) => {
|
||||||
id="fname"
|
if (!missingError) {
|
||||||
name="intervieweeName"
|
errorLine.innerHTML = "Please Select a Date and a Time";
|
||||||
placeholder="Jaeinceins"
|
}
|
||||||
required
|
// impossible state
|
||||||
/>
|
/*
|
||||||
<p>(what to call you)</p>
|
else if (missingError.date === null) {
|
||||||
</div>
|
errorLine.innerHTML = "Please Select a Date";
|
||||||
<div>
|
*/
|
||||||
<label for="email">UCalgary Email:</label>
|
else if (missingError.startTime) {
|
||||||
<input
|
errorLine.innerHTML = "Please Select a Time";
|
||||||
type="text"
|
}
|
||||||
id="email"
|
};
|
||||||
name="intervieweeEmail"
|
return (
|
||||||
placeholder="jaeinceins.bhaja@ucalgary.ca"
|
<>
|
||||||
required
|
<form onSubmit={formsubmit}>
|
||||||
/>
|
<div id="InterviewForm">
|
||||||
<p>(for interview confirmation email)</p>
|
<div>
|
||||||
</div>
|
<label for="name">Name:</label>
|
||||||
</div>
|
<input
|
||||||
|
type="text"
|
||||||
|
id="fname"
|
||||||
|
name="intervieweeName"
|
||||||
|
placeholder="Jaeinceins"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<p>(what to call you)</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="email">UCalgary Email:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="email"
|
||||||
|
name="intervieweeEmail"
|
||||||
|
placeholder="jaeinceins.bhaja@ucalgary.ca"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<p>(for interview confirmation email)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Time Slot Selector */}
|
{/* Time Slot Selector */}
|
||||||
<TimeDateSelector
|
<TimeDateSelector
|
||||||
onTimeSlotSelect={(timeSlot) => setSelectedTimeSlot(timeSlot)}
|
onTimeSlotSelect={(timeSlot) => setSelectedTimeSlot(timeSlot)}
|
||||||
timeDateSelectorGet={getTimeDates}
|
timeDateSelectorGet={getTimeDates}
|
||||||
/>
|
/>
|
||||||
<div id="InterviewText">
|
<div id="InterviewText">
|
||||||
<h4>
|
<h4>
|
||||||
What to do if I cannot make it to any of the avaliable time slots or
|
What to do if I cannot make it to any of the avaliable time slots or
|
||||||
need to rescedule?
|
need to rescedule?
|
||||||
</h4>
|
</h4>
|
||||||
<p>
|
<p>
|
||||||
While we highly encourage sceduling an interview in one of the above
|
While we highly encourage sceduling an interview in one of the above
|
||||||
time slots, we recongize that not everyone can make it work with
|
time slots, we recongize that not everyone can make it work with
|
||||||
their personal and university schedules.
|
their personal and university schedules.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Please email us at{" "}
|
Please email us at{" "}
|
||||||
<a href="mailto:uofcbaja@gmail.com">uofcbaja@gmail.com</a> to work
|
<a href="mailto:uofcbaja@gmail.com">uofcbaja@gmail.com</a> to work
|
||||||
out an alternate interview time or for rescheduling.
|
out an alternate interview time or for rescheduling.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p id="InterviewError"> </p>
|
|
||||||
<div id="InterviewSubmit">
|
|
||||||
<button type="submit" disabled={isButtonDisabled}>
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{/* Success Dialog */}
|
<p id="InterviewError"> </p>
|
||||||
<dialog ref={dialogRef}>
|
|
||||||
{" "}
|
<div id="InterviewSubmit">
|
||||||
{/* Add the `ref` attribute */}
|
<button
|
||||||
<h2>Booking Successful!</h2>
|
type="submit"
|
||||||
<p>
|
disabled={isButtonDisabled}>
|
||||||
Thank you for booking your interview slot. We’ll contact you soon.
|
Submit
|
||||||
</p>
|
</button>
|
||||||
<h4>
|
</div>
|
||||||
What to do if I cannot make it to any of the avaliable time slots or
|
</form>
|
||||||
need to rescedule?
|
|
||||||
</h4>
|
{/* Success Dialog */}
|
||||||
<p>
|
<dialog ref={dialogRef}>
|
||||||
While we highly encourage sceduling an interview in one of the above
|
{" "}
|
||||||
time slots, we recongize that not everyone can make it work with their
|
{/* Add the `ref` attribute */}
|
||||||
personal and university schedules.
|
<h2>Booking Successful!</h2>
|
||||||
</p>
|
<p>
|
||||||
<p>
|
Thank you for booking your interview slot. We’ll contact you soon.
|
||||||
Please email us at{" "}
|
</p>
|
||||||
<a href="mailto:uofcbaja@gmail.com">uofcbaja@gmail.com</a> to work out
|
<h4>
|
||||||
an alternate interview time or for rescheduling.
|
What to do if I cannot make it to any of the avaliable time slots or
|
||||||
</p>
|
need to rescedule?
|
||||||
</dialog>
|
</h4>
|
||||||
</>
|
<p>
|
||||||
);
|
While we highly encourage sceduling an interview in one of the above
|
||||||
|
time slots, we recongize that not everyone can make it work with their
|
||||||
|
personal and university schedules.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Please email us at{" "}
|
||||||
|
<a href="mailto:uofcbaja@gmail.com">uofcbaja@gmail.com</a> to work out
|
||||||
|
an alternate interview time or for rescheduling.
|
||||||
|
</p>
|
||||||
|
</dialog>
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default InterviewForm;
|
export default InterviewForm;
|
||||||
|
@ -2,145 +2,167 @@ import React, { useState, useEffect } from "react";
|
|||||||
import DatePicker from "react-datepicker";
|
import DatePicker from "react-datepicker";
|
||||||
import "react-datepicker/dist/react-datepicker.css";
|
import "react-datepicker/dist/react-datepicker.css";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} onTimeSlotSelect - Used to pass back up the selected values from child component
|
||||||
|
* @param {Function} timeDateSelectorGet - Used to display dates avaialable
|
||||||
|
* @returns {JSX.element} JSX - HTML and JS functionality
|
||||||
|
* @description Used for picking an interview date
|
||||||
|
* @author Ahmad <ahmadmuhammadofficial@gmail.com>
|
||||||
|
*/
|
||||||
export default function TimeDateSelector({
|
export default function TimeDateSelector({
|
||||||
onTimeSlotSelect,
|
onTimeSlotSelect,
|
||||||
timeDateSelectorGet,
|
timeDateSelectorGet,
|
||||||
}) {
|
}) {
|
||||||
const [allDatesAvailable, setAllDatesAvailable] = useState({});
|
const [allDatesAvailable, setAllDatesAvailable] = useState({});
|
||||||
const [selectedDate, setSelectedDate] = useState(null);
|
const [selectedDate, setSelectedDate] = useState(null);
|
||||||
const [timeSlotsAvialable, setTimeSlotsAvialable] = useState([]);
|
const [timeSlotsAvialable, setTimeSlotsAvialable] = useState([]);
|
||||||
const [selectedTime, setSelectedTime] = useState("");
|
const [selectedTime, setSelectedTime] = useState("");
|
||||||
|
const [selectedTimeButton, setSelectedTimeButton] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getInterviewDates();
|
getInterviewDates();
|
||||||
}, [timeDateSelectorGet]);
|
}, [timeDateSelectorGet]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {null} null - Takes in nothing
|
* @param {null} null - Takes in nothing
|
||||||
* @returns {null} null - Returns in nothing
|
* @returns {null} null - Returns in nothing
|
||||||
* @description Gets interview timeslots and dates from backend
|
* @description Gets interview timeslots and dates from backend
|
||||||
* @author Ahmad <ahmadmuhammadofficial@gmail.com>, Brock <darkicewolf50@gmail.com>
|
* @author Ahmad <ahmadmuhammadofficial@gmail.com>, Brock <darkicewolf50@gmail.com>
|
||||||
* @todo refactor to not call backend so much, see useEffect above
|
* @todo refactor to not call backend so much, see useEffect above
|
||||||
*/
|
*/
|
||||||
const getInterviewDates = async () => {
|
const getInterviewDates = async () => {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
"https://bajabackend.bajacloud.duckdns.org/getAppointments",
|
"https://bajabackend.bajacloud.duckdns.org/getAppointments",
|
||||||
{ method: "GET" }
|
{ method: "GET" }
|
||||||
);
|
);
|
||||||
// const res = await fetch(
|
// const res = await fetch(
|
||||||
// "http://127.0.0.1:8000/getAppointments",
|
// "http://127.0.0.1:8000/getAppointments",
|
||||||
// { method: "GET" }
|
// { method: "GET" }
|
||||||
// );
|
// );
|
||||||
let json = await res.json();
|
let json = await res.json();
|
||||||
// console.log(json);
|
// console.log(json);
|
||||||
// can input dates right away, no other requirements to show it
|
// can input dates right away, no other requirements to show it
|
||||||
let dates = await json["body"]["interviewDates"];
|
let dates = await json["body"]["interviewDates"];
|
||||||
setAllDatesAvailable(await dates);
|
setAllDatesAvailable(await dates);
|
||||||
};
|
};
|
||||||
|
|
||||||
// helper section
|
// helper section
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Date} date - Takes in a date object from the date picker
|
* @param {Date} date - Takes in a date object from the date picker
|
||||||
* @returns {null} null - Returns in nothing
|
* @returns {null} null - Returns in nothing
|
||||||
* @description checks if date is available from the backend
|
* @description checks if date is available from the backend
|
||||||
* @author Brock <darkicewolf50@gmail.com>
|
* @author Brock <darkicewolf50@gmail.com>
|
||||||
*/
|
*/
|
||||||
const isDateAvailable = (date) => {
|
const isDateAvailable = (date) => {
|
||||||
return Object.keys(allDatesAvailable).includes(
|
return Object.keys(allDatesAvailable).includes(
|
||||||
date.toISOString().split("T")[0]
|
date.toISOString().split("T")[0]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDateChange = (date) => {
|
const handleDateChange = (date) => {
|
||||||
setSelectedDate(date); // Capture the selected date in date object
|
setSelectedDate(date); // Capture the selected date in date object
|
||||||
const selectedDateStr = date.toISOString().split("T")[0];
|
const selectedDateStr = date.toISOString().split("T")[0];
|
||||||
|
|
||||||
// get and set time slots for a given day
|
// get and set time slots for a given day
|
||||||
setTimeSlotsAvialable(Object.keys(allDatesAvailable[selectedDateStr]));
|
setTimeSlotsAvialable(Object.keys(allDatesAvailable[selectedDateStr]));
|
||||||
setSelectedTime(""); // clear because of date change
|
setSelectedTime(""); // clear because of date change
|
||||||
};
|
// set prematurely for better error messages
|
||||||
|
onTimeSlotSelect({
|
||||||
|
date: selectedDateStr,
|
||||||
|
startTime: selectedTime,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleTimeSlotChange = (e) => {
|
const handleTimeSlotChange = (e) => {
|
||||||
let startTime = e.target.innerHTML;
|
e.currentTarget.id = "CurrentSelected";
|
||||||
setSelectedTime(startTime);
|
|
||||||
|
|
||||||
onTimeSlotSelect({
|
if (selectedTimeButton !== null) {
|
||||||
date: selectedDate.toLocaleDateString(),
|
selectedTimeButton.id = "";
|
||||||
startTime: selectedTime,
|
}
|
||||||
});
|
setSelectedTimeButton(e.currentTarget);
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
let startTime = e.currentTarget.dataset.time;
|
||||||
<div id="TimeSlotSelector">
|
setSelectedTime(startTime);
|
||||||
{Object.keys(allDatesAvailable).length > 0 ? (
|
|
||||||
<>
|
onTimeSlotSelect({
|
||||||
<div className="TimeSlot">
|
date: selectedDate.toLocaleDateString(),
|
||||||
<h4>Interview Date</h4>
|
startTime: selectedTime,
|
||||||
<label htmlFor="date-picker">
|
});
|
||||||
<p>Select a Date:</p>
|
};
|
||||||
</label>
|
|
||||||
<DatePicker
|
return (
|
||||||
selected={selectedDate}
|
<div id="TimeSlotSelector">
|
||||||
onChange={handleDateChange}
|
{Object.keys(allDatesAvailable).length > 0 ? (
|
||||||
inline
|
<>
|
||||||
filterDate={isDateAvailable} // Filter/grey out unavailable dates
|
<div className="TimeSlot">
|
||||||
dateFormat="yyyy-MM-dd"
|
<h4>Interview Date</h4>
|
||||||
required // Make date selection required
|
<label htmlFor="date-picker">
|
||||||
/>
|
<p>Select a Date:</p>
|
||||||
</div>
|
</label>
|
||||||
<div className="TimeSlot">
|
<DatePicker
|
||||||
<h4>Interview Time</h4>
|
selected={selectedDate}
|
||||||
{!selectedDate ? (
|
onChange={handleDateChange}
|
||||||
<>
|
inline
|
||||||
<p>Available Time Slots:</p>
|
filterDate={isDateAvailable} // Filter/grey out unavailable dates
|
||||||
<div
|
dateFormat="yyyy-MM-dd"
|
||||||
style={{
|
required // Make date selection required
|
||||||
height: "241.633px",
|
/>
|
||||||
display: "flex",
|
</div>
|
||||||
alignItems: "center",
|
<div className="TimeSlot">
|
||||||
}}
|
<h4>Interview Time</h4>
|
||||||
>
|
{!selectedDate ? (
|
||||||
<p>Please select the a date to see time slots.</p>
|
<>
|
||||||
</div>
|
<p>Available Time Slots:</p>
|
||||||
</>
|
<div
|
||||||
) : (
|
style={{
|
||||||
<>
|
height: "241.633px",
|
||||||
<label htmlFor="time-picker">
|
display: "flex",
|
||||||
<p>
|
alignItems: "center",
|
||||||
Available Time Slots for{" "}
|
}}>
|
||||||
{selectedDate.toISOString().split("T")[0]}:
|
<p>Please select the a date to see time slots.</p>
|
||||||
</p>
|
</div>
|
||||||
</label>
|
</>
|
||||||
{selectedDate === undefined ? (
|
) : (
|
||||||
<>
|
<>
|
||||||
<p>Please select a date.</p>
|
<label htmlFor="time-picker">
|
||||||
</>
|
<p>
|
||||||
) : timeSlotsAvialable !== "" ? (
|
Available Time Slots for{" "}
|
||||||
<>
|
{selectedDate.toISOString().split("T")[0]}:
|
||||||
{Object.values(timeSlotsAvialable).map((time) => {
|
</p>
|
||||||
return (
|
</label>
|
||||||
<button
|
{selectedDate === undefined ? (
|
||||||
key={time}
|
<>
|
||||||
type="button"
|
<p>Please select a date.</p>
|
||||||
onClick={(self) => {
|
</>
|
||||||
handleTimeSlotChange(self);
|
) : timeSlotsAvialable !== "" ? (
|
||||||
}}
|
<>
|
||||||
>
|
{Object.values(timeSlotsAvialable).map((time) => {
|
||||||
{time}
|
// console.log(timeSlotsAvialable.indexOf(time));
|
||||||
</button>
|
return (
|
||||||
);
|
<button
|
||||||
})}
|
className={
|
||||||
</>
|
"TimeSlotSide" +
|
||||||
) : (
|
(timeSlotsAvialable.indexOf(time) % 2)
|
||||||
<>
|
}
|
||||||
<p>No available time slots for the selected date.</p>
|
key={time}
|
||||||
</>
|
type="button"
|
||||||
)}
|
data-time={time}
|
||||||
</>
|
onClick={handleTimeSlotChange}>
|
||||||
)}
|
{time.slice(0, 5)}
|
||||||
</div>
|
</button>
|
||||||
{/* {selectedDate && selectedTime && (
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<p>No available time slots for the selected date.</p>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{/* {selectedDate && selectedTime && (
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
You have selected:
|
You have selected:
|
||||||
@ -150,10 +172,10 @@ export default function TimeDateSelector({
|
|||||||
Time: {selectedTime}
|
Time: {selectedTime}
|
||||||
</p>
|
</p>
|
||||||
</div>)} */}
|
</div>)} */}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<p>Loading ...</p>
|
<p id="interviewLoading">Loading ...</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user