diff --git a/src/pages/auth/Login.jsx b/src/pages/auth/Login.jsx
index 334dcb3..0183a9d 100644
--- a/src/pages/auth/Login.jsx
+++ b/src/pages/auth/Login.jsx
@@ -6,8 +6,8 @@ import { checkAuthThunk, loginThunk } from '../../store/auth/auth.thunk';
export default function Login() {
const dispatch = useDispatch();
const navigate = useNavigate();
- const [username, setUsername] = useState('');
- const [password, setPassword] = useState('');
+ const [username, setUsername] = useState('member2');
+ const [password, setPassword] = useState('member123');
const [errors, setErrors] = useState({});
const [submitted, setSubmitted] = useState(false);
@@ -18,9 +18,11 @@ export default function Login() {
}, [dispatch]);
const handleCheckAuth = async () => {
- console.log('login page handleCheckAuth');
- await dispatch(checkAuthThunk()).unwrap();
- if (user) navigate('/');
+ console.log('login page handleCheckAuth');
+ try {
+ await dispatch(checkAuthThunk()).unwrap();
+ if (user) navigate('/');
+ } catch (error) {}
};
const validateForm = () => {
@@ -37,17 +39,20 @@ export default function Login() {
return Object.keys(newErrors).length === 0;
};
- const handleSubmit = (e) => {
+ const handleSubmit = async (e) => {
e.preventDefault();
setSubmitted(true);
- console.log(validateForm());
if (validateForm()) {
console.log('Form submitted successfully!');
console.log('Username:', username);
console.log('Password:', password);
-
- dispatch(loginThunk({ username, password }));
+ try {
+ await dispatch(loginThunk({ username, password })).unwrap();
+ navigate('/');
+ } catch (error) {
+ console.error('Login failed:', error);
+ }
}
};
return (
@@ -60,6 +65,7 @@ export default function Login() {
>
{
console.log('signup page handleCheckAuth');
- await dispatch(checkAuthThunk()).unwrap();
- if (user) navigate('/');
+ try {
+ await dispatch(checkAuthThunk()).unwrap();
+ if (user) navigate('/');
+ } catch (error) {}
};
const validateForm = () => {
@@ -35,7 +37,7 @@ export default function Signup() {
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(email)) {
newErrors.email = 'Invalid email address';
}
-
+
if (!password) {
newErrors.password = 'Password is required';
} else if (password.length < 6) {
@@ -45,7 +47,7 @@ export default function Signup() {
return Object.keys(newErrors).length === 0;
};
- const handleSubmit = (e) => {
+ const handleSubmit = async (e) => {
e.preventDefault();
setSubmitted(true);
console.log(validateForm());
@@ -55,8 +57,12 @@ export default function Signup() {
console.log('Username:', username);
console.log('Email:', email);
console.log('Password:', password);
-
- dispatch(signupThunk({ username, password, email }));
+ try {
+ await dispatch(signupThunk({ username, password, email })).unwrap();
+ navigate('/');
+ } catch (error) {
+ console.error('Signup failed:', error);
+ }
}
};
diff --git a/src/router/router.jsx b/src/router/router.jsx
index dff99e8..39664b6 100644
--- a/src/router/router.jsx
+++ b/src/router/router.jsx
@@ -2,14 +2,15 @@ import React, { Suspense } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import Mainlayout from '../layouts/Mainlayout';
import KnowledgeBase from '../pages/KnowledgeBase/KnowledgeBase';
+import KnowledgeBaseDetail from '../pages/KnowledgeBase/KnowledgeBaseDetail';
import Loading from '../components/Loading';
-import Login from '../pages/auth/Login';
-import Signup from '../pages/auth/Signup';
+import Login from '../pages/Auth/Login';
+import Signup from '../pages/Auth/Signup';
import ProtectedRoute from './protectedRoute';
import { useSelector } from 'react-redux';
function AppRouter() {
- const { id } = useSelector((state) => state.auth);
+ const { user } = useSelector((state) => state.auth);
return (
}>
@@ -23,10 +24,26 @@ function AppRouter() {
}
/>
+
+
+
+ }
+ />
+
+
+
+ }
+ />
} />
} />
- } />
+ } />
);
diff --git a/src/services/api.js b/src/services/api.js
index 1f003dc..7f69131 100644
--- a/src/services/api.js
+++ b/src/services/api.js
@@ -1,14 +1,22 @@
import axios from 'axios';
+import CryptoJS from 'crypto-js';
+
+const secretKey = import.meta.env.VITE_SECRETKEY;
// Create Axios instance with base URL
const api = axios.create({
- baseURL: 'api',
+ baseURL: '/api',
withCredentials: true, // Include cookies if needed
});
// Request Interceptor
api.interceptors.request.use(
(config) => {
+ const encryptedToken = sessionStorage.getItem('token') || '';
+ if (encryptedToken) {
+ const decryptedToken = CryptoJS.AES.decrypt(encryptedToken, secretKey).toString(CryptoJS.enc.Utf8);
+ config.headers.Authorization = `Token ${decryptedToken}`;
+ }
return config;
},
(error) => {
@@ -26,8 +34,8 @@ api.interceptors.response.use(
// Handle errors in the response
if (error.response) {
// monitor /verify
- if (error.response.status === 401 && error.config.url === '/check-token') {
- if (window.location.pathname !== '/login' && window.location.pathname !== '/register') {
+ if (error.response.status === 401 && error.config.url === '/check-token/') {
+ if (window.location.pathname !== '/login' && window.location.pathname !== '/signup') {
window.location.href = '/login';
}
}
@@ -58,7 +66,7 @@ const get = async (url, params = {}) => {
const post = async (url, data, isMultipart = false) => {
const headers = isMultipart
? { 'Content-Type': 'multipart/form-data' } // For file uploads
- : { 'Content-Type': 'application/json' }; // For JSON data
+ : { 'Content-Type': 'application/json' }; // For JSON data
const res = await api.post(url, data, { headers });
return res.data;
diff --git a/src/store/auth/auth.slice.js b/src/store/auth/auth.slice.js
index 7c16ef7..615a97a 100644
--- a/src/store/auth/auth.slice.js
+++ b/src/store/auth/auth.slice.js
@@ -20,7 +20,7 @@ const setRejected = (state, action) => {
const authSlice = createSlice({
name: 'auth',
- initialState: { loading: false, error: null, user: {id: 123, username: 'test'} },
+ initialState: { loading: false, error: null, user: null },
reducers: {
login: (state, action) => {
state.user = action.payload;
diff --git a/src/store/auth/auth.thunk.js b/src/store/auth/auth.thunk.js
index 331d6b1..a29ace2 100644
--- a/src/store/auth/auth.thunk.js
+++ b/src/store/auth/auth.thunk.js
@@ -2,15 +2,22 @@ import { createAsyncThunk } from '@reduxjs/toolkit';
import { get, post } from '../../services/api';
import { showNotification } from '../notification.slice';
import { logout } from './auth.slice';
+import CryptoJS from 'crypto-js';
+
+const secretKey = import.meta.env.VITE_SECRETKEY;
export const loginThunk = createAsyncThunk(
'auth/login',
async ({ username, password }, { rejectWithValue, dispatch }) => {
try {
- const { message, user } = await post('/login', { username, password });
+ const { message, user, token } = await post('/login/', { username, password });
if (!user) {
throw new Error(message || 'Something went wrong');
}
+ // encrypt token
+ const encryptedToken = CryptoJS.AES.encrypt(token, secretKey).toString();
+ sessionStorage.setItem('token', encryptedToken);
+
return user;
} catch (error) {
const errorMessage = error.response?.data?.message || 'Something went wrong';
@@ -46,7 +53,7 @@ export const signupThunk = createAsyncThunk('auth/signup', async (config, { reje
export const checkAuthThunk = createAsyncThunk('auth/check', async (_, { rejectWithValue, dispatch }) => {
try {
- const { user, message } = await get('/check-token');
+ const { user, message } = await get('/check-token/');
if (!user) {
dispatch(logout());
throw new Error(message || 'No token found');
@@ -62,7 +69,7 @@ export const checkAuthThunk = createAsyncThunk('auth/check', async (_, { rejectW
export const logoutThunk = createAsyncThunk('auth/logout', async (_, { rejectWithValue, dispatch }) => {
try {
// Send the logout request to the server (this assumes your server clears any session-related info)
- await post('/logout');
+ await post('/logout/');
dispatch(logout());
} catch (error) {
const errorMessage = error.response?.data?.message || 'Log out failed';
diff --git a/src/styles/style.scss b/src/styles/style.scss
index e652e38..898fcb5 100644
--- a/src/styles/style.scss
+++ b/src/styles/style.scss
@@ -1,5 +1,8 @@
@import 'bootstrap/scss/bootstrap';
+#root {
+ min-width: 24rem;
+}
.dropdown-toggle {
outline: 0;
}
@@ -9,6 +12,9 @@
}
.knowledge-card {
+ min-width: 20rem;
+ cursor: pointer;
+
.hoverdown:hover .hoverdown-menu{
display: block;
color: red;
diff --git a/vite.config.js b/vite.config.js
index 90cdbfd..2e6c3c9 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,13 +1,23 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
+import { defineConfig, loadEnv } from 'vite';
+import react from '@vitejs/plugin-react';
// https://vite.dev/config/
-export default defineConfig({
- plugins: [react()],
- build: {
- outDir: '../dist'
- },
- server: {
- port: 8080
- }
-})
+export default defineConfig(({ mode }) => {
+ const env = loadEnv(mode, process.cwd());
+
+ return {
+ plugins: [react()],
+ build: {
+ outDir: '../dist',
+ },
+ server: {
+ port: env.VITE_PORT,
+ proxy: {
+ '/api': {
+ target: env.VITE_API_URL || 'http://124.222.236.141:58000',
+ changeOrigin: true,
+ },
+ },
+ },
+ };
+});