diff --git a/.vscode/settings.json b/.vscode/settings.json index 525f77f..08e57d9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,5 +13,11 @@ "[sql]": { "editor.defaultFormatter": "adpyke.vscode-sql-formatter" }, - "cSpell.words": ["argothim", "MIDDLAWARE", "Middlawre", "mutilp"] + "cSpell.words": [ + "argothim", + "Localstorage", + "MIDDLAWARE", + "Middlawre", + "mutilp" + ] } diff --git a/backend-manager-student/src/admin_api/v1/Swagger/admin_api/admin.swagger.yaml b/backend-manager-student/src/admin_api/v1/Swagger/admin_api/admin.swagger.yaml index c07c799..74c380f 100644 --- a/backend-manager-student/src/admin_api/v1/Swagger/admin_api/admin.swagger.yaml +++ b/backend-manager-student/src/admin_api/v1/Swagger/admin_api/admin.swagger.yaml @@ -283,7 +283,7 @@ paths: #!created_at 28/02/2023 #!description: New Token /api/v1/admin/renew-token: - post: + get: summary: New Token tags: [New Token] operationId: reNewToken diff --git a/backend-manager-student/src/admin_api/v1/controllers/admin.controller/admin.controller.js b/backend-manager-student/src/admin_api/v1/controllers/admin.controller/admin.controller.js index 2263019..c7d56a3 100644 --- a/backend-manager-student/src/admin_api/v1/controllers/admin.controller/admin.controller.js +++ b/backend-manager-student/src/admin_api/v1/controllers/admin.controller/admin.controller.js @@ -118,7 +118,7 @@ const adminController = { domain: CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT ? req.headers[CONSTANTS.HEADER_HEADER_FORWARDED_HOST]?.split(':')[0] - : '', + : CONSTANTS.HEADER_DOMAIN, maxAge: CONSTANTS._1_MONTH, }); @@ -260,7 +260,10 @@ const adminController = { httpOnly: CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT ? true : false, sameSite: CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT ? true : false, secure: CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT ? true : false, - domain: req.headers[CONSTANTS.HEADER_HEADER_FORWARDED_HOST]?.split(':')[0] || '', + domain: + CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT + ? req.headers[CONSTANTS.HEADER_HEADER_FORWARDED_HOST]?.split(':')[0] + : CONSTANTS.HEADER_DOMAIN, maxAge: CONSTANTS._1_MONTH, }); diff --git a/backend-manager-student/src/admin_api/v1/routes/admin.routes/admin.route.js b/backend-manager-student/src/admin_api/v1/routes/admin.routes/admin.route.js index 11e1b47..3107f2f 100644 --- a/backend-manager-student/src/admin_api/v1/routes/admin.routes/admin.route.js +++ b/backend-manager-student/src/admin_api/v1/routes/admin.routes/admin.route.js @@ -12,8 +12,8 @@ router.post('/login', adminController.LoginAdmin); * @author Nguyễn Tiến Tài * @created_at 28/02/2023 * @description Route renew-token token - * @param {('POST')} [method='POST'] The request's method + * @param {('GET')} [method='GET'] The request's method */ -router.post('/renew-token', adminController.reNewToken); +router.get('/renew-token', adminController.reNewToken); module.exports = router; diff --git a/backend-manager-student/src/share/configs/constants.js b/backend-manager-student/src/share/configs/constants.js index f07d5f8..fa3f84a 100644 --- a/backend-manager-student/src/share/configs/constants.js +++ b/backend-manager-student/src/share/configs/constants.js @@ -248,6 +248,7 @@ module.exports = { HEADER_HEADER_FORWARDED_HOST: 'x-forwarded-host', HEADER_FORWARDED_FOR: 'x-forwarded-for', HEADER_DEVICE: 'user-agent', + HEADER_DOMAIN: 'localhost', /** * @author Nguyễn Tiến Tài * @created_at 05/02/2023 diff --git a/backend-manager-student/src/share/middleware/access.admin.middleware.js b/backend-manager-student/src/share/middleware/access.admin.middleware.js index 407ecbe..c951316 100644 --- a/backend-manager-student/src/share/middleware/access.admin.middleware.js +++ b/backend-manager-student/src/share/middleware/access.admin.middleware.js @@ -81,7 +81,6 @@ const accessAdminMiddleware = async (req, res, next) => { // Continue return next(); - } catch (error) { return res.status(503).json({ status: 503, diff --git a/backend-manager-student/src/user_api/v1/Swagger/user_api/user.swagger.yaml b/backend-manager-student/src/user_api/v1/Swagger/user_api/user.swagger.yaml index 2214f10..8e9f8cb 100644 --- a/backend-manager-student/src/user_api/v1/Swagger/user_api/user.swagger.yaml +++ b/backend-manager-student/src/user_api/v1/Swagger/user_api/user.swagger.yaml @@ -215,7 +215,7 @@ paths: #!updated_at 08/02/2023 #!description: New Token /api/v1/user/renew-token: - post: + get: summary: New Token tags: [New Token] operationId: reNewToken diff --git a/backend-manager-student/src/user_api/v1/controllers/user.controller.js b/backend-manager-student/src/user_api/v1/controllers/user.controller.js index 310378c..1004323 100644 --- a/backend-manager-student/src/user_api/v1/controllers/user.controller.js +++ b/backend-manager-student/src/user_api/v1/controllers/user.controller.js @@ -168,7 +168,10 @@ const userController = { httpOnly: CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT ? true : false, sameSite: CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT ? true : false, secure: CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT ? true : false, - domain: req.headers[CONSTANTS.HEADER_HEADER_FORWARDED_HOST]?.split(':')[0] || '', + domain: + CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT + ? req.headers[CONSTANTS.HEADER_HEADER_FORWARDED_HOST]?.split(':')[0] + : CONSTANTS.HEADER_DOMAIN, maxAge: CONSTANTS._1_MONTH, }); @@ -388,7 +391,10 @@ const userController = { httpOnly: CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT ? true : false, sameSite: CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT ? true : false, secure: CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT ? true : false, - domain: req.headers[CONSTANTS.HEADER_HEADER_FORWARDED_HOST]?.split(':')[0] || '', + domain: + CONFIGS.NODE_ENV === CONSTANTS.ENVIRONMENT_PRODUCT + ? req.headers[CONSTANTS.HEADER_HEADER_FORWARDED_HOST]?.split(':')[0] + : CONSTANTS.HEADER_DOMAIN, maxAge: CONSTANTS._1_MONTH, }); diff --git a/backend-manager-student/src/user_api/v1/routes/users/user.route.js b/backend-manager-student/src/user_api/v1/routes/users/user.route.js index 0e7ce64..fb8237c 100644 --- a/backend-manager-student/src/user_api/v1/routes/users/user.route.js +++ b/backend-manager-student/src/user_api/v1/routes/users/user.route.js @@ -16,9 +16,9 @@ router.post('/login', userController.loginStudent); * @author Nguyễn Tiến Tài * @created_at 04/02/2023 * @description Route renew-token token - * @param {('POST')} [method='POST'] The request's method + * @param {('GET')} [method='GET'] The request's method */ -router.post('/renew-token', userController.reNewToken); +router.get('/renew-token', userController.reNewToken); /** * @author Nguyễn Tiến Tài diff --git a/frontend-manager-cms/src/configs/constants.js b/frontend-manager-cms/src/configs/constants.js index 7ceb7a5..7c28c3a 100644 --- a/frontend-manager-cms/src/configs/constants.js +++ b/frontend-manager-cms/src/configs/constants.js @@ -69,5 +69,14 @@ const CONSTANTS = { * @return {Number} */ AUTH_TOKEN: 'auth-token', + /** + * @author Nguyễn Tiến Tài + * @created_at 04/03/2023 + * @descriptionKey Header + * @return {Number} + */ + OS_TYPE_HEADER: 'web', + OS_VERSION_HEADER: '1.0', + APP_VERSION_HEADER: '1.0', }; export default CONSTANTS; diff --git a/frontend-manager-cms/src/utils/helper.js b/frontend-manager-cms/src/utils/helper.js index 786da33..854acee 100644 --- a/frontend-manager-cms/src/utils/helper.js +++ b/frontend-manager-cms/src/utils/helper.js @@ -1,10 +1,12 @@ //! SHARE +import CONSTANTS from 'configs/constants'; import { getDeviceId, getToken } from './auth'; const HELPERS = { /** * @author Nguyễn Tiến Tài * @created_at 02/03/2023 + * @uodated_at 04/03/2023 * @descriptionKey return header browser * @function getToken * @return {String} @@ -13,14 +15,14 @@ const HELPERS = { // add the authorization to the headers const headers = { 'X-DEVICE-ID': getDeviceId(), - 'X-OS-TYPE': 'web', - 'X-OS-VERSION': '1.0', - 'X-APP-VERSION': '1.0', + 'X-OS-TYPE': CONSTANTS.OS_TYPE_HEADER, + 'X-OS-VERSION': CONSTANTS.OS_VERSION_HEADER, + 'X-APP-VERSION': CONSTANTS.APP_VERSION_HEADER, 'X-DEVICE-NAME': window.navigator.userAgent, }; const token = getToken(); if (token) { - headers.authorization = token ? `Bearer ${token}` : null; + headers.Authorization = token ? `Bearer ${token}` : null; } return headers; diff --git a/frontend-manager-student/makefile b/frontend-manager-student/makefile index e69de29..7a2d4bf 100644 --- a/frontend-manager-student/makefile +++ b/frontend-manager-student/makefile @@ -0,0 +1,7 @@ +# Run Frontend dev +run-dev: + npm run dev + +# Run Production +run-product: + npm start diff --git a/frontend-manager-student/package-lock.json b/frontend-manager-student/package-lock.json index e482bfb..0eba412 100644 --- a/frontend-manager-student/package-lock.json +++ b/frontend-manager-student/package-lock.json @@ -20,6 +20,7 @@ "axios": "^0.25.0", "bootstrap": "^5.2.3", "framer-motion": "^6.2.8", + "jwt-decode": "^3.1.2", "moment": "^2.29.1", "nanoid": "^4.0.1", "react": "^17.0.2", @@ -12828,6 +12829,11 @@ "node": ">=4.0" } }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -28498,6 +28504,11 @@ "object.assign": "^4.1.3" } }, + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", diff --git a/frontend-manager-student/package.json b/frontend-manager-student/package.json index 9ecd087..78e430b 100644 --- a/frontend-manager-student/package.json +++ b/frontend-manager-student/package.json @@ -17,6 +17,7 @@ "axios": "^0.25.0", "bootstrap": "^5.2.3", "framer-motion": "^6.2.8", + "jwt-decode": "^3.1.2", "moment": "^2.29.1", "nanoid": "^4.0.1", "react": "^17.0.2", @@ -50,6 +51,7 @@ }, "scripts": { "start": "react-scripts start", + "dev": "set PORT=3000 && react-scripts start", "build": "set \"GENERATE_SOURCEMAP=false\" && react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", diff --git a/frontend-manager-student/src/api/api_user.js b/frontend-manager-student/src/api/api_user.js index 8d11421..dcea145 100644 --- a/frontend-manager-student/src/api/api_user.js +++ b/frontend-manager-student/src/api/api_user.js @@ -5,5 +5,17 @@ const API_STUDENT = { * @descriptionKey API login student */ LOGIN_STUDENT: '/student/v1/user/login', + /** + * @author Nguyễn Tiến Tài + * @created_at 03/03/2023 + * @descriptionKey API profile student + */ + PROFILE_STUDENT: '/student/v1/user/private/profile', + /** + * @author Nguyễn Tiến Tài + * @created_at 04/03/2023 + * @descriptionKey API new token student + */ + RE_NEW_TOKEN_STUDENT: '/student/v1/user/renew-token', }; export default API_STUDENT; diff --git a/frontend-manager-student/src/components/Header.jsx b/frontend-manager-student/src/components/Header.jsx index b753a46..a5f681a 100644 --- a/frontend-manager-student/src/components/Header.jsx +++ b/frontend-manager-student/src/components/Header.jsx @@ -1,54 +1,16 @@ -import { useEffect, useRef, useState } from 'react'; +//! LIBRARY +import React, { Fragment, useRef, useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; import { Link, useLocation } from 'react-router-dom'; + +//! SHARE +import { navInfo } from 'utils/dummy'; + +//! IMPORT import { SCHOOL_LOGO } from '../imports/home_import/index'; -import Button from './Button'; -const navInfo = [ - { - displayText: 'Giới thiệu', - path: '/', - submenu: [ - { - displayText: 'Submenu 1', - path: '/sub', - }, - { - displayText: 'Submenu 1', - path: '/sub', - }, - { - displayText: 'Submenu 1', - path: '/sub', - }, - ], - }, - { - displayText: 'Tra cứu', - path: '/book', - submenu: [ - { - displayText: 'Thể loại', - path: '/category', - }, - { - displayText: 'Tất cả tài liệu', - path: '/book', - }, - { - displayText: 'Submenu 1', - path: '/sub', - }, - ], - }, - { - displayText: 'Phụ kiện', - path: '/accessories', - }, - { - displayText: 'Liên hệ', - path: '/contact', - }, -]; +//! COMPONENTS +import Button from './Button'; const userSubNav = [ { @@ -68,6 +30,11 @@ const userSubNav = [ ]; const Header = (props) => { + // Take profile account store + const { profile_student } = useSelector((state) => ({ + ...state.auth_student, + })); + const { pathname } = useLocation(); const headerRef = useRef(null); const menuLeftRef = useRef(null); @@ -88,7 +55,7 @@ const Header = (props) => { }; return ( - <> +
@@ -188,7 +155,7 @@ const Header = (props) => {
- +
); }; diff --git a/frontend-manager-student/src/configs/constants.js b/frontend-manager-student/src/configs/constants.js index 7ceb7a5..c090e6b 100644 --- a/frontend-manager-student/src/configs/constants.js +++ b/frontend-manager-student/src/configs/constants.js @@ -15,6 +15,7 @@ const CONSTANTS = { */ _1_MINUTES: 60 * 1000, _5_MINUTES: 5 * 60 * 1000, + _4_MINUTES: 4 * 60 * 1000, _15_MINUTES: 15 * 60 * 1000, _45_MINUTES: 45 * 60 * 1000, _1_DAY: 24 * 60 * 60 * 1000, @@ -69,5 +70,14 @@ const CONSTANTS = { * @return {Number} */ AUTH_TOKEN: 'auth-token', + /** + * @author Nguyễn Tiến Tài + * @created_at 04/03/2023 + * @descriptionKey Header + * @return {Number} + */ + OS_TYPE_HEADER: 'web', + OS_VERSION_HEADER: '1.0', + APP_VERSION_HEADER: '1.0', }; export default CONSTANTS; diff --git a/frontend-manager-student/src/configs/text_notification.js b/frontend-manager-student/src/configs/text_notification.js new file mode 100644 index 0000000..089dee6 --- /dev/null +++ b/frontend-manager-student/src/configs/text_notification.js @@ -0,0 +1,9 @@ +const TEXT_NOTIFICATION = { + /** + * @author Nguyễn Tiến Tài + * @created_at 04/03/2023 + * @description LOgin success + */ + NOTIFICATION_LOGIN_SUCCESS: 'Login Student Success', +}; +export default TEXT_NOTIFICATION; diff --git a/frontend-manager-student/src/contexts/auth_student/auth_student.js b/frontend-manager-student/src/contexts/auth_student/auth_student.js new file mode 100644 index 0000000..c9b1830 --- /dev/null +++ b/frontend-manager-student/src/contexts/auth_student/auth_student.js @@ -0,0 +1,31 @@ +//! LIBRARY +import { useEffect } from 'react'; +import { useDispatch } from 'react-redux'; + +//! SHARE +import HELPERS from 'utils/helper'; +import CONSTANTS from '../../configs/constants'; +import { getToken } from '../../utils/auth'; + +//! REDUX THUNK +import { Profile_Student_Initial } from '../../redux/student/authentication_slice/auth_thunk'; + +const AuthStudent = () => { + // InitialState Action + const dispatch = useDispatch(); + + // Get Token localStore + const token_localStorage = getToken(CONSTANTS.AUTH_TOKEN); + + //Check Token + const decodedToken = HELPERS.isTokenExpired(token_localStorage); + + useEffect(() => { + if (token_localStorage && decodedToken) { + dispatch(Profile_Student_Initial(token_localStorage)); + } + }, []); + + return {}; +}; +export default AuthStudent; diff --git a/frontend-manager-student/src/contexts/global_context.js b/frontend-manager-student/src/contexts/global_context.js new file mode 100644 index 0000000..385875b --- /dev/null +++ b/frontend-manager-student/src/contexts/global_context.js @@ -0,0 +1,70 @@ +//! LIBRARY +import React, { createContext, useContext, useEffect, useState } from 'react'; + +//! SHARE +import CONSTANTS from 'configs/constants'; +import { getToken } from 'utils/auth'; + +//! CONTEXT CHILD +import AuthStudent from './auth_student/auth_student'; +import HELPERS from 'utils/helper'; +import { useDispatch } from 'react-redux'; + +//! REDUX THUNK CALL API +import { Renew_Token_Student_Initial } from 'redux/student/authentication_slice/auth_thunk'; + +/** + * @author Nguyễn Tiến Tài + * @created_at 03/03/2023 + * @descriptionKey Setting Context + */ + +//! Create Context +export const store_library_school_contextUser = createContext(); + +//! Give Store Context +export const useContextStudent = () => useContext(store_library_school_contextUser); + +export const DataProviderStudent = ({ 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_Student_Initial()); + } + // Schedule next token renewal + setTimeout(() => { + //Start + newToken(); + }, CONSTANTS._4_MINUTES); + }; + + //Start + newToken(); + } + }, [token_access_localStorage, dispatch]); + + //! Data + const data = { + profile_student_context: AuthStudent(), + }; + + //! Name conText + store_library_school_contextUser.displayName = 'Library School'; + + //! Use Context Global + return {children}; +}; diff --git a/frontend-manager-student/src/index.js b/frontend-manager-student/src/index.js index 99877d2..c6908ae 100644 --- a/frontend-manager-student/src/index.js +++ b/frontend-manager-student/src/index.js @@ -13,6 +13,8 @@ import './styles/style.scss'; //! REDUX import store from 'redux/store'; +//! CONTEXT +import { DataProviderStudent } from 'contexts/global_context'; //! MAIN import App from './App'; @@ -20,9 +22,11 @@ import reportWebVitals from './reportWebVitals'; ReactDOM.render( - - - + + + + + , document.getElementById('root'), diff --git a/frontend-manager-student/src/pages/UserProfile/index.jsx b/frontend-manager-student/src/pages/UserProfile/index.jsx index 25c10c7..a89da63 100644 --- a/frontend-manager-student/src/pages/UserProfile/index.jsx +++ b/frontend-manager-student/src/pages/UserProfile/index.jsx @@ -5,12 +5,24 @@ import { Col, Row } from 'react-bootstrap'; const UserProfile = () => { return ( -
+
Thông tin tài khoản - + +
+
+ + Hello + Hello + +
+
+ + +
Hello
+
diff --git a/frontend-manager-student/src/redux/store.js b/frontend-manager-student/src/redux/store.js index 16b4458..3f8553e 100644 --- a/frontend-manager-student/src/redux/store.js +++ b/frontend-manager-student/src/redux/store.js @@ -12,10 +12,9 @@ const rootReducer = (state, action) => { return AuthenticationSlice(state, action); }; -let store; -store = configureStore({ +const store = configureStore({ reducer: { - auth_user: AuthenticationSlice, + auth_student: AuthenticationSlice, reducer: rootReducer, }, middleware: diff --git a/frontend-manager-student/src/redux/student/authentication_slice/auth_slice.js b/frontend-manager-student/src/redux/student/authentication_slice/auth_slice.js index de41113..2ae0ccf 100644 --- a/frontend-manager-student/src/redux/student/authentication_slice/auth_slice.js +++ b/frontend-manager-student/src/redux/student/authentication_slice/auth_slice.js @@ -2,35 +2,64 @@ import { createSlice } from '@reduxjs/toolkit'; //! CALL API REDUX THUNK -import { Login_Mssv_Initial } from './auth_thunk'; +import { Login_Mssv_Initial, Profile_Student_Initial, Renew_Token_Student_Initial } from './auth_thunk'; const initialState = { loading: false, error: null, - student_auth: [], + token_student: null, + profile_student: null, }; const Authentication = createSlice({ - name: 'STUDENT AUTH', + name: 'AUTH STUDENT', initialState, reducers: { - reset_auth: (state) => { - state.student_auth = []; + reset_profile: (state) => { + state.profile_student = null; + }, + reset_token: (state) => { + state.token_student = null; }, }, extraReducers: { - //* Login Email_Phone have Password + //* POST LOGIN MSSV STUDENT [Login_Mssv_Initial.pending]: (state, action) => { state.loading = true; }, [Login_Mssv_Initial.fulfilled]: (state, action) => { state.loading = false; - state.student_auth = action.payload; + state.token_student = action.payload; }, [Login_Mssv_Initial.rejected]: (state, action) => { state.loading = false; state.error = action.payload; }, + + //* GET PROFILE + [Profile_Student_Initial.pending]: (state, action) => { + state.loading = true; + }, + [Profile_Student_Initial.fulfilled]: (state, action) => { + state.loading = false; + state.profile_student = action.payload; + }, + [Profile_Student_Initial.rejected]: (state, action) => { + state.loading = false; + state.error = action.payload; + }, + //* GET RE_NEW_TOKEN + [Renew_Token_Student_Initial.pending]: (state, action) => { + state.loading = true; + }, + [Renew_Token_Student_Initial.fulfilled]: (state, action) => { + state.loading = false; + state.token_student = action.payload; + }, + [Renew_Token_Student_Initial.rejected]: (state, action) => { + state.loading = false; + state.error = action.payload; + }, }, }); const AuthenticationSlice = Authentication.reducer; diff --git a/frontend-manager-student/src/redux/student/authentication_slice/auth_thunk.js b/frontend-manager-student/src/redux/student/authentication_slice/auth_thunk.js index 5143d44..6028af7 100644 --- a/frontend-manager-student/src/redux/student/authentication_slice/auth_thunk.js +++ b/frontend-manager-student/src/redux/student/authentication_slice/auth_thunk.js @@ -1,6 +1,6 @@ //! LIBRARY -import axios from 'axios'; import { createAsyncThunk } from '@reduxjs/toolkit'; +import axios from 'axios'; //! NOTIFICATION import NOTIFICATION from 'utils/notification'; @@ -9,8 +9,10 @@ import NOTIFICATION from 'utils/notification'; import API_STUDENT from 'api/api_user'; //! SHARE -import HELPERS from 'utils/helper'; +import CONSTANTS from 'configs/constants'; +import TEXT_NOTIFICATION from 'configs/text_notification'; import { setToken } from 'utils/auth'; +import HELPERS from 'utils/helper'; /** * @author Nguyễn Tiến Tài @@ -42,20 +44,109 @@ export const Login_Mssv_Initial = createAsyncThunk('student/mssv', async ({ mssv //Check data if (successData) { - const success_general = { - message: successData?.element?.result || successData.message, - status: successData.status, - access_token: successData?.element?.result?.access_token, - }; + // return result data + const result_data = HELPERS.takeDataResponse(successData); // Save LocalStorage - setToken(success_general.access_token); + setToken(CONSTANTS.AUTH_TOKEN, result_data.access_token); // Notification Success - NOTIFICATION.notifySuccess('Đăng nhập thành công' || successData.message); + NOTIFICATION.notifySuccess(TEXT_NOTIFICATION.NOTIFICATION_LOGIN_SUCCESS || result_data.message); // return result data - return successData; + return result_data; + } + } catch (error) { + if (error) { + //Take response Error + const errorData = error.response.data; + + // return result data + const result_data = HELPERS.takeDataResponse(errorData); + + if (errorData) { + // Notification Error + NOTIFICATION.notifyError(result_data.data || result_data.message); + } + + // return error + return rejectWithValue(result_data); + } + } +}); + +/** + * @author Nguyễn Tiến Tài + * @created_at 03/03/2023 + * @descriptionKey Call api Profile Student + * @function Profile_Student_Initial + * @return {Object} + */ +export const Profile_Student_Initial = createAsyncThunk('student/profile', async (_, { rejectWithValue }) => { + try { + //Call Api axios + const response = await axios.get(`${API_STUDENT.PROFILE_STUDENT}`, { + headers: HELPERS.headerBrowser(), + withCredentials: true, + }); + + //Take response Success + const successData = response.data; + + //Check data + if (successData) { + // return result data + const result_data = HELPERS.takeDataResponse(successData); + return result_data; + } + } catch (error) { + if (error) { + //Take response Error + const errorData = error.response.data; + + if (errorData) { + const error_general = { + message: errorData?.element?.result || errorData.message, + status: errorData.status, + }; + + // Notification Error + NOTIFICATION.notifyError(error_general.message); + } + + // return error + return rejectWithValue(errorData); + } + } +}); + +/** + * @author Nguyễn Tiến Tài + * @created_at 03/03/2023 + * @descriptionKey Call api renew token Student + * @function Renew_Token_Student_Initial + * @return {Object} + */ +export const Renew_Token_Student_Initial = createAsyncThunk('student/new/token', async (_, { rejectWithValue }) => { + try { + //Call Api axios + const response = await axios.get(`${API_STUDENT.RE_NEW_TOKEN_STUDENT}`, { + headers: HELPERS.headerBrowser(), + withCredentials: true, + }); + + //Take response Success + const successData = response.data; + + //Check data + if (successData) { + // return result data + const result_data = HELPERS.takeDataResponse(successData); + + // Save LocalStorage + setToken(CONSTANTS.AUTH_TOKEN, result_data.data.access_token); + + return result_data; } } catch (error) { if (error) { diff --git a/frontend-manager-student/src/styles/_base.scss b/frontend-manager-student/src/styles/_base.scss index 38b8a72..2ba8488 100644 --- a/frontend-manager-student/src/styles/_base.scss +++ b/frontend-manager-student/src/styles/_base.scss @@ -87,7 +87,6 @@ img { .main { margin-top: $header-height; margin-bottom: 2rem; - min-height: 100vh; @include tablet { margin-top: calc(#{$header-tablet-height} + 20px); diff --git a/frontend-manager-student/src/styles/pages/_user_profile.scss b/frontend-manager-student/src/styles/pages/_user_profile.scss new file mode 100644 index 0000000..f44b060 --- /dev/null +++ b/frontend-manager-student/src/styles/pages/_user_profile.scss @@ -0,0 +1,3 @@ +.profile { + padding: 0 8rem; +} diff --git a/frontend-manager-student/src/styles/style.scss b/frontend-manager-student/src/styles/style.scss index 2dc84a5..b751d5d 100644 --- a/frontend-manager-student/src/styles/style.scss +++ b/frontend-manager-student/src/styles/style.scss @@ -15,3 +15,4 @@ @import './pages/book'; @import './pages/detail-book'; @import './pages/change-password'; +@import './pages/user_profile'; diff --git a/frontend-manager-student/src/utils/auth.js b/frontend-manager-student/src/utils/auth.js index 3a1a415..6231617 100644 --- a/frontend-manager-student/src/utils/auth.js +++ b/frontend-manager-student/src/utils/auth.js @@ -29,8 +29,8 @@ export function getDeviceId() { * @function getToken * @return {String} */ -export function getToken() { - return localStorage.getItem(CONSTANTS.AUTH_TOKEN); +export function getToken(key) { + return localStorage.getItem(key); } /** @@ -40,6 +40,6 @@ export function getToken() { * @function getToken * @return {String} */ -export function setToken(token) { - return localStorage.setItem(CONSTANTS.AUTH_TOKEN, JSON.stringify(token)); +export function setToken(key, value) { + return localStorage.setItem(key, value); } diff --git a/frontend-manager-student/src/utils/dummy.js b/frontend-manager-student/src/utils/dummy.js new file mode 100644 index 0000000..1f9d6df --- /dev/null +++ b/frontend-manager-student/src/utils/dummy.js @@ -0,0 +1,51 @@ +/** + * @author Nguyễn Tiến Tài + * @created_at 04/03/2023 + * @descriptionKey Nav Info + */ +export const navInfo = [ + { + displayText: 'Giới thiệu', + path: '/', + submenu: [ + { + displayText: 'Submenu 1', + path: '/sub', + }, + { + displayText: 'Submenu 1', + path: '/sub', + }, + { + displayText: 'Submenu 1', + path: '/sub', + }, + ], + }, + { + displayText: 'Tra cứu', + path: '/book', + submenu: [ + { + displayText: 'Thể loại', + path: '/category', + }, + { + displayText: 'Tất cả tài liệu', + path: '/book', + }, + { + displayText: 'Submenu 1', + path: '/sub', + }, + ], + }, + { + displayText: 'Phụ kiện', + path: '/accessories', + }, + { + displayText: 'Liên hệ', + path: '/contact', + }, +]; diff --git a/frontend-manager-student/src/utils/helper.js b/frontend-manager-student/src/utils/helper.js index 786da33..275386d 100644 --- a/frontend-manager-student/src/utils/helper.js +++ b/frontend-manager-student/src/utils/helper.js @@ -1,5 +1,9 @@ +//!LIBRARY +import jwt_decode from 'jwt-decode'; + //! SHARE import { getDeviceId, getToken } from './auth'; +import CONSTANTS from 'configs/constants'; const HELPERS = { /** @@ -12,23 +16,75 @@ const HELPERS = { headerBrowser: () => { // add the authorization to the headers const headers = { + 'Content-Type': 'application/json', 'X-DEVICE-ID': getDeviceId(), - 'X-OS-TYPE': 'web', - 'X-OS-VERSION': '1.0', - 'X-APP-VERSION': '1.0', + 'X-OS-TYPE': CONSTANTS.OS_TYPE_HEADER, + 'X-OS-VERSION': CONSTANTS.OS_VERSION_HEADER, + '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; } return headers; }, + /** + * @author Nguyễn Tiến Tài + * @created_at 02/03/2023 + * @descriptionKey Form input + * @return {Object} + */ formDataGeneral: (target) => { const formData = new FormData(target); return Object.fromEntries(formData); }, + /** + * @author Nguyễn Tiến Tài + * @created_at 04/03/2023 + * @descriptionKey Convert data response Thunk + * @return {Object} + */ + takeDataResponse: (successData) => { + if (successData.element) { + return { + status: successData.status, + message: successData.message, + data: successData.element.result || null, + }; + } + return { + status: successData.status, + message: successData.message, + }; + }, + /** + * @author Nguyễn Tiến Tài + * @created_at 04/03/2023 + * @descriptionKey Check token access expired + * @return {Object} + */ + isTokenExpired: (access_token) => { + //Check token not found + if (!access_token) { + return false; + } + try { + //Take Data from token + const decodedToken = jwt_decode(access_token); + + // Expired + const currentTime = Math.floor(Date.now() / 1000); + if (decodedToken.exp < currentTime) { + return false; + } + // Due + return true; + } catch (err) { + return false; + } + }, }; export default HELPERS; diff --git a/frontend-manager-student/src/utils/notification.js b/frontend-manager-student/src/utils/notification.js index 9dd9042..d02aa8f 100644 --- a/frontend-manager-student/src/utils/notification.js +++ b/frontend-manager-student/src/utils/notification.js @@ -27,7 +27,6 @@ const NOTIFICATION = { * @descriptionKey error */ notifyError(message) { - console.log(message); return toast.error(message, { pposition: toast.POSITION.TOP_RIGHT, autoClose: CONSTANTS.AUTO_CLOSE, diff --git a/server-media-service/src/share/middlewares/access.token.middleware.js b/server-media-service/src/share/middlewares/access.token.middleware.js index 5b9bd26..89ee2c1 100644 --- a/server-media-service/src/share/middlewares/access.token.middleware.js +++ b/server-media-service/src/share/middlewares/access.token.middleware.js @@ -39,7 +39,7 @@ const accessTokenMiddleware = async (req, res, next) => { // Take token const { device_id } = req.device; - console.log(device_id, 'device_id') + // Take data device student const data_device = await user_device_model.getDeviceId( { device_uuid: device_id },