i have an issue when use navigate from login page to /dashboard
when user click to login , correctly redirect in /dashboard
but show me a blank page but when refresh it every things work correctly .
//authSlice.js
import {createSlice, createAsyncThunk} from "@reduxjs/toolkit";
import api from "../../services/api.js";
export const login = createAsyncThunk(
"auth/login",
async (payload) => {
try {
const response = await api.request({
url: `/api/account/token/portal/organic`,
method: "post",
data: payload,
});
return response.data.result;
} catch (error) {
console.error("error", error);
return Promise.reject(error);
}
});
const authSlice = createSlice({
name: "auth",
initialState: {
token: JSON.parse(localStorage.getItem("token")) || {},
isLoading: false,
hasError: null
},
reducers: {
logout: (state) => {
state.token = {};
localStorage.removeItem("token");
}
},
extraReducers: (builder) => {
builder
.addCase(login.pending, (state) => {
state.isLoading = true;
state.hasError = null;
})
.addCase(login.fulfilled, (state, action) => {
state.token = action.payload;
state.isLoading = false;
state.hasError = null
localStorage.setItem("token", JSON.stringify(action.payload));
})
.addCase(login.rejected, (state, action) => {
state.isLoading = false;
state.hasError = action.error;
})
}
});
// Selectors
export const selectToken = state => state.auth.token;
export const selectLoadingState = state => state.auth.isLoading;
export const selectErrorState = state => state.auth.hasError;
export const { logout } = authSlice.actions;
export default authSlice.reducer;
//DashboardLayout.jsx
import {Navigate, Outlet} from "react-router-dom";
import {useDispatch, useSelector} from "react-redux";
import {selectToken} from "../store/auth/authSlice.js";
import { logout } from "../store/auth/authSlice.js";
const DashboardLayout = () => {
const {accessToken} = useSelector(selectToken);
const dispatch = useDispatch();
const handleLogout = () => {
dispatch(logout());
};
if (!accessToken) {
return <Navigate to="/login" />;
}
return (
<>
<Outlet/>
<button onClick={handleLogout}>
Logout
</button>
</>
)
}
export default DashboardLayout
//LoginPage.jsx
import React, {useEffect, useState} from 'react';
import {Form, Input, Button, Card, Alert, Layout} from 'antd';
import {useDispatch, useSelector} from "react-redux";
import {login, selectErrorState, selectToken} from "../store/auth/authSlice.js";
import {useNavigate} from "react-router-dom";
const LoginPage = () => {
const [form] = Form.useForm();
const dispatch = useDispatch();
const [errorMessage, setErrorMessage] = useState('');
const error = useSelector(selectErrorState);
const navigate = useNavigate()
const onFinish = (values) => {
dispatch(login(values))
.then(() => {
navigate('/dashboard');
})
.catch((error) => {
console.log('Login failed:', error);
});
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
return (
<Layout
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100vh',
}}
>
<Card
title="Login"
style={{
width: 480,
}}
>
{error && (
<Alert message={error.message} type="error" showIcon closable />
)}
<Form
form={form}
name="basic"
labelCol={{
span: 6,
}}
wrapperCol={{
span: 17,
}}
initialValues={{
remember: true,
}}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<Form.Item
label="Username"
name="Username"
rules={[
{
required: true,
message: 'Please input your username!',
},
]}
>
<Input />
</Form.Item>
<Form.Item
label="Password"
name="Password"
rules={[
{
required: true,
message: 'Please input your password!',
},
]}
>
<Input.Password />
</Form.Item>
<Form.Item
wrapperCol={{
offset: 8,
span: 16,
}}
>
<Button type="primary" htmlType="submit">
Login
</Button>
</Form.Item>
</Form>
</Card>
</Layout>
);
};
export default LoginPage;
//Route.js
import {createBrowserRouter, RouterProvider} from "react-router-dom";
import {useSelector} from "react-redux";
import {selectToken} from "../store/auth/authSlice.js";
import DashboardLayout from "../template/DashboardLayout.jsx";
import LoginPage from "../pages/Login.jsx";
const Routes = () => {
const {accessToken} = useSelector(selectToken);
// Define public routes accessible to all users
const routesForPublic = [
{
path: "/service",
element: <div>Service Page</div>,
},
{
path: "/about-us",
element: <div>About Us</div>,
},
];
// Define routes accessible only to authenticated users
const routesForAuthenticatedOnly = [
{
path: "/dashboard",
element: <DashboardLayout/>, // Wrap the component in ProtectedRoute
children: [
{
path: "",
element: <h1>Dashboard</h1>,
},
],
},
];
// Define routes accessible only to non-authenticated users
const routesForNotAuthenticatedOnly = [
{
path: "/",
element: <div>Home Page</div>,
},
{
path: "/login",
element: <LoginPage/>,
},
];
// Combine and conditionally include routes based on authentication status
const router = createBrowserRouter([
...routesForPublic,
...(!accessToken ? routesForNotAuthenticatedOnly : []),
...routesForAuthenticatedOnly,
]);
// Provide the router configuration using RouterProvider
return <RouterProvider router={router}/>;
};
export default Routes;
//store.js
import {combineReducers, configureStore} from "@reduxjs/toolkit";
import authReducer from "./auth/authSlice.js";
const rootReducer = combineReducers({
auth: authReducer,
});
const store = configureStore({
reducer: rootReducer,
});
export default store;
//api.js
import axios from "axios";
const token = localStorage.getItem("token");
const baseURL = import.meta.env.VITE_API_BASE_URL;
const api = axios.create({
baseURL
});
api.interceptors.request.use(
(config) => {
if (token) {
const { accessToken } = JSON.parse(token);
config.headers.Authorization = `Bearer ${accessToken}`;
}
// Do something before request is sent
return config;
},
(error) => {
// Do something with request error
return Promise.reject(error);
}
);
// Add a response interceptor
api.interceptors.response.use(
(response) => {
// Do something with response data
return response;
},
(error) => {
// Do something with response error
return Promise.reject(error);
}
);
export default api;
try to navigate /dashboard without refresh but not work and show me a blank page !