feat(TimeDateSelector): better date selector implemented and naming scheme cleaned up to make more sense

This commit is contained in:
darkicewolf50 2025-02-22 12:04:38 -07:00
parent 583be5dcd2
commit 7999abaf25
8 changed files with 7482 additions and 9320 deletions

16416
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,8 +9,8 @@
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-datepicker": "^8.1.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-native": "^0.72.6",
"react-router-dom": "^6.20.0", "react-router-dom": "^6.20.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"

View File

@ -1,6 +1,7 @@
import InterviewForm from "./InterviewForm"; import InterviewForm from "./InterviewForm";
import logo from "../Header/logo.webp"; import logo from "../Header/logo.webp";
import Ender from "../Footer/Ender"; import Ender from "../Footer/Ender";
import DateTimePicker from "./TestDateSelector";
/** /**
* @param {null} null - requires onthing * @param {null} null - requires onthing
* @returns {JSX.Element} Page - HTML tags and JS functionality * @returns {JSX.Element} Page - HTML tags and JS functionality
@ -8,7 +9,7 @@ import Ender from "../Footer/Ender";
* @author Brock <darkicewolf50@gmail.com> * @author Brock <darkicewolf50@gmail.com>
* @todo add who helped developed the site and finalize css * @todo add who helped developed the site and finalize css
*/ */
const InterviewBooking = () => { export default function InterviewBooking () {
return ( return (
<> <>
<img id="logo" src={logo} alt="Schulich Off-Road's logo" /> <img id="logo" src={logo} alt="Schulich Off-Road's logo" />
@ -29,9 +30,10 @@ const InterviewBooking = () => {
<a href="mailto:uofcbaja@gmail.com">uofcbaja@gmail.com</a> to work out <a href="mailto:uofcbaja@gmail.com">uofcbaja@gmail.com</a> to work out
an alternate interview time or for rescheduling. an alternate interview time or for rescheduling.
</p> </p>
{/* <DateTimePicker /> */}
<Ender /> <Ender />
</> </>
); );
}; };
export default InterviewBooking;

View File

@ -1,5 +1,5 @@
import { useEffect, useState, useRef } from "react"; import { useEffect, useState, useRef } from "react";
import TimeSlotSelector from "./TimeSlotSelector"; // Import the TimeSlotSelector component import TimeDateSelector from "./TimeDateSelector"; // Import the TimeSlotSelector component
/** /**
* @param {null} null - Takes in nothing * @param {null} null - Takes in nothing
@ -74,13 +74,14 @@ const InterviewForm = () => {
/> />
{/* Time Slot Selector */} {/* Time Slot Selector */}
<TimeSlotSelector <TimeDateSelector
onTimeSlotSelect={(timeSlot) => setSelectedTimeSlot(timeSlot)} onTimeSlotSelect={(timeSlot) => setSelectedTimeSlot(timeSlot)}
/> />
<button type="submit" disabled={isButtonDisabled}> <button type="submit" disabled={isButtonDisabled}>
Submit Submit
</button> </button>
</form> </form>
{/* Success Dialog */} {/* Success Dialog */}
<dialog ref={dialogRef}> <dialog ref={dialogRef}>
{" "} {" "}

View File

@ -0,0 +1,114 @@
import React, { useState, useEffect } from 'react';
import DatePicker from 'react-datepicker';
import "react-datepicker/dist/react-datepicker.css";
// Mocking the API response
const mockApiResponse = {
body: {
interviewDates: {
'2024-09-16': {
'11:30:00': {
'Meeting Duration': '30 min',
},
},
'2025-02-25': {
'11:00:00': {
'Meeting Duration': '30 min',
},
'11:30:00': {
'Meeting Duration': '30 min',
},
},
'2025-02-15': {
'11:00:00': {
'Meeting Duration': '30 min',
},
},
},
},
};
const DateTimePicker = () => {
const [availableDates, setAvailableDates] = useState([]);
const [selectedDate, setSelectedDate] = useState(null);
const [availableTimes, setAvailableTimes] = useState([]);
const [selectedTime, setSelectedTime] = useState('');
useEffect(() => {
const interviewDates = mockApiResponse.body.interviewDates;
const dates = Object.keys(interviewDates); // Get the available dates
setAvailableDates(dates);
}, []);
// Function to check if a date is available (based on your API data)
const isDateAvailable = (date) => {
return availableDates.includes(date.toISOString().split('T')[0]);
};
// Handle date change
const handleDateChange = (date) => {
setSelectedDate(date);
const selectedDateString = date.toISOString().split('T')[0];
// Get available times for the selected date
const times = Object.keys(mockApiResponse.body.interviewDates[selectedDateString] || {});
setAvailableTimes(times);
setSelectedTime(''); // Reset selected time when date changes
};
// Handle time change
const handleTimeChange = (event) => {
setSelectedTime(event.target.value);
};
return (
<form>
<h2>Select Interview Date and Time</h2>
<label htmlFor="date-picker">Select a date:</label>
<DatePicker
selected={selectedDate}
onChange={handleDateChange}
inline
filterDate={isDateAvailable} // Filter out unavailable dates
dateFormat="yyyy-MM-dd"
required // Make date selection required
/>
{selectedDate && (
<>
<label htmlFor="time-picker">Select a time:</label>
<select
id="time-picker"
value={selectedTime}
onChange={handleTimeChange}
required // Make time selection required
>
<option value="">--Select a time--</option>
{availableTimes.map((time) => (
<option key={time} value={time}>
{time}
</option>
))}
</select>
</>
)}
{selectedDate && selectedTime && (
<div>
<p>
You have selected:
<br />
Date: {selectedDate.toLocaleDateString()}
<br />
Time: {selectedTime}
</p>
</div>
)}
<button type="submit">Submit</button>
</form>
);
};
export default DateTimePicker;

