From 13f332f8a5e88bde71071e940d2b42d1bf9d19cf Mon Sep 17 00:00:00 2001 From: Aji Kamaludin Date: Tue, 17 Aug 2021 20:43:36 +0700 Subject: [PATCH] fix context axios interception --- src/App.js | 1 - src/_nav.js | 6 ++++ src/api/index.js | 3 +- src/axiosSetup.js | 50 -------------------------- src/context/AppContext.js | 72 +++++++++++++++++++++++++++++++++++--- src/views/products/List.js | 2 +- 6 files changed, 76 insertions(+), 58 deletions(-) delete mode 100644 src/axiosSetup.js diff --git a/src/App.js b/src/App.js index 47ded45..86f1a5f 100644 --- a/src/App.js +++ b/src/App.js @@ -12,7 +12,6 @@ import { import "react-datepicker/dist/react-datepicker.css"; import "@fontsource/raleway/400.css" import "@fontsource/open-sans/700.css" -import "./axiosSetup" import { library } from '@fortawesome/fontawesome-svg-core' import { fas } from '@fortawesome/free-solid-svg-icons' import { AppProvider } from "./context/AppContext" diff --git a/src/_nav.js b/src/_nav.js index f37c79d..be5a87e 100644 --- a/src/_nav.js +++ b/src/_nav.js @@ -35,4 +35,10 @@ export const navs = [ icon: "list", role: "admin", }, + { + name: "pengguna", + to: "/users", + icon: "list", + role: "admin", + }, ] \ No newline at end of file diff --git a/src/api/index.js b/src/api/index.js index ac1349e..206de0c 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -1,6 +1,5 @@ import axios from "axios" -import useSWR from 'swr' -import "../axiosSetup" +import useSWR from "swr" import { useAuth } from "../context/AppContext" import { formatDate } from "../utils" diff --git a/src/axiosSetup.js b/src/axiosSetup.js deleted file mode 100644 index ac032cc..0000000 --- a/src/axiosSetup.js +++ /dev/null @@ -1,50 +0,0 @@ -import axios from 'axios' -import { API_URL } from './config' - -axios.defaults.baseURL = API_URL -const axiosApiInstance = axios.create(); - -const refreshAccessToken = (refreshToken) => { - return axios({ - method: "PUT", - url: '/authentications', - data: { refreshToken } - }).then(res => res.data) -} - -axios.interceptors.response.use( - (response) => { - return response - }, - async (error) => { - const { status, data: { message } } = error.response - if (status === 401 && message === 'Unauthenticated.') { - window.localStorage.clear() - window.location.reload() - return - } - - if(status === 401 && message === "Token maximum age exceeded") { - const originalRequest = error.config; - originalRequest._retry = true; - - const user = JSON.parse(window.localStorage.getItem('KASIRAJA_USER')) - const res = await refreshAccessToken(user.refreshToken); - - window.localStorage.setItem( - 'KASIRAJA_USER', - JSON.stringify({ - ...user, - accessToken: res.data.accessToken - }) - ) - axios.defaults.headers.common['Authorization'] = `Bearer ${res.data.accessToken}`; - return axiosApiInstance(originalRequest); - } - - if (status === 403) { - window.alert('Anda tidak mempunyai akses untuk aksi ini') - } - - throw error -}) diff --git a/src/context/AppContext.js b/src/context/AppContext.js index e18129d..d24da00 100644 --- a/src/context/AppContext.js +++ b/src/context/AppContext.js @@ -1,5 +1,28 @@ -import React, { useState, useMemo, useContext } from 'react' -import is from 'is_js' +import React, { useState, useMemo, useContext, useEffect } from "react" +import is from "is_js" +import axios from "axios" +import { API_URL } from "../config" + +// why im create this , maybe it cause +// im think this singlethon call for 401 token timeout so it only call from one instance +const axioInstance = axios.create() +axios.defaults.baseURL = API_URL + +const refreshAccessToken = (refreshToken) => { + return axios({ + method: "PUT", + url: '/authentications', + data: { refreshToken } + }).then(res => res.data) +} + +const logoutApi = (refreshToken) => { + return axios({ + method: "DELETE", + url: '/authentications', + data: { refreshToken } + }).then(res => res.data) +} const userManager = { set(val) { @@ -19,9 +42,47 @@ function AppProvider(props) { const [user, setUser] = useState(JSON.parse(userManager.get())) const value = useMemo( - () => ({ user, setUser }), - [user] + () => ({ + user, + setUser, + }), + [user, setUser] ) + + useEffect(() => { + axios.interceptors.response.use(res => res, + async (error) => { + const { status, data: { message } } = error.response + if (status === 401 && message === 'Unauthenticated.') { + window.localStorage.clear() + window.location.reload() + return + } + + if(status === 401 && message === "Token maximum age exceeded") { + const originalRequest = error.config; + originalRequest._retry = true; + + const { refreshToken } = user + const res = await refreshAccessToken(refreshToken); + const newUser = { ...user, accessToken: res.data.accessToken } + + setUser(newUser) + userManager.set(JSON.stringify(newUser)) + + axios.defaults.headers.common['Authorization'] = `Bearer ${res.data.accessToken}`; + return axioInstance(originalRequest); + } + + if (status === 403) { + window.alert('Anda tidak mempunyai akses untuk aksi ini') + } + + throw error + }) + }, [user]) + + return } @@ -38,11 +99,14 @@ function useAuth() { const isLoggedIn = () => { return is.not.empty(user) && is.not.null(user) } + const persistUser = user => { userManager.set(JSON.stringify(user)) setUser(user) } + const logout = () => { + logoutApi(user.refreshToken) userManager.remove() setUser(null) } diff --git a/src/views/products/List.js b/src/views/products/List.js index cf0bf11..e25cea7 100644 --- a/src/views/products/List.js +++ b/src/views/products/List.js @@ -43,7 +43,7 @@ export default function List({ history }) { {data ? ( - +
nama