summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-11-13 18:51:45 +0900
committerJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-11-13 18:51:45 +0900
commitccf02576c640dd69500a81720dc2f17f05fb8a2c (patch)
treef96c821e4786f938b4d1e70b7990c51b809d128b
parentcf487bf7f47e0eb30280f0c0abfa7189e890472b (diff)
implement some global stateHEADmaster
-rw-r--r--src/App.js115
-rw-r--r--src/utils.js36
2 files changed, 111 insertions, 40 deletions
diff --git a/src/App.js b/src/App.js
index f2794dc..a10c27b 100644
--- a/src/App.js
+++ b/src/App.js
@@ -46,10 +46,11 @@ import NavigateBeforeIcon from '@material-ui/icons/NavigateBefore';
import Grow from '@material-ui/core/Grow';
import Link from '@material-ui/core/Link';
import Breadcrumbs from '@material-ui/core/Breadcrumbs';
+import Snackbar from '@material-ui/core/Snackbar';
import LazyLoad from 'react-lazyload';
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
import useTimeout from 'use-timeout'
-import { useWindowDimensions } from './utils.js';
+import { GlobalState, useGlobalState, useWindowDimensions } from './utils.js';
import 'pure-react-carousel/dist/react-carousel.es.css';
import 'fontsource-roboto';
@@ -71,6 +72,14 @@ const StyledBadge = withStyles((theme) => ({
},
}))(Badge);
+
+const global = {
+ store: { data: new GlobalState({data:[], loaded:false}), location: '/store' },
+ library: { data: new GlobalState({data:[], loaded:false}), location: '/library' },
+ account: { data: new GlobalState({data:[], loaded:false}), location: '/account' },
+ status: new GlobalState(null),
+}
+
function StoreItemDetails(props) {
const { t } = useTranslation();
@@ -373,25 +382,31 @@ function StoreList(props) {
}
function StoreView(props) {
- const [state, setState] = useState({data: [], loaded: false});
+ const [state, setState] = useGlobalState(global.store.data);
+ const [, setStatus] = useGlobalState(global.status);
useTimeout(() => {
async function fetchData() {
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
- var result = await fetch('https://cors-anywhere.herokuapp.com/https://www.eisys-bcs.jp/data.json?key[]=dlsite-doujin_home_center2').then(result => result.json());
- result = result.data.['dlsite-doujin_home_center2'].banners.map(item => { return {
- id: 'no-id',
- author: he.decode(item.title),
- title: he.decode(item.title),
- shortdesc: 'foobar',
- desc: 'foobar',
- img: 'https:' + item.ssl_path,
- cat: 'Misc',
- price: getRandomInt(3000) + '円',
- rating: getRandomInt(5),
- }})
- setState({data: result, loaded: true});
+ try {
+ var result = await fetch('https://cors-anywhere.herokuapp.com/https://www.eisys-bcs.jp/data.json?key[]=dlsite-doujin_home_center2').then(result => result.json());
+ result = result.data.['dlsite-doujin_home_center2'].banners.map(item => { return {
+ id: 'no-id',
+ author: he.decode(item.title),
+ title: he.decode(item.title),
+ shortdesc: 'foobar',
+ desc: 'foobar',
+ img: 'https:' + item.ssl_path,
+ cat: 'Misc',
+ price: getRandomInt(3000) + '円',
+ rating: getRandomInt(5),
+ }})
+ } catch (err) {
+ result = [];
+ setStatus(err);
+ }
+ setState({data:result, loaded:true});
}
fetchData();
}, 600);
@@ -406,25 +421,31 @@ function StoreView(props) {
}
function LibraryView(props) {
- const [state, setState] = useState({data: [], loaded: false});
+ const [state, setState] = useGlobalState(global.library.data);
+ const [, setStatus] = useGlobalState(global.status);
useTimeout(() => {
async function fetchData() {
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
- var result = await fetch('https://cors-anywhere.herokuapp.com/https://www.eisys-bcs.jp/data.json?key[]=dlsite-doujin_home_center2').then(result => result.json());
- result = result.data.['dlsite-doujin_home_center2'].banners.map(item => { return {
- id: 'no-id',
- author: he.decode(item.title),
- title: he.decode(item.title),
- shortdesc: 'foobar',
- desc: 'foobar',
- img: 'https:' + item.ssl_path,
- cat: 'Misc',
- price: getRandomInt(3000) + '円',
- rating: getRandomInt(5),
- }})
- setState({data: result, loaded: true});
+ try {
+ var result = await fetch('https://cors-anywhere.herokuapp.com/https://www.eisys-bcs.jp/data.json?key[]=dlsite-doujin_home_center2').then(result => result.json());
+ result = result.data.['dlsite-doujin_home_center2'].banners.map(item => { return {
+ id: 'no-id',
+ author: he.decode(item.title),
+ title: he.decode(item.title),
+ shortdesc: 'foobar',
+ desc: 'foobar',
+ img: 'https:' + item.ssl_path,
+ cat: 'Misc',
+ price: getRandomInt(3000) + '円',
+ rating: getRandomInt(5),
+ }})
+ } catch (err) {
+ result = [];
+ setStatus(err);
+ }
+ setState({data:result, loaded:true});
}
fetchData();
}, 600);
@@ -527,6 +548,13 @@ function ItemSearch(props) {
}
function BottomBar(props) {
+ var location = useLocation();
+ const components = location.pathname.split('/');
+
+ switch (components[1]) {
+ case 'store': case 'library': case 'account': global[components[1]].location = location;
+ }
+
const { t } = useTranslation();
const classes = makeStyles((theme) => ({
stickyBottom: {
@@ -536,25 +564,27 @@ function BottomBar(props) {
},
}))();
return (
- <BottomNavigation className={classes.stickyBottom} value={props.path} showLabels>
- <BottomNavigationAction label={t('Store')} value='store' icon={<StoreIcon/>} component={RouteLink} to='/store'/>
- <BottomNavigationAction label={t('Library')} value='library' icon={<LibraryBooksIcon/>} component={RouteLink} to='/library'/>
- <BottomNavigationAction label={t('Account')} value='account' icon={<AccountCircleIcon/>} component={RouteLink} to='/account'/>
+ <BottomNavigation className={classes.stickyBottom} value={components[1]} showLabels>
+ <BottomNavigationAction label={t('Store')} value='store' icon={<StoreIcon/>} component={RouteLink} to={global.store.location}/>
+ <BottomNavigationAction label={t('Library')} value='library' icon={<LibraryBooksIcon/>} component={RouteLink} to={global.library.location}/>
+ <BottomNavigationAction label={t('Account')} value='account' icon={<AccountCircleIcon/>} component={RouteLink} to={global.account.location}/>
</BottomNavigation>
);
}
function TopBar(props) {
+ var location = useLocation();
+ const components = location.pathname.split('/');
const { t } = useTranslation();
const classes = makeStyles((theme) => ({
title: { flexGrow: 1 },
backButton: { marginRight: theme.spacing(1) },
}))();
- const search = (props.components[1] !== 'account');
+ const search = (components[1] !== 'account');
return (
<AppBar position="fixed">
<Toolbar variant="dense">
- <Grow in={props.components.length > 2} unmountOnExit>
+ <Grow in={components.length > 2} unmountOnExit>
<IconButton edge="start" color="inherit" aria-label="back" className={classes.backButton} onClick={() => window.history.back()}>
<NavigateBeforeIcon/>
</IconButton>
@@ -577,8 +607,6 @@ function TopBar(props) {
}
function Routing() {
- var location = useLocation();
- const components = location.pathname.split('/');
const classes = makeStyles((theme) => ({
content: {
paddingTop: 105,
@@ -586,9 +614,10 @@ function Routing() {
minHeight: '100vh',
},
}))();
+ const [status, setStatus] = useGlobalState(global.status);
return (
<>
- <TopBar components={components}/>
+ <TopBar/>
<Paper className={classes.content} elevation={0} square>
<Switch>
<Route path='/store/:id' component={StoreItemDetails}/>
@@ -597,8 +626,16 @@ function Routing() {
<Route path='/account' component={AccountView}/>
<Route path='/'><Redirect to='/store'/></Route>
</Switch>
+ <Snackbar
+ onClose={() => setStatus(null)}
+ autoHideDuration={6000}
+ anchorOrigin={{vertical: 'top', horizontal: 'center'}}
+ open={status !== null}
+ message={status ? status : ''}
+ key={status}
+ />
</Paper>
- <BottomBar path={components[1]}/>
+ <BottomBar/>
</>
);
}
diff --git a/src/utils.js b/src/utils.js
index 3c072fa..c16c1b7 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -11,7 +11,7 @@ export function useWindowDimensions() {
function handleResize() { setWindowDimensions(getWindowDimensions()); }
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
- }, []);
+ });
return windowDimensions;
}
@@ -23,3 +23,37 @@ export function useDebounce(value, delay) {
}, [value, delay]);
return debouncedValue;
}
+
+export function GlobalState(initialValue) {
+ this.value = initialValue;
+ this.subscribers = [];
+ this.getValue = () => this.value;
+
+ this.setValue = (newState) => {
+ if (this.getValue() === newState) return;
+ this.value = newState;
+ this.subscribers.forEach(subscriber => subscriber(this.value));
+ }
+
+ this.subscribe = (itemToSubscribe) => {
+ if (this.subscribers.indexOf(itemToSubscribe) > -1) return
+ this.subscribers.push(itemToSubscribe);
+ }
+
+ this.unsubscribe = (itemToUnsubscribe) => {
+ this.subscribers = this.subscribers.filter(subscriber => subscriber !== itemToUnsubscribe);
+ }
+}
+
+export function useGlobalState(globalState) {
+ const [, setState] = useState();
+ const state = globalState.getValue();
+ function reRender(newState) { setState({}); }
+ useEffect(() => {
+ globalState.subscribe(reRender);
+ return () => globalState.unsubscribe(reRender);
+ })
+ function setGlobalState(newState) { globalState.setValue(newState); }
+ return [state, setGlobalState];
+}
+