aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.json3
-rw-r--r--package-lock.json41
-rw-r--r--package.json1
-rw-r--r--src/components/Fab/Fab.tsx23
-rw-r--r--src/components/ModalScreen/ModalScreen.tsx80
-rw-r--r--src/containers/Page/Page.tsx13
-rw-r--r--src/containers/Page/Router.tsx48
-rw-r--r--src/containers/PollCreation/PollCreation.tsx60
8 files changed, 194 insertions, 75 deletions
diff --git a/.eslintrc.json b/.eslintrc.json
index 479e04f..1102af4 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -25,6 +25,7 @@
"react/prop-types": 0,
"react/no-children-prop": 0,
"react/no-danger": 0,
- "react/jsx-one-expression-per-line": 0
+ "react/jsx-one-expression-per-line": 0,
+ "react/jsx-props-no-spreading": 0
}
}
diff --git a/package-lock.json b/package-lock.json
index d80d20f..03961ee 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6397,16 +6397,11 @@
"integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
},
"history": {
- "version": "4.10.1",
- "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
- "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/history/-/history-5.0.0.tgz",
+ "integrity": "sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==",
"requires": {
- "@babel/runtime": "^7.1.2",
- "loose-envify": "^1.2.0",
- "resolve-pathname": "^3.0.0",
- "tiny-invariant": "^1.0.2",
- "tiny-warning": "^1.0.0",
- "value-equal": "^1.0.1"
+ "@babel/runtime": "^7.7.6"
}
},
"hmac-drbg": {
@@ -10998,6 +10993,19 @@
"tiny-warning": "^1.0.0"
},
"dependencies": {
+ "history": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
+ "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
+ "requires": {
+ "@babel/runtime": "^7.1.2",
+ "loose-envify": "^1.2.0",
+ "resolve-pathname": "^3.0.0",
+ "tiny-invariant": "^1.0.2",
+ "tiny-warning": "^1.0.0",
+ "value-equal": "^1.0.1"
+ }
+ },
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
@@ -11025,6 +11033,21 @@
"react-router": "5.2.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0"
+ },
+ "dependencies": {
+ "history": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
+ "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
+ "requires": {
+ "@babel/runtime": "^7.1.2",
+ "loose-envify": "^1.2.0",
+ "resolve-pathname": "^3.0.0",
+ "tiny-invariant": "^1.0.2",
+ "tiny-warning": "^1.0.0",
+ "value-equal": "^1.0.1"
+ }
+ }
}
},
"react-scripts": {
diff --git a/package.json b/package.json
index 2bb2500..f45d4e7 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"bluebird": "^3.7.2",
"compressorjs": "^1.0.6",
"formik": "^2.1.5",
+ "history": "^5.0.0",
"lodash": "^4.17.15",
"notistack": "^0.9.17",
"react": "^16.13.1",
diff --git a/src/components/Fab/Fab.tsx b/src/components/Fab/Fab.tsx
index 7ca2893..f6b85e5 100644
--- a/src/components/Fab/Fab.tsx
+++ b/src/components/Fab/Fab.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { useHistory } from 'react-router-dom';
+import { useLocation, Link } from 'react-router-dom';
import { Fab as FabBase, Slide, useScrollTrigger } from '@material-ui/core/';
import { makeStyles } from '@material-ui/core/styles';
import PlusIcon from '@material-ui/icons/Add';
@@ -26,22 +26,19 @@ const useStyles = makeStyles(theme => ({
const Fab: React.FC<PropTypes> = ({ hideOnScroll = false }) => {
const classes = useStyles();
- const history = useHistory();
+ const location = useLocation();
const trigger = useScrollTrigger();
- const handleClick = () => {
- history.push('/new');
- };
-
return (
<Slide appear={false} direction="up" in={(!hideOnScroll) || !trigger}>
- <FabBase
- onClick={handleClick}
- className={classes.root}
- color="secondary"
- >
- <PlusIcon />
- </FabBase>
+ <Link to={{ pathname: '/new', state: { background: location } }}>
+ <FabBase
+ className={classes.root}
+ color="secondary"
+ >
+ <PlusIcon />
+ </FabBase>
+ </Link>
</Slide>
);
};
diff --git a/src/components/ModalScreen/ModalScreen.tsx b/src/components/ModalScreen/ModalScreen.tsx
new file mode 100644
index 0000000..81e5c5a
--- /dev/null
+++ b/src/components/ModalScreen/ModalScreen.tsx
@@ -0,0 +1,80 @@
+import React, { useState, useCallback } from 'react';
+import { useHistory } from 'react-router-dom';
+import {
+ AppBar,
+ Dialog,
+ Toolbar,
+ Typography,
+ IconButton,
+ Divider,
+ Slide,
+ useMediaQuery,
+ useTheme
+} from '@material-ui/core';
+import { makeStyles } from '@material-ui/core/styles';
+import CloseIcon from '@material-ui/icons/Close';
+import { TransitionProps } from '@material-ui/core/transitions';
+
+interface PropTypes {
+ title: string;
+}
+
+const useStyles = makeStyles(theme => ({
+ root: {
+ backgroundColor: theme.palette.background.default
+ },
+ content: {
+ padding: theme.spacing(3, 0, 0, 0)
+ },
+ toolbar: {
+ display: 'flex',
+ justifyContent: 'space-between'
+ }
+}));
+
+const Transition = React.forwardRef((
+ props: TransitionProps & { children?: React.ReactElement },
+ ref: React.Ref<unknown>
+) => <Slide direction="left" ref={ref} {...props} />);
+
+const ModalScreen: React.FC<PropTypes> = ({ title, children }) => {
+ const [isOpen, setIsOpen] = useState<boolean>(true);
+ const classes = useStyles();
+ const theme = useTheme();
+ const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
+ const history = useHistory();
+
+ const handleClose = useCallback(() => setIsOpen(false), [setIsOpen]);
+ const onExited = useCallback(() => history.goBack(), [history]);
+
+ return (
+ <Dialog
+ open={isOpen}
+ onExited={onExited}
+ TransitionComponent={Transition}
+ PaperProps={{ className: classes.root }}
+ fullScreen={isMobile}
+ fullWidth
+ >
+ <AppBar position="static">
+ <Toolbar className={classes.toolbar}>
+ <IconButton onClick={handleClose}>
+ <CloseIcon />
+ </IconButton>
+ <Typography variant="h6">
+ { title }
+ </Typography>
+ <IconButton style={{ opacity: 0, pointerEvents: 'none' }}>
+ <CloseIcon />
+ </IconButton>
+ </Toolbar>
+ </AppBar>
+ <Divider />
+ <div className={classes.content}>
+ { children }
+ </div>
+ </Dialog>
+ );
+};
+
+export default ModalScreen;
diff --git a/src/containers/Page/Page.tsx b/src/containers/Page/Page.tsx
index 7df62cd..b7e1938 100644
--- a/src/containers/Page/Page.tsx
+++ b/src/containers/Page/Page.tsx
@@ -5,11 +5,14 @@ import { SnackbarProvider } from 'notistack';
import { ErrorBoundary } from 'react-error-boundary';
import { useHistory } from 'react-router-dom';
-import Router from './Router';
+import Router, { LocationState } from './Router';
import DynoWaiter from './DynoWaiter';
import Loading from '../../components/Loading/Loading';
import EmptyState from '../../components/EmptyState/EmptyState';
+interface HistoryChange {
+ state?: LocationState | null;
+}
const useStyles = makeStyles(theme => ({
root: {
@@ -32,11 +35,9 @@ const Page: React.FC = () => {
const history = useHistory();
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
- useEffect(() => {
- return history.listen(() => {
- window.scrollTo(0, 0);
- });
- }, [history]);
+ useEffect(() => history.listen((update: HistoryChange) => {
+ if (!update.state?.background) window.scrollTo(0, 0);
+ }), [history]);
return (
<SnackbarProvider
diff --git a/src/containers/Page/Router.tsx b/src/containers/Page/Router.tsx
index 7067eea..7c3a418 100644
--- a/src/containers/Page/Router.tsx
+++ b/src/containers/Page/Router.tsx
@@ -1,5 +1,8 @@
import React from 'react';
-import { Switch, Route } from 'react-router-dom';
+import { Switch, Route, useLocation } from 'react-router-dom';
+import { Location } from 'history';
+
+import PollCreation from '../PollCreation/PollCreation';
const Profile = React.lazy(() => import('../Profile/Profile'));
const Feed = React.lazy(() => import('../Feed/Feed'));
@@ -7,20 +10,35 @@ const Login = React.lazy(() => import('../Login/Login'));
const Registration = React.lazy(() => import('../Registration/Registration'));
const Home = React.lazy(() => import('../Home/Home'));
const Notifications = React.lazy(() => import('../Notifications/Notifications'));
-const PollCreation = React.lazy(() => import('../PollCreation/PollCreation'));
-
-
-const Router: React.FC = React.memo(() => (
- <Switch>
- <Route exact path="/" component={Home} />
- <Route exact path="/login" component={Login} />
- <Route exact path="/registration" component={Registration} />
- <Route exact path="/feed" component={Feed} />
- <Route exact path="/notifications" component={Notifications} />
- <Route exact path="/new" component={PollCreation} />
- <Route path="/profile/:username" component={Profile} />
- </Switch>
-));
+
+export interface LocationState {
+ background?: Location;
+}
+
+const Router: React.FC = React.memo(() => {
+ const location = useLocation<LocationState>();
+ const background = location.state && location.state.background;
+
+ const ModalSwitch = (
+ <Switch>
+ <Route path="/new" component={PollCreation} />
+ </Switch>
+ );
+
+ return (
+ <>
+ {ModalSwitch}
+ <Switch location={background || location}>
+ <Route exact path="/" component={Home} />
+ <Route exact path="/login" component={Login} />
+ <Route exact path="/registration" component={Registration} />
+ <Route exact path="/notifications" component={Notifications} />
+ <Route path="/feed" component={Feed} />
+ <Route path="/profile/:username" component={Profile} />
+ </Switch>
+ </>
+ );
+});
export default Router;
diff --git a/src/containers/PollCreation/PollCreation.tsx b/src/containers/PollCreation/PollCreation.tsx
index ecc6757..b7ee00a 100644
--- a/src/containers/PollCreation/PollCreation.tsx
+++ b/src/containers/PollCreation/PollCreation.tsx
@@ -5,7 +5,6 @@ import { makeStyles } from '@material-ui/core/styles';
import {
Button,
Card,
- Divider,
Container,
LinearProgress
} from '@material-ui/core';
@@ -13,16 +12,14 @@ import { useSnackbar } from 'notistack';
import useS3Preupload from './useS3Preupload';
import ImageInput from './ImageInput';
+import ModalScreen from '../../components/ModalScreen/ModalScreen';
import UserStrip from '../../components/UserStrip/UserStrip';
import { post } from '../../requests';
-import { useAuth } from '../../hooks/useAuth';
import { useFeed } from '../../hooks/APIClient';
+import { useAuth } from '../../hooks/useAuth';
const useStyles = makeStyles(theme => ({
- root: {
- marginBottom: theme.spacing(4)
- },
images: {
height: theme.spacing(50),
display: 'flex'
@@ -33,8 +30,8 @@ const useStyles = makeStyles(theme => ({
const PollCreation: React.FC = () => {
const classes = useStyles();
const history = useHistory();
- const { enqueueSnackbar } = useSnackbar();
const { user } = useAuth();
+ const { enqueueSnackbar } = useSnackbar();
const { mutate: updateFeed } = useFeed();
const {
file: left,
@@ -71,31 +68,32 @@ const PollCreation: React.FC = () => {
};
return (
- <Container maxWidth="sm" disableGutters>
- <Card className={classes.root}>
- {user && <UserStrip user={user} info="" />}
- <Divider />
- <div className={classes.images}>
- <ImageInput callback={setLeft} progress={leftProgress} />
- <ImageInput callback={setRight} progress={rightProgress} />
- </div>
- {
- leftProgress || rightProgress
- ? <LinearProgress color="primary" />
- : (
- <Button
- color="primary"
- disabled={!(left && right)}
- variant="contained"
- onClick={handleClick}
- fullWidth
- >
- Submit
- </Button>
- )
- }
- </Card>
- </Container>
+ <ModalScreen title="Create a poll">
+ <Container maxWidth="sm" disableGutters>
+ <Card elevation={3}>
+ {user && <UserStrip user={user} info="" />}
+ <div className={classes.images}>
+ <ImageInput callback={setLeft} progress={leftProgress} />
+ <ImageInput callback={setRight} progress={rightProgress} />
+ </div>
+ {
+ leftProgress || rightProgress
+ ? <LinearProgress color="primary" />
+ : (
+ <Button
+ color="primary"
+ disabled={!(left && right)}
+ variant="contained"
+ onClick={handleClick}
+ fullWidth
+ >
+ Submit
+ </Button>
+ )
+ }
+ </Card>
+ </Container>
+ </ModalScreen>
);
};