View File

@ -0,0 +1,123 @@
import React, { useState, useEffect } from "react";
import DatePicker from 'react-datepicker';
import "react-datepicker/dist/react-datepicker.css";
export default function TimeDateSelector ({ onTimeSlotSelect }) {
const [allTimeDatesAvailable, setAllTimeDatesAvailable] = useState();
const [allDatesAvailable, setAllDatesAvailable] = useState([]);
const [selectedDate, setSelectedDate] = useState(null);
const [timeSlotsAvialable, setTimeSlotsAvialable] = useState([]);
const [selectedTime, setSelectedTime] = useState('');
useEffect(() => {
getInterviewDates();
}, []);
/**
* @param {null} null - Takes in nothing
* @returns {null} null - Returns in nothing
* @description Gets interview timeslots and dates
* @authors Ahmad <ahmadmuhammadofficial@gmail.com>, Brock <darkicewolf50@gmail.com>
* @todo refactor to not call backend so much
*/
const getInterviewDates = async () => {
const res = await fetch(
"https://bajabackend.bajacloud.duckdns.org/getAppointments",
{ method: "GET" }
);
let json = await res.json();
// can input dates right away, no other requirements to show it
let dates = await Object.keys(json["body"]["interviewDates"]);
await setAllDatesAvailable(dates);
// storing here for use in time slot selection
// date is needed in order to show time
await setAllTimeDatesAvailable(json["body"]);
console.log(json["body"]);
};
const isDateAvailable = (date) => {
return allDatesAvailable.includes(date.toISOString().split('T')[0]);
}
const handleDateChange = (date) => {
setSelectedDate(date); // Capture the selected date in date object
const selectedDateStr = date.toISOString().split('T')[0];
// get and set time slots for a given day
setTimeSlotsAvialable(Object.keys(allTimeDatesAvailable["interviewDates"][selectedDateStr]));
setSelectedTime(''); // clear because of date change
};
const handleTimeSlotChange = (e) => {
let startTime = e.target.innerHTML;
setSelectedTime(startTime);
};
return (
<div>
<label htmlFor="date-picker"><h3>Select a Date:</h3></label>
{/* old and bad */}
{/* Replace Calendar with input type="date" */}
{/* <input type="date" value={selectedDate} onChange={handleDateChange} /> */}
<DatePicker
selected={selectedDate}
onChange={handleDateChange}
inline
filterDate={isDateAvailable} // Filter out unavailable dates
dateFormat="yyyy-MM-dd"
required // Make date selection required
/>
{!selectedDate ? (
<>
<h4>Available Time Slots:</h4>
<p>Please select the a date to see time slots.</p>
</>
) : (
<>
<h4>Available Time Slots for {selectedDate.toISOString().split('T')[0]}:</h4>
{selectedDate === undefined ? (
<>
<p>Please select a date.</p>
</>
// ) : timeSlots.length 0 > 0 ? (
) : timeSlotsAvialable !== '' ? (
<>
{Object.values(timeSlotsAvialable).map((time) => {
return (
<button
key={time}
onClick={(self) => {
console.log(self.target.innerHTML);
handleTimeSlotChange(self);
}}
>
{time}
</button>
);
})}
</>
) : (
<>
<p>No available time slots for the selected date.</p>
</>
)}
</>
)}
{selectedDate && selectedTime && (
<div>
<p>
You have selected:
<br />
Date: {selectedDate.toLocaleDateString()}
<br />
Time: {selectedTime}
</p>
</div>)}
</div>
);
};

View File

