From 1f646377c35b65b97d6eeebb1e88f6d8307e1ef0 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 29 Jun 2020 23:59:15 +0300 Subject: feat!: create useAuth hook --- src/hooks/useAuth.tsx | 75 +++++++++++++++++++++++++++++++++++ src/index.tsx | 45 ++------------------- src/pages/AuthPage/AuthPage.tsx | 11 ++--- src/pages/AuthPage/SignInForm.tsx | 10 ++--- src/pages/AuthPage/SignUpForm.tsx | 9 ++--- src/pages/FeedPage/FeedPage.tsx | 7 ++-- src/pages/FeedPage/PollSubmission.tsx | 9 +++-- src/pages/ProfilePage/MoreMenu.tsx | 11 +++-- src/pages/ProfilePage/ProfileInfo.tsx | 24 +++++------ src/pages/ProfilePage/ProfilePage.tsx | 10 +---- 10 files changed, 118 insertions(+), 93 deletions(-) create mode 100644 src/hooks/useAuth.tsx (limited to 'src') diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx new file mode 100644 index 0000000..4f76593 --- /dev/null +++ b/src/hooks/useAuth.tsx @@ -0,0 +1,75 @@ +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; + logout: () => void; + isAuthenticated: () => boolean; +} + +const authContext = createContext({ + user: null, + setUser: () => {}, + login: async () => false, + logout: () => {}, + isAuthenticated: () => false +}); + +const useProvideAuth = () => { + const [user, setUser] = useState(null); + + const login = (username: string, password: string, remember = true): Promise => { + 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(null); + localStorage.removeItem('userId'); + localStorage.removeItem('token'); + // navigate('auth'); + }; + + 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 {children} +}; + +export const useAuth = () => { + return useContext(authContext); +} + diff --git a/src/index.tsx b/src/index.tsx index 02f7969..f9114c3 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -17,6 +17,7 @@ import AuthPage from './pages/AuthPage/AuthPage'; import { Page } from './types'; import { get, post } from './requests'; import ScrollTopArrow from './components/ScrollTopArrow/ScrollTopArrow'; +import { useAuth, AuthProvider } from './hooks/useAuth'; const theme = createMuiTheme({ @@ -37,9 +38,9 @@ const useStyles = makeStyles({ }); const App: React.FC = () => { - const [user, setUser] = React.useState(); const [page, setPage] = useState({ prefix: 'feed', id: '' }); const classes = useStyles(); + const user = { _id: '', avatarUrl: '' }; const navigate = (prefix: string, id?: string): void => { if (prefix === 'profile' && !id && !user) { @@ -55,42 +56,6 @@ const App: React.FC = () => { } }; - const logIn = (username: string, password: string, remember = true): Promise => { - 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 ( @@ -98,14 +63,12 @@ const App: React.FC = () => {
{ page.prefix === 'profile' && ( ) } - { page.prefix === 'feed' && } - { page.prefix === 'auth' && } + { page.prefix === 'feed' && } + { page.prefix === 'auth' && }
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; -} - const useStyles = makeStyles({ formTransfer: { display: 'flex', @@ -20,7 +15,7 @@ const useStyles = makeStyles({ } }); -const AuthPage: React.FC = ({ logIn }) => { +const AuthPage: React.FC = () => { const [auth, setAuth] = useState<'signIn' | 'signUp'>('signIn'); const classes = useStyles(); @@ -35,8 +30,8 @@ const AuthPage: React.FC = ({ logIn }) => { return ( <> - {auth === 'signIn' && } - {auth === 'signUp' && } + {auth === 'signIn' && } + {auth === 'signUp' && }
{footerInfo[auth][0]}
Promise; -} +import { useAuth } from '../../hooks/useAuth'; const useStyles = makeStyles(theme => ({ root: { @@ -28,12 +25,13 @@ const useStyles = makeStyles(theme => ({ } })); -const SignInForm: React.FC = ({ logIn }) => { +const SignInForm: React.FC = () => { const [error, setError] = useState(false); const [remember, setRemember] = useState(true); const classes = useStyles(); const nameRef = useRef(); const passwordRef = useRef(); + const { login } = useAuth(); const handleCheck = () => { setRemember(!remember); @@ -43,7 +41,7 @@ const SignInForm: React.FC = ({ logIn }) => { const name = nameRef.current?.value; const password = passwordRef.current?.value; if (name && password) { - logIn(name, password, remember).then(success => { + login(name, password, remember).then(success => { if (!success) setError(true); }); } diff --git a/src/pages/AuthPage/SignUpForm.tsx b/src/pages/AuthPage/SignUpForm.tsx index 25b79ff..af7a0f8 100644 --- a/src/pages/AuthPage/SignUpForm.tsx +++ b/src/pages/AuthPage/SignUpForm.tsx @@ -3,10 +3,8 @@ 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'; -interface PropTypes { - logIn: (name: string, password: string) => Promise; -} const useStyles = makeStyles(theme => ({ root: { @@ -25,12 +23,13 @@ const useStyles = makeStyles(theme => ({ } })); -const SignUpForm: React.FC = ({ logIn }) => { +const SignUpForm: React.FC = () => { const [error, setError] = useState(false); const classes = useStyles(); const usernameRef = useRef(); const emailRef = useRef(); const passwordRef = useRef(); + const { login } = useAuth(); const onClick = () => { const username = usernameRef.current?.value; @@ -38,7 +37,7 @@ const SignUpForm: React.FC = ({ logIn }) => { const email = emailRef.current?.value; if (username && password) { post('/users', { username, password, email }).then(() => { - logIn(username, password); + login(username, password); }); } else setError(true); }; diff --git a/src/pages/FeedPage/FeedPage.tsx b/src/pages/FeedPage/FeedPage.tsx index 0017275..6561991 100644 --- a/src/pages/FeedPage/FeedPage.tsx +++ b/src/pages/FeedPage/FeedPage.tsx @@ -4,15 +4,16 @@ import { Poll, User } 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 = ({ navigate, user }) => { +const FeedPage: React.FC = ({ navigate }) => { const [polls, setPolls] = useState([]); + const { isAuthenticated } = useAuth(); useEffect(() => { get('/feed').then(response => { @@ -28,7 +29,7 @@ const FeedPage: React.FC = ({ navigate, user }) => { return ( <> - {user && } + {isAuthenticated() && } ); diff --git a/src/pages/FeedPage/PollSubmission.tsx b/src/pages/FeedPage/PollSubmission.tsx index 16c8350..4e06254 100644 --- a/src/pages/FeedPage/PollSubmission.tsx +++ b/src/pages/FeedPage/PollSubmission.tsx @@ -12,9 +12,9 @@ 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 = ({ user, addPoll }) => { +const PollSubmission: React.FC = ({ addPoll }) => { const classes = useStyles(); const [expanded, setExpanded] = useState(false); const [contents, setContents] = useState(emptyContents); + const { user } = useAuth(); const readyToSubmit = contents.left.url && contents.right.url; @@ -47,7 +48,7 @@ const PollSubmission: React.FC = ({ 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 = ({ user, addPoll }) => { - {}} /> + {user && {}} />}
diff --git a/src/pages/ProfilePage/MoreMenu.tsx b/src/pages/ProfilePage/MoreMenu.tsx index bf3347b..7c17f1e 100644 --- a/src/pages/ProfilePage/MoreMenu.tsx +++ b/src/pages/ProfilePage/MoreMenu.tsx @@ -4,10 +4,7 @@ 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'; const ITEM_HEIGHT = 48; @@ -19,9 +16,11 @@ const useStyles = makeStyles({ } }); -const MoreMenu: React.FC = ({ logOut }) => { +const MoreMenu: React.FC = () => { const classes = useStyles(); const [anchorEl, setAnchorEl] = React.useState(null); + const { logout } = useAuth(); + const open = Boolean(anchorEl); const handleClick = (event: React.MouseEvent) => { @@ -56,7 +55,7 @@ const MoreMenu: React.FC = ({ logOut }) => { } }} > - Log out + Log out
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 = ({ - 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 = ({ return (
{ - user?._id === localStorage.getItem('userId') + userInfo?._id === localStorage.getItem('userId') ? (
- +
= ({
)} > - +
) - : + : } - {user?.username} - {user?.verified && } + {userInfo?.username} + {userInfo?.verified && }
diff --git a/src/pages/ProfilePage/ProfilePage.tsx b/src/pages/ProfilePage/ProfilePage.tsx index b0ac103..ad2da46 100644 --- a/src/pages/ProfilePage/ProfilePage.tsx +++ b/src/pages/ProfilePage/ProfilePage.tsx @@ -6,15 +6,11 @@ import Feed from '../../components/Feed/Feed'; import { get } from '../../requests'; interface PropTypes { - logOut: () => void; navigate: (prefix: string, id: string) => void; id: string; - setUser:(a:User)=>void; } -const ProfilePage: React.FC = ({ - logOut, id, navigate, setUser -}) => { +const ProfilePage: React.FC = ({ id, navigate }) => { const [userInfo, setUserInfo] = useState(); const [polls, setPolls] = useState([]); const [totalVotes, setTotalVotes] = useState(0); @@ -40,10 +36,8 @@ const ProfilePage: React.FC = ({ return ( <> -- cgit v1.2.3 From aa63dea15c71ab014b4b57010574c7abf1f9628b Mon Sep 17 00:00:00 2001 From: eug-vs Date: Tue, 30 Jun 2020 00:08:42 +0300 Subject: feat: useAuth in header --- src/components/Header/Header.tsx | 9 +++++---- src/index.tsx | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index d0d9081..49f427f 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -9,11 +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 SearchBar from './SearchBar'; interface PropTypes { - userImage: string | undefined; navigate: (prefix: string) => void; } @@ -33,8 +33,9 @@ const useStyles = makeStyles({ } }); -const Header: React.FC = ({ navigate, userImage }) => { +const Header: React.FC = ({ navigate }) => { const classes = useStyles(); + const { user } = useAuth(); const handleHome = (): void => { navigate('feed'); @@ -62,8 +63,8 @@ const Header: React.FC = ({ navigate, userImage }) => { { - userImage?.match(/\.(jpeg|jpg|gif|png)$/) - ? + user?.avatarUrl?.match(/\.(jpeg|jpg|gif|png)$/) + ? : } diff --git a/src/index.tsx b/src/index.tsx index f9114c3..a82a28b 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -40,7 +40,7 @@ const useStyles = makeStyles({ const App: React.FC = () => { const [page, setPage] = useState({ prefix: 'feed', id: '' }); const classes = useStyles(); - const user = { _id: '', avatarUrl: '' }; + const { user } = useAuth(); const navigate = (prefix: string, id?: string): void => { if (prefix === 'profile' && !id && !user) { @@ -59,7 +59,7 @@ const App: React.FC = () => { return ( -
+
{ page.prefix === 'profile' && ( { ); }; -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( , document.getElementById('root')); -- cgit v1.2.3 From 1499c0126d1a7a2377b0267b761479100c636ee9 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Tue, 30 Jun 2020 00:41:09 +0300 Subject: feat!: create useNavigate hook --- src/components/Feed/Feed.tsx | 5 +-- src/components/Header/Header.tsx | 10 ++--- src/components/Header/SearchBar.tsx | 9 ++--- src/components/PollCard/PollCard.tsx | 5 +-- src/components/UserStrip/UserStrip.tsx | 16 +++----- src/hooks/useNavigate.tsx | 42 ++++++++++++++++++++ src/index.tsx | 71 ++++++++-------------------------- src/pages/FeedPage/FeedPage.tsx | 8 +--- src/pages/FeedPage/PollSubmission.tsx | 2 +- src/pages/Page.tsx | 31 +++++++++++++++ src/pages/ProfilePage/ProfilePage.tsx | 14 ++++--- src/types.d.ts | 4 -- 12 files changed, 117 insertions(+), 100 deletions(-) create mode 100644 src/hooks/useNavigate.tsx create mode 100644 src/pages/Page.tsx (limited to 'src') 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 = ({ polls, navigate }) => { +const Feed: React.FC = ({ polls }) => { const classes = useStyles(); return (
- {polls.map(poll => )} + {polls.map(poll => )}
); }; diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 49f427f..546ecc3 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -10,13 +10,10 @@ 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 { - navigate: (prefix: string) => void; -} - const useStyles = makeStyles({ root: { display: 'flex', @@ -33,9 +30,10 @@ const useStyles = makeStyles({ } }); -const Header: React.FC = ({ navigate }) => { +const Header: React.FC = () => { const classes = useStyles(); const { user } = useAuth(); + const { navigate } = useNavigate(); const handleHome = (): void => { navigate('feed'); @@ -53,7 +51,7 @@ const Header: React.FC = ({ navigate }) => { Which - +
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 = ({ navigate }) => { +const SearchBar: React.FC = () => { const [results, setResults] = useState([]); const [query, setQuery] = useState(''); const [debouncedQuery, setDebouncedQuery] = useState(query); + const { navigate } = useNavigate(); const classes = useStyles(); useEffect(() => { @@ -79,7 +78,7 @@ const SearchBar: React.FC = ({ navigate }) => { results.map((result, index) => (
- + {(index < results.length - 1) && }
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 = ({ initialPoll, navigate }) => { +const PollCard: React.FC = ({ initialPoll }) => { const [poll, setPoll] = useState(initialPoll); const classes = useStyles(); const { author, contents: { left, right }, vote } = poll; @@ -87,7 +86,7 @@ const PollCard: React.FC = ({ initialPoll, navigate }) => { return ( - +
void; info?: string | JSX.Element } @@ -31,13 +28,10 @@ const useStyles = makeStyles(theme => ({ })); -const UserStrip: React.FC = ({ user, info, navigate }) => { +const UserStrip: React.FC = ({ 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/useNavigate.tsx b/src/hooks/useNavigate.tsx new file mode 100644 index 0000000..0650f55 --- /dev/null +++ b/src/hooks/useNavigate.tsx @@ -0,0 +1,42 @@ +import React, { useState, useContext, createContext } from 'react'; +import { User } from 'which-types'; + +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({ + page: landingPage, + setPage: () => {}, + navigate: () => {} +}); + +const useProvideNavigation = () => { + const [page, setPage] = useState(landingPage); + + const navigate = (prefix: string, id?: string): void => { + setPage({ prefix, id }); + }; + + return { page, setPage, navigate }; +}; + +export const NavigationProvider: React.FC = ({ children }) => { + const navigation = useProvideNavigation(); + const { Provider } = context; + return {children}; +}; + +export const useNavigate = () => { + return useContext(context); +} + diff --git a/src/index.tsx b/src/index.tsx index a82a28b..180f80c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,23 +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 { useAuth, AuthProvider } from './hooks/useAuth'; +import Page from './pages/Page'; +import { AuthProvider } from './hooks/useAuth'; +import { NavigationProvider } from './hooks/useNavigate'; const theme = createMuiTheme({ @@ -29,52 +21,21 @@ const theme = createMuiTheme({ } }); -const useStyles = makeStyles({ - root: { - width: theme.spacing(75), - marginTop: theme.spacing(15), - margin: '0 auto' - } -}); const App: React.FC = () => { - const [page, setPage] = useState({ prefix: 'feed', id: '' }); - const classes = useStyles(); - const { user } = useAuth(); - - const navigate = (prefix: string, id?: string): void => { - if (prefix === 'profile' && !id && !user) { - setPage({ - prefix: 'auth', - id: '' - }); - } else { - setPage({ - prefix, - id: (id || user?._id || '') - }); - } - }; - return ( - - -
-
- { page.prefix === 'profile' && ( - - ) } - { page.prefix === 'feed' && } - { page.prefix === 'auth' && } -
- - - + + + + +
+ + + + + ); }; -ReactDOM.render( , document.getElementById('root')); +ReactDOM.render(, document.getElementById('root')); diff --git a/src/pages/FeedPage/FeedPage.tsx b/src/pages/FeedPage/FeedPage.tsx index 6561991..87a56ec 100644 --- a/src/pages/FeedPage/FeedPage.tsx +++ b/src/pages/FeedPage/FeedPage.tsx @@ -7,11 +7,7 @@ import PollSubmission from './PollSubmission'; import { useAuth } from '../../hooks/useAuth'; -interface PropTypes { - navigate: (prefix: string, id: string) => void; -} - -const FeedPage: React.FC = ({ navigate }) => { +const FeedPage: React.FC = () => { const [polls, setPolls] = useState([]); const { isAuthenticated } = useAuth(); @@ -30,7 +26,7 @@ const FeedPage: React.FC = ({ navigate }) => { return ( <> {isAuthenticated() && } - + ); }; diff --git a/src/pages/FeedPage/PollSubmission.tsx b/src/pages/FeedPage/PollSubmission.tsx index 4e06254..42612f0 100644 --- a/src/pages/FeedPage/PollSubmission.tsx +++ b/src/pages/FeedPage/PollSubmission.tsx @@ -60,7 +60,7 @@ const PollSubmission: React.FC = ({ addPoll }) => { - {user && {}} />} + {user && }
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 ( +
+ { page.prefix === 'profile' && } + { page.prefix === 'feed' && } + { page.prefix === 'auth' && } +
+ ); +}; + + +export default Page; + diff --git a/src/pages/ProfilePage/ProfilePage.tsx b/src/pages/ProfilePage/ProfilePage.tsx index ad2da46..808d43a 100644 --- a/src/pages/ProfilePage/ProfilePage.tsx +++ b/src/pages/ProfilePage/ProfilePage.tsx @@ -4,16 +4,18 @@ 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 { - navigate: (prefix: string, id: string) => void; - id: string; -} -const ProfilePage: React.FC = ({ id, navigate }) => { +const ProfilePage: React.FC = () => { const [userInfo, setUserInfo] = useState(); const [polls, setPolls] = useState([]); const [totalVotes, setTotalVotes] = useState(0); + const { page } = useNavigate(); + const { user } = useAuth(); + + const id = page?.id || user?._id; useEffect(() => { get(`/users/${id}`).then(response => { @@ -41,7 +43,7 @@ const ProfilePage: React.FC = ({ id, navigate }) => { savedPolls={polls.length} totalVotes={totalVotes} /> - + ); }; 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; -} -- cgit v1.2.3 From 5ccb1ec0be71ed4efb22b4942d70d9132415f69e Mon Sep 17 00:00:00 2001 From: eug-vs Date: Tue, 30 Jun 2020 00:43:48 +0300 Subject: style: fix some eslint errors --- src/components/UserStrip/UserStrip.tsx | 2 +- src/hooks/useAuth.tsx | 12 ++++++++---- src/hooks/useNavigate.tsx | 3 +-- src/pages/FeedPage/FeedPage.tsx | 2 +- src/pages/FeedPage/PollSubmission.tsx | 2 +- src/pages/FeedPage/PollSubmissionImage.tsx | 2 +- src/pages/ProfilePage/ProfilePage.tsx | 4 ++-- 7 files changed, 15 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/components/UserStrip/UserStrip.tsx b/src/components/UserStrip/UserStrip.tsx index bbd595e..3ac47b3 100644 --- a/src/components/UserStrip/UserStrip.tsx +++ b/src/components/UserStrip/UserStrip.tsx @@ -30,7 +30,7 @@ const useStyles = makeStyles(theme => ({ const UserStrip: React.FC = ({ user, info }) => { const classes = useStyles(); - const { navigate } = useNavigate(); + const { navigate } = useNavigate(); const { username, avatarUrl, verified } = user; const handleNavigate = () => { diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx index 4f76593..00d0c7c 100644 --- a/src/hooks/useAuth.tsx +++ b/src/hooks/useAuth.tsx @@ -1,4 +1,6 @@ -import React, { useState, useEffect, useContext, createContext } from 'react'; +import React, { + useState, useEffect, useContext, createContext +} from 'react'; import { User } from 'which-types'; import { post, get } from '../requests'; @@ -60,16 +62,18 @@ const useProvideAuth = () => { } }, []); - return { user, setUser, login, logout, isAuthenticated }; + return { + user, setUser, login, logout, isAuthenticated + }; }; export const AuthProvider: React.FC = ({ children }) => { const auth = useProvideAuth(); const { Provider } = authContext; - return {children} + return {children}; }; export const useAuth = () => { return useContext(authContext); -} +}; diff --git a/src/hooks/useNavigate.tsx b/src/hooks/useNavigate.tsx index 0650f55..9513f13 100644 --- a/src/hooks/useNavigate.tsx +++ b/src/hooks/useNavigate.tsx @@ -1,5 +1,4 @@ import React, { useState, useContext, createContext } from 'react'; -import { User } from 'which-types'; export interface Page { prefix: string; @@ -38,5 +37,5 @@ export const NavigationProvider: React.FC = ({ children }) => { export const useNavigate = () => { return useContext(context); -} +}; diff --git a/src/pages/FeedPage/FeedPage.tsx b/src/pages/FeedPage/FeedPage.tsx index 87a56ec..d29103a 100644 --- a/src/pages/FeedPage/FeedPage.tsx +++ b/src/pages/FeedPage/FeedPage.tsx @@ -1,5 +1,5 @@ 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'; diff --git a/src/pages/FeedPage/PollSubmission.tsx b/src/pages/FeedPage/PollSubmission.tsx index 42612f0..18f029c 100644 --- a/src/pages/FeedPage/PollSubmission.tsx +++ b/src/pages/FeedPage/PollSubmission.tsx @@ -7,7 +7,7 @@ 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'; 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 = ({ url, setUrl }) => { if (!isModalOpen) { if (url) setUrl(''); else setIsModalOpen(!isModalOpen); - }; + } }; const handleMouseEnter = (): void => { diff --git a/src/pages/ProfilePage/ProfilePage.tsx b/src/pages/ProfilePage/ProfilePage.tsx index 808d43a..d354a45 100644 --- a/src/pages/ProfilePage/ProfilePage.tsx +++ b/src/pages/ProfilePage/ProfilePage.tsx @@ -4,8 +4,8 @@ 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'; +import { useAuth } from '../../hooks/useAuth'; +import { useNavigate } from '../../hooks/useNavigate'; const ProfilePage: React.FC = () => { -- cgit v1.2.3 From b31ed66aafbe1d5dbe70d0cdfd70864204510d81 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Tue, 30 Jun 2020 01:27:39 +0300 Subject: fix: re-implement navigation logic --- src/components/Header/Header.tsx | 3 ++- src/hooks/useAuth.tsx | 2 -- src/pages/AuthPage/SignInForm.tsx | 5 ++++- src/pages/AuthPage/SignUpForm.tsx | 8 +++++--- src/pages/ProfilePage/MoreMenu.tsx | 9 ++++++++- src/pages/ProfilePage/ProfilePage.tsx | 36 +++++++++++++++++------------------ 6 files changed, 36 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 546ecc3..72e40f8 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -40,7 +40,8 @@ const Header: React.FC = () => { }; const handleProfile = (): void => { - navigate('profile'); + if (user) navigate('profile'); + else navigate('auth'); }; const handleNotifications = (): void => {}; diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx index 00d0c7c..de64c46 100644 --- a/src/hooks/useAuth.tsx +++ b/src/hooks/useAuth.tsx @@ -33,7 +33,6 @@ const useProvideAuth = () => { 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'); @@ -45,7 +44,6 @@ const useProvideAuth = () => { setUser(null); localStorage.removeItem('userId'); localStorage.removeItem('token'); - // navigate('auth'); }; const isAuthenticated = () => Boolean(user); diff --git a/src/pages/AuthPage/SignInForm.tsx b/src/pages/AuthPage/SignInForm.tsx index 662a312..e68483b 100644 --- a/src/pages/AuthPage/SignInForm.tsx +++ b/src/pages/AuthPage/SignInForm.tsx @@ -7,6 +7,7 @@ import { Switch } from '@material-ui/core'; import { useAuth } from '../../hooks/useAuth'; +import { useNavigate } from '../../hooks/useNavigate'; const useStyles = makeStyles(theme => ({ root: { @@ -32,6 +33,7 @@ const SignInForm: React.FC = () => { const nameRef = useRef(); const passwordRef = useRef(); const { login } = useAuth(); + const { navigate } = useNavigate(); const handleCheck = () => { setRemember(!remember); @@ -42,7 +44,8 @@ const SignInForm: React.FC = () => { const password = passwordRef.current?.value; if (name && password) { login(name, password, remember).then(success => { - if (!success) setError(true); + if (success) navigate('profile'); + else setError(true); }); } }; diff --git a/src/pages/AuthPage/SignUpForm.tsx b/src/pages/AuthPage/SignUpForm.tsx index af7a0f8..1dacd45 100644 --- a/src/pages/AuthPage/SignUpForm.tsx +++ b/src/pages/AuthPage/SignUpForm.tsx @@ -4,6 +4,7 @@ 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'; const useStyles = makeStyles(theme => ({ @@ -30,15 +31,16 @@ const SignUpForm: React.FC = () => { const emailRef = useRef(); const passwordRef = useRef(); 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/ProfilePage/MoreMenu.tsx b/src/pages/ProfilePage/MoreMenu.tsx index 7c17f1e..4e681f5 100644 --- a/src/pages/ProfilePage/MoreMenu.tsx +++ b/src/pages/ProfilePage/MoreMenu.tsx @@ -5,6 +5,7 @@ import MenuItem from '@material-ui/core/MenuItem'; import MoreHorizIcon from '@material-ui/icons/MoreHoriz'; import { makeStyles } from '@material-ui/core'; import { useAuth } from '../../hooks/useAuth'; +import { useNavigate } from '../../hooks/useNavigate'; const ITEM_HEIGHT = 48; @@ -20,6 +21,7 @@ const MoreMenu: React.FC = () => { const classes = useStyles(); const [anchorEl, setAnchorEl] = React.useState(null); const { logout } = useAuth(); + const { navigate } = useNavigate(); const open = Boolean(anchorEl); @@ -27,6 +29,11 @@ const MoreMenu: React.FC = () => { setAnchorEl(event.currentTarget); }; + const handleLogout = () => { + logout(); + navigate('auth'); + }; + const handleClose = () => { setAnchorEl(null); }; @@ -55,7 +62,7 @@ const MoreMenu: React.FC = () => { } }} > - Log out + Log out
diff --git a/src/pages/ProfilePage/ProfilePage.tsx b/src/pages/ProfilePage/ProfilePage.tsx index d354a45..ca39746 100644 --- a/src/pages/ProfilePage/ProfilePage.tsx +++ b/src/pages/ProfilePage/ProfilePage.tsx @@ -12,28 +12,26 @@ const ProfilePage: React.FC = () => { const [userInfo, setUserInfo] = useState(); const [polls, setPolls] = useState([]); const [totalVotes, setTotalVotes] = useState(0); - const { page } = useNavigate(); + const { page, navigate } = useNavigate(); const { user } = useAuth(); - const id = page?.id || user?._id; - - 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 ( <> -- cgit v1.2.3 From e170d04d5d2c8c86d2683f3accb4feb2d94c881a Mon Sep 17 00:00:00 2001 From: eug-vs Date: Tue, 30 Jun 2020 01:34:51 +0300 Subject: style: fix linting errors --- src/hooks/useAuth.tsx | 4 ++-- src/hooks/useNavigate.tsx | 4 ++-- src/pages/ProfilePage/ProfilePage.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx index de64c46..55e142c 100644 --- a/src/hooks/useAuth.tsx +++ b/src/hooks/useAuth.tsx @@ -24,7 +24,7 @@ const authContext = createContext({ const useProvideAuth = () => { const [user, setUser] = useState(null); - const login = (username: string, password: string, remember = true): Promise => { + const login: ContextType['login'] = (username, password, remember = true) => { return post('/authentication', { strategy: 'local', username, @@ -71,7 +71,7 @@ export const AuthProvider: React.FC = ({ children }) => { return {children}; }; -export const useAuth = () => { +export const useAuth = (): ContextType => { return useContext(authContext); }; diff --git a/src/hooks/useNavigate.tsx b/src/hooks/useNavigate.tsx index 9513f13..befc529 100644 --- a/src/hooks/useNavigate.tsx +++ b/src/hooks/useNavigate.tsx @@ -22,7 +22,7 @@ const context = createContext({ const useProvideNavigation = () => { const [page, setPage] = useState(landingPage); - const navigate = (prefix: string, id?: string): void => { + const navigate: ContextType['navigate'] = (prefix, id?) => { setPage({ prefix, id }); }; @@ -35,7 +35,7 @@ export const NavigationProvider: React.FC = ({ children }) => { return {children}; }; -export const useNavigate = () => { +export const useNavigate = (): ContextType => { return useContext(context); }; diff --git a/src/pages/ProfilePage/ProfilePage.tsx b/src/pages/ProfilePage/ProfilePage.tsx index ca39746..2c18466 100644 --- a/src/pages/ProfilePage/ProfilePage.tsx +++ b/src/pages/ProfilePage/ProfilePage.tsx @@ -16,7 +16,7 @@ const ProfilePage: React.FC = () => { const { user } = useAuth(); useEffect(() => { - const id = page?.id || user?._id + const id = page?.id || user?._id; if (id) { get(`/users/${id}`).then(response => { setUserInfo(response.data); -- cgit v1.2.3