Skip to content

Commit

Permalink
feat: add terms to custom events
Browse files Browse the repository at this point in the history
  • Loading branch information
Slo1k committed Jan 1, 2025
1 parent 8b6db5d commit e079db0
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export interface CustomEvent extends CommonCalendarEvent {
isCustomEvent: true;
building: string;
days: string[];
term: string;
}

export type CalendarEvent = CourseEvent | CustomEvent;
Expand Down Expand Up @@ -280,7 +281,7 @@ const CourseCalendarEvent = (props: CourseCalendarEventProps) => {
</Paper>
);
} else {
const { title, customEventID, building } = selectedEvent;
const { title, customEventID, building, term } = selectedEvent;
return (
<Paper className={classes.customEventContainer} ref={paperRef}>
<div className={classes.title}>{title}</div>
Expand All @@ -296,6 +297,12 @@ const CourseCalendarEvent = (props: CourseCalendarEventProps) => {
</Link>
</div>
)}
{term && (
<tr className={classes.table}>
<td className={classes.alignToTop}>Term:&nbsp;</td>
<td className={classes.rightCells}>{term}</td>
</tr>
)}
<div className={classes.buttonBar}>
<div className={`${classes.colorPicker}`}>
<ColorPicker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import ScheduleSelector from './ScheduleSelector';
import { addCustomEvent, editCustomEvent } from '$actions/AppStoreActions';
import { BuildingSelect, ExtendedBuilding } from '$components/inputs/building-select';
import analyticsEnum, { logAnalytics } from '$lib/analytics';
import { getLatestTermByShortName } from '$lib/termData';
import AppStore from '$stores/AppStore';
import { useThemeStore } from '$stores/SettingsStore';

Expand All @@ -36,6 +37,7 @@ const defaultCustomEventValues: RepeatingCustomEvent = {
days: [false, false, false, false, false, false, false],
customEventID: 0,
building: undefined,
term: undefined,
};

function CustomEventDialogs(props: CustomEventDialogProps) {
Expand Down Expand Up @@ -110,6 +112,8 @@ function CustomEventDialogs(props: CustomEventDialogProps) {
const handleAddToCalendar = () => {
if (!days.some((day) => day) || scheduleIndices.length === 0) return;

const termsShortNames = AppStore.schedule.getCoursesFromSchedules(scheduleIndices).map((course) => course.term);

const newCustomEvent: RepeatingCustomEvent = {
color: props.customEvent ? props.customEvent.color : '#551a8b',
title: title,
Expand All @@ -118,6 +122,7 @@ function CustomEventDialogs(props: CustomEventDialogProps) {
end: end,
customEventID: props.customEvent ? props.customEvent.customEventID : Date.now(),
building: building,
term: getLatestTermByShortName(termsShortNames)?.shortName,
};

resetForm();
Expand Down
51 changes: 51 additions & 0 deletions apps/antalmanac/src/lib/termData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,56 @@ function getFinalsStartDateForTerm(term: string) {
return year && month && day ? new Date(year, month, day + 1) : undefined;
}

/**
* Get latest term by short name.
*
* By default, use a static index.
* If an array of terms short names is provided, select the term with the latest start date.
* for example, if the events array contains terms from 2023 Winter, 2024 Spring and 2023 Summer the function will return 2024 Spring
*/

function getLatestTermByShortName(termsShortNames: string[] = []): Term {
if (termsShortNames.length === 0) {
return termData[defaultTerm];
}

// Initialize latestTerm as the oldest term in termData
let latestTermIndex = termData.length - 1;
let latestTerm = termData[latestTermIndex];
let foundMatchingTerm = false;

for (const termShortName of termsShortNames) {
const existingTermIndex = termData.findIndex((t) => t.shortName === termShortName);
const existingTerm = termData[existingTermIndex];
foundMatchingTerm = true;

// Compare start dates of existingTerm and latestTerm to determine which term is the latest
if (existingTerm.startDate && latestTerm.startDate) {
const existingStartDate = new Date(...existingTerm.startDate);
const latestStartDate = new Date(...latestTerm.startDate);

if (existingStartDate > latestStartDate) {
latestTerm = existingTerm;
latestTermIndex = existingTermIndex;
}

// If latestTerm or existingTerm does not have a startDate, set latestTerm to term with the smallest index
} else {
if (existingTermIndex < latestTermIndex) {
latestTerm = existingTerm;
latestTermIndex = existingTermIndex;
}
}
}

if (foundMatchingTerm) {
return latestTerm;
} else {
// Return defaultTerm if no matching terms are found in termData
return termData[defaultTerm];
}
}

export {
defaultTerm,
getDefaultTerm,
Expand All @@ -154,4 +204,5 @@ export {
getDefaultFinalsStartDate,
getFinalsStartForTerm,
getFinalsStartDateForTerm,
getLatestTermByShortName,
};
12 changes: 11 additions & 1 deletion apps/antalmanac/src/stores/Schedules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import type {
ScheduleUndoState,
ShortCourseSchedule,
RepeatingCustomEvent,
CourseInfo,
} from '@packages/antalmanac-types';
import type { CourseInfo } from '@packages/antalmanac-types';

import { calendarizeCourseEvents, calendarizeCustomEvents, calendarizeFinals } from './calendarizeHelpers';

Expand Down Expand Up @@ -180,6 +180,16 @@ export class Schedules {
return this.schedules.map((schedule) => schedule.courses).flat(1);
}

/**
* Get combined list of courses from schedules specified by the given indices.
*/
getCoursesFromSchedules(scheduleIndices: number[]) {
return scheduleIndices
.filter((index) => index >= 0 && index < this.getNumberOfSchedules())
.map((index) => this.schedules[index].courses)
.flat(1);
}

/**
* Get course that matches the params across **all** schedules.
*/
Expand Down
1 change: 1 addition & 0 deletions apps/antalmanac/src/stores/calendarizeHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ export function calendarizeCustomEvents(currentCustomEvents: RepeatingCustomEven
title: customEvent.title,
building: customEvent.building ?? '',
days,
term: customEvent.term ?? '',
};
});
});
Expand Down
4 changes: 4 additions & 0 deletions apps/antalmanac/tests/calendarize-helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ describe('calendarize-helpers', () => {
title: 'title',
building: '',
days: ['Su', 'Tu', 'Th', 'Sa'],
term: '2018 Winter',
},
{
isCustomEvent: true,
Expand All @@ -221,6 +222,7 @@ describe('calendarize-helpers', () => {
title: 'title',
building: '',
days: ['Su', 'Tu', 'Th', 'Sa'],
term: '2018 Winter',
},
{
isCustomEvent: true,
Expand All @@ -231,6 +233,7 @@ describe('calendarize-helpers', () => {
title: 'title',
building: '',
days: ['Su', 'Tu', 'Th', 'Sa'],
term: '2018 Winter',
},
{
isCustomEvent: true,
Expand All @@ -241,6 +244,7 @@ describe('calendarize-helpers', () => {
title: 'title',
building: '',
days: ['Su', 'Tu', 'Th', 'Sa'],
term: '2018 Winter',
},
];

Expand Down
1 change: 1 addition & 0 deletions packages/types/src/customevent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const RepeatingCustomEventSchema = type({
customEventID: 'string | number', // Unique only within the schedule.
'color?': 'string',
'building?': 'string | undefined',
'term?': 'string | undefined',
});

export type RepeatingCustomEvent = typeof RepeatingCustomEventSchema.infer;

0 comments on commit e079db0

Please sign in to comment.