chore: lint-format-docs-tests-bugfixes (#105)

* docs: add jsdoc

* feat: change enums to as const objects

* chore(test): add themeColors.test.ts

* fix: fix tests and bugs with strings.ts util

* fix: path alias imports and tsconfig file bug

* fix: remove --max-warnings 0
This commit is contained in:
doprz
2024-02-22 22:42:58 -06:00
parent 8ab60c9f01
commit 8a6e9070e0
134 changed files with 986 additions and 623 deletions

View File

@@ -1,19 +1,20 @@
import { Course, ScrapedRow } from '@shared/types/Course';
import type { Course, ScrapedRow } from '@shared/types/Course';
import React, { useEffect, useState } from 'react';
import { useKeyPress } from '../hooks/useKeyPress';
import useSchedules from '../hooks/useSchedules';
import { CourseCatalogScraper } from '../lib/CourseCatalogScraper';
import getCourseTableRows from '../lib/getCourseTableRows';
import { SiteSupport } from '../lib/getSiteSupport';
import type { SiteSupport } from '../lib/getSiteSupport';
import { populateSearchInputs } from '../lib/populateSearchInputs';
import ExtensionRoot from './common/ExtensionRoot/ExtensionRoot';
import AutoLoad from './injected/AutoLoad/AutoLoad';
import CourseCatalogInjectedPopup from './injected/CourseCatalogInjectedPopup/CourseCatalogInjectedPopup';
import CoursePopup from './injected/CoursePopupOld/CoursePopup';
import RecruitmentBanner from './injected/RecruitmentBanner/RecruitmentBanner';
import TableHead from './injected/TableHead';
import TableRow from './injected/TableRow/TableRow';
import TableSubheading from './injected/TableSubheading/TableSubheading';
import CourseCatalogInjectedPopup from './injected/CourseCatalogInjectedPopup/CourseCatalogInjectedPopup';
interface Props {
support: SiteSupport.COURSE_CATALOG_DETAILS | SiteSupport.COURSE_CATALOG_LIST;

View File

@@ -1,97 +1,158 @@
import logoImage from '@assets/logo.png'; // Adjust the path as necessary
import { Status } from '@shared/types/Course';
import { StatusIcon } from '@shared/util/icons';
import Divider from '@views/components/common/Divider/Divider';
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot';
import List from '@views/components/common/List/List'; // Ensure this path is correctly pointing to your List component
import PopupCourseBlock from '@views/components/common/PopupCourseBlock/PopupCourseBlock';
import Text from '@views/components/common/Text/Text';
import { handleOpenCalendar } from '@views/components/injected/CourseCatalogInjectedPopup/HeadingAndActions';
import useSchedules from '@views/hooks/useSchedules';
import { openTabFromContentScript } from '@views/lib/openNewTabFromContentScript';
import React from 'react';
import { FaCalendarAlt, FaCog, FaRedo } from 'react-icons/fa'; // Added FaRedo for the refresh icon
import { StatusIcon } from '@shared/util/icons';
import { Status } from 'src/shared/types/Course';
import { test_colors } from 'src/stories/components/PopupCourseBlock.stories';
import ExtensionRoot from './common/ExtensionRoot/ExtensionRoot';
import PopupCourseBlock from './common/PopupCourseBlock/PopupCourseBlock';
import Text from './common/Text/Text';
import Divider from './common/Divider/Divider';
import logoImage from '../../assets/logo.png'; // Adjust the path as necessary
import List from './common/List/List'; // Ensure this path is correctly pointing to your List component
import useSchedules from '../hooks/useSchedules';
import { handleOpenCalendar } from './injected/CourseCatalogInjectedPopup/HeadingAndActions';
import { openTabFromContentScript } from '../lib/openNewTabFromContentScript';
import { TestColors } from 'src/stories/components/PopupCourseBlock.stories';
/**
* Renders the main popup component.
* This component displays the main schedule, courses, and options buttons.
*/
export default function PopupMain() {
const [activeSchedule] = useSchedules();
const [activeSchedule] = useSchedules();
const draggableElements = activeSchedule?.courses.map((course, i) => (
<PopupCourseBlock
key={course.uniqueId}
course={course}
colors={test_colors[i]}
/>
const draggableElements = activeSchedule?.courses.map((course, i) => (
<PopupCourseBlock key={course.uniqueId} course={course} colors={TestColors[i]} />
));
const handleOpenOptions = async () => { // Not sure if it's bad practice to export this
const handleOpenOptions = async () => {
// Not sure if it's bad practice to export this
const url = chrome.runtime.getURL('/src/pages/options/index.html');
await openTabFromContentScript(url);
};
return (
<ExtensionRoot>
<div className="mx-auto max-w-sm rounded-lg bg-white p-4 shadow-md">
<div className="mb-2 flex items-center justify-between bg-white">
<div className="flex items-center">
<img src={logoImage} alt="Logo" style={{ width: '40px', height: '40px', marginRight: '8px' }} />
<div className='mx-auto max-w-sm rounded-lg bg-white p-4 shadow-md'>
<div className='mb-2 flex items-center justify-between bg-white'>
<div className='flex items-center'>
<img src={logoImage} alt='Logo' style={{ width: '40px', height: '40px', marginRight: '8px' }} />
<div>
<Text as="div" variant="h1-course" style={{ color: '#bf5700', fontSize: '1.3rem' }}>UT Registration</Text>
<Text as="div" variant="h1-course" style={{ color: '#f8971f', fontSize: '1.3rem' }}>Plus</Text>
<Text as='div' variant='h1-course' style={{ color: '#bf5700', fontSize: '1.3rem' }}>
UT Registration
</Text>
<Text as='div' variant='h1-course' style={{ color: '#f8971f', fontSize: '1.3rem' }}>
Plus
</Text>
</div>
</div>
<div className="flex items-center">
<button style={{ backgroundColor: '#bf5700', borderRadius: '8px', padding: '8px' }} onClick={handleOpenCalendar}>
<FaCalendarAlt color="white" />
<div className='flex items-center'>
<button
style={{ backgroundColor: '#bf5700', borderRadius: '8px', padding: '8px' }}
onClick={handleOpenCalendar}
>
<FaCalendarAlt color='white' />
</button>
<button style={{ backgroundColor: 'white', marginLeft: '10px', borderRadius: '8px', padding: '8px', boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)' }}
onClick = {handleOpenOptions}>
<FaCog color="#C05621" />
<button
style={{
backgroundColor: 'white',
marginLeft: '10px',
borderRadius: '8px',
padding: '8px',
boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)',
}}
onClick={handleOpenOptions}
>
<FaCog color='#C05621' />
</button>
</div>
</div>
<Divider color="#E2E8F0" type="solid" style={{ margin: '1rem 0' }} />
<div className="mb-4 rounded-lg bg-white p-2 text-left shadow-inner" style={{ backgroundColor: 'white', border: '1px solid #FBD38D', borderRadius: '0.5rem' }}>
<Text as="div" variant="h2-course" style={{ color: '#DD6B20', fontSize: '1.2rem' }}>MAIN SCHEDULE:</Text>
<Divider color='#E2E8F0' type='solid' style={{ margin: '1rem 0' }} />
<div
className='mb-4 rounded-lg bg-white p-2 text-left shadow-inner'
style={{ backgroundColor: 'white', border: '1px solid #FBD38D', borderRadius: '0.5rem' }}
>
<Text as='div' variant='h2-course' style={{ color: '#DD6B20', fontSize: '1.2rem' }}>
MAIN SCHEDULE:
</Text>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'start', color: '#333f48' }}>
<Text as="div" variant="h1" style={{ fontSize: '1.2rem', fontWeight: 'bold', marginRight: '0.5rem' }}>22 HOURS</Text>
<Text as="div" variant="h2-course" style={{ fontSize: '1.2rem' }}>8 Courses</Text>
<Text
as='div'
variant='h1'
style={{ fontSize: '1.2rem', fontWeight: 'bold', marginRight: '0.5rem' }}
>
22 HOURS
</Text>
<Text as='div' variant='h2-course' style={{ fontSize: '1.2rem' }}>
8 Courses
</Text>
</div>
</div>
{/* Integrate the List component here */}
{activeSchedule ? <List
draggableElements={draggableElements}
itemHeight={100} // Adjust based on your content size
listHeight={500} // Adjust based on total height you want for the list
listWidth={350} // Adjust based on your layout/design
gap={12} // Spacing between items
/> : null}
<div className="mt-4 flex justify-between border-t border-gray-200 p-4 text-xs">
<div className="flex items-center">
<div style={{ backgroundColor: '#6B7280', padding: '1px', borderRadius: '4px', marginRight: '3px', marginLeft: '8px' }}>
<StatusIcon status={Status.WAITLISTED} className="h-5 w-5 text-white" />
{activeSchedule ? (
<List
draggableElements={draggableElements}
itemHeight={100} // Adjust based on your content size
listHeight={500} // Adjust based on total height you want for the list
listWidth={350} // Adjust based on your layout/design
gap={12} // Spacing between items
/>
) : null}
<div className='mt-4 flex justify-between border-t border-gray-200 p-4 text-xs'>
<div className='flex items-center'>
<div
style={{
backgroundColor: '#6B7280',
padding: '1px',
borderRadius: '4px',
marginRight: '3px',
marginLeft: '8px',
}}
>
<StatusIcon status={Status.WAITLISTED} className='h-5 w-5 text-white' />
</div>
<Text as="span" variant="mini">WAITLISTED</Text>
<Text as='span' variant='mini'>
WAITLISTED
</Text>
</div>
<div className="flex items-center">
<div style={{ backgroundColor: '#6B7280', padding: '1px', borderRadius: '4px', marginRight: '3px', marginLeft: '8px' }}>
<StatusIcon status={Status.CLOSED} className="h-5 w-5 text-white" />
<div className='flex items-center'>
<div
style={{
backgroundColor: '#6B7280',
padding: '1px',
borderRadius: '4px',
marginRight: '3px',
marginLeft: '8px',
}}
>
<StatusIcon status={Status.CLOSED} className='h-5 w-5 text-white' />
</div>
<Text as="span" variant="mini">CLOSED</Text>
<Text as='span' variant='mini'>
CLOSED
</Text>
</div>
<div className="flex items-center">
<div style={{ backgroundColor: '#6B7280', padding: '1px', borderRadius: '4px', marginRight: '3px', marginLeft: '8px' }}>
<StatusIcon status={Status.CANCELLED} className="h-5 w-5 text-white" />
<div className='flex items-center'>
<div
style={{
backgroundColor: '#6B7280',
padding: '1px',
borderRadius: '4px',
marginRight: '3px',
marginLeft: '8px',
}}
>
<StatusIcon status={Status.CANCELLED} className='h-5 w-5 text-white' />
</div>
<Text as="span" variant="mini">CANCELLED</Text>
<Text as='span' variant='mini'>
CANCELLED
</Text>
</div>
</div>
<div className="mt-2 text-center text-xs">
<div className="inline-flex items-center justify-center">
<Text as="div" variant="mini">DATA UPDATED ON: 12:00 AM 02/01/2024</Text>
<FaRedo className="ml-2 h-4 w-4 text-gray-600" />
<div className='mt-2 text-center text-xs'>
<div className='inline-flex items-center justify-center'>
<Text as='div' variant='mini'>
DATA UPDATED ON: 12:00 AM 02/01/2024
</Text>
<FaRedo className='ml-2 h-4 w-4 text-gray-600' />
</div>
</div>
</div>

View File

@@ -1,9 +1,10 @@
import React from 'react';
import CalendarHeader from 'src/views/components/calendar/CalendarHeader/CalenderHeader';
import { CalendarBottomBar } from '../CalendarBottomBar/CalendarBottomBar';
import CalendarGrid from '../CalendarGrid/CalendarGrid';
import { CalendarSchedules } from '../CalendarSchedules/CalendarSchedules';
import ImportantLinks from '../ImportantLinks';
import CalendarGrid from '../CalendarGrid/CalendarGrid';
export const flags = ['WR', 'QR', 'GC', 'CD', 'E', 'II'];

View File

@@ -1,10 +1,13 @@
import React from 'react';
import clsx from 'clsx';
import Text from '../../common/Text/Text';
import CalendarCourseBlock, { CalendarCourseCellProps } from '../CalendarCourseCell/CalendarCourseCell';
import { Button } from '../../common/Button/Button';
import ImageIcon from '~icons/material-symbols/image';
import React from 'react';
import CalendarMonthIcon from '~icons/material-symbols/calendar-month';
import ImageIcon from '~icons/material-symbols/image';
import { Button } from '../../common/Button/Button';
import Text from '../../common/Text/Text';
import type { CalendarCourseCellProps } from '../CalendarCourseCell/CalendarCourseCell';
import CalendarCourseBlock from '../CalendarCourseCell/CalendarCourseCell';
type CalendarBottomBarProps = {
courses?: CalendarCourseCellProps[];

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { Course } from 'src/shared/types/Course';
import { CourseMeeting } from 'src/shared/types/CourseMeeting';
import type { Course } from 'src/shared/types/Course';
import type { CourseMeeting } from 'src/shared/types/CourseMeeting';
import styles from './CalendarCourseMeeting.module.scss';
/**
@@ -26,6 +27,8 @@ export interface CalendarCourseMeetingProps {
const CalendarCourseMeeting: React.FC<CalendarCourseMeetingProps> = ({
course,
meetingIdx,
color,
rightIcon,
}: CalendarCourseMeetingProps) => {
let meeting: CourseMeeting | null = meetingIdx !== undefined ? course.schedule.meetings[meetingIdx] : null;
return (

View File

@@ -1,12 +1,17 @@
import { Status } from '@shared/types/Course';
import Text from '@views/components/common/Text/Text';
import clsx from 'clsx';
import React from 'react';
import { CourseColors, pickFontColor } from 'src/shared/util/colors';
import type { CourseColors } from 'src/shared/util/colors';
import { pickFontColor } from 'src/shared/util/colors';
import ClosedIcon from '~icons/material-symbols/lock';
import WaitlistIcon from '~icons/material-symbols/timelapse';
import CancelledIcon from '~icons/material-symbols/warning';
import Text from '../../common/Text/Text';
/**
* Props for the CalendarCourseCell component.
*/
export interface CalendarCourseCellProps {
courseDeptAndInstr: string;
timeAndLocation?: string;
@@ -15,6 +20,18 @@ export interface CalendarCourseCellProps {
className?: string;
}
/**
* Renders a cell for a calendar course.
*
* @component
* @param {CalendarCourseCellProps} props - The component props.
* @param {string} props.courseDeptAndInstr - The course department and instructor.
* @param {string} props.timeAndLocation - The time and location of the course.
* @param {Status} props.status - The status of the course.
* @param {Colors} props.colors - The colors for styling the cell.
* @param {string} props.className - Additional CSS class name for the cell.
* @returns {JSX.Element} The rendered component.
*/
const CalendarCourseCell: React.FC<CalendarCourseCellProps> = ({
courseDeptAndInstr,
timeAndLocation,

View File

@@ -1,12 +1,13 @@
import React, { useState, useRef, useEffect } from 'react';
import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule';
import React, { useEffect, useRef, useState } from 'react';
// import html2canvas from 'html2canvas';
import { DAY_MAP } from 'src/shared/types/CourseMeeting';
import { CalendarGridCourse } from 'src/views/hooks/useFlattenedCourseSchedule';
import CalendarCourseCell from '../CalendarCourseCell/CalendarCourseCell';
/* import calIcon from 'src/assets/icons/cal.svg';
import pngIcon from 'src/assets/icons/png.svg';
*/
import CalendarCell from '../CalendarGridCell/CalendarGridCell';
import CalendarCourseCell from '../CalendarCourseCell/CalendarCourseCell';
import styles from './CalendarGrid.module.scss';
/* const daysOfWeek = Object.keys(DAY_MAP).filter(key => !['S', 'SU'].includes(key));
@@ -107,7 +108,7 @@ function CalendarGrid({ courseCells, saturdayClass }: React.PropsWithChildren<Pr
newGrid.push(row);
}
setGrid(newGrid);
}, []);
}, [hoursOfDay]);
return (
<div className={styles.calendarGrid}>
@@ -119,7 +120,7 @@ function CalendarGrid({ courseCells, saturdayClass }: React.PropsWithChildren<Pr
</div>
))}
{grid.map((row, rowIndex) => row)}
{courseCells ? <AccountForCourseConflicts courseCells={courseCells}/> : null}
{courseCells ? <AccountForCourseConflicts courseCells={courseCells} /> : null}
{/* courseCells.map((block: CalendarGridCourse) => (
<div
key={`${block}`}

View File

@@ -1,4 +1,5 @@
import React from 'react';
import styles from './CalendarGridCell.module.scss';
interface Props {

View File

@@ -1,16 +1,21 @@
import React from 'react';
import { Status } from '@shared/types/Course';
import Divider from '../../common/Divider/Divider';
import { Button } from '../../common/Button/Button';
import Text from '../../common/Text/Text';
import MenuIcon from '~icons/material-symbols/menu';
import UndoIcon from '~icons/material-symbols/undo';
import RedoIcon from '~icons/material-symbols/redo';
import SettingsIcon from '~icons/material-symbols/settings';
import ScheduleTotalHoursAndCourses from '../../common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses';
import CourseStatus from '../../common/CourseStatus/CourseStatus';
import { Button } from '@views/components/common/Button/Button';
import CourseStatus from '@views/components/common/CourseStatus/CourseStatus';
import Divider from '@views/components/common/Divider/Divider';
import ScheduleTotalHoursAndCourses from '@views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses';
import Text from '@views/components/common/Text/Text';
import React from 'react';
import calIcon from 'src/assets/logo.png';
import MenuIcon from '~icons/material-symbols/menu';
import RedoIcon from '~icons/material-symbols/redo';
import SettingsIcon from '~icons/material-symbols/settings';
import UndoIcon from '~icons/material-symbols/undo';
/**
* Renders the header component for the calendar.
* @returns The CalendarHeader component.
*/
const CalendarHeader = () => (
<div className='min-h-79px min-w-672px flex px-0 py-15'>
<div className='flex flex-row gap-20'>
@@ -18,9 +23,9 @@ const CalendarHeader = () => (
<div className='flex gap-1'>
<Button variant='single' icon={MenuIcon} color='ut-gray' />
<div className='flex items-center'>
<img src={calIcon} className='min-w-[48px] max-w-[48px]' alt='UT Registration Plus Logo' />
<img src={calIcon} className='max-w-[48px] min-w-[48px]' alt='UT Registration Plus Logo' />
<div className='flex flex-col whitespace-nowrap'>
<Text className='leading-trim text-cap font-roboto text-base text-ut-burntorange font-medium'>
<Text className='leading-trim font-roboto text-cap text-base text-ut-burntorange font-medium'>
UT Registration
</Text>
<Text className='leading-trim text-cap font-roboto text-base text-ut-orange font-medium'>

View File

@@ -1,16 +1,26 @@
import { UserSchedule } from '@shared/types/UserSchedule';
import type { UserSchedule } from '@shared/types/UserSchedule';
import List from '@views/components/common/List/List';
import ScheduleListItem from '@views/components/common/ScheduleListItem/ScheduleListItem';
import Text from '@views/components/common/Text/Text';
import React, { useState } from 'react';
import AddSchedule from '~icons/material-symbols/add';
import List from '../../common/List/List';
import ScheduleListItem from '../../common/ScheduleListItem/ScheduleListItem';
import Text from '../../common/Text/Text';
import AddSchedule from '~icons/material-symbols/add';
/**
* Props for the CalendarSchedules component.
*/
export type Props = {
style?: React.CSSProperties;
dummySchedules?: UserSchedule[];
dummyActiveIndex?: number;
};
/**
* Renders a component that displays a list of schedules.
*
* @param props - The component props.
* @returns The rendered component.
*/
export function CalendarSchedules(props: Props) {
const [activeScheduleIndex, setActiveScheduleIndex] = useState(props.dummyActiveIndex || 0);
const [schedules, setSchedules] = useState(props.dummySchedules || []);

View File

@@ -1,8 +1,10 @@
import React from 'react';
import clsx from 'clsx';
import Text from '../common/Text/Text';
import React from 'react';
import OutwardArrowIcon from '~icons/material-symbols/arrow-outward';
import Text from '../common/Text/Text';
type Props = {
className?: string;
};

View File

@@ -1,7 +1,10 @@
import clsx from 'clsx';
import React from 'react';
import type IconComponent from '~icons/material-symbols';
import { ThemeColor, getThemeColorHexByName, getThemeColorRgbByName } from '../../../../shared/util/themeColors';
import type { ThemeColor } from '../../../../shared/util/themeColors';
import { getThemeColorHexByName, getThemeColorRgbByName } from '../../../../shared/util/themeColors';
import Text from '../Text/Text';
interface Props {

View File

@@ -1,7 +1,11 @@
import clsx from 'clsx';
import React from 'react';
import styles from './Card.module.scss';
/**
* Props for the Card component.
*/
export type Props = {
style?: React.CSSProperties;
className?: string;

View File

@@ -1,4 +1,5 @@
import React from 'react';
import Text from '../Text/Text';
/**

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { Course } from 'src/shared/types/Course';
import clsx from 'clsx';
import React from 'react';
import type { Course } from 'src/shared/types/Course';
import Text from '../Text/Text';
/**
@@ -28,9 +29,7 @@ export default function ConflictsWithWarning({ className, conflicts }: Conflicts
>
<div>Conflicts With:</div>
{conflicts.map(course => (
<div>
{`${course.department} ${course.number} (${course.uniqueId})`}
</div>
<div>{`${course.department} ${course.number} (${course.uniqueId})`}</div>
))}
</Text>
);

View File

@@ -1,7 +1,8 @@
import { Status } from '@shared/types/Course';
import type { Status } from '@shared/types/Course';
import { StatusIcon } from '@shared/util/icons';
import clsx from 'clsx';
import React from 'react';
import Text from '../Text/Text';
type SizeType = 'small' | 'mini';

View File

@@ -1,3 +1,4 @@
import type { Color } from '@views/styles/colors.module.scss';
import clsx from 'clsx';
import React from 'react';

View File

@@ -1,12 +1,16 @@
import { Disclosure, Transition } from '@headlessui/react';
import { UserSchedule } from '@shared/types/UserSchedule';
import type { UserSchedule } from '@shared/types/UserSchedule';
import List from '@views/components/common/List/List';
import Text from '@views/components/common/Text/Text';
import React from 'react';
import userScheduleHandler from 'src/pages/background/handler/userScheduleHandler';
import DropdownArrowDown from '~icons/material-symbols/arrow-drop-down';
import DropdownArrowUp from '~icons/material-symbols/arrow-drop-up';
import List from '../List/List';
import Text from '../Text/Text';
/**
* Props for the Dropdown component.
*/
export type Props = {
style?: React.CSSProperties;
// Dummy value solely for storybook
@@ -62,7 +66,7 @@ export default function Dropdown(props: Props) {
<Disclosure.Button>
<div className='flex items-center border-none bg-white p-3 text-left'>
<div className='flex-1'>
<Text as='div' variant='h4' className='text-ut-burntorange mb-1 w-100%'>
<Text as='div' variant='h4' className='mb-1 w-100% text-ut-burntorange'>
MAIN SCHEDULE:
</Text>
<div>
@@ -74,7 +78,7 @@ export default function Dropdown(props: Props) {
</Text>
</div>
</div>
<Text className='text-ut-burntorange text-2xl font-normal'>
<Text className='text-2xl text-ut-burntorange font-normal'>
{expanded ? <DropdownArrowDown /> : <DropdownArrowUp />}
</Text>
</div>

View File

@@ -1,9 +1,10 @@
import React from 'react';
import styles from './ExtensionRoot.module.scss';
import '@unocss/reset/tailwind-compat.css';
import 'uno.css';
import React from 'react';
import styles from './ExtensionRoot.module.scss';
interface Props {
testId?: string;
}

View File

@@ -1,9 +1,12 @@
import type { Color } from '@views/styles/colors.module.scss';
import colors from '@views/styles/colors.module.scss';
import type { Size } from '@views/styles/fonts.module.scss';
import fonts from '@views/styles/fonts.module.scss';
import clsx from 'clsx';
import React from 'react';
import colors, { Color } from '@views/styles/colors.module.scss';
import fonts, { Size } from '@views/styles/fonts.module.scss';
import styles from './Icon.module.scss';
import { MaterialIconCode } from './MaterialIcons';
import type { MaterialIconCode } from './MaterialIcons';
/**
*

View File

@@ -2194,4 +2194,7 @@ const icons = [
'zoom_out_map',
] as const;
export type MaterialIconCode = typeof icons[number];
/**
* Represents a type that corresponds to a material icon code.
*/
export type MaterialIconCode = (typeof icons)[number];

View File

@@ -1,4 +1,5 @@
import React from 'react';
import Text from '../Text/Text';
interface Props {
@@ -10,31 +11,35 @@ interface Props {
* A maybe reusable InfoCard component that follows the design system of the extension.
* @returns
*/
export function InfoCard({
titleText,
bodyText
}: React.PropsWithChildren<Props>): JSX.Element {
export function InfoCard({ titleText, bodyText }: React.PropsWithChildren<Props>): JSX.Element {
return (
<div
className = 'w-50 flex flex-col items-start justify-center border rounded p-4'
style = {{
border: "1px solid #D6D2C4",
background: "#FFF" // White
}}>
<div className="flex flex-col items-start self-stretch gap-1.5">
<Text variant = "h4" as = 'span'
style = {{
color: '#F8971F', // Orange
}}>
{titleText}
</Text>
<Text variant = "small" as = 'span'
style = {{
color: '#333F48', // Black
}}>
{bodyText}
</Text>
</ div>
className='w-50 flex flex-col items-start justify-center border rounded p-4'
style={{
border: '1px solid #D6D2C4',
background: '#FFF', // White
}}
>
<div className='flex flex-col items-start self-stretch gap-1.5'>
<Text
variant='h4'
as='span'
style={{
color: '#F8971F', // Orange
}}
>
{titleText}
</Text>
<Text
variant='small'
as='span'
style={{
color: '#333F48', // Black
}}
>
{bodyText}
</Text>
</div>
</div>
);
}

View File

@@ -1,7 +1,10 @@
import { background } from '@shared/messages';
import clsx from 'clsx';
import React, { PropsWithChildren } from 'react';
import Text, { TextProps } from '../Text/Text';
import type { PropsWithChildren } from 'react';
import React from 'react';
import type { TextProps } from '../Text/Text';
import Text from '../Text/Text';
import styles from './Link.module.scss';
type Props = Omit<TextProps, 'span'> & {

View File

@@ -1,5 +1,6 @@
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
import React, { ReactElement, useCallback, useState } from 'react';
import type { ReactElement } from 'react';
import React, { useCallback, useState } from 'react';
import { areEqual } from 'react-window';
/*

View File

@@ -1,5 +1,7 @@
import clsx from 'clsx';
import React, { PropsWithChildren, useCallback } from 'react';
import type { PropsWithChildren } from 'react';
import React, { useCallback } from 'react';
import styles from './Popup.module.scss';
interface Props {
@@ -19,8 +21,6 @@ export default function Popup({ onClose, children, className, style, testId, ove
const containerRef = React.useRef<HTMLDivElement>(null);
const bodyRef = React.useRef<HTMLDivElement>(null);
const handleClickOutside = useCallback(
(event: MouseEvent) => {
if (!bodyRef.current) return;

View File

@@ -1,9 +1,13 @@
import { Course, Status } from '@shared/types/Course';
import { CourseColors, pickFontColor } from '@shared/util/colors';
import type { Course } from '@shared/types/Course';
import { Status } from '@shared/types/Course';
import type { CourseColors } from '@shared/util/colors';
import { pickFontColor } from '@shared/util/colors';
import { StatusIcon } from '@shared/util/icons';
import clsx from 'clsx';
import React from 'react';
import DragIndicatorIcon from '~icons/material-symbols/drag-indicator';
import Text from '../Text/Text';
/**

View File

@@ -1,8 +1,12 @@
import Text from '@views/components/common/Text/Text';
import clsx from 'clsx';
import React from 'react';
import DragIndicatorIcon from '~icons/material-symbols/drag-indicator';
import Text from '../Text/Text';
import DragIndicatorIcon from '~icons/material-symbols/drag-indicator';
/**
* Props for the ScheduleListItem component.
*/
export type Props = {
style?: React.CSSProperties;
active?: boolean;
@@ -18,11 +22,11 @@ export default function ScheduleListItem(props: Props) {
console.log(props);
return (
<div style={{ ...props.style }} className='items-center'>
<li className='text-ut-burntorange w-100% flex cursor-pointer items-center self-stretch justify-left'>
<li className='w-100% flex cursor-pointer items-center self-stretch justify-left text-ut-burntorange'>
<div className='group flex justify-center'>
<div
<div
className='flex cursor-move items-center self-stretch rounded rounded-r-0'
{...dragHandleProps}
{...dragHandleProps}
>
<DragIndicatorIcon className='h-6 w-6 cursor-move text-zinc-300 btn-transition -ml-1.5 hover:text-zinc-400' />
</div>

View File

@@ -1,4 +1,5 @@
import React from 'react';
import Text from '../Text/Text';
/**
@@ -21,7 +22,7 @@ export default function ScheduleTotalHoursAndCourses({
totalCourses,
}: ScheduleTotalHoursAndCoursesProps): JSX.Element {
return (
<div className='min-w-64 flex whitespace-nowrap content-center items-baseline gap-2 uppercase'>
<div className='min-w-64 flex content-center items-baseline gap-2 whitespace-nowrap uppercase'>
<Text className='text-[#BF5700]' variant='h1' as='span'>
{`${scheduleName}: `}
</Text>

View File

@@ -1,5 +1,6 @@
import clsx from 'clsx';
import React from 'react';
import styles from './Spinner.module.scss';
type Props = {

View File

@@ -1,5 +1,7 @@
import clsx from 'clsx';
import React, { PropsWithChildren } from 'react';
import type { PropsWithChildren } from 'react';
import React from 'react';
import styles from './Text.module.scss';
/**

View File

@@ -1,6 +1,4 @@
import { ScrapedRow } from '@shared/types/Course';
import React, { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import type { ScrapedRow } from '@shared/types/Course';
import useInfiniteScroll from '@views/hooks/useInfiniteScroll';
import { CourseCatalogScraper } from '@views/lib/CourseCatalogScraper';
import { SiteSupport } from '@views/lib/getSiteSupport';
@@ -9,6 +7,9 @@ import {
loadNextCourseCatalogPage,
removePaginationButtons,
} from '@views/lib/loadNextCourseCatalogPage';
import React, { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import styles from './AutoLoad.module.scss';
type Props = {

View File

@@ -1,7 +1,8 @@
import Popup from '@views/components/common/Popup/Popup';
import React from 'react';
import { Course } from 'src/shared/types/Course';
import { UserSchedule } from 'src/shared/types/UserSchedule';
import type { Course } from 'src/shared/types/Course';
import type { UserSchedule } from 'src/shared/types/UserSchedule';
import Description from './Description';
import GradeDistribution from './GradeDistribution';
import HeadingAndActions from './HeadingAndActions';
@@ -12,6 +13,16 @@ interface CourseCatalogInjectedPopupProps {
onClose: () => void;
}
/**
* CourseCatalogInjectedPopup component displays a popup with course details.
*
* @component
* @param {CourseCatalogInjectedPopupProps} 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 CourseCatalogInjectedPopup component.
*/
const CourseCatalogInjectedPopup: React.FC<CourseCatalogInjectedPopupProps> = ({ course, activeSchedule, onClose }) => (
<Popup overlay className='max-w-[780px] px-6' onClose={onClose}>
<div className='flex flex-col'>

View File

@@ -1,11 +1,19 @@
import Text from '@views/components/common/Text/Text';
import clsx from 'clsx';
import React from 'react';
import Text from '../../common/Text/Text';
interface DescriptionProps {
lines: string[];
}
/**
* Renders the description component.
*
* @component
* @param {DescriptionProps} props - The component props.
* @param {string[]} props.lines - The lines of text to render.
* @returns {JSX.Element} The rendered description component.
*/
const Description: React.FC<DescriptionProps> = ({ lines }: DescriptionProps) => {
const keywords = ['prerequisite', 'restricted'];
return (

View File

@@ -1,29 +1,31 @@
import type { Course } from '@shared/types/Course';
import type { Distribution, LetterGrade } from '@shared/types/Distribution';
import { colors } from '@shared/util/themeColors';
import Spinner from '@views/components/common/Spinner/Spinner';
import Text from '@views/components/common/Text/Text';
import Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import React from 'react';
import { Course } from 'src/shared/types/Course';
import { Distribution, LetterGrade } from 'src/shared/types/Distribution';
import { colors } from 'src/shared/util/themeColors';
import {
NoDataError,
queryAggregateDistribution,
querySemesterDistribution,
} from 'src/views/lib/database/queryDistribution';
} from '@views/lib/database/queryDistribution';
import Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import React from 'react';
interface GradeDistributionProps {
course: Course;
}
enum DataStatus {
LOADING = 'LOADING',
FOUND = 'FOUND',
NOT_FOUND = 'NOT_FOUND',
ERROR = 'ERROR',
}
const DataStatus = {
LOADING: 'LOADING',
FOUND: 'FOUND',
NOT_FOUND: 'NOT_FOUND',
ERROR: 'ERROR',
} as const;
const GRADE_COLORS: Record<LetterGrade, string> = {
type DataStatusType = (typeof DataStatus)[keyof typeof DataStatus];
const GRADE_COLORS = {
A: colors.gradeDistribution.a,
'A-': colors.gradeDistribution.aminus,
'B+': colors.gradeDistribution.bplus,
@@ -36,12 +38,20 @@ const GRADE_COLORS: Record<LetterGrade, string> = {
D: colors.gradeDistribution.d,
'D-': colors.gradeDistribution.dminus,
F: colors.gradeDistribution.f,
};
} as const satisfies Record<LetterGrade, string>;
/**
* Renders the grade distribution chart for a specific course.
*
* @component
* @param {GradeDistributionProps} props - The component props.
* @param {Course} props.course - The course for which to display the grade distribution.
* @returns {JSX.Element} The grade distribution chart component.
*/
const GradeDistribution: React.FC<GradeDistributionProps> = ({ course }) => {
const [semester, setSemester] = React.useState('Aggregate');
const [distributions, setDistributions] = React.useState<Record<string, Distribution>>({});
const [status, setStatus] = React.useState(DataStatus.LOADING);
const [status, setStatus] = React.useState<DataStatusType>(DataStatus.LOADING);
const ref = React.useRef<HighchartsReact.RefObject>(null);
const chartData = React.useMemo(() => {

View File

@@ -1,20 +1,21 @@
import React, { useState } from 'react';
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 React, { useState } from 'react';
import addCourse from 'src/pages/background/lib/addCourse';
import removeCourse from 'src/pages/background/lib/removeCourse';
import type { Course } from 'src/shared/types/Course';
import type { UserSchedule } from 'src/shared/types/UserSchedule';
import { openTabFromContentScript } from 'src/views/lib/openNewTabFromContentScript';
import { Course } from 'src/shared/types/Course';
import { UserSchedule } from 'src/shared/types/UserSchedule';
import Add from '~icons/material-symbols/add';
import Remove from '~icons/material-symbols/remove';
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';
interface HeadingAndActionProps {
@@ -26,7 +27,11 @@ interface HeadingAndActionProps {
onClose: () => void;
}
export const handleOpenCalendar = async () => { // Not sure if it's bad practice to export this
/**
* Opens the calendar in a new tab.
* @returns {Promise<void>} A promise that resolves when the tab is opened.
*/
export const handleOpenCalendar = async () => {
const url = chrome.runtime.getURL('calendar.html');
await openTabFromContentScript(url);
};
@@ -41,7 +46,7 @@ const HeadingAndActions: React.FC<HeadingAndActionProps> = ({ course, onClose, a
const { courseName, department, number: courseNumber, uniqueId, instructors, flags, schedule } = course;
const [courseAdded, setCourseAdded] = useState<boolean>(
activeSchedule.courses.some(course => course.uniqueId === uniqueId)
);
);
const instructorString = instructors
.map(instructor => {
@@ -74,8 +79,7 @@ const HeadingAndActions: React.FC<HeadingAndActionProps> = ({ course, onClose, a
const handleAddOrRemoveCourse = async () => {
if (!courseAdded) {
await addCourse(activeSchedule.name, course);
}
else {
} else {
await removeCourse(activeSchedule.name, course);
}
setCourseAdded(!courseAdded);
@@ -137,7 +141,12 @@ const HeadingAndActions: React.FC<HeadingAndActionProps> = ({ course, onClose, a
<Button variant='outline' color='ut-orange' icon={Description} onClick={handleOpenPastSyllabi}>
Past Syllabi
</Button>
<Button variant='filled' color={!courseAdded ? 'ut-green' : 'ut-red'} icon={!courseAdded ? Add : Remove} onClick={handleAddOrRemoveCourse}>
<Button
variant='filled'
color={!courseAdded ? 'ut-green' : 'ut-red'}
icon={!courseAdded ? Add : Remove}
onClick={handleAddOrRemoveCourse}
>
{!courseAdded ? 'Add Course' : 'Remove Course'}
</Button>
</div>

View File

@@ -1,29 +1,36 @@
import { Course } from '@shared/types/Course';
import clsx from 'clsx';
import React, { useEffect, useState } from 'react';
import type { Course } from '@shared/types/Course';
import Card from '@views/components/common/Card/Card';
import Spinner from '@views/components/common/Spinner/Spinner';
import Text from '@views/components/common/Text/Text';
import { CourseCatalogScraper } from '@views/lib/CourseCatalogScraper';
import { SiteSupport } from '@views/lib/getSiteSupport';
import Card from '../../../common/Card/Card';
import clsx from 'clsx';
import React, { useEffect, useState } from 'react';
import styles from './CourseDescription.module.scss';
type Props = {
course: Course;
};
enum LoadStatus {
LOADING = 'LOADING',
DONE = 'DONE',
ERROR = 'ERROR',
}
const LoadStatus = {
LOADING: 'LOADING',
DONE: 'DONE',
ERROR: 'ERROR',
} as const;
type LoadStatusType = (typeof LoadStatus)[keyof typeof LoadStatus];
/**
* Renders the course description component.
*
* @param {Props} props - The component props.
* @param {Course} props.course - The course object.
* @returns {JSX.Element} The rendered course description component.
*/
export default function CourseDescription({ course }: Props) {
const [description, setDescription] = useState<string[]>([]);
const [status, setStatus] = useState<LoadStatus>(LoadStatus.LOADING);
const [status, setStatus] = useState<LoadStatusType>(LoadStatus.LOADING);
useEffect(() => {
fetchDescription(course)
@@ -71,11 +78,7 @@ function DescriptionLine({ line }: LineProps) {
[styles.restriction]: lowerCaseLine.includes('restrict'),
});
return (
<Text className={className} /* size='medium' */>
{line}
</Text>
);
return <Text className={className} /* size='medium' */>{line}</Text>;
}
async function fetchDescription(course: Course): Promise<string[]> {

View File

@@ -1,11 +1,12 @@
import { background } from '@shared/messages';
import { Course } from '@shared/types/Course';
import { UserSchedule } from '@shared/types/UserSchedule';
import type { Course } from '@shared/types/Course';
import type { UserSchedule } from '@shared/types/UserSchedule';
import { Button } from '@views/components/common/Button/Button';
import Card from '@views/components/common/Card/Card';
import Icon from '@views/components/common/Icon/Icon';
import Text from '@views/components/common/Text/Text';
import React from 'react';
import styles from './CourseButtons.module.scss';
type Props = {

View File

@@ -1,15 +1,17 @@
import { Course } from '@shared/types/Course';
import { UserSchedule } from '@shared/types/UserSchedule';
import React from 'react';
import type { Course } from '@shared/types/Course';
import type { UserSchedule } from '@shared/types/UserSchedule';
import { Button } from '@views/components/common/Button/Button';
import Card from '@views/components/common/Card/Card';
import Icon from '@views/components/common/Icon/Icon';
import Link from '@views/components/common/Link/Link';
import Text from '@views/components/common/Text/Text';
import { Button } from 'src/views/components/common/Button/Button';
import React from 'react';
import CloseIcon from '~icons/material-symbols/close';
import CopyIcon from '~icons/material-symbols/content-copy';
import CourseButtons from './CourseButtons/CourseButtons';
import styles from './CourseHeader.module.scss';
import CopyIcon from '~icons/material-symbols/content-copy';
import CloseIcon from '~icons/material-symbols/close';
type Props = {
course: Course;
@@ -40,7 +42,7 @@ export default function CourseHeader({ course, activeSchedule, onClose }: Props)
<Button icon={CopyIcon} variant='single' className='mr-1 px-2' color='ut-burntorange'>
{course.uniqueId}
</Button>
<button className='btn bg-transparent p-0'>
<button className='bg-transparent p-0 btn'>
<CloseIcon className='h-7 w-7' />
</button>
</div>

View File

@@ -1,6 +1,7 @@
import { Course } from '@shared/types/Course';
import { UserSchedule } from '@shared/types/UserSchedule';
import type { Course } from '@shared/types/Course';
import type { UserSchedule } from '@shared/types/UserSchedule';
import React from 'react';
import Popup from '../../common/Popup/Popup';
import CourseDescription from './CourseDescription/CourseDescription';
import CourseHeader from './CourseHeader/CourseHeader';

View File

@@ -1,9 +1,5 @@
/* eslint-disable no-nested-ternary */
import { Course, Semester } from '@shared/types/Course';
import { Distribution, LetterGrade } from '@shared/types/Distribution';
import Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import React, { useEffect, useRef, useState } from 'react';
import type { Course, Semester } from '@shared/types/Course';
import type { Distribution, LetterGrade } from '@shared/types/Distribution';
import Card from '@views/components/common/Card/Card';
import Icon from '@views/components/common/Icon/Icon';
import Spinner from '@views/components/common/Spinner/Spinner';
@@ -14,20 +10,26 @@ import {
querySemesterDistribution,
} from '@views/lib/database/queryDistribution';
import colors from '@views/styles/colors.module.scss';
import Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import React, { useEffect, useRef, useState } from 'react';
import styles from './GradeDistribution.module.scss';
enum DataStatus {
LOADING = 'LOADING',
FOUND = 'FOUND',
NOT_FOUND = 'NOT_FOUND',
ERROR = 'ERROR',
}
const DataStatus = {
LOADING: 'LOADING',
FOUND: 'FOUND',
NOT_FOUND: 'NOT_FOUND',
ERROR: 'ERROR',
} as const;
type DataStatusType = (typeof DataStatus)[keyof typeof DataStatus];
interface Props {
course: Course;
}
const GRADE_COLORS: Record<LetterGrade, string> = {
const GRADE_COLORS = {
A: colors.turtle_pond,
'A-': colors.turtle_pond,
'B+': colors.cactus,
@@ -40,7 +42,7 @@ const GRADE_COLORS: Record<LetterGrade, string> = {
D: colors.tangerine,
'D-': colors.tangerine,
F: colors.speedway_brick,
};
} as const satisfies Record<LetterGrade, string>;
/**
* A chart to fetch and display the grade distribution for a course
@@ -51,7 +53,7 @@ export default function GradeDistribution({ course }: Props) {
const [semesters, setSemesters] = useState<Semester[]>([]);
const [selectedSemester, setSelectedSemester] = useState<Semester | null>(null);
const [distribution, setDistribution] = useState<Distribution | null>(null);
const [status, setStatus] = useState<DataStatus>(DataStatus.LOADING);
const [status, setStatus] = useState<DataStatusType>(DataStatus.LOADING);
const [chartOptions, setChartOptions] = useState<Highcharts.Options>({
title: {
@@ -206,7 +208,7 @@ export default function GradeDistribution({ course }: Props) {
<Text color='speedway_brick' /* size='medium' weight='semi_bold' */>
There was an error fetching the grade distribution data
</Text>
<Icon color='speedway_brick' /* size='large' */ name='sentiment_dissatisfied' />
<Icon color='speedway_brick' /* size='large' */ name='sentiment_dissatisfied' />
</Card>
)}
{status === DataStatus.NOT_FOUND && (

View File

@@ -1,5 +1,6 @@
import React, { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import Link from '../../common/Link/Link';
import Text from '../../common/Text/Text';
import styles from './RecruitmentBanner.module.scss';
@@ -50,6 +51,10 @@ export default function RecruitmentBanner() {
);
}
/**
* Determines if recruitment can be done from the current department.
* @returns {boolean} True if recruitment can be done from the current department, false otherwise.
*/
export function canRecruitFrom(): boolean {
const params = ['fos_fl', 'fos_cn'];
let department = '';

View File

@@ -1,4 +1,5 @@
import React, { PropsWithChildren, useEffect, useState } from 'react';
import type { PropsWithChildren } from 'react';
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
/**

View File

@@ -1,12 +1,14 @@
import { Course, ScrapedRow } from '@shared/types/Course';
import { UserSchedule } from '@shared/types/UserSchedule';
import type { Course, ScrapedRow } from '@shared/types/Course';
import type { UserSchedule } from '@shared/types/UserSchedule';
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
import { Button } from '../../common/Button/Button';
import styles from './TableRow.module.scss';
import ConflictsWithWarning from '../../common/ConflictsWithWarning/ConflictsWithWarning';
import AddIcon from '~icons/material-symbols/add-circle';
import { Button } from '../../common/Button/Button';
import ConflictsWithWarning from '../../common/ConflictsWithWarning/ConflictsWithWarning';
import styles from './TableRow.module.scss';
interface Props {
isSelected: boolean;
row: ScrapedRow;

View File

@@ -1,5 +1,6 @@
import { ScrapedRow } from '@shared/types/Course';
import type { ScrapedRow } from '@shared/types/Course';
import { useEffect } from 'react';
import styles from './TableSubheading.module.scss';
interface Props {