import { background } from '@shared/messages'; import type { Course } from '@shared/types/Course'; import { Status } from '@shared/types/Course'; import type Instructor from '@shared/types/Instructor'; import type { UserSchedule } from '@shared/types/UserSchedule'; import { Button } from '@views/components/common/Button/Button'; import { Chip, flagMap } from '@views/components/common/Chip/Chip'; import Divider from '@views/components/common/Divider/Divider'; import Text from '@views/components/common/Text/Text'; import { openTabFromContentScript } from '@views/lib/openNewTabFromContentScript'; import React, { useState } from 'react'; import Add from '~icons/material-symbols/add'; import CalendarMonth from '~icons/material-symbols/calendar-month'; import CloseIcon from '~icons/material-symbols/close'; import Copy from '~icons/material-symbols/content-copy'; import Description from '~icons/material-symbols/description'; import Mood from '~icons/material-symbols/mood'; import Remove from '~icons/material-symbols/remove'; import Reviews from '~icons/material-symbols/reviews'; const { openNewTab, addCourse, removeCourse, openCESPage } = background; interface HeadingAndActionProps { /* The course to display */ course: Course; /* The active schedule */ activeSchedule?: UserSchedule; /* The function to call when the popup should be closed */ onClose: () => void; } /** * Opens the calendar in a new tab. * @returns {Promise} A promise that resolves when the tab is opened. */ export const handleOpenCalendar = async (): Promise => { const url = chrome.runtime.getURL('calendar.html'); openNewTab({ url }); }; const capitalizeString = (str: string) => str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); /** * Renders the heading component for the CoursePopup component. * * @param {HeadingAndActionProps} props - The component props. * @param {Course} props.course - The course object containing course details. * @param {Schedule} props.activeSchedule - The active schedule object. * @param {Function} props.onClose - The function to close the popup. * @returns {JSX.Element} The rendered component. */ const HeadingAndActions: React.FC = ({ course, activeSchedule, onClose, }: HeadingAndActionProps): JSX.Element => { const { courseName, department, number: courseNumber, uniqueId, instructors, flags, schedule } = course; const [courseAdded, setCourseAdded] = useState( activeSchedule !== undefined ? activeSchedule.courses.some(course => course.uniqueId === uniqueId) : false ); const getInstructorFullName = (instructor: Instructor) => { const { firstName, lastName } = instructor; if (firstName === '') return capitalizeString(lastName); return `${capitalizeString(firstName)} ${capitalizeString(lastName)}`; }; const instructorString = instructors.map(getInstructorFullName).join(', '); const handleCopy = () => { navigator.clipboard.writeText(uniqueId.toString()); }; const handleOpenRateMyProf = async () => { const openTabs = instructors.map(instructor => { const instructorSearchTerm = getInstructorFullName(instructor); instructorSearchTerm.replace(' ', '+'); const url = `https://www.ratemyprofessors.com/search/professors/1255?q=${instructorSearchTerm}`; return openNewTab({ url }); }); await Promise.all(openTabs); }; const handleOpenCES = async () => { const openTabs = instructors.map(instructor => { let { firstName, lastName } = instructor; firstName = capitalizeString(firstName); lastName = capitalizeString(lastName); return openCESPage({ instructorFirstName: firstName, instructorLastName: lastName }); }); await Promise.all(openTabs); }; const handleOpenPastSyllabi = async () => { // not specific to professor const url = `https://utdirect.utexas.edu/apps/student/coursedocs/nlogon/?year=&semester=&department=${department}&course_number=${courseNumber}&course_title=${courseName}&unique=&instructor_first=&instructor_last=&course_type=In+Residence&search=Search`; openNewTab({ url }); }; const handleAddOrRemoveCourse = async () => { if (!activeSchedule) return; if (!courseAdded) { addCourse({ course, scheduleName: activeSchedule.name }); } else { removeCourse({ course, scheduleName: activeSchedule.name }); } setCourseAdded(prev => !prev); }; return (
{courseName} {' '} ({department} {courseNumber})
{instructorString.length > 0 && ( with {instructorString} )}
{flags.map(flag => ( ))}
{schedule.meetings.map(meeting => { const daysString = meeting.getDaysString({ format: 'long', separator: 'long' }); const timeString = meeting.getTimeString({ separator: ' to ', capitalize: false }); const locationString = meeting.location ? ` in ${meeting.location.building}` : ''; return ( {daysString} {timeString} {locationString} ); })}
); }; export default HeadingAndActions;