-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: injected button - add all courses from MyUT AND passing URL to …
…handler (#291) * feat: first button attempt * feat: fetching each course code * feat: adding courses function from there but idk where to get the active schedule from * docs: todo * feat: retrieved active schedule * feat: button tactics * feat: add support for my.utexas.edu * feat: inject button into MyUT * feat: refactor code to render components dynamically based on site * feat: scrape course ids from MyUT and remove duplicates * feat: site support links for classlist * feat: add utility function to add course by URL * feat: support additional case for course cal * feat: duplicates * chore: cleanup * feat: temporary checkpoint * feat: reroute to use new add course by url * feat: linking to new function, cleaning up, adding messaging for course url add * chore: unused import * feat: relinking addCourse function to the button fingers crossed * feat: we did it! * chore: remove comment * chore: cleanup cleanup * feat: tried to handle the async stuff because of that small bug but nothing fixed. doesnt hurt tho * feat: i have fixed it holy kevinnn * chore: delete unused file and organization * chore: removed unused log * feat: better log for course add * chore: refactor via data destructuring * chore: pass component as prop via React.ComponentType --------- Co-authored-by: Ethan Lanting <[email protected]> Co-authored-by: doprz <[email protected]>
- Loading branch information
1 parent
9ad3239
commit c41467c
Showing
9 changed files
with
179 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import addCourse from '@pages/background/lib/addCourse'; | ||
import { background } from '@shared/messages'; | ||
import type { UserSchedule } from '@shared/types/UserSchedule'; | ||
import { CourseCatalogScraper } from '@views/lib/CourseCatalogScraper'; | ||
import getCourseTableRows from '@views/lib/getCourseTableRows'; | ||
import { SiteSupport } from '@views/lib/getSiteSupport'; | ||
|
||
/** | ||
* Adds a course to the active schedule by fetching course details from a provided URL. | ||
* If no URL is provided, prompts the user to enter one. | ||
* Sriram and Elie made this | ||
* | ||
* @param activeSchedule - The user's active schedule to which the course will be added. | ||
* @param link - The URL from which to fetch the course details. If not provided, a prompt will ask for it. | ||
* | ||
* @returns A promise that resolves when the course has been added or the operation is cancelled. | ||
* | ||
* @throws an error if there is an issue with scraping the course details. | ||
*/ | ||
export async function addCourseByURL(activeSchedule: UserSchedule, link?: string): Promise<void> { | ||
// todo: Use a proper modal instead of a prompt | ||
// eslint-disable-next-line no-param-reassign, no-alert | ||
if (!link) link = prompt('Enter course link') || undefined; | ||
|
||
// Exit if the user cancels the prompt | ||
if (!link) return; | ||
|
||
try { | ||
let htmlText: string; | ||
try { | ||
htmlText = await background.addCourseByURL({ | ||
url: link, | ||
method: 'GET', | ||
response: 'text', | ||
}); | ||
} catch (e) { | ||
// eslint-disable-next-line no-alert | ||
alert(`Failed to fetch url '${link}'`); | ||
return; | ||
} | ||
|
||
const doc = new DOMParser().parseFromString(htmlText, 'text/html'); | ||
|
||
const scraper = new CourseCatalogScraper(SiteSupport.COURSE_CATALOG_DETAILS, doc, link); | ||
const tableRows = getCourseTableRows(doc); | ||
const scrapedCourses = scraper.scrape(tableRows, false); | ||
|
||
if (scrapedCourses.length !== 1) return; | ||
|
||
const description = scraper.getDescription(doc); | ||
const row = scrapedCourses[0]!; | ||
const course = row.course!; | ||
course.description = description; | ||
|
||
if (activeSchedule.courses.every(c => c.uniqueId !== course.uniqueId)) { | ||
console.log('adding course'); | ||
await addCourse(activeSchedule.id, course); | ||
} else { | ||
console.log('course already exists'); | ||
} | ||
} catch (error) { | ||
console.error('Error scraping course:', error); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,27 @@ | ||
import CourseCatalogMain from '@views/components/CourseCatalogMain'; | ||
import InjectedButton from '@views/components/injected/AddAllButton'; | ||
import getSiteSupport, { SiteSupport } from '@views/lib/getSiteSupport'; | ||
import React from 'react'; | ||
import { createRoot } from 'react-dom/client'; | ||
|
||
const support = getSiteSupport(window.location.href); | ||
|
||
if (support === SiteSupport.COURSE_CATALOG_DETAILS || support === SiteSupport.COURSE_CATALOG_LIST) { | ||
const renderComponent = (Component: React.ComponentType) => { | ||
const container = document.createElement('div'); | ||
container.id = 'extension-root'; | ||
document.body.appendChild(container); | ||
|
||
createRoot(container).render( | ||
<React.StrictMode> | ||
<CourseCatalogMain support={support} /> | ||
<Component /> | ||
</React.StrictMode> | ||
); | ||
}; | ||
|
||
if (support === SiteSupport.COURSE_CATALOG_DETAILS || support === SiteSupport.COURSE_CATALOG_LIST) { | ||
renderComponent(() => <CourseCatalogMain support={support} />); | ||
} | ||
|
||
if (support === SiteSupport.MY_UT) { | ||
renderComponent(InjectedButton); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { addCourseByURL } from '@pages/background/lib/addCourseByURL'; | ||
import { Button } from '@views/components/common/Button'; | ||
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot'; | ||
import useSchedules from '@views/hooks/useSchedules'; | ||
import React, { useEffect, useState } from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
|
||
/** | ||
* InjectedButton component renders a button that adds courses to UTRP from official MyUT calendar | ||
* and adds the courses to the active schedule. | ||
* | ||
* @returns The rendered button component or null if the container is not found. | ||
*/ | ||
export default function InjectedButton(): JSX.Element | null { | ||
const [container, setContainer] = useState<HTMLDivElement | null>(null); | ||
const [activeSchedule, _] = useSchedules(); | ||
|
||
const extractCoursesFromCalendar = async () => { | ||
const calendarElement = document.querySelector('#kgoui_Rcontent_I3_Rprimary_I1_Rcontent_I1_Rcontent_I0_Ritems'); | ||
|
||
if (!calendarElement) { | ||
console.error('Calendar element not found'); | ||
return []; | ||
} | ||
|
||
const anchorTags = Array.from(calendarElement.querySelectorAll('a')).filter( | ||
anchor => !anchor.href.includes('google.com') | ||
); | ||
|
||
// Make sure to remove duplicate anchorTags using set | ||
const uniqueAnchorTags = Array.from(new Set(anchorTags.map(a => a.href))); | ||
|
||
for (const a of uniqueAnchorTags) { | ||
// eslint-disable-next-line no-await-in-loop | ||
await addCourseByURL(activeSchedule, a); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
const targetElement = document.getElementById('kgoui_Rcontent_I3_Rsecondary'); | ||
|
||
if ( | ||
targetElement && | ||
targetElement.classList.contains('kgoui_container_responsive_asymmetric2_column_secondary') | ||
) { | ||
const buttonContainer = document.createElement('div'); | ||
targetElement.appendChild(buttonContainer); | ||
setContainer(buttonContainer); | ||
|
||
return () => { | ||
buttonContainer.remove(); | ||
}; | ||
} | ||
}, []); | ||
|
||
if (!container) { | ||
return null; | ||
} | ||
|
||
return ReactDOM.createPortal( | ||
<ExtensionRoot> | ||
<Button variant='filled' color='ut-burntorange' onClick={extractCoursesFromCalendar}> | ||
Add Courses to UT Registration+ | ||
</Button> | ||
</ExtensionRoot>, | ||
container | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters