Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Schedules builder now has a calendar where you can visualize your schedule #184

Merged
merged 39 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b53fac1
Calendar MVP
Oct 9, 2024
a78ee9d
Add tabs for schedule view
Oct 9, 2024
81d87d7
Fixed bug in getting time
Oct 9, 2024
fa9efb4
Temporary fix to scrolling
Oct 9, 2024
2c2a62c
Added colors
Oct 9, 2024
da02d88
Added colors
Oct 9, 2024
4341fa8
Shifted position of tabs
Oct 11, 2024
c3da9e8
Refactored handling of selecting sessions
Oct 11, 2024
14221ef
Removed line-clamp which is now included by default
Xavilien Oct 19, 2024
fb0bea1
Fix CSS
Xavilien Oct 19, 2024
10cc918
Added nullish check, removed console.log
Xavilien Oct 19, 2024
5a56e6e
Updated margins
Xavilien Oct 19, 2024
0084440
Added nothing in your schedule yet
Xavilien Oct 19, 2024
2eb5a99
Added no lectures
Xavilien Oct 19, 2024
e16bd2f
Added dropdown to add automatically to schedule
Xavilien Oct 19, 2024
5e2ad50
Added dropdown to add automatically to schedule
Xavilien Oct 19, 2024
3294da4
Sort semesters
Xavilien Oct 19, 2024
f58b14b
Fix color issue
Xavilien Oct 19, 2024
0e5c968
Fixed compatibility issues
Xavilien Nov 30, 2024
a668c86
Change location of show/hide calendar
Xavilien Nov 30, 2024
0a31c17
Make show button more consistent
Xavilien Nov 30, 2024
0cd8443
Changed schedules course search bar to make sense in small screens
Xavilien Nov 30, 2024
65081d9
Made sidebar smaller when in small screen
Xavilien Nov 30, 2024
6d58110
Select lecture based on section
Xavilien Dec 1, 2024
23c8a6a
Added remove button in section selector
Xavilien Dec 1, 2024
dc12b85
Scrolling for sidebar
Xavilien Dec 1, 2024
f498597
Scrolling for sidebar
Xavilien Dec 1, 2024
03e8fed
Give space at bottom of overflow
Xavilien Dec 1, 2024
87af518
Changed from listbox to radiogroup
Xavilien Dec 1, 2024
594af8a
Changed to flushedbutton
Xavilien Dec 1, 2024
becd671
Remove unused imports
Xavilien Dec 1, 2024
673200c
Refactored some code
Xavilien Dec 1, 2024
9f883a2
Made sure text sizes are ok
Xavilien Dec 1, 2024
e8d043c
Cosmetic change
Xavilien Dec 1, 2024
27e684a
Cosmetic change
Xavilien Dec 1, 2024
facf42d
Show possible on hover
Xavilien Dec 1, 2024
8d3e48e
Light colors for hover
Xavilien Dec 1, 2024
e46b92b
Show message when course not in selected semester
Xavilien Dec 1, 2024
9b18bd6
Remove existing lecture in calendar on hover
Xavilien Dec 1, 2024
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
2 changes: 2 additions & 0 deletions apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"passlink": "^1.1.0",
"posthog-js": "^1.181.0",
"react": "^18.2.0",
"react-big-calendar": "^1.15.0",
"react-dom": "^18.2.0",
"react-headless-pagination": "^0.1.0",
"react-hot-toast": "^2.2.0",
Expand All @@ -50,6 +51,7 @@
"@types/jest": "^27.0.1",
"@types/node": "^16.9.1",
"@types/react": "^17.0.21",
"@types/react-big-calendar": "^1.8.12",
"@types/react-dom": "^17.0.9",
"@types/react-redux": "^7.1.18",
"autoprefixer": "^10.4.0",
Expand Down
31 changes: 30 additions & 1 deletion apps/frontend/src/app/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,33 @@ export const GENED_SOURCES = {
Dietrich: "https://www.cmu.edu/dietrich/gened/fall-2021-and-beyond/course-options/index.html",
};

