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

feat(website): Add TA mode #3875

Merged
merged 30 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
21c9a05
Add TA mode to hide lectures
leslieyip02 Nov 28, 2024
b372c98
Fix false exam clash on hidden and TA modules
leslieyip02 Nov 28, 2024
d829507
Add visual indicator for TA modules
leslieyip02 Nov 29, 2024
69a12f6
Update export to support TA modules
leslieyip02 Nov 29, 2024
b8ff368
Add choice of lesson types to TA mode
leslieyip02 Dec 1, 2024
e2df4f6
Fix missing property
leslieyip02 Dec 1, 2024
637f96d
Fix type mismatch
leslieyip02 Dec 1, 2024
f06d98e
Merge branch 'master' into add-ta-mode
zwliew Dec 16, 2024
3eae3a6
Merge branch 'master' into add-ta-mode
zwliew Dec 17, 2024
012d9df
Merge branch 'master' of https://github.com/nusmodifications/nusmods …
leslieyip02 Dec 22, 2024
0f7c4e0
Merge branch 'add-ta-mode' of https://github.com/leslieyip02/nusmods …
leslieyip02 Dec 22, 2024
b311cb1
Allow multiple lesson slots of the same type
leslieyip02 Dec 22, 2024
8e54fed
Improve toggle
leslieyip02 Dec 23, 2024
50d72ac
Merge branch 'master' into add-ta-mode
zwliew Dec 24, 2024
2f36ae6
Replace toggle by lesson type to toggle by module
leslieyip02 Dec 27, 2024
71e4355
Merge branch 'master' into add-ta-mode
leslieyip02 Dec 27, 2024
571e8d5
Merge branch 'master' into add-ta-mode
leslieyip02 Dec 29, 2024
eadbd5b
Update export
leslieyip02 Dec 29, 2024
4995b68
Merge branch 'master' into add-ta-mode
leslieyip02 Jan 2, 2025
d323978
Update lesson hydrate functions
leslieyip02 Jan 2, 2025
f7c4f80
Merge branch 'master' into add-ta-mode
zwliew Jan 3, 2025
826a51b
Fix test failures
zwliew Jan 3, 2025
28c0506
Use proper types
zwliew Jan 3, 2025
c3fcb79
Clean up some code
zwliew Jan 3, 2025
77b72b8
Clean up more code
zwliew Jan 3, 2025
48f5a98
Rename set/unset -> enable/disable
zwliew Jan 3, 2025
fc91c31
More clean ups
zwliew Jan 3, 2025
29a6850
More clean ups
zwliew Jan 3, 2025
b769ddc
Final clean ups
zwliew Jan 3, 2025
6c07267
Remove unnecessary code
zwliew Jan 3, 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
2 changes: 1 addition & 1 deletion docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ services:
- NODE_ENV=production
- PORT=8082
- HOST=0.0.0.0
- PAGE=http://website:8081
- PAGE=http://website:8081/timetable-only/
- CHROME_EXECUTABLE=/usr/bin/chromium-browser
restart: on-failure
labels:
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ services:
- NODE_ENV=development
- PORT=8082
- HOST=0.0.0.0
- PAGE=http://website:8081
- PAGE=http://website:8081/timetable-only/
- CHROME_EXECUTABLE=/usr/bin/chromium-browser
user: ${CURRENT_UID:-1000:1000}
restart: on-failure
Expand Down
2 changes: 1 addition & 1 deletion export/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:12-alpine
FROM node:18-alpine

# Installs Chromium package.
RUN apk update && apk upgrade && \
Expand Down
2 changes: 1 addition & 1 deletion export/Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:12-alpine
FROM node:18-alpine

