pramod_Bug#494 : update axios client and auth repository for public/private route handling #207
@ -67,9 +67,13 @@ const ResetPasswordPage = () => {
|
|||||||
navigate("/auth/login", { replace: true });
|
navigate("/auth/login", { replace: true });
|
||||||
// setLoading(false);
|
// setLoading(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast("Link is expries or Invalid ", "error");
|
debugger;
|
||||||
setTokenExpired(true);
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
if (error?.response?.status === 400) {
|
||||||
|
showToast("Please check valid Credentials", "error");
|
||||||
|
} else {
|
||||||
|
setTokenExpired(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -77,7 +81,10 @@ const ResetPasswordPage = () => {
|
|||||||
return (
|
return (
|
||||||
<AuthWrapper>
|
<AuthWrapper>
|
||||||
<h4 className="mb-2 ">Invalid Link 🔒</h4>
|
<h4 className="mb-2 ">Invalid Link 🔒</h4>
|
||||||
<p className="mb-4" style={{fontSize: "12px"}}>This link appears to be invalid or expired. Please use the 'Forgot Password' feature to set your new password.</p>
|
<p className="mb-4" style={{ fontSize: "12px" }}>
|
||||||
|
This link appears to be invalid or expired. Please use the 'Forgot
|
||||||
|
Password' feature to set your new password.
|
||||||
|
</p>
|
||||||
<div className="text-center mb-4">
|
<div className="text-center mb-4">
|
||||||
<Link to="/auth/forgot-password" className="btn btn-outline-primary">
|
<Link to="/auth/forgot-password" className="btn btn-outline-primary">
|
||||||
Go to Forgot Password
|
Go to Forgot Password
|
||||||
@ -142,7 +149,6 @@ const ResetPasswordPage = () => {
|
|||||||
borderTopLeftRadius: 0,
|
borderTopLeftRadius: 0,
|
||||||
borderBottomLeftRadius: 0,
|
borderBottomLeftRadius: 0,
|
||||||
borderLeft: 0,
|
borderLeft: 0,
|
||||||
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{hidepass ? (
|
{hidepass ? (
|
||||||
@ -185,7 +191,6 @@ const ResetPasswordPage = () => {
|
|||||||
borderTopLeftRadius: 0,
|
borderTopLeftRadius: 0,
|
||||||
borderBottomLeftRadius: 0,
|
borderBottomLeftRadius: 0,
|
||||||
borderLeft: 0,
|
borderLeft: 0,
|
||||||
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{hidepass1 ? (
|
{hidepass1 ? (
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
import { api } from "../utils/axiosClient";
|
import { api } from "../utils/axiosClient";
|
||||||
|
|
||||||
const AuthRepository = {
|
const AuthRepository = {
|
||||||
login: (data) => api.post("/api/auth/login", data),
|
// Public routes (no auth token required)
|
||||||
refreshToken: (data) => api.post("/api/auth/refresh-token", data),
|
login: (data) => api.postPublic("/api/auth/login", data),
|
||||||
|
refreshToken: (data) => api.postPublic("/api/auth/refresh-token", data),
|
||||||
|
forgotPassword: (data) => api.postPublic("/api/auth/forgot-password", data),
|
||||||
|
resetPassword: (data) => api.postPublic("/api/auth/reset-password", data),
|
||||||
|
sendOTP: (data) => api.postPublic("/api/auth/send-otp", data),
|
||||||
|
verifyOTP: (data) => api.postPublic("/api/auth/login-otp", data),
|
||||||
|
register: (data) => api.postPublic("/api/auth/register", data),
|
||||||
|
sendMail: (data) => api.postPublic("/api/auth/sendmail", data),
|
||||||
|
|
||||||
|
// Protected routes (require auth token)
|
||||||
logout: (data) => api.post("/api/auth/logout", data),
|
logout: (data) => api.post("/api/auth/logout", data),
|
||||||
profile: () => api.get(`/api/user/profile`),
|
profile: () => api.get("/api/user/profile"),
|
||||||
register: (data) => api.post("api/auth/register", data),
|
|
||||||
resetPassword: (data) => api.post("/api/auth/reset-password", data),
|
|
||||||
forgotPassword: (data) => api.post("/api/auth/forgot-password", data),
|
|
||||||
sendMail: (data) => api.post("/api/auth/sendmail", data),
|
|
||||||
changepassword: (data) => api.post("/api/auth/change-password", data),
|
changepassword: (data) => api.post("/api/auth/change-password", data),
|
||||||
sendOTP: ( data ) => api.post( 'api/auth/send-otp', data ),
|
|
||||||
verifyOTP:(data)=>api.post("api/auth/login-otp",data)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AuthRepository;
|
export default AuthRepository;
|
||||||
|
@ -5,18 +5,22 @@ import showToast from "../services/toastService";
|
|||||||
const base_Url = process.env.VITE_BASE_URL;
|
const base_Url = process.env.VITE_BASE_URL;
|
||||||
// const base_Url = "https://api.marcoaiot.com";
|
// const base_Url = "https://api.marcoaiot.com";
|
||||||
export const axiosClient = axios.create({
|
export const axiosClient = axios.create({
|
||||||
baseURL: base_Url, // Your Web API URL
|
baseURL: base_Url,
|
||||||
withCredentials: false, // Required if the API uses cookies
|
withCredentials: false,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json", // Specify the content type
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Auto retry failed requests (e.g., network issues)
|
||||||
axiosRetry(axiosClient, { retries: 3 });
|
axiosRetry(axiosClient, { retries: 3 });
|
||||||
|
|
||||||
// Request interceptor to add Bearer token
|
// Request Interceptor — Add Bearer token if required
|
||||||
axiosClient.interceptors.request.use(
|
axiosClient.interceptors.request.use(
|
||||||
async (config) => {
|
async (config) => {
|
||||||
if (config.authRequired) {
|
const requiresAuth = config.authRequired !== false; // default to true
|
||||||
|
|
||||||
|
if (requiresAuth) {
|
||||||
const token = localStorage.getItem("jwtToken");
|
const token = localStorage.getItem("jwtToken");
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers["Authorization"] = `Bearer ${token}`;
|
config.headers["Authorization"] = `Bearer ${token}`;
|
||||||
@ -25,25 +29,24 @@ axiosClient.interceptors.request.use(
|
|||||||
config._retry = false;
|
config._retry = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error) => Promise.reject(error)
|
(error) => Promise.reject(error)
|
||||||
);
|
);
|
||||||
|
|
||||||
// // Response interceptor to handle responses globally (optional)
|
// 🔄 Response Interceptor — Handle 401, refresh token, etc.
|
||||||
// Add an interceptor to handle expired tokens
|
|
||||||
axiosClient.interceptors.response.use(
|
axiosClient.interceptors.response.use(
|
||||||
(response) => response,
|
(response) => response,
|
||||||
|
|
||||||
async (error) => {
|
async (error) => {
|
||||||
const originalRequest = error.config;
|
const originalRequest = error.config;
|
||||||
|
|
||||||
// Prevent infinite loop
|
// Skip retry for public requests or already retried ones
|
||||||
if (!originalRequest || originalRequest._retry) {
|
if (!originalRequest || originalRequest._retry || originalRequest.authRequired === false) {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only show one toast per request
|
// Avoid showing multiple toasts
|
||||||
if (!originalRequest._toastShown) {
|
if (!originalRequest._toastShown) {
|
||||||
originalRequest._toastShown = true;
|
originalRequest._toastShown = true;
|
||||||
|
|
||||||
@ -59,7 +62,6 @@ axiosClient.interceptors.response.use(
|
|||||||
const isRefreshRequest = error.config.url.includes("refresh-token");
|
const isRefreshRequest = error.config.url.includes("refresh-token");
|
||||||
|
|
||||||
if (status === 401 && !isRefreshRequest) {
|
if (status === 401 && !isRefreshRequest) {
|
||||||
// Mark as retried to avoid loops
|
|
||||||
originalRequest._retry = true;
|
originalRequest._retry = true;
|
||||||
|
|
||||||
const refreshToken = localStorage.getItem("refreshToken");
|
const refreshToken = localStorage.getItem("refreshToken");
|
||||||
@ -70,7 +72,7 @@ axiosClient.interceptors.response.use(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Refresh token
|
// Refresh token call
|
||||||
const res = await axiosClient.post("/api/Auth/refresh-token", {
|
const res = await axiosClient.post("/api/Auth/refresh-token", {
|
||||||
token: localStorage.getItem("jwtToken"),
|
token: localStorage.getItem("jwtToken"),
|
||||||
refreshToken,
|
refreshToken,
|
||||||
@ -78,15 +80,13 @@ axiosClient.interceptors.response.use(
|
|||||||
|
|
||||||
const { token, refreshToken: newRefreshToken } = res.data.data;
|
const { token, refreshToken: newRefreshToken } = res.data.data;
|
||||||
|
|
||||||
// Save new tokens
|
// Save updated tokens
|
||||||
localStorage.setItem("jwtToken", token);
|
localStorage.setItem("jwtToken", token);
|
||||||
localStorage.setItem("refreshToken", newRefreshToken);
|
localStorage.setItem("refreshToken", newRefreshToken);
|
||||||
|
|
||||||
// Set Authorization header
|
// Retry original request with new token
|
||||||
originalRequest.headers["Authorization"] = `Bearer ${token}`;
|
originalRequest.headers["Authorization"] = `Bearer ${token}`;
|
||||||
|
return axiosClient(originalRequest);
|
||||||
// Optional: Instead of retrying, you may choose to reload app or go to home
|
|
||||||
return axiosClient(originalRequest); // <== only retry once
|
|
||||||
} catch (refreshError) {
|
} catch (refreshError) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
return Promise.reject(refreshError);
|
return Promise.reject(refreshError);
|
||||||
@ -96,11 +96,12 @@ axiosClient.interceptors.response.use(
|
|||||||
showToast("An unknown error occurred.", "error");
|
showToast("An unknown error occurred.", "error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Generic API Call
|
// Generic API function
|
||||||
const apiRequest = async (method, url, data = {}, config = {}) => {
|
const apiRequest = async (method, url, data = {}, config = {}) => {
|
||||||
try {
|
try {
|
||||||
const response = await axiosClient({
|
const response = await axiosClient({
|
||||||
@ -116,15 +117,16 @@ const apiRequest = async (method, url, data = {}, config = {}) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Exported API wrapper
|
||||||
export const api = {
|
export const api = {
|
||||||
// For public routes like login, set authRequired: false
|
// Public routes (no token required)
|
||||||
postPublic: (url, data = {}, customHeaders = {}) =>
|
postPublic: (url, data = {}, customHeaders = {}) =>
|
||||||
apiRequest("post", url, data, {
|
apiRequest("post", url, data, {
|
||||||
headers: { ...customHeaders },
|
headers: { ...customHeaders },
|
||||||
authRequired: false,
|
authRequired: false,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// For protected routes, authRequired defaults to true
|
// Authenticated routes
|
||||||
get: (url, params = {}, customHeaders = {}) =>
|
get: (url, params = {}, customHeaders = {}) =>
|
||||||
apiRequest("get", url, params, {
|
apiRequest("get", url, params, {
|
||||||
headers: { ...customHeaders },
|
headers: { ...customHeaders },
|
||||||
@ -149,7 +151,8 @@ export const api = {
|
|||||||
authRequired: true,
|
authRequired: true,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
//export default axiosClient;
|
|
||||||
|
// Redirect helper
|
||||||
function redirectToLogin() {
|
function redirectToLogin() {
|
||||||
window.location.href = "/auth/login";
|
window.location.href = "/auth/login";
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user