addded remember me functionality
This commit is contained in:
parent
198e31290c
commit
61b209a082
@ -12,6 +12,7 @@ import {
|
||||
closeAuthModal,
|
||||
openAuthModal,
|
||||
} from "../slices/localVariablesSlice.jsx";
|
||||
import { removeSession } from "../utils/authUtils.js";
|
||||
|
||||
export const useTenants = () => {
|
||||
return useQuery({
|
||||
@ -28,18 +29,24 @@ export const useSelectTenant = (onSuccessCallBack) => {
|
||||
const res = await AuthRepository.selectTenant(tenantId);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
||||
onSuccess: (data) => {
|
||||
localStorage.setItem("jwtToken", data.token);
|
||||
localStorage.setItem("refreshToken", data.refreshToken);
|
||||
if (localStorage.getItem("jwtToken")) {
|
||||
localStorage.setItem("jwtToken", data.token);
|
||||
localStorage.setItem("refreshToken", data.refreshToken);
|
||||
} else {
|
||||
sessionStorage.setItem("jwtToken", data.token);
|
||||
sessionStorage.setItem("refreshToken", data.refreshToken);
|
||||
}
|
||||
|
||||
if (onSuccessCallBack) onSuccessCallBack();
|
||||
},
|
||||
|
||||
onError: (error) => {
|
||||
showToast(error.message || "Error while creating project", "error");
|
||||
localStorage.removeItem("jwtToken");
|
||||
localStorage.removeItem("refreshToken")
|
||||
localStorage.removeItem("ctnt")
|
||||
localStorage.removeItem("refreshToken");
|
||||
localStorage.removeItem("ctnt");
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -55,29 +62,26 @@ export const useAuthModal = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const useLogout = ()=>{
|
||||
|
||||
export const useLogout = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
let payload = {refreshToken: localStorage.getItem("refreshToken")}
|
||||
return await AuthRepository.logout(payload);
|
||||
let payload = { refreshToken: localStorage.getItem("refreshToken") || sessionStorage.getItem("refreshToken") };
|
||||
return await AuthRepository.logout(payload);
|
||||
},
|
||||
|
||||
|
||||
onSuccess: (data) => {
|
||||
localStorage.removeItem("jwtToken");
|
||||
localStorage.removeItem("refreshToken");
|
||||
localStorage.removeItem("ctnt");
|
||||
localStorage.clear();
|
||||
window.location.href = "/auth/login";
|
||||
removeSession()
|
||||
|
||||
window.location.href = "/auth/login";
|
||||
if (onSuccessCallBack) onSuccessCallBack();
|
||||
},
|
||||
|
||||
onError: (error) => {
|
||||
showToast(error.message || "Error while creating project", "error");
|
||||
localStorage.removeItem("jwtToken");
|
||||
localStorage.removeItem("refreshToken")
|
||||
localStorage.removeItem("ctnt")
|
||||
removeSession()
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -16,13 +16,13 @@ const LoginPage = () => {
|
||||
|
||||
const loginSchema = IsLoginWithOTP
|
||||
? z.object({
|
||||
username: z.string().trim().email({ message: "Valid email required" }),
|
||||
})
|
||||
username: z.string().trim().email({ message: "Valid email required" }),
|
||||
})
|
||||
: z.object({
|
||||
username: z.string().trim().email({ message: "Valid email required" }),
|
||||
password: z.string().trim().min(1, { message: "Password required" }),
|
||||
rememberMe: z.boolean(),
|
||||
});
|
||||
username: z.string().trim().email({ message: "Valid email required" }),
|
||||
password: z.string().trim().min(1, { message: "Password required" }),
|
||||
rememberMe: z.boolean(),
|
||||
});
|
||||
|
||||
const {
|
||||
register,
|
||||
@ -41,8 +41,13 @@ const LoginPage = () => {
|
||||
password: data.password,
|
||||
};
|
||||
const response = await AuthRepository.login(userCredential);
|
||||
localStorage.setItem("jwtToken", response.data.token);
|
||||
localStorage.setItem("refreshToken", response.data.refreshToken);
|
||||
if (data.rememberMe) {
|
||||
localStorage.setItem("jwtToken", response.data.token);
|
||||
localStorage.setItem("refreshToken", response.data.refreshToken);
|
||||
} else {
|
||||
sessionStorage.setItem("jwtToken", response.data.token);
|
||||
sessionStorage.setItem("refreshToken", response.data.refreshToken);
|
||||
}
|
||||
setLoading(false);
|
||||
navigate("/auth/switch/org");
|
||||
} else {
|
||||
@ -69,6 +74,16 @@ const LoginPage = () => {
|
||||
}
|
||||
}, [IsLoginWithOTP]);
|
||||
|
||||
useEffect(() => {
|
||||
const token =
|
||||
localStorage.getItem("jwtToken") ||
|
||||
sessionStorage.getItem("jwtToken");
|
||||
|
||||
if (token) {
|
||||
navigate("/dashboard", { replace: true });
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="col-12 col-lg-5 col-xl-4 d-flex align-items-center p-4 p-sm-5 bg-gray-60">
|
||||
<div className="w-100" style={{ maxWidth: 420, margin: "0 auto" }}>
|
||||
@ -106,36 +121,6 @@ const LoginPage = () => {
|
||||
{/* Password */}
|
||||
{!IsLoginWithOTP && (
|
||||
<>
|
||||
{/* <div className="mb-3 text-start">
|
||||
<label htmlFor="password" className="form-label">
|
||||
Password
|
||||
</label>
|
||||
<div className="input-group input-group-merge">
|
||||
<input
|
||||
type={hidepass ? "password" : "text"}
|
||||
id="password"
|
||||
className={`form-control ${errors.password ? "is-invalid" : ""
|
||||
}`}
|
||||
placeholder="••••••••"
|
||||
{...register("password")}
|
||||
/>
|
||||
<span
|
||||
className="input-group-text cursor-pointer"
|
||||
onClick={() => setHidepass(!hidepass)}
|
||||
>
|
||||
<i className={`bx ${hidepass ? "bx-hide" : "bx-show"}`}></i>
|
||||
</span>
|
||||
</div>
|
||||
{errors.password && (
|
||||
<div
|
||||
className="invalid-feedback text-start"
|
||||
style={{ fontSize: "12px" }}
|
||||
>
|
||||
{errors.password.message}
|
||||
</div>
|
||||
)}
|
||||
</div> */}
|
||||
|
||||
<div className="mb-3 form-password-toggle text-start">
|
||||
<label htmlFor="password" className="form-label">
|
||||
Password
|
||||
@ -146,8 +131,9 @@ const LoginPage = () => {
|
||||
type={hidepass ? "password" : "text"}
|
||||
autoComplete="new-password"
|
||||
id="password"
|
||||
className={`form-control form-control-xl shadow-none ${errors.password ? "is-invalid" : ""
|
||||
}`}
|
||||
className={`form-control form-control-xl shadow-none ${
|
||||
errors.password ? "is-invalid" : ""
|
||||
}`}
|
||||
name="password"
|
||||
{...register("password")}
|
||||
placeholder="••••••••••••"
|
||||
@ -168,15 +154,16 @@ const LoginPage = () => {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* ✅ Error message */}
|
||||
{errors.password && (
|
||||
<div className="invalid-feedback text-start" style={{ fontSize: "12px" }}>
|
||||
<div
|
||||
className="invalid-feedback text-start"
|
||||
style={{ fontSize: "12px" }}
|
||||
>
|
||||
{errors.password.message}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
{/* Remember Me + Forgot Password */}
|
||||
<div className="mb-3 d-flex justify-content-between align-items-center">
|
||||
<div className="form-check">
|
||||
@ -209,8 +196,8 @@ const LoginPage = () => {
|
||||
{loading
|
||||
? "Please Wait..."
|
||||
: IsLoginWithOTP
|
||||
? "Send OTP"
|
||||
: "Sign In"}
|
||||
? "Send OTP"
|
||||
: "Sign In"}
|
||||
</button>
|
||||
|
||||
{/* Login With OTP Button */}
|
||||
@ -254,4 +241,4 @@ const LoginPage = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginPage;
|
||||
export default LoginPage;
|
||||
|
@ -18,7 +18,7 @@ const TenantSelectionPage = () => {
|
||||
chooseTenant(tenantId);
|
||||
};
|
||||
|
||||
const {mutate:handleLogout,isPending:isLogouting} = useLogout(()=>{})
|
||||
const {mutate:handleLogout,isPending:isLogouting} = useLogout()
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -2,13 +2,69 @@ import React, { useState, useEffect } from "react";
|
||||
import { Navigate, Outlet } from "react-router-dom";
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
import AuthRepository from "../repositories/AuthRepository";
|
||||
import { removeSession } from "../utils/authUtils";
|
||||
|
||||
const isTokenExpired = (token) => {
|
||||
if (!token) return true;
|
||||
try {
|
||||
const { exp } = jwtDecode(token);
|
||||
return exp * 1000 < Date.now();
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
const validateToken = async () => {
|
||||
const token =
|
||||
localStorage.getItem("jwtToken") ||
|
||||
sessionStorage.getItem("jwtToken");
|
||||
|
||||
const refreshTokenStored =
|
||||
localStorage.getItem("refreshToken") ||
|
||||
sessionStorage.getItem("refreshToken");
|
||||
|
||||
if (!refreshTokenStored){
|
||||
console.log("no refrh tokem");
|
||||
removeSession()
|
||||
return false
|
||||
};
|
||||
|
||||
if (isTokenExpired(token)) {
|
||||
return await attemptTokenRefresh(refreshTokenStored);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const attemptTokenRefresh = async (storedRefreshToken) => {
|
||||
try {
|
||||
const currentToken =
|
||||
localStorage.getItem("jwtToken") ||
|
||||
sessionStorage.getItem("jwtToken");
|
||||
|
||||
const response = await AuthRepository.refreshToken({
|
||||
token: currentToken,
|
||||
refreshToken: storedRefreshToken,
|
||||
});
|
||||
|
||||
const { token: newToken, refreshToken: newRefreshToken } = response.data;
|
||||
|
||||
if (localStorage.getItem("jwtToken")) {
|
||||
localStorage.setItem("jwtToken", newToken);
|
||||
localStorage.setItem("refreshToken", newRefreshToken);
|
||||
} else {
|
||||
sessionStorage.setItem("jwtToken", newToken);
|
||||
sessionStorage.setItem("refreshToken", newRefreshToken);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Token refresh failed:", error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const ProtectedRoute = () => {
|
||||
// const isAuthenticated = localStorage.getItem("jwtToken"); // Example authentication check
|
||||
// // const isAuthenticated = true;
|
||||
// isTokenValid();
|
||||
// return isAuthenticated ? <Outlet /> : <Navigate to="/auth/login" />
|
||||
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
@ -21,80 +77,10 @@ const ProtectedRoute = () => {
|
||||
}, []);
|
||||
|
||||
if (isAuthenticated === null) {
|
||||
return <div>Loading...</div>; // Show a loader while checking
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
return isAuthenticated ? <Outlet /> : <Navigate to="/auth/login" replace />;
|
||||
};
|
||||
|
||||
// Function to check if the token is expired
|
||||
const isTokenExpired = (token) => {
|
||||
if (!token) return true;
|
||||
try {
|
||||
const { exp } = jwtDecode(token);
|
||||
return exp * 1000 < Date.now(); // Check if expired
|
||||
} catch (error) {
|
||||
return true; // If decoding fails, treat as expired
|
||||
}
|
||||
};
|
||||
|
||||
// Function to validate and refresh the token if expired
|
||||
export const validateToken = async () => {
|
||||
const token = localStorage.getItem("jwtToken");
|
||||
const refreshTokenStored = localStorage.getItem("refreshToken");
|
||||
// If refresh token is absent, cannot proceed
|
||||
if (!refreshTokenStored) {
|
||||
console.warn("No refresh token available. Redirecting to login.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If access token expired, try to refresh
|
||||
if (isTokenExpired(token)) {
|
||||
return await attemptTokenRefresh(refreshTokenStored);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Attempt to refresh the access token
|
||||
const attemptTokenRefresh = async (storedRefreshToken) => {
|
||||
try {
|
||||
const response = await AuthRepository.refreshToken({
|
||||
token: localStorage.getItem("jwtToken"),
|
||||
refreshToken: storedRefreshToken,
|
||||
});
|
||||
|
||||
localStorage.setItem("jwtToken", response.data.token);
|
||||
localStorage.setItem("refreshToken", response.data.refreshToken);
|
||||
return true;
|
||||
// api
|
||||
// .post("/api/auth/refresh-token", {
|
||||
// token: localStorage.getItem("jwtToken"),
|
||||
// refreshToken: refreshToken,
|
||||
// })
|
||||
// .then((data) => {
|
||||
// localStorage.setItem("jwtToken", response.data.token);
|
||||
// localStorage.setItem("refreshToken", response.data.refreshToken);
|
||||
// return true;
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// console.error("Token refresh failed:", error);
|
||||
// });
|
||||
|
||||
// const refreshToken = localStorage.getItem("refreshToken");
|
||||
// const response = await axiosClient.post(`/api/auth/refresh-token`, {
|
||||
// token: localStorage.getItem("jwtToken"),
|
||||
// refreshToken: refreshToken,
|
||||
// });
|
||||
|
||||
// if (response.status === 200) {
|
||||
// localStorage.setItem("jwtToken", response.data.token);
|
||||
// localStorage.setItem("refreshToken", response.data.refreshToken);
|
||||
// return true;
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error("Token refresh failed:", error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default ProtectedRoute;
|
||||
|
@ -0,0 +1,7 @@
|
||||
export const removeSession = () => {
|
||||
localStorage.removeItem("jwtToken");
|
||||
localStorage.removeItem("refreshToken");
|
||||
sessionStorage.removeItem("jwtToken");
|
||||
sessionStorage.removeItem("refreshToken");
|
||||
localStorage.removeItem("ctnt");
|
||||
};
|
@ -16,14 +16,15 @@ export const axiosClient = axios.create({
|
||||
|
||||
// Auto retry failed requests (e.g., network issues)
|
||||
axiosRetry(axiosClient, { retries: 3 });
|
||||
|
||||
debugger
|
||||
// Request Interceptor — Add Bearer token if required
|
||||
axiosClient.interceptors.request.use(
|
||||
async (config) => {
|
||||
const requiresAuth = config.authRequired !== false; // default to true
|
||||
|
||||
if (requiresAuth) {
|
||||
const token = localStorage.getItem("jwtToken");
|
||||
const token =
|
||||
localStorage.getItem("jwtToken") || sessionStorage.getItem("jwtToken");
|
||||
if (token) {
|
||||
config.headers["Authorization"] = `Bearer ${token}`;
|
||||
config._retry = true;
|
||||
@ -72,7 +73,7 @@ axiosClient.interceptors.response.use(
|
||||
if (status === 401 && !isRefreshRequest) {
|
||||
originalRequest._retry = true;
|
||||
|
||||
const refreshToken = localStorage.getItem("refreshToken");
|
||||
const refreshToken = localStorage.getItem("refreshToken") || sessionStorage.getItem("refreshToken");
|
||||
|
||||
if (
|
||||
!refreshToken ||
|
||||
@ -87,15 +88,20 @@ axiosClient.interceptors.response.use(
|
||||
try {
|
||||
// Refresh token call
|
||||
const res = await axiosClient.post("/api/Auth/refresh-token", {
|
||||
token: localStorage.getItem("jwtToken"),
|
||||
token: localStorage.getItem("jwtToken") || sessionStorage.getItem("jwtToken"),
|
||||
refreshToken,
|
||||
});
|
||||
|
||||
const { token, refreshToken: newRefreshToken } = res.data.data;
|
||||
|
||||
// Save updated tokens
|
||||
localStorage.setItem("jwtToken", token);
|
||||
localStorage.setItem("refreshToken", newRefreshToken);
|
||||
if (localStorage.getItem("jwtToken")) {
|
||||
localStorage.setItem("jwtToken", token);
|
||||
localStorage.setItem("refreshToken", newRefreshToken);
|
||||
} else {
|
||||
sessionStorage.setItem("jwtToken", token);
|
||||
sessionStorage.setItem("refreshToken", newRefreshToken);
|
||||
}
|
||||
|
||||
startSignalR();
|
||||
// Set Authorization header
|
||||
|
Loading…
x
Reference in New Issue
Block a user