aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreug-vs <eug-vs@keemail.me>2020-08-10 00:02:24 +0300
committereug-vs <eug-vs@keemail.me>2020-08-10 00:02:24 +0300
commitfd6e663a1bcc43cfc49bda99ccbfab380489324b (patch)
treeea25ea2c81db0f64e10123dbadd73f361b904da2
parent359ec6a68ea92b3d1eecf020742157eb3be90b9f (diff)
downloadwhich-ui-fd6e663a1bcc43cfc49bda99ccbfab380489324b.tar.gz
feat!: add useLocalStorage hook
-rw-r--r--src/components/Feed/Feed.tsx3
-rw-r--r--src/components/PollCard/PollCard.tsx2
-rw-r--r--src/hooks/APIClient.ts6
-rw-r--r--src/hooks/useAuth.tsx65
-rw-r--r--src/hooks/useLocalStorage.ts16
-rw-r--r--src/pages/FeedPage/FeedPage.tsx2
-rw-r--r--src/pages/HomePage/HomePage.tsx4
-rw-r--r--src/pages/Page.tsx12
-rw-r--r--src/pages/ProfilePage/ProfileInfo.tsx7
-rw-r--r--src/pages/ProfilePage/ProfilePage.tsx6
-rw-r--r--src/requests.ts2
11 files changed, 67 insertions, 58 deletions
diff --git a/src/components/Feed/Feed.tsx b/src/components/Feed/Feed.tsx
index b857cc0..5805e35 100644
--- a/src/components/Feed/Feed.tsx
+++ b/src/components/Feed/Feed.tsx
@@ -16,12 +16,11 @@ interface RenderPropTypes {
const Feed: React.FC<PropTypes> = ({ polls }) => {
-
const RenderItem: React.FC<RenderPropTypes> = ({ index, style, key }) => {
const poll = polls[index];
return (
// To re-render on list resize, add this info to key
- <div key={key + polls.length} style={style}>
+ <div key={key + polls.length} style={style}>
<PollCard initialPoll={poll} />
</div>
);
diff --git a/src/components/PollCard/PollCard.tsx b/src/components/PollCard/PollCard.tsx
index 98ae001..2378945 100644
--- a/src/components/PollCard/PollCard.tsx
+++ b/src/components/PollCard/PollCard.tsx
@@ -58,7 +58,7 @@ const PollCard: React.FC<PropTypes> = ({ initialPoll }) => {
const date: string = new Date(poll.createdAt).toLocaleString('default', DATE_FORMAT);
const handleVote = (which: Which) => {
- if (!isAuthenticated()) {
+ if (!isAuthenticated) {
enqueueSnackbar('Unauthorized users can not vote in polls', {
variant: 'error'
});
diff --git a/src/hooks/APIClient.ts b/src/hooks/APIClient.ts
index ce11134..7f7d170 100644
--- a/src/hooks/APIClient.ts
+++ b/src/hooks/APIClient.ts
@@ -9,9 +9,9 @@ const arrayOptions = {
revalidateOnMount: true
};
-export const useUser = (username: string) => {
+export const useUser = (username: string | null) => {
return useSWR(
- `/users?username=${username}`,
+ username && `/users?username=${username}`,
(url: string) => get(url).then(response => response.data[0])
);
};
@@ -21,5 +21,5 @@ export const useProfile = (id: string) => {
};
export const useFeed = () => {
- return useSWR(`/feed`, fetcher, arrayOptions);
+ return useSWR('/feed', fetcher, arrayOptions);
};
diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx
index 55e142c..ed1e428 100644
--- a/src/hooks/useAuth.tsx
+++ b/src/hooks/useAuth.tsx
@@ -1,67 +1,60 @@
import React, {
- useState, useEffect, useContext, createContext
+ useEffect, useCallback, useMemo, useContext, createContext
} from 'react';
import { User } from 'which-types';
-import { post, get } from '../requests';
+import { post } from '../requests';
+import { useUser } from './APIClient';
+import useLocalStorage from './useLocalStorage';
interface ContextType {
user: User | null,
- setUser: (user: User) => void;
login: (username: string, password: string, remember?: boolean) => Promise<boolean>;
logout: () => void;
- isAuthenticated: () => boolean;
+ isAuthenticated: boolean;
}
const authContext = createContext<ContextType>({
user: null,
- setUser: () => {},
login: async () => false,
logout: () => {},
- isAuthenticated: () => false
+ isAuthenticated: false
});
const useProvideAuth = () => {
- const [user, setUser] = useState<User | null>(null);
+ const [remember, setRemember] = useLocalStorage('remember');
+ const [username, setUsername] = useLocalStorage('username');
+ const [token, setToken] = useLocalStorage('token');
+ const { data: user } = useUser(username);
- const login: ContextType['login'] = (username, password, remember = true) => {
+ const isAuthenticated = useMemo(() => Boolean(username), [username]);
+
+ const logout = useCallback(() => {
+ setToken(null);
+ setUsername(null);
+ }, [setToken, setUsername]);
+
+ useEffect(() => {
+ // If should not remember, logout
+ if (!remember) logout();
+ }, [remember, logout]);
+
+
+ const login: ContextType['login'] = (name, password, shouldRemember = true) => {
return post('/authentication', {
strategy: 'local',
- username,
+ username: name,
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');
+ setToken(response.data.accessToken);
+ setUsername(name);
+ setRemember(shouldRemember ? 'true' : null);
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
+ user, login, logout, token, isAuthenticated
};
};
diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts
new file mode 100644
index 0000000..faf1411
--- /dev/null
+++ b/src/hooks/useLocalStorage.ts
@@ -0,0 +1,16 @@
+import { useState, useCallback } from 'react';
+
+type Value = string | null;
+type Setter = (value: Value) => void;
+
+export default (key: string): [Value, Setter] => {
+ const [state, setState] = useState<Value>(() => localStorage.getItem(key) || null);
+
+ const update: Setter = useCallback(value => {
+ if (value) localStorage.setItem(key, value);
+ else localStorage.removeItem(key);
+ setState(value);
+ }, [key]);
+
+ return [state, update];
+};
diff --git a/src/pages/FeedPage/FeedPage.tsx b/src/pages/FeedPage/FeedPage.tsx
index 8e7fb55..da0fb2a 100644
--- a/src/pages/FeedPage/FeedPage.tsx
+++ b/src/pages/FeedPage/FeedPage.tsx
@@ -17,7 +17,7 @@ const FeedPage: React.FC = () => {
return (
<Container maxWidth="sm" disableGutters>
- {isAuthenticated() && <PollSubmission addPoll={addPoll} />}
+ {isAuthenticated && <PollSubmission addPoll={addPoll} />}
<Feed polls={data} />
</Container>
);
diff --git a/src/pages/HomePage/HomePage.tsx b/src/pages/HomePage/HomePage.tsx
index 17e377a..b1dc506 100644
--- a/src/pages/HomePage/HomePage.tsx
+++ b/src/pages/HomePage/HomePage.tsx
@@ -92,7 +92,7 @@ const HomePage: React.FC = () => {
Here you can share your thougts about Which with us!
Note that you can ony leave feedback once per application version (there will be plenty of them later).
</p>
- {isAuthenticated() ? <ReviewForm /> : (
+ {isAuthenticated ? <ReviewForm /> : (
<>
<p> You must be authorized to leave feedback.</p>
<Button
@@ -142,7 +142,7 @@ const HomePage: React.FC = () => {
<Button variant="contained" color="primary" size="large" onClick={handleLetsGo}>
{'let\'s go!'}
</Button>
- {!isAuthenticated() && (
+ {!isAuthenticated && (
<Button
variant="outlined"
color="primary"
diff --git a/src/pages/Page.tsx b/src/pages/Page.tsx
index 49c941a..a77a98e 100644
--- a/src/pages/Page.tsx
+++ b/src/pages/Page.tsx
@@ -5,12 +5,12 @@ import { SnackbarProvider } from 'notistack';
import { Switch, Route } from 'react-router-dom';
import Loading from '../components/Loading/Loading';
-const ProfilePage = React.lazy(() => import( './ProfilePage/ProfilePage'));
-const FeedPage = React.lazy(() => import( './FeedPage/FeedPage'));
-const LoginPage = React.lazy(() => import( './LoginPage/LoginPage'));
-const RegistrationPage = React.lazy(() => import( './RegistrationPage/RegistrationPage'));
-const HomePage = React.lazy(() => import( './HomePage/HomePage'));
-const NotificationsPage = React.lazy(() => import( './NotificationsPage/NotificationsPage'));
+const ProfilePage = React.lazy(() => import('./ProfilePage/ProfilePage'));
+const FeedPage = React.lazy(() => import('./FeedPage/FeedPage'));
+const LoginPage = React.lazy(() => import('./LoginPage/LoginPage'));
+const RegistrationPage = React.lazy(() => import('./RegistrationPage/RegistrationPage'));
+const HomePage = React.lazy(() => import('./HomePage/HomePage'));
+const NotificationsPage = React.lazy(() => import('./NotificationsPage/NotificationsPage'));
const useStyles = makeStyles(theme => ({
diff --git a/src/pages/ProfilePage/ProfileInfo.tsx b/src/pages/ProfilePage/ProfileInfo.tsx
index 8b1447a..9eee4c1 100644
--- a/src/pages/ProfilePage/ProfileInfo.tsx
+++ b/src/pages/ProfilePage/ProfileInfo.tsx
@@ -86,7 +86,7 @@ const ProfileInfo: React.FC<PropTypes> = ({
}) => {
const classes = useStyles();
const [input, setInput] = useState(false);
- const { setUser } = useAuth();
+ const { user } = useAuth();
const dateSince = new Date(userInfo?.createdAt || '').toLocaleDateString();
const handleClick = () => {
@@ -94,10 +94,9 @@ const ProfileInfo: React.FC<PropTypes> = ({
};
const patchAvatar = (url: string) => {
- const id = localStorage.getItem('userId');
+ const id = user?._id;
patch(`/users/${id}`, { avatarUrl: url }).then(res => {
setUserInfo(res.data);
- setUser(res.data);
});
};
@@ -106,7 +105,7 @@ const ProfileInfo: React.FC<PropTypes> = ({
{
!userInfo
? <Skeleton animation="wave" variant="circle" width={150} height={150} className={classes.avatar} />
- : userInfo?._id === localStorage.getItem('userId')
+ : userInfo?._id === user?._id
? (
<div>
<MoreMenu />
diff --git a/src/pages/ProfilePage/ProfilePage.tsx b/src/pages/ProfilePage/ProfilePage.tsx
index 293b766..9e00784 100644
--- a/src/pages/ProfilePage/ProfilePage.tsx
+++ b/src/pages/ProfilePage/ProfilePage.tsx
@@ -21,7 +21,7 @@ const ProfilePage: React.FC = () => {
if (!username) {
if (user) history.push(`/profile/${user.username}`);
else history.push('/login');
- };
+ }
}, [username, history, user]);
@@ -31,7 +31,9 @@ const ProfilePage: React.FC = () => {
const { left, right } = current.contents;
return total + left.votes + right.votes;
}, 0
- ), [polls]);
+ ),
+ [polls]
+ );
return (
<Container maxWidth="sm" disableGutters>
diff --git a/src/requests.ts b/src/requests.ts
index e1f82b4..8ec8e3d 100644
--- a/src/requests.ts
+++ b/src/requests.ts
@@ -14,7 +14,7 @@ requests.interceptors.request.use(config => {
requests.interceptors.response.use(response => response, error => {
if (error.message === 'Request failed with status code 401' && localStorage.getItem('token')) {
- localStorage.setItem('shouldClear', 'true');
+ localStorage.removeItem('remember');
window.location.reload();
}
return Promise.reject(error);