# Installs Chromium package.
RUN apk update && apk upgrade && \
Expand Down
5 changes: 5 additions & 0 deletions export/src/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ export function validateExportData(data: ExportData) {
Joi.string(),
Joi.object().pattern(Joi.string(), Joi.string()),
);
const taModulesConfigSchema = Joi.object().pattern(
Joi.string(),
Joi.array().length(2).ordered(Joi.string(), Joi.string()),
);
const themeSchema = Joi.object({
id: Joi.string(),
timetableOrientation: Joi.string().valid('HORIZONTAL', 'VERTICAL'),
Expand All @@ -75,6 +79,7 @@ export function validateExportData(data: ExportData) {
timetable: timetableSchema,
colors: Joi.object().pattern(Joi.string(), Joi.number().integer().min(0)),
hidden: Joi.array().items(Joi.string()),
ta: taModulesConfigSchema,
settings: Joi.object({
colorScheme: Joi.string().valid('LIGHT_COLOR_SCHEME', 'DARK_COLOR_SCHEME'),
}),
Expand Down
1 change: 1 addition & 0 deletions export/src/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export async function launch() {
headless: true,
executablePath: config.chromeExecutable,
devtools: !!process.env.DEVTOOLS,
args: ['--disable-gpu'],
});

const page = await browser.newPage();
Expand Down
22 changes: 13 additions & 9 deletions export/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,27 @@ import type { Page } from 'puppeteer-core';
// These types are duplicated from `website/`.
// TODO: Move these types to a shared package.
export type TimetableOrientation = 'HORIZONTAL' | 'VERTICAL';
export type Semester = number;
export type SemTimetableConfig = {
[moduleCode: string]: ModuleLessonConfig;
};
export type ColorIndex = number;
export type ColorMapping = { [moduleCode: string]: ColorIndex };
export type ModuleCode = string;
export type ThemeState = Readonly<{
id: string;
timetableOrientation: TimetableOrientation;
showTitle: boolean;
}>;
export type ColorScheme = 'LIGHT_COLOR_SCHEME' | 'DARK_COLOR_SCHEME';
export type Semester = number;
export type ClassNo = string; // E.g. "1", "A"
export type LessonType = string; // E.g. "Lecture", "Tutorial"
export type ModuleCode = string; // E.g. "CS3216"
export type SemTimetableConfig = {
[moduleCode: ModuleCode]: ModuleLessonConfig;
};
export interface ModuleLessonConfig {
[lessonType: LessonType]: ClassNo;
}
export type TaModulesConfig = {
[moduleCode: ModuleCode]: [lessonType: LessonType, classNo: ClassNo][];
};

// `ExportData` is duplicated from `website/src/types/export.ts`.
export interface ExportData {
Expand All @@ -29,10 +37,6 @@ export interface ExportData {
};
}

export interface ModuleLessonConfig {
[lessonType: string]: string;
}

export interface State {
data: ExportData;
page: Page;
Expand Down
26 changes: 23 additions & 3 deletions website/src/actions/export.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import type { Module, ModuleCode, Semester } from 'types/modules';
import type { ExportData } from 'types/export';
import type { Dispatch, GetState } from 'types/redux';
import { hydrateSemTimetableWithLessons } from 'utils/timetables';
import {
hydrateSemTimetableWithLessons,
hydrateTaModulesConfigWithLessons,
} from 'utils/timetables';
import { captureException } from 'utils/error';
import retryImport from 'utils/retryImport';
import { getSemesterTimetableLessons } from 'selectors/timetables';
import { TaModulesConfig } from 'types/timetables';
import { SET_EXPORTED_DATA } from './constants';

function downloadUrl(blob: Blob, filename: string) {
Expand All @@ -31,12 +35,28 @@
.then(([ical, icalUtils]) => {
const state = getState();
const { modules } = state.moduleBank;
const hiddenModules: ModuleCode[] = state.timetables.hidden[semester] || [];
const hiddenModules: ModuleCode[] = state.timetables.hidden[semester] ?? [];
const taModules: TaModulesConfig = state.timetables.ta[semester] ?? {};

Check warning on line 39 in website/src/actions/export.ts

View check run for this annotation

Codecov / codecov/patch

website/src/actions/export.ts#L38-L39

Added lines #L38 - L39 were not covered by tests

const timetable = getSemesterTimetableLessons(state)(semester);
const timetableWithLessons = hydrateSemTimetableWithLessons(timetable, modules, semester);
const timetableWithTaLessons = hydrateTaModulesConfigWithLessons(

Check warning on line 43 in website/src/actions/export.ts

View check run for this annotation

Codecov / codecov/patch

website/src/actions/export.ts#L43

Added line #L43 was not covered by tests
taModules,
modules,
semester,
);
const filteredTimetableWithLessons = {

Check warning on line 48 in website/src/actions/export.ts

View check run for this annotation

Codecov / codecov/patch

website/src/actions/export.ts#L48

Added line #L48 was not covered by tests
...timetableWithLessons,
...timetableWithTaLessons,
};

const events = icalUtils.default(semester, timetableWithLessons, modules, hiddenModules);
const events = icalUtils.default(

Check warning on line 53 in website/src/actions/export.ts

View check run for this annotation

Codecov / codecov/patch

website/src/actions/export.ts#L53

Added line #L53 was not covered by tests
semester,
filteredTimetableWithLessons,
modules,
hiddenModules,
taModules,
);
const cal = ical.default({
domain: 'nusmods.com',
prodId: '//NUSMods//NUSMods//EN',
Expand Down
69 changes: 61 additions & 8 deletions website/src/actions/timetables.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { each, flatMap } from 'lodash';

import type { ColorIndex, Lesson, ModuleLessonConfig, SemTimetableConfig } from 'types/timetables';
import type {
ColorIndex,
Lesson,
ModuleLessonConfig,
SemTimetableConfig,
TaModulesConfig,
} from 'types/timetables';
import type { Dispatch, GetState } from 'types/redux';
import type { ColorMapping } from 'types/reducers';
import type { ClassNo, LessonType, Module, ModuleCode, Semester } from 'types/modules';
Expand All @@ -19,17 +25,18 @@
export const SET_TIMETABLE = 'SET_TIMETABLE' as const;
export const ADD_MODULE = 'ADD_MODULE' as const;
export const SET_HIDDEN_IMPORTED = 'SET_HIDDEN_IMPORTED' as const;
export const HIDDEN_IMPORTED_SEM = 'HIDDEN_IMPORTED_SEM' as const;
export const SET_TA_IMPORTED = 'SET_TA_IMPORTED' as const;
export const Internal = {
setTimetable(
semester: Semester,
timetable: SemTimetableConfig | undefined,
colors?: ColorMapping,
hiddenModules?: ModuleCode[],
taModules?: TaModulesConfig,
) {
return {
type: SET_TIMETABLE,
payload: { semester, timetable, colors, hiddenModules },
payload: { semester, timetable, colors, hiddenModules, taModules },
};
},

Expand Down Expand Up @@ -165,7 +172,8 @@
semester,
validatedTimetable,
colors,
getState().timetables.hidden[HIDDEN_IMPORTED_SEM] || [],
getState().timetables.hidden[semester] ?? [],
getState().timetables.ta[semester] ?? {},
),
);
};
Expand Down Expand Up @@ -211,14 +219,25 @@
};
}

export function setHiddenModulesFromImport(hiddenModules: ModuleCode[]) {
return (dispatch: Dispatch) => dispatch(setHiddenImported(hiddenModules));
export function setHiddenModulesFromImport(semester: Semester, hiddenModules: ModuleCode[]) {
return (dispatch: Dispatch) => dispatch(setHiddenImported(semester, hiddenModules));

Check warning on line 223 in website/src/actions/timetables.ts

View check run for this annotation

Codecov / codecov/patch

website/src/actions/timetables.ts#L222-L223

Added lines #L222 - L223 were not covered by tests
}

export function setHiddenImported(hiddenModules: ModuleCode[]) {
export function setHiddenImported(semester: Semester, hiddenModules: ModuleCode[]) {
return {
type: SET_HIDDEN_IMPORTED,
payload: { semester: HIDDEN_IMPORTED_SEM, hiddenModules },
payload: { semester, hiddenModules },
};
}

export function setTaModulesFromImport(semester: Semester, taModules: TaModulesConfig) {
return (dispatch: Dispatch) => dispatch(setTaImported(semester, taModules));

Check warning on line 234 in website/src/actions/timetables.ts

View check run for this annotation

Codecov / codecov/patch

website/src/actions/timetables.ts#L233-L234

Added lines #L233 - L234 were not covered by tests
}

export function setTaImported(semester: Semester, taModules: TaModulesConfig) {
return {

Check warning on line 238 in website/src/actions/timetables.ts

View check run for this annotation

Codecov / codecov/patch

website/src/actions/timetables.ts#L237-L238

Added lines #L237 - L238 were not covered by tests
type: SET_TA_IMPORTED,
payload: { semester, taModules },
};
}

Expand Down Expand Up @@ -253,3 +272,37 @@
payload: { moduleCode, semester },
};
}

export const ADD_TA_LESSON_IN_TIMETABLE = 'ADD_TA_LESSON_IN_TIMETABLE' as const;
export function addTaLessonInTimetable(
semester: Semester,
moduleCode: ModuleCode,
lessonType: LessonType,
classNo: ClassNo,
) {
return {
type: ADD_TA_LESSON_IN_TIMETABLE,
payload: { semester, moduleCode, lessonType, classNo },
};
}

export const REMOVE_TA_LESSON_IN_TIMETABLE = 'REMOVE_TA_LESSON_IN_TIMETABLE' as const;
export function removeTaLessonInTimetable(
semester: Semester,
moduleCode: ModuleCode,
lessonType: LessonType,
classNo: ClassNo,
) {
return {
type: REMOVE_TA_LESSON_IN_TIMETABLE,
payload: { semester, moduleCode, lessonType, classNo },
};
}

export const DISABLE_TA_MODE_IN_TIMETABLE = 'DISABLE_TA_MODE_IN_TIMETABLE' as const;
export function disableTaModeInTimetable(semester: Semester, moduleCode: ModuleCode) {
return {

Check warning on line 304 in website/src/actions/timetables.ts

View check run for this annotation

Codecov / codecov/patch

website/src/actions/timetables.ts#L303-L304

Added lines #L303 - L304 were not covered by tests
type: DISABLE_TA_MODE_IN_TIMETABLE,
payload: { semester, moduleCode },
};
}
1 change: 1 addition & 0 deletions website/src/apis/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type ExportOptions = {
pixelRatio?: number;
};

// Replace with http://localhost:8080/export when testing export
const baseUrl = 'https://export.nusmods.com/api/export';

function serializeState(
Expand Down
4 changes: 3 additions & 1 deletion website/src/entry/export/TimetableOnly.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@
timetable: {},
colors: {},
hidden: [],
ta: {},
};

override render() {
const { store } = this.props;
const theme = store.getState().theme.id;

const { semester, timetable, colors, hidden } = this.state;
const { semester, timetable, colors, hidden, ta } = this.state;

Check warning on line 37 in website/src/entry/export/TimetableOnly.tsx

View check run for this annotation

Codecov / codecov/patch

website/src/entry/export/TimetableOnly.tsx#L37

Added line #L37 was not covered by tests
const filledColors = fillColorMapping(timetable, colors);

return (
Expand All @@ -46,6 +47,7 @@
timetable={timetable}
colors={filledColors}
hiddenImportedModules={hidden}
taImportedModules={ta}
readOnly
/>
</div>
Expand Down
8 changes: 8 additions & 0 deletions website/src/reducers/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ const exportData: ExportData = {
PC1222: 2,
},
hidden: ['PC1222'],
ta: {
CS1010S: [['Tutorial', '1']],
},
theme: {
id: 'google',
timetableOrientation: VERTICAL,
Expand Down Expand Up @@ -74,6 +77,11 @@ test('reducers should set export data state', () => {
},
},
hidden: { [1]: ['PC1222'] },
ta: {
[1]: {
CS1010S: [['Tutorial', '1']],
},
},
academicYear: expect.any(String),
archive: {},
});
Expand Down
Loading