From b6f9dbc3cbb21447fdeb22420b005da37de2af8e Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sun, 9 Aug 2020 19:51:32 +0300 Subject: feat: use SWR in profile page --- src/hooks/APIClient.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/hooks/APIClient.ts (limited to 'src/hooks') diff --git a/src/hooks/APIClient.ts b/src/hooks/APIClient.ts new file mode 100644 index 0000000..fa23a21 --- /dev/null +++ b/src/hooks/APIClient.ts @@ -0,0 +1,17 @@ +import useSWR from 'swr'; +import { get } from '../requests'; + + +const fetcher = (endpoint: string) => get(endpoint).then(response => response.data); + + +export const useUser = (username: string) => { + return useSWR( + `/users?username=${username}`, + (url: string) => get(url).then(response => response.data[0]) + ); +}; + +export const useProfile = (id: string) => { + return useSWR(id && `/profiles/${id}`, fetcher, { initialData: [] }); +}; -- cgit v1.2.3 From 359ec6a68ea92b3d1eecf020742157eb3be90b9f Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sun, 9 Aug 2020 21:17:33 +0300 Subject: feat: add useFeed hook --- src/hooks/APIClient.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/hooks') diff --git a/src/hooks/APIClient.ts b/src/hooks/APIClient.ts index fa23a21..ce11134 100644 --- a/src/hooks/APIClient.ts +++ b/src/hooks/APIClient.ts @@ -4,6 +4,10 @@ import { get } from '../requests'; const fetcher = (endpoint: string) => get(endpoint).then(response => response.data); +const arrayOptions = { + initialData: [], + revalidateOnMount: true +}; export const useUser = (username: string) => { return useSWR( @@ -13,5 +17,9 @@ export const useUser = (username: string) => { }; export const useProfile = (id: string) => { - return useSWR(id && `/profiles/${id}`, fetcher, { initialData: [] }); + return useSWR(id && `/profiles/${id}`, fetcher, arrayOptions); +}; + +export const useFeed = () => { + return useSWR(`/feed`, fetcher, arrayOptions); }; -- cgit v1.2.3 From fd6e663a1bcc43cfc49bda99ccbfab380489324b Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 10 Aug 2020 00:02:24 +0300 Subject: feat!: add useLocalStorage hook --- src/hooks/APIClient.ts | 6 ++-- src/hooks/useAuth.tsx | 65 ++++++++++++++++++++------------------------ src/hooks/useLocalStorage.ts | 16 +++++++++++ 3 files changed, 48 insertions(+), 39 deletions(-) create mode 100644 src/hooks/useLocalStorage.ts (limited to 'src/hooks') 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; logout: () => void; - isAuthenticated: () => boolean; + isAuthenticated: boolean; } const authContext = createContext({ user: null, - setUser: () => {}, login: async () => false, logout: () => {}, - isAuthenticated: () => false + isAuthenticated: false }); const useProvideAuth = () => { - const [user, setUser] = useState(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(() => 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]; +}; -- cgit v1.2.3 From a5c7950b65652d105c8eff22d14aeeacade6d31f Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 10 Aug 2020 11:32:13 +0300 Subject: feat: useSWR for feedbacks --- src/hooks/APIClient.ts | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/hooks') diff --git a/src/hooks/APIClient.ts b/src/hooks/APIClient.ts index 7f7d170..59bf4fc 100644 --- a/src/hooks/APIClient.ts +++ b/src/hooks/APIClient.ts @@ -23,3 +23,7 @@ export const useProfile = (id: string) => { export const useFeed = () => { return useSWR('/feed', fetcher, arrayOptions); }; + +export const useFeedback = () => { + return useSWR('/feedback', fetcher, arrayOptions); +}; -- cgit v1.2.3 From a8424edaea142f159022506dc8c8799718469d30 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 10 Aug 2020 12:00:01 +0300 Subject: feat: do not revalidate Feed on focus --- src/hooks/APIClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/hooks') diff --git a/src/hooks/APIClient.ts b/src/hooks/APIClient.ts index 59bf4fc..2322af4 100644 --- a/src/hooks/APIClient.ts +++ b/src/hooks/APIClient.ts @@ -21,7 +21,7 @@ export const useProfile = (id: string) => { }; export const useFeed = () => { - return useSWR('/feed', fetcher, arrayOptions); + return useSWR('/feed', fetcher, { ...arrayOptions, revalidateOnFocus: false }); }; export const useFeedback = () => { -- cgit v1.2.3 From 78218c0f3427ad79de003ac59cffb99b08f0ae7d Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 10 Aug 2020 13:47:02 +0300 Subject: fix: resolve eslint errors --- src/hooks/APIClient.ts | 23 ++++++++++++++--------- src/hooks/useAuth.tsx | 4 ++-- 2 files changed, 16 insertions(+), 11 deletions(-) (limited to 'src/hooks') diff --git a/src/hooks/APIClient.ts b/src/hooks/APIClient.ts index 2322af4..9563bd6 100644 --- a/src/hooks/APIClient.ts +++ b/src/hooks/APIClient.ts @@ -1,7 +1,12 @@ -import useSWR from 'swr'; +import useSWR, { responseInterface } from 'swr'; +import { User, Poll, Feedback } from 'which-types'; import { get } from '../requests'; +interface Response extends responseInterface { + data: T; +} + const fetcher = (endpoint: string) => get(endpoint).then(response => response.data); const arrayOptions = { @@ -9,21 +14,21 @@ const arrayOptions = { revalidateOnMount: true }; -export const useUser = (username: string | null) => { +export const useUser = (username: string | null): Response => { return useSWR( username && `/users?username=${username}`, (url: string) => get(url).then(response => response.data[0]) - ); + ) as Response; }; -export const useProfile = (id: string) => { - return useSWR(id && `/profiles/${id}`, fetcher, arrayOptions); +export const useProfile = (id: string): Response => { + return useSWR(id && `/profiles/${id}`, fetcher, arrayOptions) as Response; }; -export const useFeed = () => { - return useSWR('/feed', fetcher, { ...arrayOptions, revalidateOnFocus: false }); +export const useFeed = (): Response => { + return useSWR('/feed', fetcher, { ...arrayOptions, revalidateOnFocus: false }) as Response; }; -export const useFeedback = () => { - return useSWR('/feedback', fetcher, arrayOptions); +export const useFeedback = (): Response => { + return useSWR('/feedback', fetcher, arrayOptions) as Response; }; diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx index ed1e428..2f03a33 100644 --- a/src/hooks/useAuth.tsx +++ b/src/hooks/useAuth.tsx @@ -8,14 +8,14 @@ import useLocalStorage from './useLocalStorage'; interface ContextType { - user: User | null, + user: User | undefined, login: (username: string, password: string, remember?: boolean) => Promise; logout: () => void; isAuthenticated: boolean; } const authContext = createContext({ - user: null, + user: undefined, login: async () => false, logout: () => {}, isAuthenticated: false -- cgit v1.2.3