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 <ethanlanting@gmail.com> Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
This commit is contained in:
@@ -19,6 +19,6 @@ export default async function addCourse(scheduleId: string, course: Course): Pro
|
||||
course.colors = getUnusedColor(activeSchedule, course);
|
||||
activeSchedule.courses.push(course);
|
||||
activeSchedule.updatedAt = Date.now();
|
||||
|
||||
await UserScheduleStore.set('schedules', schedules);
|
||||
console.log(`Course added: ${course.courseName} (ID: ${course.uniqueId})`);
|
||||
}
|
||||
|
||||
64
src/pages/background/lib/addCourseByURL.ts
Normal file
64
src/pages/background/lib/addCourseByURL.ts
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user