diff --git a/src/stories/components/calendar/CalendarGrid.stories.tsx b/src/stories/components/calendar/CalendarGrid.stories.tsx index 43cf9d86..e538b8c5 100644 --- a/src/stories/components/calendar/CalendarGrid.stories.tsx +++ b/src/stories/components/calendar/CalendarGrid.stories.tsx @@ -1,8 +1,13 @@ -import { Meta, StoryObj } from '@storybook/react'; -import CalendarGrid from 'src/views/components/calendar/CalendarGrid/CalendarGrid'; +import { Course, Status } from '@shared/types/Course'; import { getCourseColors } from '@shared/util/colors'; -import { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule'; -import { Status } from '@shared/types/Course'; +import type { Meta, StoryObj } from '@storybook/react'; +import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule'; +import { Serialized } from 'chrome-extension-toolkit'; +import { CourseMeeting, DAY_MAP } from 'src/shared/types/CourseMeeting'; +import { CourseSchedule } from 'src/shared/types/CourseSchedule'; +import Instructor from 'src/shared/types/Instructor'; +import { UserSchedule } from 'src/shared/types/UserSchedule'; +import CalendarGrid from 'src/views/components/calendar/CalendarGrid/CalendarGrid'; const meta = { title: 'Components/Calendar/CalendarGrid', @@ -17,6 +22,57 @@ const meta = { } satisfies Meta; export default meta; +const exampleCourse: Course = new Course({ + uniqueId: 50805, + number: '314', + fullName: 'C S 314 DATA STRUCTURES', + courseName: 'DATA STRUCTURES', + department: 'C S', + creditHours: 3, + status: Status.OPEN, + instructors: [ + new Instructor({ fullName: 'SCOTT, MICHAEL', firstName: 'MICHAEL', lastName: 'SCOTT', middleInitial: 'D' }), + ], + isReserved: true, + description: [ + 'Second part of a two-part sequence in programming. Introduction to specifications, simple unit testing, and debugging; building and using canonical data structures; algorithm analysis and reasoning techniques such as assertions and invariants.', + 'Computer Science 314 and 314H may not both be counted.', + 'BVO 311C and 312H may not both be counted.', + 'Prerequisite: Computer Science 312 or 312H with a grade of at least C-.', + 'May be counted toward the Quantitative Reasoning flag requirement.', + ], + schedule: new CourseSchedule({ + meetings: [ + new CourseMeeting({ + days: [DAY_MAP.T, DAY_MAP.TH], + startTime: 480, + endTime: 570, + location: { building: 'UTC', room: '123' }, + }), + new CourseMeeting({ + days: [DAY_MAP.TH], + startTime: 570, + endTime: 630, + location: { building: 'JES', room: '123' }, + }), + ], + }), + url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20242/12345/', + flags: ['Writing', 'Independent Inquiry'], + instructionMode: 'In Person', + semester: { + code: '12345', + year: 2024, + season: 'Spring', + }, +}); + +const exampleSchedule = new UserSchedule({ + name: 'Example Schedule', + courses: [exampleCourse], + hours: 3, +} as Serialized); + const testData: CalendarGridCourse[] = [ { calendarGridPoint: { @@ -30,6 +86,11 @@ const testData: CalendarGridCourse[] = [ status: Status.OPEN, colors: getCourseColors('emerald', 500), }, + popupProps: { + course: exampleCourse, + activeSchedule: exampleSchedule, + onClose: () => {}, + }, }, { calendarGridPoint: { @@ -43,6 +104,11 @@ const testData: CalendarGridCourse[] = [ status: Status.OPEN, colors: getCourseColors('emerald', 500), }, + popupProps: { + course: exampleCourse, + activeSchedule: exampleSchedule, + onClose: () => {}, + }, }, { calendarGridPoint: { @@ -56,6 +122,11 @@ const testData: CalendarGridCourse[] = [ status: Status.CLOSED, colors: getCourseColors('emerald', 500), }, + popupProps: { + course: exampleCourse, + activeSchedule: exampleSchedule, + onClose: () => {}, + }, }, { calendarGridPoint: { @@ -69,6 +140,11 @@ const testData: CalendarGridCourse[] = [ status: Status.OPEN, colors: getCourseColors('emerald', 500), }, + popupProps: { + course: exampleCourse, + activeSchedule: exampleSchedule, + onClose: () => {}, + }, }, { calendarGridPoint: { @@ -82,6 +158,11 @@ const testData: CalendarGridCourse[] = [ status: Status.CLOSED, colors: getCourseColors('emerald', 500), }, + popupProps: { + course: exampleCourse, + activeSchedule: exampleSchedule, + onClose: () => {}, + }, }, { calendarGridPoint: { @@ -95,6 +176,11 @@ const testData: CalendarGridCourse[] = [ status: Status.CLOSED, colors: getCourseColors('emerald', 500), }, + popupProps: { + course: exampleCourse, + activeSchedule: exampleSchedule, + onClose: () => {}, + }, }, { calendarGridPoint: { @@ -108,6 +194,11 @@ const testData: CalendarGridCourse[] = [ status: Status.CLOSED, colors: getCourseColors('emerald', 500), }, + popupProps: { + course: exampleCourse, + activeSchedule: exampleSchedule, + onClose: () => {}, + }, }, ]; diff --git a/src/views/components/calendar/CalendarCourseCell/CalendarCourseCell.tsx b/src/views/components/calendar/CalendarCourseCell/CalendarCourseCell.tsx index fc05fc03..98b7583d 100644 --- a/src/views/components/calendar/CalendarCourseCell/CalendarCourseCell.tsx +++ b/src/views/components/calendar/CalendarCourseCell/CalendarCourseCell.tsx @@ -1,10 +1,13 @@ import { Status } from '@shared/types/Course'; 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'; export interface CalendarCourseCellProps { @@ -13,6 +16,7 @@ export interface CalendarCourseCellProps { status: Status; colors: CourseColors; className?: string; + popup?: any; } const CalendarCourseCell: React.FC = ({ @@ -21,7 +25,9 @@ const CalendarCourseCell: React.FC = ({ status, colors, className, + popup, }: CalendarCourseCellProps) => { + const [showPopup, setShowPopup] = React.useState(false); let rightIcon: React.ReactNode | null = null; if (status === Status.WAITLISTED) { rightIcon = ; @@ -31,15 +37,26 @@ const CalendarCourseCell: React.FC = ({ rightIcon = ; } + // popup.onClose = () => setShowPopup(false); + + const handleClick = () => { + setShowPopup(true); + }; + // whiteText based on secondaryColor const fontColor = pickFontColor(colors.primaryColor); return (
= ({ {rightIcon}
)} +
{showPopup ? popup : null}
); }; diff --git a/src/views/components/calendar/CalendarGrid/CalendarGrid.tsx b/src/views/components/calendar/CalendarGrid/CalendarGrid.tsx index 3635bf9c..eec98019 100644 --- a/src/views/components/calendar/CalendarGrid/CalendarGrid.tsx +++ b/src/views/components/calendar/CalendarGrid/CalendarGrid.tsx @@ -1,14 +1,17 @@ -import React, { useState, useRef, useEffect } from 'react'; +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 CourseCatalogInjectedPopup from 'src/views/components/injected/CourseCatalogInjectedPopup/CourseCatalogInjectedPopup'; +import type { 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)); const hoursOfDay = Array.from({ length: 14 }, (_, index) => index + 8); const grid = []; @@ -119,7 +122,7 @@ function CalendarGrid({ courseCells, saturdayClass }: React.PropsWithChildren ))} {grid.map((row, rowIndex) => row)} - {courseCells ? : null} + {courseCells ? : null} {/* courseCells.map((block: CalendarGridCourse) => (
} />
)); diff --git a/src/views/components/calendar/CalendarGridCell/CalendarGridCell.tsx b/src/views/components/calendar/CalendarGridCell/CalendarGridCell.tsx index 77c35553..30409830 100644 --- a/src/views/components/calendar/CalendarGridCell/CalendarGridCell.tsx +++ b/src/views/components/calendar/CalendarGridCell/CalendarGridCell.tsx @@ -1,4 +1,5 @@ import React from 'react'; + import styles from './CalendarGridCell.module.scss'; interface Props { diff --git a/src/views/components/injected/CourseCatalogInjectedPopup/CourseCatalogInjectedPopup.tsx b/src/views/components/injected/CourseCatalogInjectedPopup/CourseCatalogInjectedPopup.tsx index 19a19920..f02445db 100644 --- a/src/views/components/injected/CourseCatalogInjectedPopup/CourseCatalogInjectedPopup.tsx +++ b/src/views/components/injected/CourseCatalogInjectedPopup/CourseCatalogInjectedPopup.tsx @@ -3,11 +3,12 @@ import React from 'react'; 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'; -interface CourseCatalogInjectedPopupProps { +export interface CourseCatalogInjectedPopupProps { course: Course; activeSchedule?: UserSchedule; onClose: () => void; diff --git a/src/views/components/injected/CoursePopupOld/CoursePopup.tsx b/src/views/components/injected/CoursePopupOld/CoursePopup.tsx index 8cc99978..d67475a6 100644 --- a/src/views/components/injected/CoursePopupOld/CoursePopup.tsx +++ b/src/views/components/injected/CoursePopupOld/CoursePopup.tsx @@ -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'; diff --git a/src/views/hooks/useFlattenedCourseSchedule.ts b/src/views/hooks/useFlattenedCourseSchedule.ts index f449d7dc..ff7ad8d9 100644 --- a/src/views/hooks/useFlattenedCourseSchedule.ts +++ b/src/views/hooks/useFlattenedCourseSchedule.ts @@ -1,4 +1,5 @@ import type { CalendarCourseCellProps } from 'src/views/components/calendar/CalendarCourseCell/CalendarCourseCell'; +import type { CourseCatalogInjectedPopupProps } from 'src/views/components/injected/CourseCatalogInjectedPopup/CourseCatalogInjectedPopup'; import useSchedules from './useSchedules'; @@ -25,6 +26,7 @@ export interface CalendarGridCourse { gridColumnStart?: number; gridColumnEnd?: number; totalColumns?: number; + popupProps: CourseCatalogInjectedPopupProps; } export const convertMinutesToIndex = (minutes: number): number => Math.floor(minutes - 420 / 30); @@ -58,6 +60,7 @@ export function useFlattenedCourseSchedule(): CalendarGridCourse[] { }, componentProps: { courseDeptAndInstr, + timeAndLocation: 'Asynchronous', status, colors: { // TODO: figure out colors - these are defaults @@ -65,6 +68,11 @@ export function useFlattenedCourseSchedule(): CalendarGridCourse[] { secondaryColor: 'ut-gray', }, }, + popupProps: { + course, + activeSchedule, + onClose: () => {}, + }, }, ]; } @@ -91,6 +99,11 @@ export function useFlattenedCourseSchedule(): CalendarGridCourse[] { secondaryColor: 'ut-orange', }, }, + popupProps: { + course, + activeSchedule, + onClose: () => {}, // Add onClose property here + }, })); }); })