diff --git a/webclient/src/Admin.js b/webclient/src/Admin.js index c1903bd..631f0b4 100644 --- a/webclient/src/Admin.js +++ b/webclient/src/Admin.js @@ -38,19 +38,17 @@ export function Admin(props) {

-

- Automate with wget (keep secret, that's your login token): - {reveal ? -

-								wget \
-								
--content-disposition \ -
--header="Authorization: Token {token}" \ -
{apiUrl}/backup/ -
- : -
- } -

+ Automate with wget (keep secret, that's your login token):
+ {reveal ? +
+							wget \
+							
--content-disposition \ +
--header="Authorization: Token {token}" \ +
{apiUrl}/backup/ +
+ : + + } :

Loading...

diff --git a/webclient/src/App.js b/webclient/src/App.js index b6a380d..70743da 100644 --- a/webclient/src/App.js +++ b/webclient/src/App.js @@ -4,6 +4,7 @@ import './semantic-ui/semantic.min.css'; import './light.css'; import { Container, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react'; import { isAdmin, requester } from './utils.js'; +import { ManageScroll } from './ManageScroll.js'; import { Home } from './Home.js'; import { Account } from './Account.js'; import { Transactions, TransactionDetail } from './Transactions.js'; @@ -71,6 +72,8 @@ function App() { return (
+ +
diff --git a/webclient/src/Classes.js b/webclient/src/Classes.js index f5a3143..541dde9 100644 --- a/webclient/src/Classes.js +++ b/webclient/src/Classes.js @@ -48,14 +48,17 @@ function ClassTable(props) { ); }; +let classesCache = false; + export function Classes(props) { - const [classes, setClasses] = useState(false); + const [classes, setClasses] = useState(classesCache); const { token } = props; useEffect(() => { requester('/sessions/', 'GET', token) .then(res => { setClasses(res.results); + classesCache = res.results; }) .catch(err => { console.log(err); diff --git a/webclient/src/Courses.js b/webclient/src/Courses.js index b09648c..8609533 100644 --- a/webclient/src/Courses.js +++ b/webclient/src/Courses.js @@ -8,14 +8,17 @@ import { NotFound, PleaseLogin } from './Misc.js'; import { InstructorCourseList, InstructorCourseDetail } from './InstructorCourses.js'; import { InstructorClassList } from './InstructorClasses.js'; +let courseCache = false; + export function Courses(props) { - const [courses, setCourses] = useState(false); + const [courses, setCourses] = useState(courseCache); const { token, user } = props; useEffect(() => { requester('/courses/', 'GET', token) .then(res => { setCourses(res.results); + courseCache = res.results; }) .catch(err => { console.log(err); diff --git a/webclient/src/ManageScroll.js b/webclient/src/ManageScroll.js new file mode 100644 index 0000000..ded7bec --- /dev/null +++ b/webclient/src/ManageScroll.js @@ -0,0 +1,44 @@ +import React, { useState, useEffect, useReducer, useContext } from 'react'; +import { BrowserRouter as Router, Switch, Route, Link, useParams, useHistory } from 'react-router-dom'; + +let scrollPositions = {}; +let timeout = null; + +export function ManageScroll() { + const history = useHistory(); + + const scrollListener = () => { + if (timeout) { + window.cancelAnimationFrame(timeout); + } + + timeout = window.requestAnimationFrame(() => { + const key = history.location.key; + if (key in scrollPositions) { + scrollPositions[key] = window.scrollY; + } + }); + }; + + useEffect(() => { + window.addEventListener('scroll', scrollListener); + return () => { + window.removeEventListener('scroll', scrollListener); + } + }, []); + + useEffect(() => { + const key = history.location.key; + + if (key in scrollPositions) { + window.scrollTo(0, scrollPositions[key]); + } else { + window.scrollTo(0, 0); + scrollPositions[key] = 0; + } + }, [history.location]); + + return ( + null + ); +}; diff --git a/webclient/src/Members.js b/webclient/src/Members.js index b057992..3ab28a9 100644 --- a/webclient/src/Members.js +++ b/webclient/src/Members.js @@ -49,13 +49,16 @@ export function MembersDropdown(props) { ); }; +let searchCache = ''; + export function Members(props) { const [response, setResponse] = useState(false); - const searchDefault = {seq: 0, q: ''}; + const searchDefault = {seq: 0, q: searchCache}; const [search, setSearch] = useState(searchDefault); const { token } = props; useEffect(() => { + searchCache = search.q; requester('/search/', 'POST', token, search) .then(res => { if (!search.seq || res.seq > response.seq) { @@ -82,7 +85,7 @@ export function Members(props) { {search.q.length ?