Skip to content

Commit 71f21da

Browse files
authored
Merge branch 'main' into video_call_ui
2 parents a94525c + 9a45a88 commit 71f21da

File tree

5 files changed

+762
-0
lines changed

5 files changed

+762
-0
lines changed

frontend/package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"react": "^19.0.0",
1818
"react-calendar": "^5.1.0",
1919
"react-dom": "^19.0.0",
20+
"react-icons": "^5.5.0",
2021
"react-router-dom": "^7.4.0",
2122
"tailwindcss": "^4.0.5"
2223
},

frontend/src/App.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import Chat from "./Components/Chat.jsx";
1818
import Footer from "./Components/Footer.jsx";
1919
import Booking from "./Components/Booking.jsx";
2020
import VideoCall from "./Components/VideoCall.jsx";
21+
import Calendar from "./Components/Calendar.jsx";
2122

2223
function App() {
2324
const location = useLocation();
@@ -46,6 +47,7 @@ function App() {
4647
<Route path="/booking" element={<Booking />} />
4748
<Route path="/chat" element={<Chat />} />
4849
<Route path="/videocall" element={<VideoCall />} />
50+
<Route path="/Calendar" element={<Calendar />} />
4951
</Routes>
5052
{(location.pathname !== "/login" && location.pathname !== "/dateofbirth" && location.pathname !== "/SignUp") && <Footer />}
5153
</div>
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
import { useState } from "react"; // no need for import react
2+
import Calendar from "react-calendar";
3+
import "../Styles/Calendar.css";
4+
import { FaPlus, FaArrowLeft, FaArrowRight } from "react-icons/fa";
5+
6+
// Helper function: get the start (Sunday) of the week for a given date
7+
const getStartOfWeek = (date) => {
8+
const d = new Date(date);
9+
const day = d.getDay(); // Sunday = 0, Monday = 1, etc.
10+
d.setDate(d.getDate() - day);
11+
return d;
12+
};
13+
14+
function LessonCalendar() {
15+
// ---------------------------
16+
// STATES & SAMPLE DATA
17+
// ---------------------------
18+
const [value, setValue] = useState(new Date()); // Currently selected date
19+
const [view, setView] = useState("month"); // "month" or "week"
20+
const [searchQuery, setSearchQuery] = useState(""); // For event search (UC6)
21+
const [showProgress, setShowProgress] = useState(true); // Toggle progress tracker display
22+
23+
// Sample unscheduled tasks (UC8)
24+
const [unscheduledTasks, setUnscheduledTasks] = useState([
25+
{ id: 1, title: "Math Tutoring (Draft)", type: "Lesson" },
26+
{ id: 2, title: "Reading Club Prep", type: "Meeting" },
27+
{ id: 3, title: "Coding Practice Session", type: "Practice" },
28+
]);
29+
30+
// Sample events to display on the calendar
31+
const [events, setEvents] = useState([
32+
{ date: new Date(), title: "Math Tutoring w/ Mr. Smith" },
33+
{ date: new Date(Date.now() + 86400000), title: "Biology Lab" },
34+
{ date: new Date(Date.now() + 2 * 86400000), title: "History Discussion" },
35+
]);
36+
37+
// Filter events based on search query (UC6)
38+
const filteredEvents = events.filter((ev) =>
39+
ev.title.toLowerCase().includes(searchQuery.toLowerCase())
40+
);
41+
42+
// For week view: calculate dates for the current week
43+
const startOfWeek = getStartOfWeek(value);
44+
const weekDates = Array.from({ length: 7 }, (_, i) => {
45+
const d = new Date(startOfWeek);
46+
d.setDate(d.getDate() + i);
47+
return d;
48+
});
49+
50+
// ---------------------------
51+
// EVENT HANDLERS & FUNCTIONS
52+
// ---------------------------
53+
// Handler when a date is selected/changed on the calendar (for month view)
54+
const onDateChange = (newDate) => {
55+
setValue(newDate);
56+
};
57+
58+
// Handler for the Auto-Schedule button (UC5)
59+
const handleAutoSchedule = () => {
60+
// TODO: Integrate backend API call for auto-scheduling algorithm.
61+
console.log("Auto-scheduling lessons based on availability...");
62+
alert("Auto-scheduling triggered! (Integrate backend API)");
63+
};
64+
65+
// Handler for creating a new event/reminder (UC3)
66+
const handleCreateEvent = () => {
67+
// TODO: Open a modal with a form for event creation and call backend API on submission.
68+
alert("Open event creation modal! (Integrate with backend)");
69+
};
70+
71+
// Handler for resetting the calendar to today's date
72+
const handleToday = () => {
73+
setValue(new Date());
74+
};
75+
76+
// Handlers for navigating through the calendar (UC11)
77+
const handlePrev = () => {
78+
const tempDate = new Date(value);
79+
if (view === "month") {
80+
tempDate.setMonth(tempDate.getMonth() - 1);
81+
} else {
82+
// For week view: subtract 7 days
83+
tempDate.setDate(tempDate.getDate() - 7);
84+
}
85+
setValue(tempDate);
86+
};
87+
88+
const handleNext = () => {
89+
const tempDate = new Date(value);
90+
if (view === "month") {
91+
tempDate.setMonth(tempDate.getMonth() + 1);
92+
} else {
93+
// For week view: add 7 days
94+
tempDate.setDate(tempDate.getDate() + 7);
95+
}
96+
setValue(tempDate);
97+
};
98+
99+
// Render event markers on calendar tiles for month view
100+
const tileContent = ({ date }) => {
101+
const dayEvents = (searchQuery ? filteredEvents : events).filter(
102+
(ev) => ev.date.toDateString() === date.toDateString()
103+
);
104+
return (
105+
<div className="tile-events">
106+
{dayEvents.map((ev, index) => (
107+
<div key={index} className="calendar-event-marker">
108+
{ev.title}
109+
</div>
110+
))}
111+
</div>
112+
);
113+
};
114+
115+
// ---------------------------
116+
// COMPONENT RENDER
117+
// ---------------------------
118+
return (
119+
<div className="calendar-page">
120+
<div className="calendar-body">
121+
{/* LEFT PANEL: Calendar display & Weekly Progress Tracker */}
122+
<div className="left-panel">
123+
{/* Section: Month/Week toggle, "Today", and event creation buttons */}
124+
<div className="month-header">
125+
<div className="view-toggle">
126+
<button
127+
className={view === "week" ? "active" : ""}
128+
onClick={() => setView("week")}
129+
>
130+
Week
131+
</button>
132+
<button
133+
className={view === "month" ? "active" : ""}
134+
onClick={() => setView("month")}
135+
>
136+
Month
137+
</button>
138+
</div>
139+
<div className="month-title">
140+
{value.toLocaleString("default", { month: "long" })}{" "}
141+
{value.getFullYear()}
142+
</div>
143+
<div className="header-actions">
144+
<button className="today-btn" onClick={handleToday}>
145+
Today
146+
</button>
147+
<button className="create-event-btn" onClick={handleCreateEvent}>
148+
<FaPlus />
149+
</button>
150+
</div>
151+
</div>
152+
153+
{/* Calendar or Custom Week View (UC11) */}
154+
<div className="calendar-wrapper">
155+
<button className="nav-arrow" onClick={handlePrev}>
156+
<FaArrowLeft />
157+
</button>
158+
{view === "month" ? (
159+
<Calendar
160+
onChange={onDateChange}
161+
value={value}
162+
view="month"
163+
tileContent={tileContent}
164+
/>
165+
) : (
166+
<div className="week-view">
167+
{weekDates.map((date, i) => (
168+
<div className="week-day" key={i}>
169+
<div className="week-day-header">
170+
{date.toLocaleDateString("default", {
171+
weekday: "short",
172+
day: "numeric",
173+
})}
174+
</div>
175+
<div className="week-day-events">
176+
{(searchQuery ? filteredEvents : events)
177+
.filter(
178+
(ev) =>
179+
ev.date.toDateString() === date.toDateString()
180+
)
181+
.map((ev, index) => (
182+
<div key={index} className="calendar-event-marker">
183+
{ev.title}
184+
</div>
185+
))}
186+
</div>
187+
</div>
188+
))}
189+
</div>
190+
)}
191+
<button className="nav-arrow" onClick={handleNext}>
192+
<FaArrowRight />
193+
</button>
194+
</div>
195+
196+
{/* Weekly Progress Tracker (UC10) */}
197+
<div className="progress-section">
198+
<label className="toggle-progress">
199+
<span>Progress</span>
200+
<input
201+
type="checkbox"
202+
checked={showProgress}
203+
onChange={() => setShowProgress(!showProgress)}
204+
/>
205+
</label>
206+
{showProgress && (
207+
<div className="progress-bars">
208+
<div className="progress-item">
209+
<span>Math:</span>
210+
<div className="progress-bar">
211+
<div
212+
className="progress-fill"
213+
style={{
214+
width: "25%" /* TODO: Replace with dynamic value from backend */,
215+
}}
216+
></div>
217+
</div>
218+
<span className="progress-percent">25%</span>
219+
</div>
220+
<div className="progress-item">
221+
<span>Biology:</span>
222+
<div className="progress-bar">
223+
<div
224+
className="progress-fill"
225+
style={{
226+
width: "74%" /* TODO: Replace with dynamic value from backend */,
227+
}}
228+
></div>
229+
</div>
230+
<span className="progress-percent">74%</span>
231+
</div>
232+
</div>
233+
)}
234+
</div>
235+
</div>
236+
237+
{/* RIGHT PANEL: Auto-Schedule, Search/Filter, Unscheduled Tasks, File Attachment */}
238+
<div className="right-panel">
239+
<button className="auto-sched-btn" onClick={handleAutoSchedule}>
240+
AUTO Schedule
241+
</button>
242+
<div className="search-section">
243+
<div className="search-input-wrapper">
244+
<input
245+
className="search-bar"
246+
placeholder="Search events..."
247+
value={searchQuery}
248+
onChange={(e) => setSearchQuery(e.target.value)}
249+
/>
250+
{searchQuery && (
251+
<button
252+
className="clear-search"
253+
onClick={() => setSearchQuery("")}
254+
>
255+
Clear
256+
</button>
257+
)}
258+
</div>
259+
<div className="filter-section">
260+
<h4>Filter</h4>
261+
<ul>
262+
<li onClick={() => alert("Filter by teacher! (Integrate backend)")}>
263+
by Teacher
264+
</li>
265+
<li onClick={() => alert("Filter by subject! (Integrate backend)")}>
266+
by Subject
267+
</li>
268+
<li onClick={() => alert("Filter by skill level! (Integrate backend)")}>
269+
by Skill Level
270+
</li>
271+
<li onClick={() => alert("Filter by event! (Integrate backend)")}>
272+
by Event
273+
</li>
274+
</ul>
275+
</div>
276+
</div>
277+
<div className="unscheduled-tasks">
278+
<h4>Unscheduled Tasks</h4>
279+
<ul>
280+
{unscheduledTasks.map((task) => (
281+
<li key={task.id}>
282+
<span className="task-type">[{task.type}]</span> {task.title}
283+
{/* TODO: Add drag-and-drop functionality and integrate backend update */}
284+
</li>
285+
))}
286+
</ul>
287+
</div>
288+
<button
289+
className="file-attach-btn"
290+
onClick={() =>
291+
alert("Open file upload dialog! (Integrate backend file upload)")
292+
}
293+
>
294+
File attach
295+
</button>
296+
</div>
297+
</div>
298+
</div>
299+
);
300+
}
301+
302+
export default LessonCalendar;

0 commit comments

Comments
 (0)