Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1b2012c
Timetable frontend rough draft
Austin-X Mar 2, 2025
39cbc23
Auto-formatted the code using Prettier
Austin-X Mar 2, 2025
3a38db5
Add documentation comments
Austin-X Mar 2, 2025
469e51d
Merge branch 'ax/scrum-101-timetable-frontend' of https://github.com/…
Austin-X Mar 2, 2025
877e797
Use schedule-x package for the calendar
Austin-X Mar 3, 2025
e3160da
Auto-formatted the code using Prettier
Austin-X Mar 3, 2025
9f9a902
Update course-matrix/frontend/src/pages/Home/TimetableCompareButton.tsx
Austin-X Mar 3, 2025
ecba887
Update course-matrix/frontend/src/pages/Home/TimetableCreateNewButton…
Austin-X Mar 3, 2025
b0c59d9
Merge branch 'develop' into ax/scrum-101-timetable-frontend
Austin-X Mar 6, 2025
de5c896
Finish Integration on the Home Page
Austin-X Mar 7, 2025
63a914a
Auto-formatted the code using Prettier
Austin-X Mar 7, 2025
5b28301
Merge branch 'develop' into ax/scrum-101-timetable-frontend
Austin-X Mar 7, 2025
2dcebbe
Merge branch 'ax/scrum-101-timetable-frontend' of https://github.com/…
Austin-X Mar 7, 2025
0720fe5
Fix bugs and typos
Austin-X Mar 7, 2025
7cd8a8b
Use refetch instead of reloading the page
Austin-X Mar 7, 2025
c004d9a
Auto-formatted the code using Prettier
Austin-X Mar 7, 2025
90cf4b3
Make "Edit Timetable" button on one line
Austin-X Mar 7, 2025
34071a1
Merge branch 'ax/scrum-101-timetable-frontend' of https://github.com/…
Austin-X Mar 7, 2025
7e42364
Auto-formatted the code using Prettier
Austin-X Mar 7, 2025
9ad479f
Fix bug
Austin-X Mar 7, 2025
cf92e3d
Merge branch 'ax/scrum-101-timetable-frontend' of https://github.com/…
Austin-X Mar 7, 2025
f0c8e1b
Auto-formatted the code using Prettier
Austin-X Mar 7, 2025
1c2131f
Fix timetable switching bug
Austin-X Mar 8, 2025
bf48fa4
Auto-formatted the code using Prettier
Austin-X Mar 8, 2025
3a4418a
Merge branch 'develop' into ax/scrum-101-timetable-frontend
Austin-X Mar 8, 2025
c470b19
Merge branch 'ax/scrum-101-timetable-frontend' of https://github.com/…
Austin-X Mar 8, 2025
5bda338
Update package-lock.json
Austin-X Mar 8, 2025
dc54934
Merge branch 'develop' into ax/scrum-101-timetable-frontend
Austin-X Mar 8, 2025
2f23bf3
Update package-lock.json
Austin-X Mar 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions course-matrix/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions course-matrix/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.8",
"@reduxjs/toolkit": "^2.5.1",
"@schedule-x/drag-and-drop": "^2.21.1",
"@schedule-x/event-modal": "^2.21.1",
"@schedule-x/events-service": "^2.21.0",
"@schedule-x/react": "^2.21.0",
"@schedule-x/theme-default": "^2.21.0",
"ai": "^4.1.45",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion course-matrix/frontend/src/api/baseApiSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ const baseQuery = fetchBaseQuery({ baseUrl: BASE_URL });

export const apiSlice = createApi({
baseQuery,
tagTypes: ["Auth", "Course", "Department", "Offering", "Timetable"],
tagTypes: ["Auth", "Course", "Department", "Offering", "Timetable", "Event"],
endpoints: () => ({}),
});
2 changes: 2 additions & 0 deletions course-matrix/frontend/src/api/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export const AUTH_URL = `${SERVER_URL}/auth`;
export const COURSES_URL = `${SERVER_URL}/api/courses`;
export const DEPARTMENT_URL = `${SERVER_URL}/api/departments`;
export const OFFERINGS_URL = `${SERVER_URL}/api/offerings`;
export const TIMETABLES_URL = `${SERVER_URL}/api/timetables`;
export const EVENTS_URL = `${SERVER_URL}/api/timetables/events`;
66 changes: 66 additions & 0 deletions course-matrix/frontend/src/api/eventsApiSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { data } from "react-router-dom";
import { apiSlice } from "./baseApiSlice";
import { EVENTS_URL } from "./config";

// Endpoints for /api/timetables/events
export const eventsApiSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
createEvent: builder.mutation({
query: (data) => ({
url: `${EVENTS_URL}`,
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json, text/plain, */*",
},
providesTags: ["Event"],
body: data,
credentials: "include",
}),
}),
getEvents: builder.query<unknown, number>({
query: (id) => ({
url: `${EVENTS_URL}/${id}`,
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json, text/plain, */*",
},
providesTags: ["Event"],
credentials: "include",
}),
}),
updateEvent: builder.mutation({
query: (data) => ({
url: `${EVENTS_URL}/${data.id}`,
method: "PUT",
headers: {
"Content-Type": "application/json",
Accept: "application/json, text/plain, */*",
},
providesTags: ["Event"],
body: data,
credentials: "include",
}),
}),
deleteEvent: builder.mutation({
query: (id) => ({
url: `${EVENTS_URL}/${id}`,
method: "DELETE",
headers: {
"Content-Type": "application/json",
Accept: "application/json, text/plain, */*",
},
providesTags: ["Event"],
credentials: "include",
}),
}),
}),
});

