246 lines
7.8 KiB
TypeScript
246 lines
7.8 KiB
TypeScript
import Cookies from "js-cookie";
|
|
import { toast } from "sonner";
|
|
import {
|
|
AuthCookies,
|
|
ProfileData,
|
|
LoginFormData,
|
|
NavigationConfig
|
|
} from "@/types/auth";
|
|
import { getCookiesDecrypt, setCookiesEncrypt } from "@/lib/utils";
|
|
|
|
// Navigation configuration based on user roles
|
|
export const NAVIGATION_CONFIG: NavigationConfig[] = [
|
|
{ roleId: 2, path: "/in/dashboard/executive", label: "Executive Dashboard" },
|
|
{ roleId: 3, path: "/in/dashboard", label: "Dashboard" },
|
|
{ roleId: 4, path: "/in/dashboard", label: "Dashboard" },
|
|
{ roleId: 9, path: "/in/supervisor/ticketing/all", label: "Ticketing" },
|
|
{ roleId: 10, path: "/in/dashboard", label: "Dashboard" },
|
|
{ roleId: 11, path: "/in/dashboard", label: "Dashboard" },
|
|
{ roleId: 12, path: "/in/dashboard", label: "Dashboard" },
|
|
{ roleId: 13, path: "/in/dashboard", label: "Dashboard" },
|
|
{ roleId: 14, path: "/in/dashboard", label: "Dashboard" },
|
|
{ roleId: 15, path: "/in/dashboard", label: "Dashboard" },
|
|
{ roleId: 18, path: "/in/dashboard/executive-data", label: "Executive Data Dashboard" },
|
|
{ roleId: 19, path: "/in/dashboard", label: "Dashboard" },
|
|
];
|
|
|
|
// Cookie management utilities
|
|
export const setAuthCookies = (accessToken: string, refreshToken: string): void => {
|
|
const dateTime = new Date();
|
|
const newTime = dateTime.getTime() + 10 * 60 * 1000; // 10 minutes
|
|
|
|
Cookies.set("access_token", accessToken, { expires: 1 });
|
|
Cookies.set("refresh_token", refreshToken, { expires: 1 });
|
|
Cookies.set("time_refresh", new Date(newTime).toISOString(), { expires: 1 });
|
|
Cookies.set("is_first_login", String(true), { secure: true, sameSite: "strict" });
|
|
};
|
|
|
|
export const setProfileCookies = (profile: ProfileData): void => {
|
|
Cookies.set("home_path", profile.homePath || "", { expires: 1 });
|
|
Cookies.set("profile_picture", profile.profilePictureUrl || "", { expires: 1 });
|
|
Cookies.set("state", profile.userLevel?.name || "", { expires: 1 });
|
|
Cookies.set("state-prov", profile.userLevel?.province?.provName || "", { expires: 1 });
|
|
|
|
setCookiesEncrypt("uie", profile.id, { expires: 1 });
|
|
setCookiesEncrypt("urie", profile.roleId.toString(), { expires: 1 });
|
|
setCookiesEncrypt("urne", profile.role?.name || "", { expires: 1 });
|
|
setCookiesEncrypt("ulie", profile.userLevel?.id.toString() || "", { expires: 1 });
|
|
setCookiesEncrypt("uplie", profile.userLevel?.parentLevelId?.toString() || "", { expires: 1 });
|
|
setCookiesEncrypt("ulne", profile.userLevel?.levelNumber.toString() || "", { expires: 1 });
|
|
setCookiesEncrypt("ufne", profile.fullname, { expires: 1 });
|
|
setCookiesEncrypt("ulnae", profile.userLevel?.name || "", { expires: 1 });
|
|
setCookiesEncrypt("uinse", profile.instituteId || "", { expires: 1 });
|
|
|
|
Cookies.set("status", "login", { expires: 1 });
|
|
};
|
|
|
|
export const clearAllCookies = (): void => {
|
|
Object.keys(Cookies.get()).forEach((cookieName) => {
|
|
Cookies.remove(cookieName);
|
|
});
|
|
};
|
|
|
|
export const getAuthCookies = (): Partial<AuthCookies> => {
|
|
return {
|
|
access_token: Cookies.get("access_token"),
|
|
refresh_token: Cookies.get("refresh_token"),
|
|
time_refresh: Cookies.get("time_refresh"),
|
|
is_first_login: Cookies.get("is_first_login"),
|
|
home_path: Cookies.get("home_path"),
|
|
profile_picture: Cookies.get("profile_picture"),
|
|
state: Cookies.get("state"),
|
|
"state-prov": Cookies.get("state-prov"),
|
|
uie: getCookiesDecrypt("uie"),
|
|
urie: getCookiesDecrypt("urie"),
|
|
urne: getCookiesDecrypt("urne"),
|
|
ulie: getCookiesDecrypt("ulie"),
|
|
uplie: getCookiesDecrypt("uplie"),
|
|
ulne: getCookiesDecrypt("ulne"),
|
|
ufne: getCookiesDecrypt("ufne"),
|
|
ulnae: getCookiesDecrypt("ulnae"),
|
|
uinse: getCookiesDecrypt("uinse"),
|
|
status: Cookies.get("status"),
|
|
};
|
|
};
|
|
|
|
// User validation utilities
|
|
export const isUserEligible = (profile: ProfileData): boolean => {
|
|
return !(
|
|
profile.isInternational ||
|
|
!profile.isActive ||
|
|
profile.isDelete
|
|
);
|
|
};
|
|
|
|
export const isProtectedRole = (roleId: number): boolean => {
|
|
const protectedRoles = [2, 3, 4, 9, 10, 11, 12, 18, 19];
|
|
return protectedRoles.includes(roleId);
|
|
};
|
|
|
|
export const isSpecialLevel = (userLevelId: number, parentLevelId?: number): boolean => {
|
|
return userLevelId === 794 || parentLevelId === 761;
|
|
};
|
|
|
|
// Navigation utilities
|
|
export const getNavigationPath = (roleId: number, userLevelId?: number, parentLevelId?: number): string => {
|
|
const config = NAVIGATION_CONFIG.find(nav => nav.roleId === roleId);
|
|
|
|
console.log("Navigation Config : ", config);
|
|
|
|
if (config) {
|
|
// Special handling for role 2 with specific level conditions
|
|
if (roleId === 2 && userLevelId && parentLevelId && isSpecialLevel(userLevelId, parentLevelId)) {
|
|
return "/in/dashboard";
|
|
}
|
|
return config.path;
|
|
}
|
|
|
|
return "/"; // Default fallback
|
|
};
|
|
|
|
// Error handling utilities
|
|
export const handleAuthError = (error: any, defaultMessage: string = "Authentication failed"): string => {
|
|
if (typeof error === "string") {
|
|
return error;
|
|
}
|
|
|
|
if (error?.message) {
|
|
return error.message;
|
|
}
|
|
|
|
if (error?.response?.data?.message) {
|
|
return error.response.data.message;
|
|
}
|
|
|
|
return defaultMessage;
|
|
};
|
|
|
|
export const showAuthError = (error: any, defaultMessage: string = "Authentication failed"): void => {
|
|
const message = handleAuthError(error, defaultMessage);
|
|
toast.error(message);
|
|
};
|
|
|
|
export const showAuthSuccess = (message: string): void => {
|
|
toast.success(message);
|
|
};
|
|
|
|
// Form validation utilities
|
|
export const validateEmail = (email: string): boolean => {
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
return emailRegex.test(email);
|
|
};
|
|
|
|
export const validatePassword = (password: string): { isValid: boolean; errors: string[] } => {
|
|
const errors: string[] = [];
|
|
|
|
if (password.length < 6) {
|
|
errors.push("Password must be at least 6 characters long");
|
|
}
|
|
|
|
if (password.length > 100) {
|
|
errors.push("Password must be less than 100 characters");
|
|
}
|
|
|
|
return {
|
|
isValid: errors.length === 0,
|
|
errors
|
|
};
|
|
};
|
|
|
|
// Loading state utilities
|
|
export const createLoadingState = () => {
|
|
let isLoading = false;
|
|
|
|
return {
|
|
get: () => isLoading,
|
|
set: (loading: boolean) => { isLoading = loading; },
|
|
withLoading: async <T>(fn: () => Promise<T>): Promise<T> => {
|
|
isLoading = true;
|
|
try {
|
|
return await fn();
|
|
} finally {
|
|
isLoading = false;
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
// Constants
|
|
export const AUTH_CONSTANTS = {
|
|
CLIENT_ID: "mediahub-app",
|
|
GRANT_TYPE: "password",
|
|
TOKEN_REFRESH_INTERVAL: 10 * 60 * 1000, // 10 minutes
|
|
MAX_LOGIN_ATTEMPTS: 3,
|
|
LOCKOUT_DURATION: 15 * 60 * 1000, // 15 minutes
|
|
} as const;
|
|
|
|
// Rate limiting utilities
|
|
export class LoginRateLimiter {
|
|
private attempts: Map<string, { count: number; lastAttempt: number }> = new Map();
|
|
|
|
canAttempt(username: string): boolean {
|
|
const userAttempts = this.attempts.get(username);
|
|
|
|
if (!userAttempts) {
|
|
return true;
|
|
}
|
|
|
|
const timeSinceLastAttempt = Date.now() - userAttempts.lastAttempt;
|
|
|
|
if (timeSinceLastAttempt > AUTH_CONSTANTS.LOCKOUT_DURATION) {
|
|
this.attempts.delete(username);
|
|
return true;
|
|
}
|
|
|
|
return userAttempts.count < AUTH_CONSTANTS.MAX_LOGIN_ATTEMPTS;
|
|
}
|
|
|
|
recordAttempt(username: string): void {
|
|
const userAttempts = this.attempts.get(username);
|
|
|
|
if (userAttempts) {
|
|
userAttempts.count++;
|
|
userAttempts.lastAttempt = Date.now();
|
|
} else {
|
|
this.attempts.set(username, { count: 1, lastAttempt: Date.now() });
|
|
}
|
|
}
|
|
|
|
resetAttempts(username: string): void {
|
|
this.attempts.delete(username);
|
|
}
|
|
|
|
getRemainingTime(username: string): number {
|
|
const userAttempts = this.attempts.get(username);
|
|
|
|
if (!userAttempts) {
|
|
return 0;
|
|
}
|
|
|
|
const timeSinceLastAttempt = Date.now() - userAttempts.lastAttempt;
|
|
return Math.max(0, AUTH_CONSTANTS.LOCKOUT_DURATION - timeSinceLastAttempt);
|
|
}
|
|
}
|
|
|
|
// Global rate limiter instance
|
|
export const loginRateLimiter = new LoginRateLimiter();
|