auto-loading completely done
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
@import 'src/views/styles/base.module.scss';
|
||||
|
||||
.autoLoad {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
73
src/views/components/injected/AutoLoad/AutoLoad.tsx
Normal file
73
src/views/components/injected/AutoLoad/AutoLoad.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { ScrapedRow } from 'src/shared/types/Course';
|
||||
import useInfiniteScroll from 'src/views/hooks/useInfiniteScroll';
|
||||
import { CourseCatalogScraper } from 'src/views/lib/CourseCatalogScraper';
|
||||
import { SiteSupport } from 'src/views/lib/getSiteSupport';
|
||||
import { loadNextCourseCatalogPage, AutoLoadStatus } from 'src/views/lib/loadNextCourseCatalogPage';
|
||||
import Spinner from '../../common/Spinner/Spinner';
|
||||
import styles from './AutoLoad.module.scss';
|
||||
|
||||
type Props = {
|
||||
addRows: (rows: ScrapedRow[]) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* This component is responsible for loading the next page of courses when the user scrolls to the bottom of the page.
|
||||
* @returns
|
||||
*/
|
||||
export default function AutoLoad({ addRows }: Props) {
|
||||
const [container, setContainer] = useState<HTMLDivElement | null>(null);
|
||||
const [status, setStatus] = useState<AutoLoadStatus>(AutoLoadStatus.IDLE);
|
||||
|
||||
useEffect(() => {
|
||||
const portalContainer = document.createElement('div');
|
||||
const lastTableCell = document.querySelector('table')!;
|
||||
lastTableCell!.after(portalContainer);
|
||||
setContainer(portalContainer);
|
||||
}, []);
|
||||
|
||||
// FOR DEBUGGING
|
||||
useEffect(() => {
|
||||
console.log(`AutoLoad is now ${status}`);
|
||||
}, [status]);
|
||||
|
||||
// This hook will call the callback when the user scrolls to the bottom of the page.
|
||||
useInfiniteScroll(async () => {
|
||||
// fetch the next page of courses
|
||||
const [status, nextRows] = await loadNextCourseCatalogPage();
|
||||
setStatus(status);
|
||||
if (!nextRows) {
|
||||
return;
|
||||
}
|
||||
// scrape the courses from the page
|
||||
const ccs = new CourseCatalogScraper(SiteSupport.COURSE_CATALOG_LIST);
|
||||
const scrapedRows = ccs.scrape(nextRows);
|
||||
|
||||
// add the scraped courses to the current page
|
||||
addRows(scrapedRows);
|
||||
}, [addRows]);
|
||||
|
||||
if (!container || status === AutoLoadStatus.IDLE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createPortal(
|
||||
<div>
|
||||
{status === AutoLoadStatus.LOADING && (
|
||||
<div>
|
||||
<Spinner />
|
||||
<h2>Loading Next Page...</h2>
|
||||
</div>
|
||||
)}
|
||||
{status === AutoLoadStatus.ERROR && (
|
||||
<div className={styles.error}>
|
||||
<h2>Something went wrong</h2>
|
||||
<p>Try refreshing the page</p>
|
||||
<button onClick={() => window.location.reload()}>Refresh</button>
|
||||
</div>
|
||||
)}
|
||||
</div>,
|
||||
container
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Course, CourseRow } from 'src/shared/types/Course';
|
||||
import { Course, ScrapedRow } from 'src/shared/types/Course';
|
||||
import { SiteSupport } from 'src/views/lib/getSiteSupport';
|
||||
import { Button } from '../../common/Button/Button';
|
||||
import styles from './TableRow.module.scss';
|
||||
@@ -18,7 +18,6 @@ interface Props {
|
||||
* @returns a react portal to the new td in the column or null if the column has not been created yet.
|
||||
*/
|
||||
export default function TableRow({ support, course, element, isSelected, onClick }: Props): JSX.Element | null {
|
||||
console.log('TableRow -> isSelected:', isSelected);
|
||||
const [container, setContainer] = useState<HTMLTableCellElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user