import type { Course, StatusType } from '@shared/types/Course'; import type { CourseMeeting } from '@shared/types/CourseMeeting'; import { Button } from '@views/components/common/Button'; import Divider from '@views/components/common/Divider'; import { LargeLogo } from '@views/components/common/LogoIcon'; import Text from '@views/components/common/Text/Text'; import useChangelog from '@views/hooks/useChangelog'; import useSchedules from '@views/hooks/useSchedules'; import React, { useCallback, useEffect } from 'react'; import IconoirGitFork from '~icons/iconoir/git-fork'; import CalendarFooter from '../calendar/CalendarFooter'; import { CalendarSchedules } from '../calendar/CalendarSchedules'; import ImportantLinks from '../calendar/ImportantLinks'; import TeamLinks from '../calendar/TeamLinks'; import CampusMap from './CampusMap'; import { type DAY, DAYS } from './types'; const manifest = chrome.runtime.getManifest(); const LDIconURL = new URL('/src/assets/LD-icon.png', import.meta.url).href; const dayToNumber = { Monday: 0, Tuesday: 1, Wednesday: 2, Thursday: 3, Friday: 4, Saturday: 5, Sunday: 6, } as const satisfies Record; /** * Represents the details of an in-person meeting process. * * day - The day of the meeting. * dayIndex - The index of the day in the week. * fullName - The full name of the person. * uid - The unique identifier of the person. * time - The time of the meeting. * normalizedStartTime - The normalized start time of the meeting. * normalizedEndTime - The normalized end time of the meeting. * startIndex - The start index of the meeting. * endIndex - The end index of the meeting. * location - The location of the meeting. * status - The status of the meeting. * colors - The colors associated with the course. * course - The course details. */ export type ProcessInPersonMeetings = { day: DAY; dayIndex: number; fullName: string; uid: number; time: string; normalizedStartTime: number; normalizedEndTime: number; startIndex: number; endIndex: number; location: CourseMeeting['location']; status: StatusType; colors: Course['colors']; course: Course; }; /** * Converts minutes to an index value. * @param minutes - The number of minutes. * @returns The index value. */ const convertMinutesToIndex = (minutes: number): number => Math.floor((minutes - 420) / 30); /** * Renders the map component for the UTRP (UT Registration Plus) extension. */ export default function Map(): JSX.Element { const handleChangelogOnClick = useChangelog(); const [activeSchedule] = useSchedules(); /** * Function to extract and format basic course information */ function extractCourseInfo(course: Course) { const { status, schedule: { meetings }, } = course; let courseDeptAndInstr = `${course.department} ${course.number}`; const mainInstructor = course.instructors[0]; if (mainInstructor) { courseDeptAndInstr += ` – ${mainInstructor.toString({ format: 'first_last' })}`; } return { status, courseDeptAndInstr, meetings, course }; } // /** // * Function to process each in-person class into its distinct meeting objects for calendar grid // */ // function processAsyncCourses({ // courseDeptAndInstr, // status, // course, // }: { // courseDeptAndInstr: string; // status: StatusType; // course: Course; // }): CalendarGridCourse[] { // return [ // { // calendarGridPoint: { // dayIndex: -1, // startIndex: -1, // endIndex: -1, // }, // componentProps: { // courseDeptAndInstr, // status, // colors: course.colors, // }, // course, // async: true, // }, // ]; // } /** * Function to process each in-person class into its distinct meeting objects for calendar grid */ function processInPersonMeetings( meeting: CourseMeeting, courseDeptAndInstr: string, status: StatusType, course: Course ) { const { days, location, startTime, endTime } = meeting; const time = meeting.getTimeString({ separator: '-' }); const timeAndLocation = `${time}${location ? ` - ${location.building} ${location.room}` : ''}`; const midnightIndex = 1440; const normalizingTimeFactor = 720; const normalizedStartTime = startTime >= midnightIndex ? startTime - normalizingTimeFactor : startTime; const normalizedEndTime = endTime >= midnightIndex ? endTime - normalizingTimeFactor : endTime; return days.map(day => ({ day, dayIndex: dayToNumber[day], // fullName: `${courseDeptAndInstr} - ${timeAndLocation}`, fullName: `${timeAndLocation} - ${courseDeptAndInstr}`, uid: course.uniqueId, time, normalizedStartTime, normalizedEndTime, startIndex: convertMinutesToIndex(normalizedStartTime), endIndex: convertMinutesToIndex(normalizedEndTime), location, status, colors: course.colors, course, })); } const processedCourses: ProcessInPersonMeetings[] = activeSchedule.courses.flatMap(course => { const { status, courseDeptAndInstr, meetings } = extractCourseInfo(course); // if (meetings.length === 0) { // return processAsyncCourses({ courseDeptAndInstr, status, course }); // } return meetings.flatMap(meeting => // if (meeting.days.includes(DAY_MAP.S) || meeting.startTime < 480) { // return processAsyncCourses({ courseDeptAndInstr, status, course }); // } processInPersonMeetings(meeting, courseDeptAndInstr, status, course) ); }); const generateWeekSchedule = useCallback((): Record => { const weekSchedule: Record = {}; processedCourses.forEach(course => { const { day } = course; // Add the course to the day's schedule if (!weekSchedule[day]) weekSchedule[day] = []; weekSchedule[day].push(course.fullName); }); // TODO: Not the best way to do this // currently weekSchedule is an object with keys as days and values as an array of courses // we want to display the days in order, so we create a new object with the days in order const orderedWeekSchedule: Record = { Monday: [], Tuesday: [], Wednesday: [], Thursday: [], Friday: [], Saturday: [], Sunday: [], }; DAYS.forEach(day => { if (weekSchedule[day]) { orderedWeekSchedule[day] = weekSchedule[day]; } }); // Sort each day based on the start time of the course Object.entries(orderedWeekSchedule).forEach(([day, courses]) => { orderedWeekSchedule[day as DAY] = courses.sort((courseA, courseB) => { const courseAStartTime = processedCourses.find( course => course.fullName === courseA )?.normalizedStartTime; const courseBStartTime = processedCourses.find( course => course.fullName === courseB )?.normalizedStartTime; return (courseAStartTime ?? 0) - (courseBStartTime ?? 0); }); }); return orderedWeekSchedule; }, [processedCourses]); useEffect(() => { console.log('Active Schedule: ', activeSchedule); console.log('processedCourses:', processedCourses); console.log('generateWeekSchedule():', generateWeekSchedule()); }, [activeSchedule, processedCourses, generateWeekSchedule]); return (
UTRP Map
LD Icon
{/* Show week schedule */}

Week Schedule:

{Object.entries(generateWeekSchedule()).map(([day, courses]) => (

{day}

    {courses.map(course => (
  • {course}
  • ))}
))}
); }