@ -1,87 +0,0 @@
import React, { useState, useEffect } from "react";
const TimeSlotSelector = ({ onTimeSlotSelect }) => {
const [selectedDate, setSelectedDate] = useState();
const [timeSlots, setTimeSlots] = useState([]);
const [interviewDates, setInterviewDates] = useState([]);
useEffect(() => {
getInterviewDates();
}, []);
useEffect(() => {
if (selectedDate) {
const availableSlots =
interviewDates.interviewDates?.[selectedDate] || {};
setTimeSlots(Object.keys(availableSlots));
}
}, [selectedDate]);
/**
* @param {null} null - Takes in nothing
* @returns {null} null - Returns in nothing
* @description Hooking upto backend
* @author Ahmad <ahmadmuhammadofficial@gmail.com>
*/
const getInterviewDates = async () => {
const res = await fetch(
"https://bajabackend.bajacloud.duckdns.org/getAppointments",
{ method: "GET" }
);
let json = await res.json();
await setInterviewDates(json["body"]);
};
const handleDateChange = (e) => {
let date = e.target.value;
setSelectedDate(date); // Capture the selected date in YYYY-MM-DD format
onTimeSlotSelect({ date, startTime: null });
};
const handleTimeSlotChange = (e) => {
let startTime = e.target.innerHTML;
onTimeSlotSelect((prev) => ({ ...prev, startTime }));
};
return (
<div>
<h3>Select a Date:</h3>
{/* Replace Calendar with input type="date" */}
<input type="date" value={selectedDate} onChange={handleDateChange} />
{!selectedDate ? (
<>
<h4>Available Time Slots:</h4>
<p>Please select the a date to see time slots.</p>
</>
) : (
<>
<h4>Available Time Slots for {selectedDate}:</h4>
{selectedDate === undefined ? (
<>
<p>Please select a date.</p>
</>
) : timeSlots.length > 0 ? (
<>
{Object.values(timeSlots).map((time) => {
return (
<button
key={time}
onClick={(self) => {
console.log(self.target.innerHTML);
handleTimeSlotChange(self);
}}
>
{time}
</button>
);
})}
</>
) : (
<>
<p>No available time slots for the selected date.</p>
</>
)}
</>
)}
</div>
);
};
export default TimeSlotSelector;

View File

@ -9,26 +9,41 @@ import OurSponsors from "./OurSponsors/OurSponsors";
import JoinTheClub from "./Club Membership & Upcoming Events/JoinTheClub/JoinTheClub"; import JoinTheClub from "./Club Membership & Upcoming Events/JoinTheClub/JoinTheClub";
import UpcomingEvents from "./Club Membership & Upcoming Events/UpcominEvents/UpcomingEvents"; import UpcomingEvents from "./Club Membership & Upcoming Events/UpcominEvents/UpcomingEvents";
import Gallery from "./Gallery/Gallery"; import Gallery from "./Gallery/Gallery";
import InterviewBooking from "./Interivew Booking/InterviewBooking"; import InterviewBooking from "./Interivew Booking/InterviewBookMain";
import "./index.css"; import "./index.css";
const root = ReactDOM.createRoot(document.getElementById("root")); const root = ReactDOM.createRoot(document.getElementById("root"));
root.render( root.render(
<React.StrictMode> <React.StrictMode>
<BrowserRouter> <BrowserRouter>
<Routes> <Routes>
<Route element={<Header />}> <Route element={<Header />}>
<Route path="/" element={<AboutUs />}></Route> <Route
<Route path="/Teams" element={<SubTeams />}></Route> path="/"
<Route path="/OurSponsors" element={<OurSponsors />}></Route> element={<AboutUs />}></Route>
<Route path="/JoinTheClub" element={<JoinTheClub />}></Route> <Route
<Route path="/UpcomingEvents" element={<UpcomingEvents />}></Route> path="/Teams"
<Route path="/Gallery" element={<Gallery />}></Route> element={<SubTeams />}></Route>
</Route> <Route
<Route path="/InterviewBooking" element={<InterviewBooking />} /> path="/OurSponsors"
</Routes> element={<OurSponsors />}></Route>
</BrowserRouter> <Route
</React.StrictMode> path="/JoinTheClub"
element={<JoinTheClub />}></Route>
<Route
path="/UpcomingEvents"
element={<UpcomingEvents />}></Route>
<Route
path="/Gallery"
element={<Gallery />}></Route>
</Route>
<Route
path="/InterviewBooking"
element={<InterviewBooking />}
/>
</Routes>
</BrowserRouter>
</React.StrictMode>
); );
// If you want to start measuring performance in your app, pass a function // If you want to start measuring performance in your app, pass a function