diff --git a/src/pages/calendar/CalendarMain.tsx b/src/pages/calendar/CalendarMain.tsx index 7be7e360..a9abf555 100644 --- a/src/pages/calendar/CalendarMain.tsx +++ b/src/pages/calendar/CalendarMain.tsx @@ -1,5 +1,6 @@ import React from 'react'; import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot'; +import { Calendar } from 'src/views/components/calendar/Calendar/Calendar'; /** * Calendar page @@ -8,7 +9,7 @@ import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot' export default function CalendarMain() { return ( -
Calendar Placeholder
+
); } diff --git a/src/shared/types/UserSchedule.ts b/src/shared/types/UserSchedule.ts index 1238cfb3..2806ebe2 100644 --- a/src/shared/types/UserSchedule.ts +++ b/src/shared/types/UserSchedule.ts @@ -21,4 +21,4 @@ export class UserSchedule { containsCourse(course: Course): boolean { return this.courses.some(c => c.uniqueId === course.uniqueId); } -} \ No newline at end of file +} diff --git a/src/shared/util/themeColors.ts b/src/shared/util/themeColors.ts index 17571b8f..6a9b6da5 100644 --- a/src/shared/util/themeColors.ts +++ b/src/shared/util/themeColors.ts @@ -11,6 +11,7 @@ export const colors = { gray: '#9cadb7', offwhite: '#d6d2c4', concrete: '#95a5a6', + red: '#B91C1C' // Not sure if this should be here, but it's used for remove course, and add course is ut-green }, theme: { red: '#af2e2d', diff --git a/src/views/components/PopupMain.tsx b/src/views/components/PopupMain.tsx index 58eb8273..f441ca85 100644 --- a/src/views/components/PopupMain.tsx +++ b/src/views/components/PopupMain.tsx @@ -1,100 +1,100 @@ 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 { generateCourses } from 'src/stories/components/List.stories'; 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'; + export default function PopupMain() { - const courses = generateCourses(5); + const [activeSchedule] = useSchedules(); + + const draggableElements = activeSchedule?.courses.map((course, i) => ( + + )); - // Manually applying colors for the demonstration - const colors = { - OPEN: { primaryColor: '#34D399', secondaryColor: '#059669' }, - CLOSED: { primaryColor: '#818cf8', secondaryColor: '#4f46e5' }, - WAITLISTED: { primaryColor: '#F59E00', secondaryColor: '#B45309' }, - CANCELLED: { primaryColor: '#EF4444', secondaryColor: '#b91c1c' }, - TEMP: { primaryColor: '#fde047', secondaryColor: '#eab308' }, - }; + 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); + }; - const draggableElements = courses.map((course) => ( - -)); - - -return ( - -
-
-
- Logo -
- UT Registration - Plus + return ( + +
+
+
+ Logo +
+ UT Registration + Plus +
+
+
+ +
-
- - -
-
- -
- MAIN SCHEDULE: -
- 22 HOURS - 8 Courses -
-
- {/* Integrate the List component here */} - -
-
-
- + +
+ MAIN SCHEDULE: +
+ 22 HOURS + 8 Courses
- WAITLISTED
-
-
- + {/* Integrate the List component here */} + {activeSchedule ? : null} +
+
+
+ +
+ WAITLISTED +
+
+
+ +
+ CLOSED +
+
+
+ +
+ CANCELLED
- CLOSED
-
-
- +
+
+ DATA UPDATED ON: 12:00 AM 02/01/2024 +
- CANCELLED
-
-
- DATA UPDATED ON: 12:00 AM 02/01/2024 - -
-
-
- -); + + ); } diff --git a/src/views/components/injected/CourseCatalogInjectedPopup/HeadingAndActions.tsx b/src/views/components/injected/CourseCatalogInjectedPopup/HeadingAndActions.tsx index ee1313e1..571ea1ae 100644 --- a/src/views/components/injected/CourseCatalogInjectedPopup/HeadingAndActions.tsx +++ b/src/views/components/injected/CourseCatalogInjectedPopup/HeadingAndActions.tsx @@ -1,13 +1,15 @@ +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 from 'react'; import addCourse from 'src/pages/background/lib/addCourse'; -import openNewTab from 'src/pages/background/util/openNewTab'; +import removeCourse from 'src/pages/background/lib/removeCourse'; +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 Minus from '~icons/material-symbols/minus'; import CalendarMonth from '~icons/material-symbols/calendar-month'; import CloseIcon from '~icons/material-symbols/close'; import Copy from '~icons/material-symbols/content-copy'; @@ -24,6 +26,11 @@ interface HeadingAndActionProps { onClose: () => void; } +export const handleOpenCalendar = async () => { // Not sure if it's bad practice to export this + const url = chrome.runtime.getURL('calendar.html'); + await openTabFromContentScript(url); +}; + /** * Renders the heading component for the CoursePopup component. * @@ -32,6 +39,10 @@ interface HeadingAndActionProps { */ const HeadingAndActions: React.FC = ({ course, onClose, activeSchedule }) => { const { courseName, department, number: courseNumber, uniqueId, instructors, flags, schedule } = course; + const [courseAdded, setCourseAdded] = useState( + activeSchedule.courses.some(course => course.uniqueId === uniqueId) + ); + const instructorString = instructors .map(instructor => { const { firstName, lastName } = instructor; @@ -42,30 +53,32 @@ const HeadingAndActions: React.FC = ({ course, onClose, a const handleCopy = () => { navigator.clipboard.writeText(uniqueId.toString()); }; - const handleOpenCalendar = async () => { - const url = chrome.runtime.getURL('calendar.html'); - await openNewTab(url); - }; const handleOpenRateMyProf = async () => { const openTabs = instructors.map(instructor => { const { fullName } = instructor; const url = `https://www.ratemyprofessors.com/search/professors/1255?q=${fullName}`; - return openNewTab(url); + return openTabFromContentScript(url); }); await Promise.all(openTabs); }; const handleOpenCES = async () => { // TODO: does not look up the professor just takes you to the page const cisUrl = 'https://utexas.bluera.com/utexas/rpvl.aspx?rid=d3db767b-049f-46c5-9a67-29c21c29c580®l=en-US'; - await openNewTab(cisUrl); + await openTabFromContentScript(cisUrl); }; 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`; - await openNewTab(url); + await openTabFromContentScript(url); }; - const handleAddCourse = async () => { - await addCourse(activeSchedule.name, course); + const handleAddOrRemoveCourse = async () => { + if (!courseAdded) { + await addCourse(activeSchedule.name, course); + } + else { + await removeCourse(activeSchedule.name, course); + } + setCourseAdded(!courseAdded); }; return (
@@ -124,8 +137,8 @@ const HeadingAndActions: React.FC = ({ course, onClose, a -
diff --git a/src/views/lib/openNewTabFromContentScript.ts b/src/views/lib/openNewTabFromContentScript.ts new file mode 100644 index 00000000..cf48d447 --- /dev/null +++ b/src/views/lib/openNewTabFromContentScript.ts @@ -0,0 +1,25 @@ +import { createMessenger } from "chrome-extension-toolkit"; + +type MyMessages = { + openNewTab: { + data: { url: string }; + }; + }; + +const messenger = createMessenger('background'); + +/** + * Content scripts and background scripts are isolated environments. + * Content scripts are where our code interacting with the webpage lives, + * whereas the background script is where we can open a tab from. + * This function allows us to open a new tab from the content script by communicating + * with the background script. + */ +export async function openTabFromContentScript(url: string) { + // @ts-ignore + messenger.openNewTab({ url }).then(() => { + console.log('New tab opened with URL:', url); + }).catch((error) => { + console.error('Error opening new tab:', error); + }); +}