diff options
author | Eugene Sokolov <eug-vs@keemail.me> | 2020-10-08 13:58:18 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-08 13:58:18 +0300 |
commit | 45b4094c02301ff854b8b8017437ad9989efa117 (patch) | |
tree | 0c7c375a24519fdff596f8377e2a131b98d2501e | |
parent | c3f9271adebf37ed66664d978cfae2a6b327ebff (diff) | |
parent | 80a09a9ec176c7585dca9d81f6b3d690660ce633 (diff) | |
download | which-ui-45b4094c02301ff854b8b8017437ad9989efa117.tar.gz |
Merge pull request #101 from which-ecosystem/feat/modal
ModalScreen component
-rw-r--r-- | .eslintrc.json | 3 | ||||
-rw-r--r-- | package-lock.json | 41 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | src/components/Fab/Fab.tsx | 23 | ||||
-rw-r--r-- | src/components/ModalScreen/ModalScreen.tsx | 80 | ||||
-rw-r--r-- | src/containers/Page/Page.tsx | 13 | ||||
-rw-r--r-- | src/containers/Page/Router.tsx | 48 | ||||
-rw-r--r-- | src/containers/PollCreation/PollCreation.tsx | 60 |
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> ); }; |