export const {
useCreateEventMutation,
useGetEventsQuery,
useUpdateEventMutation,
useDeleteEventMutation,
} = eventsApiSlice;
65 changes: 65 additions & 0 deletions course-matrix/frontend/src/api/timetableApiSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { apiSlice } from "./baseApiSlice";
import { TIMETABLES_URL } from "./config";

// Endpoints for /api/timetables
export const timetableApiSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
createTimetable: builder.mutation({
query: (data) => ({
url: `${TIMETABLES_URL}`,
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json, text/plain, */*",
},
providesTags: ["Timetable"],
body: data,
credentials: "include",
}),
}),
getTimetables: builder.query<unknown, void>({
query: () => ({
url: `${TIMETABLES_URL}`,
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json, text/plain, */*",
},
providesTags: ["Timetable"],
credentials: "include",
}),
}),
updateTimetable: builder.mutation({
query: (data) => ({
url: `${TIMETABLES_URL}/${data.id}`,
method: "PUT",
headers: {
"Content-Type": "application/json",
Accept: "application/json, text/plain, */*",
},
providesTags: ["Timetable"],
body: data,
credentials: "include",
}),
}),
deleteTimetable: builder.mutation({
query: (id) => ({
url: `${TIMETABLES_URL}/${id}`,
method: "DELETE",
headers: {
"Content-Type": "application/json",
Accept: "application/json, text/plain, */*",
},
providesTags: ["Timetable"],
credentials: "include",
}),
}),
}),
});

export const {
useGetTimetablesQuery,
useUpdateTimetableMutation,
useCreateTimetableMutation,
useDeleteTimetableMutation,
} = timetableApiSlice;
1 change: 1 addition & 0 deletions course-matrix/frontend/src/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const buttonVariants = cva(
},
size: {
default: "h-10 px-4 py-2",
xs: "h-6 rounded-md px-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
Expand Down
2 changes: 1 addition & 1 deletion course-matrix/frontend/src/models/timetable-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ export const TimetableFormSchema: ZodType<TimetableForm> = z
);

export const baseTimetableForm: TimetableForm = {
name: "New Timetable",
name: "Edit Timetable",
date: new Date(),
semester: "Fall 2025",
search: "",
Expand Down
3 changes: 2 additions & 1 deletion course-matrix/frontend/src/pages/Dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { Separator } from "@radix-ui/react-separator";
import { Link, Navigate, Route, Routes, useLocation } from "react-router-dom";
import TimetableBuilder from "../TimetableBuilder/TimetableBuilder";
import AssistantPage from "../Assistant/AssistantPage";
import Home from "../Home/Home";

/**
* Dashboard Component
Expand Down Expand Up @@ -75,7 +76,7 @@ const Dashboard = () => {
<Routes>
<Route path="*" element={<Navigate to="/not-found" />} />
<Route path="/" element={<Navigate to="home" replace />} />
<Route path="/home" element={<>Home</>} />
<Route path="/home" element={<Home />} />
<Route path="/timetable" element={<TimetableBuilder />} />
<Route path="/assistant" element={<AssistantPage />} />
</Routes>
Expand Down
80 changes: 80 additions & 0 deletions course-matrix/frontend/src/pages/Home/Home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Button } from "@/components/ui/button";
import { Pin } from "lucide-react";
import TimetableCard from "./TimetableCard";
import TimetableCompareButton from "./TimetableCompareButton";
import TimetableCreateNewButton from "./TimetableCreateNewButton";
import { useGetTimetablesQuery } from "../../api/timetableApiSlice";
import { Timetable } from "../../utils/type-utils";

/**
* Home component that displays the user's timetables and provides options to create or compare timetables.
* @returns {JSX.Element} The rendered component.
*/
const Home = () => {
const user_metadata = JSON.parse(localStorage.getItem("userInfo") ?? "{}");
const name =
(user_metadata?.user?.user_metadata?.username as string) ??
(user_metadata?.user?.email as string);

const { data, isLoading } = useGetTimetablesQuery() as {
data: Timetable[];
isLoading: boolean;
};

return (
<div className="w-full">
<div className="m-8">
<div className="mb-4 flex items-center gap-2 relative group">
<h1 className="text-2xl font-medium tracking-tight">My Timetables</h1>
<Pin size={24} className="text-blue-500" />
</div>
<div className="mb-4 flex flex-row justify-between items-center">
<div className="flex gap-4">
<Button
size="xs"
className="py-3 px-5 bg-blue-100 hover:bg-blue-300 text-black"
disabled
>
All
</Button>
<Button
size="xs"
className="py-3 px-5 bg-blue-100 hover:bg-blue-300 text-black"
>
Mine
</Button>
<Button
size="xs"
className="py-3 px-5 bg-blue-100 hover:bg-blue-300 text-black"
disabled
>
Shared
</Button>
</div>
<div className="flex gap-8">
<TimetableCompareButton />
<TimetableCreateNewButton />
</div>
</div>
<hr />
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4 justify-between mt-4">
{isLoading ? (
<p className="text-sm text-muted-foreground">Loading...</p>
) : (
data?.map((timetable, index) => (
<TimetableCard
key={index}
timetableId={timetable.id}
title={timetable.timetable_title}
lastEditedDate={new Date(timetable.updated_at)}
owner={name}
/>
))
)}
</div>
</div>
</div>
);
};

export default Home;
Loading