136 lines
3.7 KiB
TypeScript
136 lines
3.7 KiB
TypeScript
// src/context/AuthContext.tsx
|
|
import { createContext, useContext, useState, useEffect } from "react";
|
|
import type { ReactNode } from "react";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { useToast } from "../components/toast/useToast";
|
|
import { useLoginMutation, UserInfo } from "../redux/services/loginApi";
|
|
|
|
|
|
interface AuthContextType {
|
|
user: UserInfo | null;
|
|
login: (email: string, password: string) => Promise<void>;
|
|
logout: () => void;
|
|
isAuthenticated: boolean;
|
|
token: string | null;
|
|
}
|
|
|
|
const AuthContext = createContext<AuthContextType | undefined>(undefined);
|
|
|
|
export const AuthProvider = ({ children }: { children: ReactNode }) => {
|
|
const [user, setUser] = useState<UserInfo | null>(() => {
|
|
const storedUser = localStorage.getItem("user");
|
|
if (storedUser) {
|
|
try {
|
|
// Try to parse as JSON first
|
|
return JSON.parse(storedUser);
|
|
} catch {
|
|
// If it fails (like "admin" string), return null or handle accordingly
|
|
return null;
|
|
}
|
|
}
|
|
return null;
|
|
});
|
|
|
|
const [token, setToken] = useState<string | null>(() => {
|
|
const storedToken = localStorage.getItem("token");
|
|
return storedToken || null;
|
|
});
|
|
|
|
const navigate = useNavigate();
|
|
const { showToast } = useToast();
|
|
const [loginMutation] = useLoginMutation();
|
|
|
|
const login = async (email: string, password: string) => {
|
|
try {
|
|
const response = await loginMutation({
|
|
email_address: email,
|
|
password
|
|
}).unwrap();
|
|
|
|
if (response.success) {
|
|
// Store token and user info
|
|
localStorage.setItem("token", response.data.access_token);
|
|
localStorage.setItem("user", JSON.stringify(response.data.user_info));
|
|
|
|
setToken(response.data.access_token);
|
|
setUser(response.data.user_info);
|
|
|
|
showToast(
|
|
"Login Successful",
|
|
response.message || "You have been logged in successfully.",
|
|
"success"
|
|
);
|
|
|
|
navigate("/hr/dashboard");
|
|
} else {
|
|
showToast(
|
|
"Login Failed",
|
|
response.message || "Invalid credentials. Please try again.",
|
|
"error"
|
|
);
|
|
}
|
|
} catch (error: any) {
|
|
console.error("Login error:", error);
|
|
|
|
showToast(
|
|
"Error",
|
|
error.data?.message || error.message || "An error occurred during login",
|
|
"error"
|
|
);
|
|
}
|
|
};
|
|
|
|
const logout = () => {
|
|
localStorage.removeItem("token");
|
|
localStorage.removeItem("user");
|
|
setToken(null);
|
|
setUser(null);
|
|
|
|
showToast(
|
|
"Logged Out",
|
|
"You have been logged out successfully.",
|
|
"success"
|
|
);
|
|
|
|
navigate("/login");
|
|
};
|
|
|
|
const isAuthenticated = !!token && !!user;
|
|
|
|
// Optional: Add token expiration check
|
|
useEffect(() => {
|
|
if (token) {
|
|
try {
|
|
// Decode token to check expiration (if needed)
|
|
const payload = JSON.parse(atob(token.split('.')[1]));
|
|
const exp = payload.exp * 1000; // Convert to milliseconds
|
|
const now = Date.now();
|
|
|
|
if (now >= exp) {
|
|
// Token expired
|
|
logout();
|
|
showToast(
|
|
"Session Expired",
|
|
"Your session has expired. Please login again.",
|
|
"error"
|
|
);
|
|
}
|
|
} catch (error) {
|
|
// Invalid token format
|
|
console.error("Error checking token expiration:", error);
|
|
}
|
|
}
|
|
}, [token]);
|
|
|
|
return (
|
|
<AuthContext.Provider value={{ user, login, logout, isAuthenticated, token }}>
|
|
{children}
|
|
</AuthContext.Provider>
|
|
);
|
|
};
|
|
|
|
export const useAuth = () => {
|
|
const ctx = useContext(AuthContext);
|
|
if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
|
|
return ctx;
|
|
}; |