feat: rework start time to checkboxes (#553)
* feat: replace dropdown with checkbox * refactor: remove console logs * refactor: eslint happy * refactor: change daysValue from string to array * style: match course schedule page styling * style: remove label font-normal * style: finalize course schedule page style match --------- Co-authored-by: Samuel Gunter <29130894+Samathingamajig@users.noreply.github.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
89
src/views/components/injected/DaysCheckbox.tsx
Normal file
89
src/views/components/injected/DaysCheckbox.tsx
Normal file
@@ -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<HTMLDivElement | null>(null);
|
||||
const [daysValue, setDaysValue] = useState<number[]>([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(
|
||||
<ExtensionRoot>
|
||||
<ul className='text-black font-[Verdana,_"Helvetica_Neue",_Helvetica,_Arial,_sans-serif]'>
|
||||
{days.map((day, index) => (
|
||||
<li key={day}>
|
||||
<input
|
||||
type='checkbox'
|
||||
id={`day_${day}`}
|
||||
checked={daysValue[index] === 1}
|
||||
onChange={e => {
|
||||
handleDayChange(index, e.target.checked);
|
||||
}}
|
||||
className='form-checkbox m-[3px_3px_3px_4px]'
|
||||
/>{' '}
|
||||
<label htmlFor={`day_${day}`}>{day}</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</ExtensionRoot>,
|
||||
container
|
||||
);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user