diff --git a/src/pages/content/index.tsx b/src/pages/content/index.tsx index 3ad26982..58ddfec8 100644 --- a/src/pages/content/index.tsx +++ b/src/pages/content/index.tsx @@ -1,5 +1,6 @@ import CourseCatalogMain from '@views/components/CourseCatalogMain'; import InjectedButton from '@views/components/injected/AddAllButton'; +import DaysCheckbox from '@views/components/injected/DaysCheckbox'; import getSiteSupport, { SiteSupport } from '@views/lib/getSiteSupport'; import React from 'react'; import { createRoot } from 'react-dom/client'; @@ -25,3 +26,7 @@ if (support === SiteSupport.COURSE_CATALOG_DETAILS || support === SiteSupport.CO if (support === SiteSupport.MY_UT) { renderComponent(InjectedButton); } + +if (support === SiteSupport.COURSE_CATALOG_SEARCH) { + renderComponent(DaysCheckbox); +} diff --git a/src/views/components/injected/DaysCheckbox.tsx b/src/views/components/injected/DaysCheckbox.tsx new file mode 100644 index 00000000..7e047300 --- /dev/null +++ b/src/views/components/injected/DaysCheckbox.tsx @@ -0,0 +1,89 @@ +import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot'; +import React, { useEffect, useState } from 'react'; +import ReactDOM from 'react-dom'; + +const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] as const; +/** + * Component that transforms the days dropdown into a series of checkboxes + * on the course catalog search page + * + * @returns The rendered checkbox component or null if the container is not found. + */ +export default function DaysCheckbox(): JSX.Element | null { + const [container, setContainer] = useState(null); + const [daysValue, setDaysValue] = useState([0, 0, 0, 0, 0, 0]); + + useEffect(() => { + const daysDropdown = document.getElementById('mtg_days_st') as HTMLSelectElement | null; + if (!daysDropdown) { + console.error('Days dropdown not found'); + return; + } + + const formElement = daysDropdown.closest('.form_element')!; + const checkboxContainer = document.createElement('div'); + + // Create a hidden input to store the value + const hiddenInput = document.createElement('input'); + hiddenInput.type = 'hidden'; + hiddenInput.name = 'mtg_days_st'; + hiddenInput.id = 'mtg_days_st_hidden'; + hiddenInput.value = daysDropdown.value; + + // Remove old dropdown + formElement.innerHTML = ''; + + // Add the label back + const newLabel = document.createElement('label'); + newLabel.className = 'primary_label'; + newLabel.htmlFor = 'mtg_days_st_hidden'; + newLabel.textContent = 'AND days'; + + formElement.appendChild(newLabel); + formElement.appendChild(hiddenInput); + formElement.appendChild(checkboxContainer); + setContainer(checkboxContainer); + + return () => { + checkboxContainer.remove(); + }; + }, []); + + useEffect(() => { + // Update hidden input when daysValue changes + const hiddenInput = document.getElementById('mtg_days_st_hidden') as HTMLInputElement | null; + if (hiddenInput) { + hiddenInput.value = daysValue.join(''); + } + }, [daysValue]); + + const handleDayChange = (position: number, checked: boolean) => { + setDaysValue(prev => prev.with(position, checked ? 1 : 0)); + }; + + if (!container) { + return null; + } + + return ReactDOM.createPortal( + +
    + {days.map((day, index) => ( +
  • + { + handleDayChange(index, e.target.checked); + }} + className='form-checkbox m-[3px_3px_3px_4px]' + />{' '} + +
  • + ))} +
+
, + container + ); +} diff --git a/src/views/lib/getSiteSupport.ts b/src/views/lib/getSiteSupport.ts index 0692f6e6..0e769f6c 100644 --- a/src/views/lib/getSiteSupport.ts +++ b/src/views/lib/getSiteSupport.ts @@ -13,6 +13,7 @@ export const SiteSupport = { MY_CALENDAR: 'MY_CALENDAR', REPORT_ISSUE: 'REPORT_ISSUE', MY_UT: 'MY_UT', + COURSE_CATALOG_SEARCH: 'COURSE_CATALOG_SEARCH', CLASSLIST: 'CLASSLIST', } as const; @@ -45,6 +46,7 @@ export default function getSiteSupport(url: string): SiteSupportType | null { if (document.querySelector('#details')) { return SiteSupport.COURSE_CATALOG_DETAILS; } + return SiteSupport.COURSE_CATALOG_SEARCH; } if (url.includes('utdirect.utexas.edu') && (url.includes('waitlist') || url.includes('classlist'))) { return SiteSupport.WAITLIST;