diff --git a/backend-manager-student/.eslintrc.js b/backend-manager-student/.eslintrc.js index 24369bc..edbec57 100644 --- a/backend-manager-student/.eslintrc.js +++ b/backend-manager-student/.eslintrc.js @@ -64,5 +64,8 @@ module.exports = { 'no-unused-expressions': 'off', 'eslint-disable-next-line implicit-arrow-linebreak': 'off', 'eslint-disable object-curly-newline': 'off', + 'brace-style': ['error', '1tbs', { allowSingleLine: true }], + 'object-curly-newline': 'off', + 'implicit-arrow-linebreak': 'off', }, }; diff --git a/frontend-manager-cms/src/App.js b/frontend-manager-cms/src/App.js index d73ac6e..281ca0a 100644 --- a/frontend-manager-cms/src/App.js +++ b/frontend-manager-cms/src/App.js @@ -1,12 +1,22 @@ //!LIBRARY -import React, { Suspense } from 'react'; +import React, { Suspense, useState } from 'react'; import { Route, Routes } from 'react-router-dom'; import { ToastContainer } from 'react-toastify'; +import axios from 'axios'; + +//! SHARE +import CONSTANTS from 'configs/constants'; +import { clearToken, setToken } from 'utils/auth'; +import HELPERS from 'utils/helper'; //! COMPONENT import Loading from 'components/Loading'; -//! PAGE +//! API +import API_ADMIN from 'api/api_admin'; + +//! PLUGIN +import { axiosIns } from 'plugins/axios/axios'; //! ROUTES import RouteDataMain from 'routers/index'; @@ -14,7 +24,55 @@ import RouteDataMain from 'routers/index'; //! IMPORT import { NotFound } from 'imports/notfound_import/index'; +//! CUSTOM HOOK +import Navigate from 'custom_hook/useNavigate/Navigate'; +import { useDispatch } from 'react-redux'; +import { Renew_Token_Cms_Initial } from 'redux/managers/authentication_slice/auth_thunk'; + function App() { + // Navigate + const { navigateChangePage } = Navigate(); + + //InitialState action + const dispatch = useDispatch(); + + // isRefreshing + const [isRefreshing, setIsRefreshing] = useState(false); + + axiosIns.interceptors.response.use( + (response) => response, + async (err) => { + const originalConfig = err?.config; + if ( + originalConfig && + originalConfig?.url !== API_ADMIN.LOGIN_ADMIN_CMS && + err.response && + err.response?.status === CONSTANTS.STATUS._UNAUTHORIZED && + !originalConfig._retry && + !isRefreshing + ) { + originalConfig._retry = CONSTANTS.DELETED_ENABLE; + originalConfig.headers = { ...originalConfig.headers }; + + setIsRefreshing(true); + + try { + dispatch(Renew_Token_Cms_Initial()); + + setIsRefreshing(false); + + return axiosIns(originalConfig); + } catch (_error) { + clearToken(CONSTANTS.AUTH_TOKEN); + + navigateChangePage('/login'); + + return Promise.reject(_error); + } + } + return Promise.reject(err); + }, + ); return ( }> diff --git a/frontend-manager-cms/src/api/api_user.js b/frontend-manager-cms/src/api/api_admin.js similarity index 100% rename from frontend-manager-cms/src/api/api_user.js rename to frontend-manager-cms/src/api/api_admin.js diff --git a/frontend-manager-cms/src/components/LoadingToRedirects/LoadingMain.jsx b/frontend-manager-cms/src/components/LoadingToRedirects/LoadingMain.jsx new file mode 100644 index 0000000..fc64315 --- /dev/null +++ b/frontend-manager-cms/src/components/LoadingToRedirects/LoadingMain.jsx @@ -0,0 +1,39 @@ +import React, { useEffect, useState } from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; +import NOTIFICATION from 'utils/notification'; + +const LoadingMain = ({ data }) => { + console.log(data, data); + const [count, setCount] = useState(2); + const navigate = useNavigate(); + const location = useLocation(); + + useEffect(() => { + if (data) { + // Check If Already login + const interval = setInterval(() => { + setCount((currentCount) => --currentCount); + }, 1000); + count === 0 && navigate('/', { replace: true, state: { from: location } }); + count === 0 && NOTIFICATION.notifyError('Please Logout😵'); + return () => clearInterval(interval); + } else { + // Check if not login + const interval = setInterval(() => { + setCount((currentCount) => --currentCount); + }, 1000); + count === 0 && navigate('/login', { replace: true, state: { from: location } }); + count === 0 && NOTIFICATION.notifyError('Please Login when you to the WebSite 😵'); + return () => clearInterval(interval); + } + }, [count]); + return ( + +
+

Loading.....

