diff options
| author | Eugene Sokolov <eug-vs@keemail.me> | 2020-06-30 01:47:27 +0300 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-06-30 01:47:27 +0300 | 
| commit | 720a32c4cb1697f3a8f90973f28c334551ab87ff (patch) | |
| tree | c9028ea3ff850774d33cbc510eb19dd0e9f7aade | |
| parent | b301bf24c5037403a1e5fc32fc8c10794941b528 (diff) | |
| parent | e170d04d5d2c8c86d2683f3accb4feb2d94c881a (diff) | |
| download | which-ui-720a32c4cb1697f3a8f90973f28c334551ab87ff.tar.gz | |
Merge pull request #54 from which-ecosystem/hooks
Use hooks logic
| -rw-r--r-- | src/components/Feed/Feed.tsx | 5 | ||||
| -rw-r--r-- | src/components/Header/Header.tsx | 20 | ||||
| -rw-r--r-- | src/components/Header/SearchBar.tsx | 9 | ||||
| -rw-r--r-- | src/components/PollCard/PollCard.tsx | 5 | ||||
| -rw-r--r-- | src/components/UserStrip/UserStrip.tsx | 16 | ||||
| -rw-r--r-- | src/hooks/useAuth.tsx | 77 | ||||
| -rw-r--r-- | src/hooks/useNavigate.tsx | 41 | ||||
| -rw-r--r-- | src/index.tsx | 106 | ||||
| -rw-r--r-- | src/pages/AuthPage/AuthPage.tsx | 11 | ||||
| -rw-r--r-- | src/pages/AuthPage/SignInForm.tsx | 15 | ||||
| -rw-r--r-- | src/pages/AuthPage/SignUpForm.tsx | 15 | ||||
| -rw-r--r-- | src/pages/FeedPage/FeedPage.tsx | 15 | ||||
| -rw-r--r-- | src/pages/FeedPage/PollSubmission.tsx | 11 | ||||
| -rw-r--r-- | src/pages/FeedPage/PollSubmissionImage.tsx | 2 | ||||
| -rw-r--r-- | src/pages/Page.tsx | 31 | ||||
| -rw-r--r-- | src/pages/ProfilePage/MoreMenu.tsx | 18 | ||||
| -rw-r--r-- | src/pages/ProfilePage/ProfileInfo.tsx | 24 | ||||
| -rw-r--r-- | src/pages/ProfilePage/ProfilePage.tsx | 52 | ||||
| -rw-r--r-- | src/types.d.ts | 4 | 
19 files changed, 266 insertions, 211 deletions
| diff --git a/src/components/Feed/Feed.tsx b/src/components/Feed/Feed.tsx index 0c4d84f..7636573 100644 --- a/src/components/Feed/Feed.tsx +++ b/src/components/Feed/Feed.tsx @@ -5,7 +5,6 @@ import PollCard from '../PollCard/PollCard';  interface PropTypes {    polls: Poll[]; -  navigate: (prefix: string, id: string) => void;  }  const useStyles = makeStyles(theme => ({ @@ -16,11 +15,11 @@ const useStyles = makeStyles(theme => ({    }  })); -const Feed: React.FC<PropTypes> = ({ polls, navigate }) => { +const Feed: React.FC<PropTypes> = ({ polls }) => {    const classes = useStyles();    return (      <div className={classes.root}> -      {polls.map(poll => <PollCard initialPoll={poll} key={poll._id} navigate={navigate} />)} +      {polls.map(poll => <PollCard initialPoll={poll} key={poll._id} />)}      </div>    );  }; diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index d0d9081..72e40f8 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -9,14 +9,11 @@ import { makeStyles } from '@material-ui/core/styles';  import AccountCircle from '@material-ui/icons/AccountCircle';  import NotificationsIcon from '@material-ui/icons/Notifications';  import HomeIcon from '@material-ui/icons/Home'; +import { useAuth } from '../../hooks/useAuth'; +import { useNavigate } from '../../hooks/useNavigate';  import SearchBar from './SearchBar'; -interface PropTypes { -  userImage: string | undefined; -  navigate: (prefix: string) => void; -} -  const useStyles = makeStyles({    root: {      display: 'flex', @@ -33,15 +30,18 @@ const useStyles = makeStyles({    }  }); -const Header: React.FC<PropTypes> = ({ navigate, userImage }) => { +const Header: React.FC = () => {    const classes = useStyles(); +  const { user } = useAuth(); +  const { navigate } = useNavigate();    const handleHome = (): void => {      navigate('feed');    };    const handleProfile = (): void => { -    navigate('profile'); +    if (user) navigate('profile'); +    else navigate('auth');    };    const handleNotifications = (): void => {}; @@ -52,7 +52,7 @@ const Header: React.FC<PropTypes> = ({ navigate, userImage }) => {          <Typography variant="h5" className={classes.logo}>            Which          </Typography> -        <SearchBar navigate={navigate} /> +        <SearchBar />          <div>            <IconButton onClick={handleHome}>              <HomeIcon /> @@ -62,8 +62,8 @@ const Header: React.FC<PropTypes> = ({ navigate, userImage }) => {            </IconButton>            <IconButton onClick={handleProfile}>              { -              userImage?.match(/\.(jpeg|jpg|gif|png)$/) -                ? <Avatar className={classes.avatar} src={userImage} /> +              user?.avatarUrl?.match(/\.(jpeg|jpg|gif|png)$/) +                ? <Avatar className={classes.avatar} src={user?.avatarUrl} />                  : <AccountCircle />              }            </IconButton> diff --git a/src/components/Header/SearchBar.tsx b/src/components/Header/SearchBar.tsx index bff16a0..253e77f 100644 --- a/src/components/Header/SearchBar.tsx +++ b/src/components/Header/SearchBar.tsx @@ -12,10 +12,8 @@ import { makeStyles } from '@material-ui/core/styles';  import { User } from 'which-types';  import { get } from '../../requests';  import UserStrip from '../UserStrip/UserStrip'; +import { useNavigate } from '../../hooks/useNavigate'; -interface PropTypes { -  navigate: (prefix: string, id: string) => void; -}  const INTERVAL = 300;  const LIMIT = 7; @@ -36,10 +34,11 @@ const useStyles = makeStyles(theme => ({    }  })); -const SearchBar: React.FC<PropTypes> = ({ navigate }) => { +const SearchBar: React.FC = () => {    const [results, setResults] = useState<User[]>([]);    const [query, setQuery] = useState<string>('');    const [debouncedQuery, setDebouncedQuery] = useState<string>(query); +  const { navigate } = useNavigate();    const classes = useStyles();    useEffect(() => { @@ -79,7 +78,7 @@ const SearchBar: React.FC<PropTypes> = ({ navigate }) => {            results.map((result, index) => (              <div key={result._id}>                <ListItem button onClick={handleNavigate(index)}> -                <UserStrip user={result} navigate={navigate} /> +                <UserStrip user={result} />                </ListItem>                {(index < results.length - 1) && <Divider />}              </div> diff --git a/src/components/PollCard/PollCard.tsx b/src/components/PollCard/PollCard.tsx index 156315a..2a23522 100644 --- a/src/components/PollCard/PollCard.tsx +++ b/src/components/PollCard/PollCard.tsx @@ -13,7 +13,6 @@ import { post } from '../../requests';  interface PropTypes {    initialPoll: Poll; -  navigate: (prefix: string, id: string) => void;  }  const DATE_FORMAT = { @@ -54,7 +53,7 @@ const useStyles = makeStyles(theme => ({    }  })); -const PollCard: React.FC<PropTypes> = ({ initialPoll, navigate }) => { +const PollCard: React.FC<PropTypes> = ({ initialPoll }) => {    const [poll, setPoll] = useState<Poll>(initialPoll);    const classes = useStyles();    const { author, contents: { left, right }, vote } = poll; @@ -87,7 +86,7 @@ const PollCard: React.FC<PropTypes> = ({ initialPoll, navigate }) => {    return (      <Card className={classes.root}> -      <UserStrip user={author} info={date} navigate={navigate} /> +      <UserStrip user={author} info={date} />        <div className={classes.imagesBlock}>          <CardActionArea onDoubleClick={handleLeft}>            <CardMedia diff --git a/src/components/UserStrip/UserStrip.tsx b/src/components/UserStrip/UserStrip.tsx index f02adc3..3ac47b3 100644 --- a/src/components/UserStrip/UserStrip.tsx +++ b/src/components/UserStrip/UserStrip.tsx @@ -1,16 +1,13 @@  import React from 'react';  import { makeStyles } from '@material-ui/core/styles';  import VerifiedIcon from '@material-ui/icons/CheckCircleOutline'; -import { -  Avatar, -  CardHeader -} from '@material-ui/core/'; +import { Avatar, CardHeader } from '@material-ui/core/';  import { User } from 'which-types'; +import { useNavigate } from '../../hooks/useNavigate';  interface PropTypes {    user: User; -  navigate: (prefix: string, id: string) => void;    info?: string | JSX.Element  } @@ -31,13 +28,10 @@ const useStyles = makeStyles(theme => ({  })); -const UserStrip: React.FC<PropTypes> = ({ user, info, navigate }) => { +const UserStrip: React.FC<PropTypes> = ({ user, info }) => {    const classes = useStyles(); -  const { -    username, -    avatarUrl, -    verified -  } = user; +  const { navigate } = useNavigate(); +  const { username, avatarUrl, verified } = user;    const handleNavigate = () => {      navigate('profile', user._id); diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx new file mode 100644 index 0000000..55e142c --- /dev/null +++ b/src/hooks/useAuth.tsx @@ -0,0 +1,77 @@ +import React, { +  useState, useEffect, useContext, createContext +} from 'react'; +import { User } from 'which-types'; +import { post, get } from '../requests'; + + +interface ContextType { +  user: User | null, +  setUser: (user: User) => void; +  login: (username: string, password: string, remember?: boolean) => Promise<boolean>; +  logout: () => void; +  isAuthenticated: () => boolean; +} + +const authContext = createContext<ContextType>({ +  user: null, +  setUser: () => {}, +  login: async () => false, +  logout: () => {}, +  isAuthenticated: () => false +}); + +const useProvideAuth = () => { +  const [user, setUser] = useState<User | null>(null); + +  const login: ContextType['login'] = (username, password, remember = true) => { +    return post('/authentication', { +      strategy: 'local', +      username, +      password +    }).then(response => { +      const me = response.data.user; +      const token = response.data.accessToken; +      setUser(me); +      localStorage.setItem('userId', me._id); +      localStorage.setItem('token', token); +      if (!remember) localStorage.setItem('shouldClear', 'true'); +      return true; +    }).catch(() => false); +  }; + +  const logout = () => { +    setUser(null); +    localStorage.removeItem('userId'); +    localStorage.removeItem('token'); +  }; + +  const isAuthenticated = () => Boolean(user); + +  useEffect(() => { +    if (localStorage.getItem('shouldClear')) { +      localStorage.clear(); +    } +    const userId = localStorage.getItem('userId'); +    if (userId) { +      get(`/users/${userId}`).then(response => { +        setUser(response.data); +      }); +    } +  }, []); + +  return { +    user, setUser, login, logout, isAuthenticated +  }; +}; + +export const AuthProvider: React.FC = ({ children }) => { +  const auth = useProvideAuth(); +  const { Provider } = authContext; +  return <Provider value={auth}>{children}</Provider>; +}; + +export const useAuth = (): ContextType => { +  return useContext(authContext); +}; + diff --git a/src/hooks/useNavigate.tsx b/src/hooks/useNavigate.tsx new file mode 100644 index 0000000..befc529 --- /dev/null +++ b/src/hooks/useNavigate.tsx @@ -0,0 +1,41 @@ +import React, { useState, useContext, createContext } from 'react'; + +export interface Page { +  prefix: string; +  id?: string; +} + +interface ContextType { +  page: Page; +  setPage: (page: Page) => void; +  navigate: (prefix: string, id?: string) => void; +} + +const landingPage = { prefix: 'feed' }; + +const context = createContext<ContextType>({ +  page: landingPage, +  setPage: () => {}, +  navigate: () => {} +}); + +const useProvideNavigation = () => { +  const [page, setPage] = useState<Page>(landingPage); + +  const navigate: ContextType['navigate'] = (prefix, id?) => { +    setPage({ prefix, id }); +  }; + +  return { page, setPage, navigate }; +}; + +export const NavigationProvider: React.FC = ({ children }) => { +  const navigation = useProvideNavigation(); +  const { Provider } = context; +  return <Provider value={navigation}>{children}</Provider>; +}; + +export const useNavigate = (): ContextType => { +  return useContext(context); +}; + diff --git a/src/index.tsx b/src/index.tsx index 02f7969..180f80c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,22 +1,15 @@ -import React, { useState, useEffect } from 'react'; +import React from 'react';  import ReactDOM from 'react-dom'; -import { -  createMuiTheme, -  ThemeProvider, -  makeStyles -} from '@material-ui/core/styles'; +import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles';  import { CssBaseline } from '@material-ui/core';  import teal from '@material-ui/core/colors/teal';  import 'typeface-roboto'; -import { User } from 'which-types';  import Header from './components/Header/Header'; -import ProfilePage from './pages/ProfilePage/ProfilePage'; -import FeedPage from './pages/FeedPage/FeedPage'; -import AuthPage from './pages/AuthPage/AuthPage'; -import { Page } from './types'; -import { get, post } from './requests';  import ScrollTopArrow from './components/ScrollTopArrow/ScrollTopArrow'; +import Page from './pages/Page'; +import { AuthProvider } from './hooks/useAuth'; +import { NavigationProvider } from './hooks/useNavigate';  const theme = createMuiTheme({ @@ -28,88 +21,19 @@ const theme = createMuiTheme({    }  }); -const useStyles = makeStyles({ -  root: { -    width: theme.spacing(75), -    marginTop: theme.spacing(15), -    margin: '0 auto' -  } -});  const App: React.FC = () => { -  const [user, setUser] = React.useState<User | undefined>(); -  const [page, setPage] = useState<Page>({ prefix: 'feed', id: '' }); -  const classes = useStyles(); - -  const navigate = (prefix: string, id?: string): void => { -    if (prefix === 'profile' && !id && !user) { -      setPage({ -        prefix: 'auth', -        id: '' -      }); -    } else { -      setPage({ -        prefix, -        id: (id || user?._id || '') -      }); -    } -  }; - -  const logIn = (username: string, password: string, remember = true): Promise<boolean> => { -    return post('/authentication', { -      strategy: 'local', -      username, -      password -    }).then(response => { -      const me = response.data.user; -      const token = response.data.accessToken; -      setUser(me); -      navigate('profile', me._id); -      localStorage.setItem('userId', me._id); -      localStorage.setItem('token', token); -      if (!remember) localStorage.setItem('shouldClear', 'true'); -      return true; -    }).catch(() => false); -  }; - -  const logOut = () => { -    setUser(undefined); -    localStorage.removeItem('userId'); -    localStorage.removeItem('token'); -    navigate('auth'); -  }; - -  useEffect(() => { -    if (localStorage.getItem('shouldClear')) { -      localStorage.clear(); -    } -    const userId = localStorage.getItem('userId'); -    if (userId) { -      get(`/users/${userId}`).then(response => { -        setUser(response.data); -      }); -    } -  }, []); -    return ( -    <ThemeProvider theme={theme}> -      <CssBaseline /> -      <Header navigate={navigate} userImage={user?.avatarUrl} /> -      <div className={classes.root}> -        { page.prefix === 'profile' && ( -          <ProfilePage -            logOut={logOut} -            id={page.id} -            navigate={navigate} -            setUser={setUser} -          /> -        ) } -        { page.prefix === 'feed' && <FeedPage navigate={navigate} user={user} /> } -        { page.prefix === 'auth' && <AuthPage logIn={logIn} /> } -      </div> -      <ScrollTopArrow /> -    </ThemeProvider> - +    <NavigationProvider> +      <AuthProvider> +        <ThemeProvider theme={theme}> +          <CssBaseline /> +          <Header /> +          <Page /> +          <ScrollTopArrow /> +        </ThemeProvider> +      </AuthProvider> +    </NavigationProvider>    );  }; diff --git a/src/pages/AuthPage/AuthPage.tsx b/src/pages/AuthPage/AuthPage.tsx index d2c2eec..ad93463 100644 --- a/src/pages/AuthPage/AuthPage.tsx +++ b/src/pages/AuthPage/AuthPage.tsx @@ -3,11 +3,6 @@ import { makeStyles } from '@material-ui/core/styles';  import SignInForm from './SignInForm';  import SignUpForm from './SignUpForm'; - -interface PropTypes { -  logIn: (name: string, password: string, remember?: boolean) => Promise<boolean>; -} -  const useStyles = makeStyles({    formTransfer: {      display: 'flex', @@ -20,7 +15,7 @@ const useStyles = makeStyles({    }  }); -const AuthPage: React.FC<PropTypes> = ({ logIn }) => { +const AuthPage: React.FC = () => {    const [auth, setAuth] = useState<'signIn' | 'signUp'>('signIn');    const classes = useStyles(); @@ -35,8 +30,8 @@ const AuthPage: React.FC<PropTypes> = ({ logIn }) => {    return (      <> -      {auth === 'signIn' && <SignInForm logIn={logIn} />} -      {auth === 'signUp' && <SignUpForm logIn={logIn} />} +      {auth === 'signIn' && <SignInForm />} +      {auth === 'signUp' && <SignUpForm />}        <div className={classes.formTransfer}>          <div>{footerInfo[auth][0]}</div>          <span diff --git a/src/pages/AuthPage/SignInForm.tsx b/src/pages/AuthPage/SignInForm.tsx index 1dad153..e68483b 100644 --- a/src/pages/AuthPage/SignInForm.tsx +++ b/src/pages/AuthPage/SignInForm.tsx @@ -6,10 +6,8 @@ import {    FormControlLabel,    Switch  } from '@material-ui/core'; - -interface PropTypes { -  logIn: (name: string, password: string, remember?: boolean) => Promise<boolean>; -} +import { useAuth } from '../../hooks/useAuth'; +import { useNavigate } from '../../hooks/useNavigate';  const useStyles = makeStyles(theme => ({    root: { @@ -28,12 +26,14 @@ const useStyles = makeStyles(theme => ({    }  })); -const SignInForm: React.FC<PropTypes> = ({ logIn }) => { +const SignInForm: React.FC = () => {    const [error, setError] = useState<boolean>(false);    const [remember, setRemember] = useState<boolean>(true);    const classes = useStyles();    const nameRef = useRef<HTMLInputElement>();    const passwordRef = useRef<HTMLInputElement>(); +  const { login } = useAuth(); +  const { navigate } = useNavigate();    const handleCheck = () => {      setRemember(!remember); @@ -43,8 +43,9 @@ const SignInForm: React.FC<PropTypes> = ({ logIn }) => {      const name = nameRef.current?.value;      const password = passwordRef.current?.value;      if (name && password) { -      logIn(name, password, remember).then(success => { -        if (!success) setError(true); +      login(name, password, remember).then(success => { +        if (success) navigate('profile'); +        else setError(true);        });      }    }; diff --git a/src/pages/AuthPage/SignUpForm.tsx b/src/pages/AuthPage/SignUpForm.tsx index 25b79ff..1dacd45 100644 --- a/src/pages/AuthPage/SignUpForm.tsx +++ b/src/pages/AuthPage/SignUpForm.tsx @@ -3,10 +3,9 @@ import { makeStyles } from '@material-ui/core/styles';  import TextField from '@material-ui/core/TextField';  import Button from '@material-ui/core/Button';  import { post } from '../../requests'; +import { useAuth } from '../../hooks/useAuth'; +import { useNavigate } from '../../hooks/useNavigate'; -interface PropTypes { -  logIn: (name: string, password: string) => Promise<boolean>; -}  const useStyles = makeStyles(theme => ({    root: { @@ -25,21 +24,23 @@ const useStyles = makeStyles(theme => ({    }  })); -const SignUpForm: React.FC<PropTypes> = ({ logIn }) => { +const SignUpForm: React.FC = () => {    const [error, setError] = useState<boolean>(false);    const classes = useStyles();    const usernameRef = useRef<HTMLInputElement>();    const emailRef = useRef<HTMLInputElement>();    const passwordRef = useRef<HTMLInputElement>(); +  const { login } = useAuth(); +  const { navigate } = useNavigate();    const onClick = () => {      const username = usernameRef.current?.value;      const password = passwordRef.current?.value;      const email = emailRef.current?.value;      if (username && password) { -      post('/users', { username, password, email }).then(() => { -        logIn(username, password); -      }); +      post('/users', { username, password, email }) +        .then(() => login(username, password)) +        .then(() => navigate('profile'));      } else setError(true);    }; diff --git a/src/pages/FeedPage/FeedPage.tsx b/src/pages/FeedPage/FeedPage.tsx index 0017275..d29103a 100644 --- a/src/pages/FeedPage/FeedPage.tsx +++ b/src/pages/FeedPage/FeedPage.tsx @@ -1,18 +1,15 @@  import React, { useState, useEffect } from 'react'; -import { Poll, User } from 'which-types'; +import { Poll } from 'which-types';  import Feed from '../../components/Feed/Feed';  import { get } from '../../requests';  import PollSubmission from './PollSubmission'; +import { useAuth } from '../../hooks/useAuth'; -interface PropTypes { -  navigate: (prefix: string, id: string) => void; -  user: User | undefined; -} - -const FeedPage: React.FC<PropTypes> = ({ navigate, user }) => { +const FeedPage: React.FC = () => {    const [polls, setPolls] = useState<Poll[]>([]); +  const { isAuthenticated } = useAuth();    useEffect(() => {      get('/feed').then(response => { @@ -28,8 +25,8 @@ const FeedPage: React.FC<PropTypes> = ({ navigate, user }) => {    return (      <> -      {user && <PollSubmission user={user} addPoll={addPoll} />} -      <Feed polls={polls} navigate={navigate} /> +      {isAuthenticated() && <PollSubmission addPoll={addPoll} />} +      <Feed polls={polls} />      </>    );  }; diff --git a/src/pages/FeedPage/PollSubmission.tsx b/src/pages/FeedPage/PollSubmission.tsx index 16c8350..18f029c 100644 --- a/src/pages/FeedPage/PollSubmission.tsx +++ b/src/pages/FeedPage/PollSubmission.tsx @@ -7,14 +7,14 @@ import {    ClickAwayListener,    Divider  } from '@material-ui/core'; -import { User, Poll, Which } from 'which-types'; +import { Poll, Which } from 'which-types';  import PollSubmissionImage from './PollSubmissionImage';  import UserStrip from '../../components/UserStrip/UserStrip';  import { post } from '../../requests';  import { Contents } from './types'; +import { useAuth } from '../../hooks/useAuth';  interface PropTypes{ -  user: User;    addPoll: (poll: Poll) => void;  } @@ -30,10 +30,11 @@ const emptyContents: Contents = {    right: { url: '' }  }; -const PollSubmission: React.FC<PropTypes> = ({ user, addPoll }) => { +const PollSubmission: React.FC<PropTypes> = ({ addPoll }) => {    const classes = useStyles();    const [expanded, setExpanded] = useState(false);    const [contents, setContents] = useState<Contents>(emptyContents); +  const { user } = useAuth();    const readyToSubmit = contents.left.url && contents.right.url; @@ -47,7 +48,7 @@ const PollSubmission: React.FC<PropTypes> = ({ user, addPoll }) => {    const handleClick = () => {      if (expanded && readyToSubmit) { -      post('/polls/', { authorId: user._id, contents }).then(response => { +      post('/polls/', { contents }).then(response => {          addPoll(response.data);        });        setContents({ ...emptyContents }); @@ -59,7 +60,7 @@ const PollSubmission: React.FC<PropTypes> = ({ user, addPoll }) => {      <ClickAwayListener onClickAway={handleClickAway}>        <Card>          <Collapse in={expanded} timeout="auto" unmountOnExit> -          <UserStrip user={user} info="" navigate={() => {}} /> +          {user && <UserStrip user={user} info="" />}            <Divider />            <div className={classes.root}>              <PollSubmissionImage url={contents.left.url} setUrl={setUrl('left')} /> diff --git a/src/pages/FeedPage/PollSubmissionImage.tsx b/src/pages/FeedPage/PollSubmissionImage.tsx index 8d82d45..e2ffad3 100644 --- a/src/pages/FeedPage/PollSubmissionImage.tsx +++ b/src/pages/FeedPage/PollSubmissionImage.tsx @@ -41,7 +41,7 @@ const PollSubmissionImage: React.FC<PropTypes> = ({ url, setUrl }) => {      if (!isModalOpen) {        if (url) setUrl('');        else setIsModalOpen(!isModalOpen); -    }; +    }    };    const handleMouseEnter = (): void => { diff --git a/src/pages/Page.tsx b/src/pages/Page.tsx new file mode 100644 index 0000000..6d4315e --- /dev/null +++ b/src/pages/Page.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import ProfilePage from './ProfilePage/ProfilePage'; +import FeedPage from './FeedPage/FeedPage'; +import AuthPage from './AuthPage/AuthPage'; +import { useNavigate } from '../hooks/useNavigate'; + +const useStyles = makeStyles(theme => ({ +  root: { +    width: theme.spacing(75), +    marginTop: theme.spacing(15), +    margin: '0 auto' +  } +})); + +const Page: React.FC = () => { +  const { page } = useNavigate(); +  const classes = useStyles(); + +  return ( +    <div className={classes.root}> +      { page.prefix === 'profile' && <ProfilePage />} +      { page.prefix === 'feed' && <FeedPage /> } +      { page.prefix === 'auth' && <AuthPage /> } +    </div> +  ); +}; + + +export default Page; + diff --git a/src/pages/ProfilePage/MoreMenu.tsx b/src/pages/ProfilePage/MoreMenu.tsx index bf3347b..4e681f5 100644 --- a/src/pages/ProfilePage/MoreMenu.tsx +++ b/src/pages/ProfilePage/MoreMenu.tsx @@ -4,10 +4,8 @@ import Menu from '@material-ui/core/Menu';  import MenuItem from '@material-ui/core/MenuItem';  import MoreHorizIcon from '@material-ui/icons/MoreHoriz';  import { makeStyles } from '@material-ui/core'; - -interface PropTypes { -  logOut: () => void; -} +import { useAuth } from '../../hooks/useAuth'; +import { useNavigate } from '../../hooks/useNavigate';  const ITEM_HEIGHT = 48; @@ -19,15 +17,23 @@ const useStyles = makeStyles({    }  }); -const MoreMenu: React.FC<PropTypes> = ({ logOut }) => { +const MoreMenu: React.FC = () => {    const classes = useStyles();    const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null); +  const { logout } = useAuth(); +  const { navigate } = useNavigate(); +    const open = Boolean(anchorEl);    const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {      setAnchorEl(event.currentTarget);    }; +  const handleLogout = () => { +    logout(); +    navigate('auth'); +  }; +    const handleClose = () => {      setAnchorEl(null);    }; @@ -56,7 +62,7 @@ const MoreMenu: React.FC<PropTypes> = ({ logOut }) => {              }            }}          > -          <MenuItem onClick={logOut}>Log out</MenuItem> +          <MenuItem onClick={handleLogout}>Log out</MenuItem>          </Menu>        </div>      </div> diff --git a/src/pages/ProfilePage/ProfileInfo.tsx b/src/pages/ProfilePage/ProfileInfo.tsx index 9fe5912..9557a5e 100644 --- a/src/pages/ProfilePage/ProfileInfo.tsx +++ b/src/pages/ProfilePage/ProfileInfo.tsx @@ -8,15 +8,14 @@ import MoreMenu from './MoreMenu';  import Highlight from './Highlight';  import UploadImage from '../../components/UploadImage/UploadImage';  import { patch } from '../../requests'; +import { useAuth } from '../../hooks/useAuth';  interface PropTypes { -  user: User | undefined; -  logOut: () => void;    savedPolls: number;    totalVotes: number; -  setUserInfo: (a: User) => void; -  setUser: (a:User) => void; +  userInfo: User | undefined; +  setUserInfo: (userInfo: User) => void;  }  const useStyles = makeStyles(theme => ({ @@ -78,13 +77,14 @@ const useStyles = makeStyles(theme => ({  const ProfileInfo: React.FC<PropTypes> = ({ -  user, logOut, savedPolls, totalVotes, setUserInfo, setUser +  savedPolls, totalVotes, setUserInfo, userInfo  }) => {    const classes = useStyles();    const [input, setInput] = useState(false); +  const { setUser } = useAuth(); -  const dateSince = new Date(user?.createdAt || '').toLocaleDateString(); +  const dateSince = new Date(userInfo?.createdAt || '').toLocaleDateString();    const handleClick = () => {      setInput(!input); @@ -101,10 +101,10 @@ const ProfileInfo: React.FC<PropTypes> = ({    return (      <div className={classes.root}>        { -        user?._id === localStorage.getItem('userId') +        userInfo?._id === localStorage.getItem('userId')            ? (              <div> -              <MoreMenu logOut={logOut} /> +              <MoreMenu />                <div className={classes.avatarContainer}>                  <Badge                    overlap="circle" @@ -118,17 +118,17 @@ const ProfileInfo: React.FC<PropTypes> = ({                      </div>                    )}                  > -                  <Avatar className={classes.avatar} src={user?.avatarUrl} /> +                  <Avatar className={classes.avatar} src={userInfo?.avatarUrl} />                  </Badge>                </div>                <UploadImage isOpen={input} setIsOpen={setInput} callback={patchAvatar} />              </div>  ) -          : <Avatar className={classes.avatar} src={user?.avatarUrl} /> +          : <Avatar className={classes.avatar} src={userInfo?.avatarUrl} />        }        <Typography variant="h5" className={classes.name}> -        {user?.username} -        {user?.verified && <VerifiedIcon className={classes.verified} color="primary" />} +        {userInfo?.username} +        {userInfo?.verified && <VerifiedIcon className={classes.verified} color="primary" />}        </Typography>        <div className={classes.profileMenu}>          <Highlight text="Polls" value={savedPolls} /> diff --git a/src/pages/ProfilePage/ProfilePage.tsx b/src/pages/ProfilePage/ProfilePage.tsx index b0ac103..2c18466 100644 --- a/src/pages/ProfilePage/ProfilePage.tsx +++ b/src/pages/ProfilePage/ProfilePage.tsx @@ -4,50 +4,44 @@ import { User, Poll } from 'which-types';  import ProfileInfo from './ProfileInfo';  import Feed from '../../components/Feed/Feed';  import { get } from '../../requests'; +import { useAuth } from '../../hooks/useAuth'; +import { useNavigate } from '../../hooks/useNavigate'; -interface PropTypes { -  logOut: () => void; -  navigate: (prefix: string, id: string) => void; -  id: string; -  setUser:(a:User)=>void; -} -const ProfilePage: React.FC<PropTypes> = ({ -  logOut, id, navigate, setUser -}) => { +const ProfilePage: React.FC = () => {    const [userInfo, setUserInfo] = useState<User>();    const [polls, setPolls] = useState<Poll[]>([]);    const [totalVotes, setTotalVotes] = useState<number>(0); +  const { page, navigate } = useNavigate(); +  const { user } = useAuth();    useEffect(() => { -    get(`/users/${id}`).then(response => { -      setUserInfo(response.data); -    }); -  }, [id]); - -  useEffect(() => { -    get(`/profiles/${id}`).then(response => { -      setPolls(response.data); -      setTotalVotes(response.data.reduce( -        (total: number, current: Poll) => { -          const { left, right } = current.contents; -          return total + left.votes + right.votes; -        }, 0 -      )); -    }); -  }, [id, userInfo]); +    const id = page?.id || user?._id; +    if (id) { +      get(`/users/${id}`).then(response => { +        setUserInfo(response.data); +      }); +      get(`/profiles/${id}`).then(response => { +        setPolls(response.data); +        setTotalVotes(response.data.reduce( +          (total: number, current: Poll) => { +            const { left, right } = current.contents; +            return total + left.votes + right.votes; +          }, 0 +        )); +      }); +    } else navigate('auth'); +  }, [navigate, page, user]);    return (      <>        <ProfileInfo -        user={userInfo} +        userInfo={userInfo}          setUserInfo={setUserInfo} -        setUser={setUser} -        logOut={logOut}          savedPolls={polls.length}          totalVotes={totalVotes}        /> -      <Feed polls={[...polls]} navigate={navigate} /> +      <Feed polls={[...polls]} />      </>    );  }; diff --git a/src/types.d.ts b/src/types.d.ts index 4b1ffd6..e69de29 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -1,4 +0,0 @@ -export interface Page { -  prefix: string; -  id: string; -} | 
