|
|
|
|
@@ -1,115 +1,122 @@
|
|
|
|
|
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
|
|
|
|
|
import { encryptString } from '../Constants/Constants'
|
|
|
|
|
|
|
|
|
|
// Define a base query function with token refresh logic
|
|
|
|
|
// Define a base query function with token refresh logic, retry mechanism, and AbortController
|
|
|
|
|
export const baseQuery = async (args, api, extraOptions) => {
|
|
|
|
|
let result = await fetchBaseQuery({
|
|
|
|
|
baseUrl: import.meta.env.VITE_BAS_URL,
|
|
|
|
|
credentials: 'include',
|
|
|
|
|
prepareHeaders: (headers) => {
|
|
|
|
|
headers.set('Content-Type', 'application/json',);
|
|
|
|
|
return headers;
|
|
|
|
|
},
|
|
|
|
|
})(args, api, extraOptions);
|
|
|
|
|
const fetchBase = fetchBaseQuery({
|
|
|
|
|
baseUrl: import.meta.env.VITE_BAS_URL,
|
|
|
|
|
credentials: 'include',
|
|
|
|
|
prepareHeaders: (headers) => {
|
|
|
|
|
headers.set('Content-Type', 'application/json');
|
|
|
|
|
return headers;
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (result.error) {
|
|
|
|
|
if (result.error.status === 403) {
|
|
|
|
|
try {
|
|
|
|
|
const { data, error } = await fetchBaseQuery({
|
|
|
|
|
baseUrl: import.meta.env.VITE_BAS_URL,
|
|
|
|
|
credentials: 'include',
|
|
|
|
|
prepareHeaders: (headers) => {
|
|
|
|
|
headers.set('Content-Type', 'application/json',);
|
|
|
|
|
return headers;
|
|
|
|
|
},
|
|
|
|
|
})(
|
|
|
|
|
{
|
|
|
|
|
url: "/auth/user/regenerate-token",
|
|
|
|
|
method: "POST",
|
|
|
|
|
},
|
|
|
|
|
api,
|
|
|
|
|
extraOptions
|
|
|
|
|
);
|
|
|
|
|
const abortController = new AbortController();
|
|
|
|
|
extraOptions = {
|
|
|
|
|
...extraOptions,
|
|
|
|
|
signal: abortController.signal,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
|
return await fetchBaseQuery({
|
|
|
|
|
baseUrl: import.meta.env.VITE_BAS_URL,
|
|
|
|
|
credentials: 'include',
|
|
|
|
|
prepareHeaders: (headers) => {
|
|
|
|
|
headers.set('Content-Type', 'application/json',);
|
|
|
|
|
return headers;
|
|
|
|
|
}
|
|
|
|
|
})(args, api, extraOptions);
|
|
|
|
|
}
|
|
|
|
|
throw error;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error("Failed to refresh token:", err);
|
|
|
|
|
localStorage.clear();
|
|
|
|
|
window.location.href = '/login'; // Redirect to login page
|
|
|
|
|
}
|
|
|
|
|
} else if (result.error.status === 401) {
|
|
|
|
|
localStorage.clear();
|
|
|
|
|
window.location.href = '/login';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
let result = await fetchBase(args, api, extraOptions);
|
|
|
|
|
|
|
|
|
|
if (result.error) {
|
|
|
|
|
if (result.error.status === 403) {
|
|
|
|
|
let retryCount = 0;
|
|
|
|
|
const maxRetries = import.meta.env.VITE_MAX_TRY_REGENRATE_TOKEN || 2;
|
|
|
|
|
|
|
|
|
|
while (retryCount < maxRetries) {
|
|
|
|
|
try {
|
|
|
|
|
const { data, error } = await fetchBase(
|
|
|
|
|
{
|
|
|
|
|
url: "/auth/user/regenerate-token",
|
|
|
|
|
method: "POST",
|
|
|
|
|
},
|
|
|
|
|
api,
|
|
|
|
|
{ ...extraOptions, signal: abortController.signal }
|
|
|
|
|
);
|
|
|
|
|
if (data) {
|
|
|
|
|
// Retry the original query after successful token regeneration
|
|
|
|
|
return await fetchBase(args, api, { ...extraOptions, signal: abortController.signal });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw error;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
retryCount++;
|
|
|
|
|
if (retryCount >= maxRetries) {
|
|
|
|
|
console.error("Failed to refresh token after retries:", err);
|
|
|
|
|
abortController.abort();
|
|
|
|
|
localStorage.clear();
|
|
|
|
|
window.location.href = '/login'; // Redirect to login page
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (result.error.status === 401) {
|
|
|
|
|
abortController.abort();
|
|
|
|
|
localStorage.clear();
|
|
|
|
|
window.location.href = '/login';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Create an RTK Query API slice
|
|
|
|
|
export const apiSlice = createApi({
|
|
|
|
|
reducerPath: "api",
|
|
|
|
|
baseQuery: baseQuery,
|
|
|
|
|
tagTypes: ["authProfile"],
|
|
|
|
|
endpoints: (builder) => ({
|
|
|
|
|
reducerPath: "api",
|
|
|
|
|
baseQuery: baseQuery,
|
|
|
|
|
tagTypes: ["authProfile"],
|
|
|
|
|
endpoints: (builder) => ({
|
|
|
|
|
|
|
|
|
|
login: builder.mutation({
|
|
|
|
|
query: (credentials) => ({
|
|
|
|
|
url: "/auth/admin",
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: credentials,
|
|
|
|
|
}),
|
|
|
|
|
async onQueryStarted(arg, { queryFulfilled }) {
|
|
|
|
|
try {
|
|
|
|
|
const { data } = await queryFulfilled;
|
|
|
|
|
localStorage.setItem("role", encryptString(data?.data?.role));
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Login failed:", error);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
login: builder.mutation({
|
|
|
|
|
query: (credentials) => ({
|
|
|
|
|
url: "/auth/admin",
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: credentials,
|
|
|
|
|
}),
|
|
|
|
|
async onQueryStarted(arg, { queryFulfilled }) {
|
|
|
|
|
try {
|
|
|
|
|
const { data } = await queryFulfilled;
|
|
|
|
|
localStorage.setItem("role", encryptString(data?.data?.role));
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Login failed:", error);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
refreshToken: builder.mutation({
|
|
|
|
|
query: (refreshToken) => ({
|
|
|
|
|
url: "/auth/user/regenerate-token",
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: { refreshToken },
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
refreshToken: builder.mutation({
|
|
|
|
|
query: (refreshToken) => ({
|
|
|
|
|
url: "/auth/user/regenerate-token",
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: { refreshToken },
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
logout: builder.mutation({
|
|
|
|
|
query: () => ({
|
|
|
|
|
url: "/auth/admin/logout",
|
|
|
|
|
method: "POST",
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
logout: builder.mutation({
|
|
|
|
|
query: () => ({
|
|
|
|
|
url: "/auth/admin/logout",
|
|
|
|
|
method: "POST",
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
authProfile: builder.query({
|
|
|
|
|
query: () => `/auth/admin/profile`,
|
|
|
|
|
providesTags: (result) => result ? [{ type: 'Auth', id: 'profile' }] : [],
|
|
|
|
|
onQueryStarted: async (args, { queryFulfilled }) => {
|
|
|
|
|
try {
|
|
|
|
|
const { data } = await queryFulfilled; // Get the data from the query response
|
|
|
|
|
if (data?.role) {
|
|
|
|
|
localStorage.setItem('role', encryptString(data.role));
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error setting role in localStorage:', error);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
authProfile: builder.query({
|
|
|
|
|
query: () => `/auth/admin/profile`,
|
|
|
|
|
providesTags: (result) => result ? [{ type: 'Auth', id: 'profile' }] : [],
|
|
|
|
|
onQueryStarted: async (args, { queryFulfilled }) => {
|
|
|
|
|
try {
|
|
|
|
|
const { data } = await queryFulfilled; // Get the data from the query response
|
|
|
|
|
if (data?.role) {
|
|
|
|
|
localStorage.setItem('role', encryptString(data.role));
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error setting role in localStorage:', error);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const { useLoginMutation, useRefreshTokenMutation, useLogoutMutation, useAuthProfileQuery } = apiSlice;
|
|
|
|
|
|