mirror of
https://github.com/UofCBaja/BajaUofCWebsite.git
synced 2025-06-15 13:24:17 -06:00
feat(TimeDateSelector): better date selector implemented and naming scheme cleaned up to make more sense
This commit is contained in:
parent
583be5dcd2
commit
7999abaf25
16416
package-lock.json
generated
16416
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -9,8 +9,8 @@
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-datepicker": "^8.1.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-native": "^0.72.6",
|
||||
"react-router-dom": "^6.20.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
|
@ -1,6 +1,7 @@
|
||||
import InterviewForm from "./InterviewForm";
|
||||
import logo from "../Header/logo.webp";
|
||||
import Ender from "../Footer/Ender";
|
||||
import DateTimePicker from "./TestDateSelector";
|
||||
/**
|
||||
* @param {null} null - requires onthing
|
||||
* @returns {JSX.Element} Page - HTML tags and JS functionality
|
||||
@ -8,7 +9,7 @@ import Ender from "../Footer/Ender";
|
||||
* @author Brock <darkicewolf50@gmail.com>
|
||||
* @todo add who helped developed the site and finalize css
|
||||
*/
|
||||
const InterviewBooking = () => {
|
||||
export default function InterviewBooking () {
|
||||
return (
|
||||
<>
|
||||
<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
|
||||
an alternate interview time or for rescheduling.
|
||||
</p>
|
||||
{/* <DateTimePicker /> */}
|
||||
<Ender />
|
||||
|
||||
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InterviewBooking;
|
@ -1,5 +1,5 @@
|
||||
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
|
||||
@ -74,13 +74,14 @@ const InterviewForm = () => {
|
||||
/>
|
||||
|
||||
{/* Time Slot Selector */}
|
||||
<TimeSlotSelector
|
||||
<TimeDateSelector
|
||||
onTimeSlotSelect={(timeSlot) => setSelectedTimeSlot(timeSlot)}
|
||||
/>
|
||||
<button type="submit" disabled={isButtonDisabled}>
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{/* Success Dialog */}
|
||||
<dialog ref={dialogRef}>
|
||||
{" "}
|
||||
|
114
src/Interivew Booking/TestDateSelector.jsx
Normal file
114
src/Interivew Booking/TestDateSelector.jsx
Normal 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;
|
123
src/Interivew Booking/TimeDateSelector.jsx
Normal file
123
src/Interivew Booking/TimeDateSelector.jsx
Normal 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>
|
||||
);
|
||||
};
|
||||
|
@ -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;
|
47
src/index.js
47
src/index.js
@ -9,26 +9,41 @@ import OurSponsors from "./OurSponsors/OurSponsors";
|
||||
import JoinTheClub from "./Club Membership & Upcoming Events/JoinTheClub/JoinTheClub";
|
||||
import UpcomingEvents from "./Club Membership & Upcoming Events/UpcominEvents/UpcomingEvents";
|
||||
import Gallery from "./Gallery/Gallery";
|
||||
import InterviewBooking from "./Interivew Booking/InterviewBooking";
|
||||
import InterviewBooking from "./Interivew Booking/InterviewBookMain";
|
||||
import "./index.css";
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route element={<Header />}>
|
||||
<Route path="/" element={<AboutUs />}></Route>
|
||||
<Route path="/Teams" element={<SubTeams />}></Route>
|
||||
<Route path="/OurSponsors" element={<OurSponsors />}></Route>
|
||||
<Route 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>
|
||||
<React.StrictMode>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route element={<Header />}>
|
||||
<Route
|
||||
path="/"
|
||||
element={<AboutUs />}></Route>
|
||||
<Route
|
||||
path="/Teams"
|
||||
element={<SubTeams />}></Route>
|
||||
<Route
|
||||
path="/OurSponsors"
|
||||
element={<OurSponsors />}></Route>
|
||||
<Route
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user