diff --git a/src/pages/background/lib/addCourse.ts b/src/pages/background/lib/addCourse.ts index cd2cd31d..511720b5 100644 --- a/src/pages/background/lib/addCourse.ts +++ b/src/pages/background/lib/addCourse.ts @@ -16,6 +16,7 @@ export default async function addCourse(scheduleName: string, course: Course): P } activeSchedule.courses.push(course); + activeSchedule.updatedAt = Date.now(); await UserScheduleStore.set('schedules', schedules); } diff --git a/src/pages/background/lib/clearCourses.ts b/src/pages/background/lib/clearCourses.ts index 296c4d80..e226b038 100644 --- a/src/pages/background/lib/clearCourses.ts +++ b/src/pages/background/lib/clearCourses.ts @@ -12,5 +12,7 @@ export default async function clearCourses(scheduleName: string): Promise throw new Error(`Schedule ${scheduleName} does not exist`); } schedule.courses = []; + schedule.updatedAt = Date.now(); + await UserScheduleStore.set('schedules', schedules); } diff --git a/src/pages/background/lib/createSchedule.ts b/src/pages/background/lib/createSchedule.ts index 3e0a9486..a602d081 100644 --- a/src/pages/background/lib/createSchedule.ts +++ b/src/pages/background/lib/createSchedule.ts @@ -15,6 +15,7 @@ export default async function createSchedule(scheduleName: string): Promise c.uniqueId !== course.uniqueId); + activeSchedule.updatedAt = Date.now(); await UserScheduleStore.set('schedules', schedules); } diff --git a/src/pages/background/lib/renameSchedule.ts b/src/pages/background/lib/renameSchedule.ts index 4cf769c4..b13a0817 100644 --- a/src/pages/background/lib/renameSchedule.ts +++ b/src/pages/background/lib/renameSchedule.ts @@ -17,6 +17,7 @@ export default async function renameSchedule(scheduleName: string, newName: stri } schedules[scheduleIndex].name = newName; + schedules[scheduleIndex].updatedAt = Date.now(); await UserScheduleStore.set('schedules', schedules); return undefined; diff --git a/src/pages/background/lib/switchSchedule.ts b/src/pages/background/lib/switchSchedule.ts index ddad8962..a72301b4 100644 --- a/src/pages/background/lib/switchSchedule.ts +++ b/src/pages/background/lib/switchSchedule.ts @@ -13,6 +13,7 @@ export default async function switchSchedule(scheduleName: string): Promise({ courses: [], name: 'Schedule 1', hours: 0, + updatedAt: Date.now(), }), ], activeIndex: 0, diff --git a/src/shared/types/UserSchedule.ts b/src/shared/types/UserSchedule.ts index f6bd1e85..e6f20483 100644 --- a/src/shared/types/UserSchedule.ts +++ b/src/shared/types/UserSchedule.ts @@ -9,6 +9,8 @@ export class UserSchedule { courses: Course[]; name: string; hours: number; + /** Unix timestamp of when the schedule was last updated */ + updatedAt: number; constructor(schedule: Serialized) { this.courses = schedule.courses.map(c => new Course(c)); @@ -17,6 +19,7 @@ export class UserSchedule { for (const course of this.courses) { this.hours += course.creditHours; } + this.updatedAt = schedule.updatedAt; } containsCourse(course: Course): boolean { diff --git a/src/stories/components/calendar/CalendarSchedules.stories.tsx b/src/stories/components/calendar/CalendarSchedules.stories.tsx index 72ffe43d..ba0a8962 100644 --- a/src/stories/components/calendar/CalendarSchedules.stories.tsx +++ b/src/stories/components/calendar/CalendarSchedules.stories.tsx @@ -65,7 +65,8 @@ const schedules = [ }), ], name: 'Main Schedule', - hours: 0, // Add the missing 'hours' property + hours: 0, + updatedAt: Date.now(), }), new UserSchedule({ courses: [ @@ -135,7 +136,8 @@ const schedules = [ }), ], name: 'Backup #3', - hours: 0, // Add the missing 'hours' property + hours: 0, + updatedAt: Date.now(), }), ]; diff --git a/src/stories/injected/CourseCatalogInjectedPopup.stories.ts b/src/stories/injected/CourseCatalogInjectedPopup.stories.ts index 843b3702..5880530d 100644 --- a/src/stories/injected/CourseCatalogInjectedPopup.stories.ts +++ b/src/stories/injected/CourseCatalogInjectedPopup.stories.ts @@ -47,7 +47,7 @@ export const ClosedCourse: Story = { ...MikeScottCS314Course, status: Status.CLOSED, } as Course, - activeSchedule: new UserSchedule({ courses: [], name: '', hours: 0 }), + activeSchedule: new UserSchedule({ courses: [], name: '', hours: 0, updatedAt: Date.now() }), }, }; diff --git a/src/stories/injected/mocked.ts b/src/stories/injected/mocked.ts index 3b6a31b0..0be0195d 100644 --- a/src/stories/injected/mocked.ts +++ b/src/stories/injected/mocked.ts @@ -57,6 +57,7 @@ export const exampleSchedule: UserSchedule = new UserSchedule({ courses: [exampleCourse], name: 'Example Schedule', hours: 3, + updatedAt: Date.now(), }); export const bevoCourse: Course = new Course({ @@ -108,6 +109,7 @@ export const bevoScheule: UserSchedule = new UserSchedule({ courses: [bevoCourse], name: 'Bevo Schedule', hours: 3, + updatedAt: Date.now(), }); export const MikeScottCS314Course: Course = new Course({ @@ -160,4 +162,5 @@ export const MikeScottCS314Schedule: UserSchedule = new UserSchedule({ courses: [MikeScottCS314Course], name: 'Mike Scott CS314 Schedule', hours: 3, + updatedAt: Date.now(), }); diff --git a/src/views/components/PopupMain.tsx b/src/views/components/PopupMain.tsx index 3ce3ca29..3d45fa89 100644 --- a/src/views/components/PopupMain.tsx +++ b/src/views/components/PopupMain.tsx @@ -6,6 +6,7 @@ import List from '@views/components/common/List/List'; import Text from '@views/components/common/Text/Text'; import { handleOpenCalendar } from '@views/components/injected/CourseCatalogInjectedPopup/HeadingAndActions'; import useSchedules, { getActiveSchedule, replaceSchedule, switchSchedule } from '@views/hooks/useSchedules'; +import { getUpdatedAtDateTimeString } from '@views/lib/getUpdatedAtDateTimeString'; import { openTabFromContentScript } from '@views/lib/openNewTabFromContentScript'; import clsx from 'clsx'; import React, { useState } from 'react'; @@ -120,7 +121,7 @@ export default function PopupMain(): JSX.Element {
- DATA UPDATED ON: 12:00 AM 02/01/2024 + LAST UPDATED: {getUpdatedAtDateTimeString(activeSchedule.updatedAt)}
- + - DATA UPDATED ON: 12:00 AM 02/01/2024 + LAST UPDATED: {getUpdatedAtDateTimeString(activeSchedule.updatedAt)}
-
+
diff --git a/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx b/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx index 0a6df0a6..d537b610 100644 --- a/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx +++ b/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx @@ -26,9 +26,9 @@ export default function ScheduleTotalHoursAndCourses({ {`${scheduleName}: `} - {totalHours} HOURS + {totalHours} {totalHours === 1 ? 'HOUR' : 'HOURS'} - {totalCourses} courses + {totalCourses} {totalCourses === 1 ? 'COURSE' : 'COURSES'}
diff --git a/src/views/hooks/useFlattenedCourseSchedule.ts b/src/views/hooks/useFlattenedCourseSchedule.ts index 6462cb57..9e195e28 100644 --- a/src/views/hooks/useFlattenedCourseSchedule.ts +++ b/src/views/hooks/useFlattenedCourseSchedule.ts @@ -61,6 +61,7 @@ export function useFlattenedCourseSchedule(): FlattenedCourseSchedule { courses: [], name: 'Something may have went wrong', hours: 0, + updatedAt: Date.now(), }), } satisfies FlattenedCourseSchedule; } diff --git a/src/views/lib/getUpdatedAtDateTimeString.ts b/src/views/lib/getUpdatedAtDateTimeString.ts new file mode 100644 index 00000000..ccfca40a --- /dev/null +++ b/src/views/lib/getUpdatedAtDateTimeString.ts @@ -0,0 +1,21 @@ +/** + * + * @param updatedAt {number} - The time in milliseconds since the epoch when the schedule was last updated. + * @returns {string} - DateTime formatted as HH:MM AM/PM MM/DD/YYYY + */ +export function getUpdatedAtDateTimeString(updatedAt: number): string { + const updatedAtDate = new Date(updatedAt); + + const timeFormat = new Intl.DateTimeFormat('en-US', { + hour: 'numeric', + minute: 'numeric', + hour12: true, + }).format(updatedAtDate); + const dateFormat = new Intl.DateTimeFormat('en-US', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + }).format(updatedAtDate); + + return `${timeFormat} ${dateFormat}`; +}