Improve scroll handling and cache fetch results
This commit is contained in:
parent
2aff4e97b6
commit
8555fbfa0f
|
@ -38,19 +38,17 @@ export function Admin(props) {
|
|||
</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Automate with wget (keep secret, that's <b>your</b> login token):
|
||||
{reveal ?
|
||||
<pre>
|
||||
wget \
|
||||
<br /> --content-disposition \
|
||||
<br /> --header="Authorization: Token {token}" \
|
||||
<br /> {apiUrl}/backup/
|
||||
</pre>
|
||||
:
|
||||
<div><Button onClick={() => setReveal(true)}>Show Secret</Button></div>
|
||||
}
|
||||
</p>
|
||||
Automate with wget (keep secret, that's <b>your</b> login token): <br />
|
||||
{reveal ?
|
||||
<pre>
|
||||
wget \
|
||||
<br /> --content-disposition \
|
||||
<br /> --header="Authorization: Token {token}" \
|
||||
<br /> {apiUrl}/backup/
|
||||
</pre>
|
||||
:
|
||||
<Button onClick={() => setReveal(true)}>Show Secret</Button>
|
||||
}
|
||||
</div>
|
||||
:
|
||||
<p>Loading...</p>
|
||||
|
|
|
@ -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 (
|
||||
<div>
|
||||
<ManageScroll />
|
||||
|
||||
<div className='content-wrap'>
|
||||
<div className='content-wrap-inside'>
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
44
webclient/src/ManageScroll.js
Normal file
44
webclient/src/ManageScroll.js
Normal file
|
@ -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
|
||||
);
|
||||
};
|
|
@ -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 ?
|
||||
<Button
|
||||
content='Clear'
|
||||
onClick={() => setSearch(searchDefault)}
|
||||
onClick={() => setSearch({seq: 0, q: ''})}
|
||||
/> : ''
|
||||
}
|
||||
|
||||
|
@ -118,17 +121,20 @@ export function Members(props) {
|
|||
);
|
||||
};
|
||||
|
||||
let resultCache = {};
|
||||
|
||||
export function MemberDetail(props) {
|
||||
const [result, setResult] = useState(false);
|
||||
const { id } = useParams();
|
||||
const [result, setResult] = useState(resultCache[id] || false);
|
||||
const [refreshCount, refreshResult] = useReducer(x => x + 1, 0);
|
||||
const [error, setError] = useState(false);
|
||||
const { token, user } = props;
|
||||
const { id } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
requester('/search/'+id+'/', 'GET', token)
|
||||
.then(res => {
|
||||
setResult(res);
|
||||
resultCache[id] = res;
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
|
|
Loading…
Reference in New Issue
Block a user