+
+
+ ); +}; + +export default LoadingMain; diff --git a/frontend-manager-cms/src/configs/constants.js b/frontend-manager-cms/src/configs/constants.js index deba90e..9ec36a9 100644 --- a/frontend-manager-cms/src/configs/constants.js +++ b/frontend-manager-cms/src/configs/constants.js @@ -79,5 +79,50 @@ const CONSTANTS = { OS_TYPE_HEADER: 'web', OS_VERSION_HEADER: '1.0', APP_VERSION_HEADER: '1.0', + ACCEPT_HEADER: 'application/json', + BEARER_HEADER: 'Bearer', + + /** + * @author Nguyễn Tiến Tài + * @created_at 15/03/2023 + * @updated_at 22/03/2023 + * @descriptionKey STATUS CODE + * @return {string} + */ + STATUS: { + // 2XX + _OK: 200, + //4X, + _BAD_REQUEST: 400, + _UNAUTHORIZED: 401, + _NOT_FOUND: 404, + }, + /** + * @author Nguyễn Tiến Tài + * @created_at 22/03/2023 + * @descriptionKey TIME OUT + * @return {number} + */ + TIME_OUT_AXIOS: 3000, + /** + * @author Nguyễn Tiến Tài + * @created_at 22/03/2023 + * @descriptionKey Type data + * @return {*} + */ + DATA: { + _NULL: 'null', + }, + /** + * @author Nguyễn Tiến Tài + * @created_at 22/03/2023 + * @descriptionKey Name redux thunk + * @return {string} + */ + REDUX_NAME: { + _AUTH: 'AUTH ADMIN', + _BOOK: 'BOOK ADMIN', + _MEDIA: 'MEDIA CLOUD', + }, }; export default CONSTANTS; diff --git a/frontend-manager-cms/src/context/global_context.js b/frontend-manager-cms/src/context/global_context.js index 74cb2fa..73bf4c7 100644 --- a/frontend-manager-cms/src/context/global_context.js +++ b/frontend-manager-cms/src/context/global_context.js @@ -26,37 +26,6 @@ export const store_library_school_contextUser = createContext(); export const useContextStudent = () => useContext(store_library_school_contextUser); export const DataProviderCMS = ({ children }) => { - //InitialState action - const dispatch = useDispatch(); - - // Get Token localStore - const token_access_localStorage = getToken(CONSTANTS.AUTH_TOKEN); - - useEffect(() => { - // Check Token LocalStorage - if (token_access_localStorage) { - // Return true or false - const decodedToken = HELPERS.isTokenExpired(token_access_localStorage); - - // Function new token - const newToken = () => { - //Token expired - if (decodedToken === CONSTANTS.DELETED_DISABLE) { - // Token expired, try to renew it - dispatch(Renew_Token_Cms_Initial()); - } - // Schedule next token renewal - setTimeout(() => { - //Start - newToken(); - }, CONSTANTS._4_MINUTES); - }; - - //Start - newToken(); - } - }, [token_access_localStorage, dispatch]); - //! Data // const data = { // profile_student_context: AuthStudent(), diff --git a/frontend-manager-cms/src/custom_hook/useNavigate/Navigate.jsx b/frontend-manager-cms/src/custom_hook/useNavigate/Navigate.jsx new file mode 100644 index 0000000..6198507 --- /dev/null +++ b/frontend-manager-cms/src/custom_hook/useNavigate/Navigate.jsx @@ -0,0 +1,16 @@ +//! LIBRARY +import { useNavigate } from 'react-router-dom'; + +const Navigate = () => { + //Create navigate + const navigate = useNavigate(); + + // Handle change page + const navigateChangePage = (link) => { + navigate(link); + }; + + return { navigateChangePage }; +}; + +export default Navigate; diff --git a/frontend-manager-cms/src/pages/Auth/Login.jsx b/frontend-manager-cms/src/pages/Auth/Login.jsx index 8eac867..8b7eea3 100644 --- a/frontend-manager-cms/src/pages/Auth/Login.jsx +++ b/frontend-manager-cms/src/pages/Auth/Login.jsx @@ -1,17 +1,45 @@ +//! LIBRARY +import React, { useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { useLocation } from 'react-router-dom'; + +//! IMPORT import { SCHOOL_LOGO } from 'imports/home_import'; -import React from 'react'; -import { useDispatch } from 'react-redux'; -import { Login_Cms_Initial } from 'redux/managers/authentication_slice/auth_thunk'; + +//! CUSTOM HOOK +import Navigate from 'custom_hook/useNavigate/Navigate'; + +//! UTILS import HELPERS from 'utils/helper'; +//! REDUX +import { Login_Cms_Initial } from 'redux/managers/authentication_slice/auth_thunk'; + const Login = () => { const dispatch = useDispatch(); + const { admin_auth } = useSelector((state) => state.admin_user); + + //Location + const location = useLocation(); + // Navigate + const { navigateChangePage } = Navigate(); + const handleLogin = (e) => { e.preventDefault(); const values = HELPERS.formDataGeneral(e.target); dispatch(Login_Cms_Initial(values)); }; + + useEffect(() => { + if (admin_auth) { + if (location.state?.from) { + navigateChangePage(location.state.from); + } else { + navigateChangePage('/'); + } + } + }, [admin_auth]); return (
diff --git a/frontend-manager-cms/src/plugins/axios/axios.jsx b/frontend-manager-cms/src/plugins/axios/axios.jsx new file mode 100644 index 0000000..8f8e7a5 --- /dev/null +++ b/frontend-manager-cms/src/plugins/axios/axios.jsx @@ -0,0 +1,36 @@ +//! LIBRARY +import axios from 'axios'; + +//! SHARE +import CONSTANTS from 'configs/constants'; +import { getToken } from 'utils/auth'; + +//! API +import API_STUDENT from 'api/api_admin'; + +export const axiosIns = axios.create({ + baseURL: '', + timeout: CONSTANTS.TIME_OUT_AXIOS, + withCredentials: CONSTANTS.DELETED_ENABLE, + headers: { + Accept: CONSTANTS.ACCEPT_HEADER, + }, +}); + +axiosIns.interceptors.request.use( + (config) => { + config.headers = config.headers ?? {}; + if (config.url !== API_STUDENT.LOGIN_STUDENT) { + const auth = getToken(CONSTANTS.AUTH_TOKEN) || CONSTANTS.DATA._NULL; + + if (auth) { + config.headers.authorization = `${CONSTANTS.BEARER_HEADER} ${auth}`; + } + } + + return config; + }, + (error) => { + return Promise.reject(error); + }, +); diff --git a/frontend-manager-cms/src/private/Admin_Private_Router.jsx b/frontend-manager-cms/src/private/Admin_Private_Router.jsx new file mode 100644 index 0000000..5a49471 --- /dev/null +++ b/frontend-manager-cms/src/private/Admin_Private_Router.jsx @@ -0,0 +1,16 @@ +//! LIBRARY +import CONSTANTS from 'configs/constants'; +import { Outlet } from 'react-router-dom'; + +//! UTILS +import { getToken } from 'utils/auth'; + +//! COMPONENT +import LoadingMain from 'components/LoadingToRedirects/LoadingMain'; + +function Admin_Private_Router({ element: Element, ...rest }) { + const token = getToken(CONSTANTS.AUTH_TOKEN); + return <>{!token ? : }; +} + +export default Admin_Private_Router; diff --git a/frontend-manager-cms/src/private/Admin_Private_Router_login.jsx b/frontend-manager-cms/src/private/Admin_Private_Router_login.jsx new file mode 100644 index 0000000..113d037 --- /dev/null +++ b/frontend-manager-cms/src/private/Admin_Private_Router_login.jsx @@ -0,0 +1,17 @@ +//! LIBRARY +import CONSTANTS from 'configs/constants'; +import { Outlet } from 'react-router-dom'; + +//! UTILS +import { getToken } from 'utils/auth'; + +//! COMPONENT +import LoadingMain from 'components/LoadingToRedirects/LoadingMain'; + +function Admin_Private_Router({ element: Element, ...rest }) { + // Take token + const token = getToken(CONSTANTS.AUTH_TOKEN); + return <>{token ? : }; +} + +export default Admin_Private_Router; diff --git a/frontend-manager-cms/src/private/auth/Login.js b/frontend-manager-cms/src/private/auth/Login.js deleted file mode 100644 index 9b8ace7..0000000 --- a/frontend-manager-cms/src/private/auth/Login.js +++ /dev/null @@ -1,15 +0,0 @@ -//!LIBRARY -import React from 'react'; - -//! COMPONENT -import TabLogin from './components/TabLogin'; - -const Login = () => { - return ( - - - - ); -}; - -export default Login; diff --git a/frontend-manager-cms/src/private/auth/components/TabLogin.js b/frontend-manager-cms/src/private/auth/components/TabLogin.js deleted file mode 100644 index 5d40ca6..0000000 --- a/frontend-manager-cms/src/private/auth/components/TabLogin.js +++ /dev/null @@ -1,38 +0,0 @@ -import axios from 'axios'; -import { useState } from 'react'; -const TabLogin = () => { - const [error, setError] = useState(false); - const [loading, setLoading] = useState(false); - const [username, setUsername] = useState(''); - const [password, setPassword] = useState(''); - const [user, setUser] = useState({}); - - const handleClick = async (e) => { - e.preventDefault(); - setLoading(true); - try { - const { data } = await axios.get('https://jsonplaceholder.typicode.com/users/1'); - setUser(data); - } catch { - setError(true); - } - setLoading(false); - }; - return ( -
- {user.name} -
- setUsername(e.target.value)} /> - setPassword(e.target.value)} /> - - - Something went wrong! - -
-
- ); -}; - -export default TabLogin; diff --git a/frontend-manager-cms/src/private/permission.js b/frontend-manager-cms/src/private/permission.js deleted file mode 100644 index 78e3eda..0000000 --- a/frontend-manager-cms/src/private/permission.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -const permission = () => { - return
permission
; -}; - -export default permission; diff --git a/frontend-manager-cms/src/redux/managers/authentication_slice/auth_thunk.js b/frontend-manager-cms/src/redux/managers/authentication_slice/auth_thunk.js index d551cad..7663f8f 100644 --- a/frontend-manager-cms/src/redux/managers/authentication_slice/auth_thunk.js +++ b/frontend-manager-cms/src/redux/managers/authentication_slice/auth_thunk.js @@ -6,12 +6,13 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; import NOTIFICATION from 'utils/notification'; //! API STUDENT -import API_ADMIN from 'api/api_user'; +import API_ADMIN from 'api/api_admin'; //! SHARE import HELPERS from 'utils/helper'; import CONSTANTS from 'configs/constants'; import { setToken } from 'utils/auth'; +import REQUEST from 'utils/request'; /** * @author Nguyễn Tiến Tài @@ -23,7 +24,7 @@ import { setToken } from 'utils/auth'; export const Login_Cms_Initial = createAsyncThunk('admin/cms/mssv', async ({ mssv, password }, { rejectWithValue }) => { try { //Call Api axios - const response = await axios.post( + const response = await REQUEST.post( `${API_ADMIN.LOGIN_ADMIN_CMS}`, { input: { @@ -68,7 +69,6 @@ export const Login_Cms_Initial = createAsyncThunk('admin/cms/mssv', async ({ mss message: errorData?.element?.result || errorData.message, status: errorData.status, }; - // Notification Error NOTIFICATION.notifyError(error_general.message); } @@ -89,7 +89,7 @@ export const Login_Cms_Initial = createAsyncThunk('admin/cms/mssv', async ({ mss export const Renew_Token_Cms_Initial = createAsyncThunk('student/new/token', async (_, { rejectWithValue }) => { try { //Call Api axios - const response = await axios.get(`${API_ADMIN.RENEW_TOKEN_CMS}`, { + const response = await REQUEST.get(`${API_ADMIN.RENEW_TOKEN_CMS}`, { headers: HELPERS.headerBrowser(), withCredentials: true, }); @@ -101,7 +101,7 @@ export const Renew_Token_Cms_Initial = createAsyncThunk('student/new/token', asy if (successData) { // return result data const result_data = HELPERS.takeDataResponse(successData); - + console.log(result_data.data.access_token, ''); // Save LocalStorage setToken(CONSTANTS.AUTH_TOKEN, result_data.data.access_token); diff --git a/frontend-manager-cms/src/redux/managers/author_slice/author_thunk.js b/frontend-manager-cms/src/redux/managers/author_slice/author_thunk.js index 32c5258..d7914ba 100644 --- a/frontend-manager-cms/src/redux/managers/author_slice/author_thunk.js +++ b/frontend-manager-cms/src/redux/managers/author_slice/author_thunk.js @@ -1,14 +1,12 @@ //! LIBRARY import { createAsyncThunk } from '@reduxjs/toolkit'; -import axios from 'axios'; - -//! NOTIFICATION //! API STUDENT -import API_ADMIN from 'api/api_user'; +import API_ADMIN from 'api/api_admin'; //! SHARE import HELPERS from 'utils/helper'; +import REQUEST from 'utils/request'; /** * @author Nguyễn Tiến Tài @@ -22,7 +20,7 @@ export const Get_Detail_Author_Cms_Initial = createAsyncThunk( async ({ id }, { rejectWithValue }) => { try { //Call Api axios - const response = await axios.get(`${API_ADMIN.GET_DETAIL_AUTHOR_CMS}/${id}`, { + const response = await REQUEST.get(`${API_ADMIN.GET_DETAIL_AUTHOR_CMS}/${id}`, { headers: HELPERS.headerBrowser(), withCredentials: true, }); @@ -57,7 +55,7 @@ export const Get_Detail_Author_Cms_Initial = createAsyncThunk( export const Get_All_Author_Cms_Initial = createAsyncThunk('admin/cms/author/all', async (_, { rejectWithValue }) => { try { //Call Api axios - const response = await axios.get(`${API_ADMIN.GET_ALL_AUTHOR_CMS}`, { + const response = await REQUEST.get(`${API_ADMIN.GET_ALL_AUTHOR_CMS}`, { headers: HELPERS.headerBrowser(), withCredentials: true, }); @@ -93,7 +91,7 @@ export const Delete_Author_Cms_Initial = createAsyncThunk( async ({ author_id }, { rejectWithValue }) => { try { //Call Api axios - const response = await axios.get( + const response = await REQUEST.get( `${API_ADMIN.GET_ALL_AUTHOR_CMS}`, { input: { diff --git a/frontend-manager-cms/src/redux/managers/book_slice/book_thunk.js b/frontend-manager-cms/src/redux/managers/book_slice/book_thunk.js index bd638fd..5a3fad5 100644 --- a/frontend-manager-cms/src/redux/managers/book_slice/book_thunk.js +++ b/frontend-manager-cms/src/redux/managers/book_slice/book_thunk.js @@ -5,11 +5,12 @@ import axios from 'axios'; //! NOTIFICATION //! API STUDENT -import API_ADMIN from 'api/api_user'; +import API_ADMIN from 'api/api_admin'; //! SHARE import HELPERS from 'utils/helper'; import NOTIFICATION from 'utils/notification'; +import REQUEST from 'utils/request'; /** * @author Nguyễn Tiến Tài @@ -21,7 +22,7 @@ import NOTIFICATION from 'utils/notification'; export const Get_All_Book_Cms_Initial = createAsyncThunk('admin/cms/book/all', async (_, { rejectWithValue }) => { try { //Call Api axios - const response = await axios.get(`${API_ADMIN.GET_ALL_BOOK_CMS}`, { + const response = await REQUEST.get(`${API_ADMIN.GET_ALL_BOOK_CMS}`, { headers: HELPERS.headerBrowser(), withCredentials: true, }); @@ -57,7 +58,7 @@ export const Delete_Book_Cms_Initial = createAsyncThunk( async ({ book_id }, { rejectWithValue }) => { try { //Call Api axios - const response = await axios.get( + const response = await REQUEST.get( `${API_ADMIN.DELETE_BOOK_CMS}`, { input: { @@ -106,7 +107,7 @@ export const Get_Detail_Book_Cms_Initial = createAsyncThunk( async ({ book_id }, { rejectWithValue }) => { try { //Call Api axios - const response = await axios.get(`${API_ADMIN.GET_DETAIL_BOOK_CMS}/${book_id}`, { + const response = await REQUEST.get(`${API_ADMIN.GET_DETAIL_BOOK_CMS}/${book_id}`, { headers: HELPERS.headerBrowser(), withCredentials: true, }); diff --git a/frontend-manager-cms/src/redux/store.js b/frontend-manager-cms/src/redux/store.js index 2c2f912..07e3b7a 100644 --- a/frontend-manager-cms/src/redux/store.js +++ b/frontend-manager-cms/src/redux/store.js @@ -17,7 +17,7 @@ const rootReducer = (state, action) => { let store; store = configureStore({ reducer: { - auth_user: AuthenticationSlice, + admin_user: AuthenticationSlice, book: BookSlice, author: AuthorSlice, reducer: rootReducer, diff --git a/frontend-manager-cms/src/routers/index.js b/frontend-manager-cms/src/routers/index.js index 7bb4003..3389a9f 100644 --- a/frontend-manager-cms/src/routers/index.js +++ b/frontend-manager-cms/src/routers/index.js @@ -7,11 +7,14 @@ import EditAuthor from 'pages/Author/EditAuthor'; import AddBook from 'pages/Book/AddBook'; import Book from 'pages/Book/AllBook'; import EditBook from 'pages/Book/EditBook'; +import Admin_Private_Router from 'private/Admin_Private_Router'; +import Admin_Private_Router_login from 'private/Admin_Private_Router_login'; import Login from '../pages/Auth/Login'; const RouteDataMain = [ { path: '/', + private: , main: ( <> @@ -20,6 +23,7 @@ const RouteDataMain = [ }, { path: '/book/all', + private: , main: ( <> } /> @@ -28,6 +32,7 @@ const RouteDataMain = [ }, { path: '/book/:id', + private: , main: ( <> } /> @@ -36,6 +41,7 @@ const RouteDataMain = [ }, { path: '/book/add', + private: , main: ( <> } /> @@ -44,6 +50,7 @@ const RouteDataMain = [ }, { path: '/user/all', + private: , main: ( <> } /> @@ -52,6 +59,7 @@ const RouteDataMain = [ }, { path: '/user/add', + private: , main: ( <> } /> @@ -60,6 +68,7 @@ const RouteDataMain = [ }, { path: '/author/all', + private: , main: ( <> } /> @@ -68,6 +77,7 @@ const RouteDataMain = [ }, { path: '/author/:id', + private: , main: ( <> } /> @@ -76,6 +86,7 @@ const RouteDataMain = [ }, { path: '/author/add', + private: , main: ( <> } /> @@ -84,6 +95,7 @@ const RouteDataMain = [ }, { path: '/login', + private: , main: ( <> diff --git a/frontend-manager-cms/src/utils/auth.js b/frontend-manager-cms/src/utils/auth.js index f4abd63..2e5b499 100644 --- a/frontend-manager-cms/src/utils/auth.js +++ b/frontend-manager-cms/src/utils/auth.js @@ -44,3 +44,14 @@ export function getToken() { export function setToken(key, value) { return localStorage.setItem(key, value); } + +/** + * @author Nguyễn Tiến Tài + * @created_at 02/03/2023 + * @descriptionKey Get Token localStorage + * @function getToken + * @return {String} + */ +export function clearToken() { + return localStorage.clear(CONSTANTS.AUTH_TOKEN); +} diff --git a/frontend-manager-cms/src/utils/helper.js b/frontend-manager-cms/src/utils/helper.js index cc2356e..351935c 100644 --- a/frontend-manager-cms/src/utils/helper.js +++ b/frontend-manager-cms/src/utils/helper.js @@ -23,9 +23,9 @@ const HELPERS = { 'X-APP-VERSION': CONSTANTS.APP_VERSION_HEADER, 'X-DEVICE-NAME': window.navigator.userAgent, }; - const token = getToken(); + const token = getToken(CONSTANTS.AUTH_TOKEN); if (token) { - headers.Authorization = token ? `Bearer ${token}` : null; + headers.authorization = token ? `Bearer ${token}` : null; } return headers; diff --git a/frontend-manager-cms/src/utils/request.js b/frontend-manager-cms/src/utils/request.js new file mode 100644 index 0000000..4149f8d --- /dev/null +++ b/frontend-manager-cms/src/utils/request.js @@ -0,0 +1,25 @@ +//! LIBRARY +import { axiosIns } from 'plugins/axios/axios'; + +const REQUEST = { + /** + * @author Nguyễn Tiến Tài + * @created_at 24/03/2023 + * @descriptionKey setup axios + * @function get,post + * @return {Object} + */ + + //!POST + post: async (url, body, header) => { + const response = await axiosIns.post(url, body, header); + return response; + }, + + //! GET + get: async (url, header) => { + const response = await axiosIns.get(url, header); + return response; + }, +}; +export default REQUEST; diff --git a/frontend-manager-student/package-lock.json b/frontend-manager-student/package-lock.json index e01424c..a1d7a1d 100644 --- a/frontend-manager-student/package-lock.json +++ b/frontend-manager-student/package-lock.json @@ -9,9 +9,11 @@ "version": "1.0.0", "dependencies": { "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", "@fortawesome/react-fontawesome": "^0.2.0", + "@mui/material": "^5.11.13", "@reduxjs/toolkit": "^1.7.2", "@stripe/stripe-js": "^1.29.0", "@testing-library/jest-dom": "^5.11.4", @@ -2379,6 +2381,41 @@ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" }, + "node_modules/@emotion/styled": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz", + "integrity": "sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.6", + "@emotion/is-prop-valid": "^1.2.0", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/styled/node_modules/@emotion/is-prop-valid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "dependencies": { + "@emotion/memoize": "^0.8.0" + } + }, + "node_modules/@emotion/styled/node_modules/@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + }, "node_modules/@emotion/unitless": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", @@ -3668,6 +3705,235 @@ "tslib": "^2.3.1" } }, + "node_modules/@mui/base": { + "version": "5.0.0-alpha.121", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.121.tgz", + "integrity": "sha512-8nJRY76UqlJV+q/Yzo0tgGfPWEOa+4N9rjO81fMmcJqP0I6m54hLDXsjvMg4tvelY5eKHXUK6Tb7en+GHfTqZA==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@emotion/is-prop-valid": "^1.2.0", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.13", + "@popperjs/core": "^2.11.6", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/base/node_modules/@emotion/is-prop-valid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "dependencies": { + "@emotion/memoize": "^0.8.0" + } + }, + "node_modules/@mui/base/node_modules/@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.11.13", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.13.tgz", + "integrity": "sha512-lx+GXBR9h/ApZsEP728tl0pyZyuajto+VnBgsoAzw1d5+CbmOo8ZWieKwVUGxZlPT1wMYNUYS5NtKzCli0xYjw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + } + }, + "node_modules/@mui/material": { + "version": "5.11.13", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.13.tgz", + "integrity": "sha512-2CnSj43F+159LbGmTLLQs5xbGYMiYlpTByQhP7c7cMX6opbScctBFE1PuyElpAmwW8Ag9ysfZH1d1MFAmJQkjg==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/base": "5.0.0-alpha.121", + "@mui/core-downloads-tracker": "^5.11.13", + "@mui/system": "^5.11.13", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.13", + "@types/react-transition-group": "^4.4.5", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "5.11.13", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.13.tgz", + "integrity": "sha512-PJnYNKzW5LIx3R+Zsp6WZVPs6w5sEKJ7mgLNnUXuYB1zo5aX71FVLtV7geyPXRcaN2tsoRNK7h444ED0t7cIjA==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/utils": "^5.11.13", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.11.tgz", + "integrity": "sha512-wV0UgW4lN5FkDBXefN8eTYeuE9sjyQdg5h94vtwZCUamGQEzmCOtir4AakgmbWMy0x8OLjdEUESn9wnf5J9MOg==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@emotion/cache": "^11.10.5", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.11.13", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.13.tgz", + "integrity": "sha512-OWP0Alp6C8ufnGm9+CZcl3d+OoRXL2PnrRT5ohaMLxvGL9OfNcL2t4JOjMmA0k1UAGd6E/Ygbu5lEPrZSDlvCg==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/private-theming": "^5.11.13", + "@mui/styled-engine": "^5.11.11", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.13", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.3.tgz", + "integrity": "sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.11.13", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.13.tgz", + "integrity": "sha512-5ltA58MM9euOuUcnvwFJqpLdEugc9XFsRR8Gt4zZNb31XzMfSKJPR4eumulyhsOTK1rWf7K4D63NKFPfX0AxqA==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@types/prop-types": "^15.7.5", + "@types/react-is": "^16.7.1 || ^17.0.0", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -4714,6 +4980,14 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-is": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", + "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-redux": { "version": "7.1.24", "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz", @@ -20740,6 +21014,34 @@ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" }, + "@emotion/styled": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz", + "integrity": "sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==", + "requires": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.6", + "@emotion/is-prop-valid": "^1.2.0", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0" + }, + "dependencies": { + "@emotion/is-prop-valid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "requires": { + "@emotion/memoize": "^0.8.0" + } + }, + "@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + } + } + }, "@emotion/unitless": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", @@ -21760,6 +22062,113 @@ "tslib": "^2.3.1" } }, + "@mui/base": { + "version": "5.0.0-alpha.121", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.121.tgz", + "integrity": "sha512-8nJRY76UqlJV+q/Yzo0tgGfPWEOa+4N9rjO81fMmcJqP0I6m54hLDXsjvMg4tvelY5eKHXUK6Tb7en+GHfTqZA==", + "requires": { + "@babel/runtime": "^7.21.0", + "@emotion/is-prop-valid": "^1.2.0", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.13", + "@popperjs/core": "^2.11.6", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "dependencies": { + "@emotion/is-prop-valid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "requires": { + "@emotion/memoize": "^0.8.0" + } + }, + "@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + } + } + }, + "@mui/core-downloads-tracker": { + "version": "5.11.13", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.13.tgz", + "integrity": "sha512-lx+GXBR9h/ApZsEP728tl0pyZyuajto+VnBgsoAzw1d5+CbmOo8ZWieKwVUGxZlPT1wMYNUYS5NtKzCli0xYjw==" + }, + "@mui/material": { + "version": "5.11.13", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.13.tgz", + "integrity": "sha512-2CnSj43F+159LbGmTLLQs5xbGYMiYlpTByQhP7c7cMX6opbScctBFE1PuyElpAmwW8Ag9ysfZH1d1MFAmJQkjg==", + "requires": { + "@babel/runtime": "^7.21.0", + "@mui/base": "5.0.0-alpha.121", + "@mui/core-downloads-tracker": "^5.11.13", + "@mui/system": "^5.11.13", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.13", + "@types/react-transition-group": "^4.4.5", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + } + }, + "@mui/private-theming": { + "version": "5.11.13", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.13.tgz", + "integrity": "sha512-PJnYNKzW5LIx3R+Zsp6WZVPs6w5sEKJ7mgLNnUXuYB1zo5aX71FVLtV7geyPXRcaN2tsoRNK7h444ED0t7cIjA==", + "requires": { + "@babel/runtime": "^7.21.0", + "@mui/utils": "^5.11.13", + "prop-types": "^15.8.1" + } + }, + "@mui/styled-engine": { + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.11.tgz", + "integrity": "sha512-wV0UgW4lN5FkDBXefN8eTYeuE9sjyQdg5h94vtwZCUamGQEzmCOtir4AakgmbWMy0x8OLjdEUESn9wnf5J9MOg==", + "requires": { + "@babel/runtime": "^7.21.0", + "@emotion/cache": "^11.10.5", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + } + }, + "@mui/system": { + "version": "5.11.13", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.13.tgz", + "integrity": "sha512-OWP0Alp6C8ufnGm9+CZcl3d+OoRXL2PnrRT5ohaMLxvGL9OfNcL2t4JOjMmA0k1UAGd6E/Ygbu5lEPrZSDlvCg==", + "requires": { + "@babel/runtime": "^7.21.0", + "@mui/private-theming": "^5.11.13", + "@mui/styled-engine": "^5.11.11", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.13", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + } + }, + "@mui/types": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.3.tgz", + "integrity": "sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==" + }, + "@mui/utils": { + "version": "5.11.13", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.13.tgz", + "integrity": "sha512-5ltA58MM9euOuUcnvwFJqpLdEugc9XFsRR8Gt4zZNb31XzMfSKJPR4eumulyhsOTK1rWf7K4D63NKFPfX0AxqA==", + "requires": { + "@babel/runtime": "^7.21.0", + "@types/prop-types": "^15.7.5", + "@types/react-is": "^16.7.1 || ^17.0.0", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + } + }, "@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -22509,6 +22918,14 @@ "csstype": "^3.0.2" } }, + "@types/react-is": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", + "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", + "requires": { + "@types/react": "*" + } + }, "@types/react-redux": { "version": "7.1.24", "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz", diff --git a/frontend-manager-student/package.json b/frontend-manager-student/package.json index b9d43a8..9216e9c 100644 --- a/frontend-manager-student/package.json +++ b/frontend-manager-student/package.json @@ -6,9 +6,11 @@ "private": true, "dependencies": { "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", "@fortawesome/react-fontawesome": "^0.2.0", + "@mui/material": "^5.11.13", "@reduxjs/toolkit": "^1.7.2", "@stripe/stripe-js": "^1.29.0", "@testing-library/jest-dom": "^5.11.4", diff --git a/frontend-manager-student/src/App.js b/frontend-manager-student/src/App.js index c2530d0..900e64a 100644 --- a/frontend-manager-student/src/App.js +++ b/frontend-manager-student/src/App.js @@ -76,7 +76,7 @@ function App() { return ( - }> + }> {RouteDataMain.map((item, key) => { diff --git a/frontend-manager-student/src/api/api_user.js b/frontend-manager-student/src/api/api_user.js index efa3233..fcdc543 100644 --- a/frontend-manager-student/src/api/api_user.js +++ b/frontend-manager-student/src/api/api_user.js @@ -69,5 +69,12 @@ const API_STUDENT = { * @descriptionKey API GET ALL BOOK */ RESET_FORGET_PASSWORD: '/student/v1/user/reset', + + /** + * @author Châu Gia Bảo + * @created_at 22/03/2023 + * @descriptionKey API GET ALL BOOK + */ + GET_ALL_BORROWED_BOOK: '/student/v1/user/reset', }; export default API_STUDENT; diff --git a/frontend-manager-student/src/imports/auth_import/index.js b/frontend-manager-student/src/imports/auth_import/index.js index c38c8ed..02f26d1 100644 --- a/frontend-manager-student/src/imports/auth_import/index.js +++ b/frontend-manager-student/src/imports/auth_import/index.js @@ -1,5 +1,5 @@ // Change Password -export { default as TabChangePassword } from 'pages/Auth/ChangePassword/component/TabChangePassword'; +export { default as TabChangePassword } from 'pages/Auth/ChangePassword/components/TabChangePassword'; // Login export { default as TabLogin } from 'pages/Auth/Login/components/TabLogin'; diff --git a/frontend-manager-student/src/pages/Auth/ChangePassword/component/TabChangePassword.jsx b/frontend-manager-student/src/pages/Auth/ChangePassword/components/TabChangePassword.jsx similarity index 100% rename from frontend-manager-student/src/pages/Auth/ChangePassword/component/TabChangePassword.jsx rename to frontend-manager-student/src/pages/Auth/ChangePassword/components/TabChangePassword.jsx diff --git a/frontend-manager-student/src/pages/Book/AllBook/components/TabAllBooks.jsx b/frontend-manager-student/src/pages/Book/AllBook/components/TabAllBooks.jsx index eb5766f..67fe944 100644 --- a/frontend-manager-student/src/pages/Book/AllBook/components/TabAllBooks.jsx +++ b/frontend-manager-student/src/pages/Book/AllBook/components/TabAllBooks.jsx @@ -7,7 +7,7 @@ import { Link } from 'react-router-dom'; import Section, { SectionBody } from 'components/Section'; import Filter from 'components/Filter'; -const TabAllBooks = ({ bookList }) => { +const TabAllBooks = ({ bookList, currentPage, totalBook, executeTime }) => { return (
@@ -18,7 +18,9 @@ const TabAllBooks = ({ bookList }) => {
-
Trang 1 trong 6151 kết quả (0.1093984 giây)
+
+ Trang {currentPage} trong {totalBook} kết quả ({executeTime} giây) +
Sắp xếp theo