export const STALE_TIME = 1000 * 60 * 60 * 24; // 1 day
export const STALE_TIME = 1000 * 60 * 60 * 24; // 1 day

export const CAL_VIEW = "cal";
export const SCHED_VIEW = "sched";

export const CALENDAR_COLORS = [
"#FFB3BA", // Red
"#FFDFBA", // Orange
"#FFFFBA", // Yellow
"#BAFFC9", // Green
"#BAE1FF", // Blue
"#D4BAFF", // Purple
"#FFC4E1", // Pink
"#C4E1FF", // Sky Blue
"#E1FFC4", // Lime
"#FFF4BA" // Cream
];

export const CALENDAR_COLORS_LIGHT = [
"#FFE1E3", // Light Red
"#FFF2E3", // Light Orange
"#FFFFE3", // Light Yellow
"#E3FFE9", // Light Green
"#E3F3FF", // Light Blue
"#EEE3FF", // Light Purple
"#FFE7F3", // Light Pink
"#E7F3FF", // Light Sky Blue
"#F3FFE7", // Light Lime
"#FFFBE3" // Light Cream
];
18 changes: 10 additions & 8 deletions apps/frontend/src/app/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type Semester = "fall" | "spring" | "summer";
export type Semester = "fall" | "spring" | "summer" | "";
export type SummerSession =
| "summer one"
| "summer two"
Expand Down Expand Up @@ -32,17 +32,19 @@ export interface Course {
fces?: FCE[];
}

export interface Time {
days: number[];
begin: string;
end: string;
building: string;
room: string;
}

interface Lesson {
instructors: string[];
name: string;
location: string;
times: {
days: number[];
begin: string;
end: string;
building: string;
room: string;
}[];
times: Time[];
}

export type Lecture = Lesson;
Expand Down
9 changes: 7 additions & 2 deletions apps/frontend/src/app/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { addToSet, removeFromSet } from "./utils";
import { SEMESTERS_COUNTED } from "./constants";
import {CAL_VIEW, SCHED_VIEW, SEMESTERS_COUNTED} from "./constants";
import { Semester } from "./types";

export interface UserState {
Expand All @@ -24,6 +24,7 @@ export interface UserState {
};
selectedSchool: string;
selectedTags: string[];
scheduleView: string;
}

const initialState: UserState = {
Expand All @@ -47,6 +48,7 @@ const initialState: UserState = {
},
selectedSchool: "SCS",
selectedTags: [],
scheduleView: "cal",
};

export const userSlice = createSlice({
Expand Down Expand Up @@ -102,7 +104,10 @@ export const userSlice = createSlice({
},
setSelectedTags: (state, action: PayloadAction<string[]>) => {
state.selectedTags = action.payload;
}
},
toggleScheduleView: (state) => {
state.scheduleView = state.scheduleView === CAL_VIEW ? SCHED_VIEW : CAL_VIEW;
},
},
});

Expand Down
105 changes: 85 additions & 20 deletions apps/frontend/src/app/userSchedules.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { addToSet, removeFromSet } from "./utils";
import { addToSet, getCalendarColor, removeFromSet, sessionToString } from "./utils";
import { Session } from "./types";
import { v4 as uuidv4 } from "uuid";
import { RootState } from "./store";

export interface CourseSessions {
[courseID: string]: {
[sessionType: string]: string;
Color: string;
};
}

export interface HoverSession {
courseID: string;
[sessionType: string]: string;
}

export interface UserSchedule {
name: string;
courses: string[];
selected: string[];
id: string;
session?: Session;
session: Session;
courseSessions: CourseSessions;
numColors: number;
hoverSession?: HoverSession;
}

