diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 111eb9e..c1e7313 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -1215,6 +1215,18 @@ "@babel/runtime": "^7.4.4" } }, + "@material-ui/lab": { + "version": "4.0.0-alpha.51", + "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.51.tgz", + "integrity": "sha512-X/qv/sZQGhXhKDn83L94gNahGDQj2Rd6r7/9tPpQbSn2A1LAt1+jlTiWD1HUgDXZEPqTsJMajOjWSEmTL7/q7w==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.9.6", + "clsx": "^1.0.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" + } + }, "@material-ui/styles": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.9.6.tgz", diff --git a/webapp/package.json b/webapp/package.json index befeda9..a92dc66 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -5,6 +5,7 @@ "dependencies": { "@material-ui/core": "^4.9.8", "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "^4.0.0-alpha.51", "react": "^16.12.0", "react-dom": "^16.12.0", "react-redux": "^7.2.0", diff --git a/webapp/src/ui/components/courses-list.js b/webapp/src/ui/components/courses-list.js index 778ad9e..f7d2099 100644 --- a/webapp/src/ui/components/courses-list.js +++ b/webapp/src/ui/components/courses-list.js @@ -1,4 +1,4 @@ -import React, {useState, useEffect} from 'react'; +import React, {useState, useEffect, useCallback} from 'react'; import { TableContainer, Paper, @@ -9,6 +9,7 @@ import { TableHead, TablePagination } from '@material-ui/core'; +import Skeleton from '@material-ui/lab/Skeleton'; const columns = [ {id: 'course_name', label: 'Course Name'}, @@ -19,14 +20,19 @@ const columns = [ {id: 'transfer_college', label: 'College'} ]; -const CoursesList = ({data}) => { - const [displayedData, setDisplayedData] = useState(data); +const CoursesList = ({data, loading}) => { const [page, setPage] = useState(0); const [rowsPerPage, setRowsPerPage] = useState(50); + const getPromisedData = useCallback(() => { + return loading ? [...new Array(rowsPerPage).keys()] : data; + }, [loading, rowsPerPage, data]); + + const [displayedData, setDisplayedData] = useState(getPromisedData()); + useEffect(() => { - setDisplayedData(data.slice(rowsPerPage * page, rowsPerPage * (page + 1))); - }, [rowsPerPage, page, data]); + setDisplayedData(getPromisedData().slice(rowsPerPage * page, rowsPerPage * (page + 1))); + }, [rowsPerPage, page, getPromisedData]); return ( @@ -46,12 +52,12 @@ const CoursesList = ({data}) => { {displayedData.map(row => ( - {row.course_name} - {row.course_subject} - {row.course_id} - {row.course_credits} - {row.transfer_state} - {row.transfer_college} + {loading ? : {row.course_name}} + {loading ? : {row.course_subject}} + {loading ? : {row.course_id}} + {loading ? : {row.course_credits}} + {loading ? : {row.transfer_state}} + {loading ? : {row.transfer_college}} ))} diff --git a/webapp/src/ui/courses.js b/webapp/src/ui/courses.js index 205a10d..d8bfe79 100644 --- a/webapp/src/ui/courses.js +++ b/webapp/src/ui/courses.js @@ -1,21 +1,17 @@ import React, {useState, useEffect} from 'react'; -import {makeStyles} from '@material-ui/core/styles'; -import {InputBase, Backdrop, CircularProgress, Paper, Box, InputAdornment} from '@material-ui/core'; +import {InputBase, CircularProgress, Paper, Box, InputAdornment} from '@material-ui/core'; import SearchIcon from '@material-ui/icons/Search'; -import ErrorIcon from '@material-ui/icons/Error'; +import Skeleton from '@material-ui/lab/Skeleton'; import {useDebounce} from 'use-debounce'; import CoursesList from './components/courses-list'; import {useDispatch, useSelector} from 'react-redux'; import {getCourses} from '../actions'; - -const useStyles = makeStyles(() => ({ - backdrop: { - zIndex: 1000 - } -})); +import useFocus from '../utils/use-focus'; const Courses = () => { const dispatch = useDispatch(); + // Const queryRef = useRef(null); + const [queryRef, setQueryFocus] = useFocus(); // Update courses on load useEffect(() => { @@ -54,14 +50,20 @@ const Courses = () => { setIsFiltering(true); }; - const classes = useStyles(); + // Focus query input after loading is finished + useEffect(() => { + if (courses.loading === false) { + setQueryFocus(); + } + }, [courses, setQueryFocus]); return (
@@ -79,24 +81,14 @@ const Courses = () => { - Matched {filteredCourses.length} out of {courses.total ? courses.total : 0} results - - - - - - {courses.error ? ( - - - - -

Oops, something weird happened. The network request failed.

-
-
+ {courses.loading ? ( + ) : ( - + Matched {filteredCourses.length} out of {courses.total ? courses.total : 0} results )} -
+ + +
); }; diff --git a/webapp/src/utils/use-focus.js b/webapp/src/utils/use-focus.js new file mode 100644 index 0000000..42a06b2 --- /dev/null +++ b/webapp/src/utils/use-focus.js @@ -0,0 +1,13 @@ +import {useRef} from 'react'; + +export default () => { + const ref = useRef(null); + + const setFocus = () => { + if (ref.current) { + ref.current.focus(); + } + }; + + return [ref, setFocus]; +};