export interface UserSchedulesState {
Expand All @@ -22,6 +37,24 @@ const initialState: UserSchedulesState = {
saved: {},
};

const getNewUserSchedule = (courseIDs: string[], id: string) : UserSchedule => {
return {
name: "My Schedule",
courses: courseIDs,
selected: courseIDs,
id: id,
session: {
year: "",
semester: "",
},
courseSessions: courseIDs.reduce((acc: CourseSessions, courseID, i: number) => {
acc[courseID] = {Lecture: "", Section: "", Color: getCalendarColor(i)};
return acc;
}, {}),
numColors: courseIDs.length,
};
}

export const userSchedulesSlice = createSlice({
name: "userSchedules",
initialState,
Expand All @@ -32,12 +65,7 @@ export const userSchedulesSlice = createSlice({
addCourseToActiveSchedule: (state, action: PayloadAction<string>) => {
if (state.active === null) {
const newId = uuidv4();
state.saved[newId] = {
name: "My Schedule",
courses: [],
selected: [],
id: newId,
};
state.saved[newId] = getNewUserSchedule([], newId);
state.active = newId;
}
state.saved[state.active].courses = addToSet(
Expand All @@ -48,6 +76,8 @@ export const userSchedulesSlice = createSlice({
state.saved[state.active].selected,
action.payload
);
state.saved[state.active].courseSessions[action.payload] = {Lecture: "", Section: "", Color: getCalendarColor(state.saved[state.active].numColors)};
state.saved[state.active].numColors += 1;
},
removeCourseFromActiveSchedule: (state, action: PayloadAction<string>) => {
if (state.active === null) return;
Expand All @@ -59,6 +89,8 @@ export const userSchedulesSlice = createSlice({
state.saved[state.active].selected,
action.payload
);

delete state.saved[state.active].courseSessions[action.payload];
},
selectCourseInActiveSchedule: (state, action: PayloadAction<string>) => {
if (state.active === null) return;
Expand Down Expand Up @@ -88,22 +120,12 @@ export const userSchedulesSlice = createSlice({
},
createEmptySchedule: (state) => {
const newId = uuidv4();
state.saved[newId] = {
name: "My Schedule",
selected: [],
courses: [],
id: newId,
};
state.saved[newId] = getNewUserSchedule([], newId);
state.active = newId;
},
createSharedSchedule: (state, action: PayloadAction<string[]>) => {
const newId = uuidv4();
state.saved[newId] = {
name: "Shared Schedule",
selected: action.payload,
courses: action.payload,
id: newId,
};
state.saved[newId] = getNewUserSchedule(action.payload, newId);
state.active = newId;
},
deleteSchedule: (state, action: PayloadAction<string>) => {
Expand All @@ -123,6 +145,26 @@ export const userSchedulesSlice = createSlice({
state.saved[state.active].name = action.payload;
}
},
updateActiveScheduleSession: (state, action: PayloadAction<Session>) => {
if (state.active !== null) {
state.saved[state.active].session = action.payload;
}
},
updateActiveScheduleCourseSession: (state, action: PayloadAction<{ courseID: string, sessionType: string, session: string }>) => {
if (state.active !== null) {
state.saved[state.active].courseSessions[action.payload.courseID][action.payload.sessionType] = action.payload.session
}
},
setHoverSession: (state, action: PayloadAction<{ courseID: string, [sessionType: string]: string }>) => {
if (state.active !== null) {
state.saved[state.active].hoverSession = action.payload;
}
},
clearHoverSession: (state) => {
if (state.active !== null) {
state.saved[state.active].hoverSession = undefined;
}
},
},
});

Expand All @@ -138,4 +180,27 @@ export const selectSelectedCoursesInActiveSchedule = (
return state.schedules.saved[state.schedules.active].selected;
};

export const selectSessionInActiveSchedule = (
state: RootState
): string => {
if (state.schedules.active === null) return "";
const session = state.schedules.saved[state.schedules.active].session;
if (session?.semester === "") return "";
return sessionToString(session);
};

export const selectCourseSessionsInActiveSchedule = (
state: RootState
): CourseSessions => {
if (state.schedules.active === null) return {};
return state.schedules.saved[state.schedules.active].courseSessions;
};

export const selectHoverSessionInActiveSchedule = (
state: RootState
): { courseID: string, [sessionType: string]: string } | undefined => {
if (state.schedules.active === null) return undefined;
return state.schedules.saved[state.schedules.active].hoverSession;
};

export const reducer = userSchedulesSlice.reducer;
53 changes: 48 additions & 5 deletions apps/frontend/src/app/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import reactStringReplace from "react-string-replace";
import Link from "~/components/Link";
import { FCE, Schedule, Session, Time } from "./types";
import { AggregateFCEsOptions, filterFCEs } from "./fce";
import { DEPARTMENT_MAP_NAME, DEPARTMENT_MAP_SHORTNAME } from "./constants";
import { DEPARTMENT_MAP_NAME, DEPARTMENT_MAP_SHORTNAME, CALENDAR_COLORS, CALENDAR_COLORS_LIGHT } from "./constants";
import namecase from "namecase";

export const courseIdRegex = /([0-9]{2}-?[0-9]{3})/g;
Expand All @@ -20,7 +20,9 @@ export const standardizeIdsInString = (str: string) => {
};

export const sessionToString = (sessionInfo: Session | FCE | Schedule) => {
const semester = sessionInfo.semester;
if (!sessionInfo) return "";

const semester = sessionInfo?.semester || "";

const sessionStrings = {
"summer one": "Summer One",
Expand All @@ -38,12 +40,14 @@ export const sessionToString = (sessionInfo: Session | FCE | Schedule) => {
if (semester === "summer" && sessionInfo.session) {
return `${sessionStrings[sessionInfo.session]} ${sessionInfo.year}`;
} else {
return `${semesterStrings[sessionInfo.semester]} ${sessionInfo.year}`;
return `${semesterStrings[semester]} ${sessionInfo.year}`;
}
};

export const sessionToShortString = (sessionInfo: Session | FCE | Schedule) => {
const semester = sessionInfo.semester;
if (!sessionInfo) return "";

const semester = sessionInfo?.semester || "";

const sessionStrings = {
"summer one": "M1",
Expand All @@ -61,10 +65,42 @@ export const sessionToShortString = (sessionInfo: Session | FCE | Schedule) => {
if (semester === "summer" && sessionInfo.session) {
return `${sessionStrings[sessionInfo.session]} ${sessionInfo.year}`;
} else {
return `${semesterStrings[sessionInfo.semester]} ${sessionInfo.year}`;
return `${semesterStrings[semester]} ${sessionInfo.year}`;
}
};

export const stringToSession = (sessionString: string): Session => {
const sessionStringSplit = sessionString.split(" ");

if (sessionStringSplit.length === 2) {
const [semester, year] = sessionStringSplit;
return {
semester: semester?.toLowerCase() as any,
year: year as string,
};
} else if (sessionStringSplit.length === 3) {
const [semester, session, year] = sessionStringSplit;

if (semester?.includes("Q")) {
return {
semester: "summer",
year: year as string,
session: "qatar summer",
};
}
return {
semester: semester?.toLowerCase() as any,
year: year as string,
session: `${semester} ${session}`.toLowerCase() as any,
};
}

return {
semester: "",
year: "",
};
}

export const compareSessions = (
session1: Session | FCE,
session2: Session | FCE
Expand Down Expand Up @@ -236,3 +272,10 @@ export function parseUnits(units: string): number {
}
return 0.0;
}

export const getCalendarColor = (i: number) => CALENDAR_COLORS[i % CALENDAR_COLORS.length] || "";

export const getCalendarColorLight = (color: string) => {
const index = CALENDAR_COLORS.indexOf(color);
return CALENDAR_COLORS_LIGHT[index];
}
Loading
Loading