inogen/app/hooks/use-route-guard.tsx

136 lines
3.4 KiB
TypeScript

import { useEffect } from "react";
import { useAuth } from "~/contexts/auth-context";
import { useNavigate, useLocation } from "react-router";
import toast from "react-hot-toast";
interface UseRouteGuardOptions {
requireAuth?: boolean;
redirectTo?: string;
showToast?: boolean;
}
export function useRouteGuard(options: UseRouteGuardOptions = {}) {
const {
requireAuth = true,
redirectTo = "/login",
showToast = true,
} = options;
const { isAuthenticated, isLoading, token, user } = useAuth();
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
// Don't do anything while loading
if (isLoading) return;
// If authentication is required but user is not authenticated
if (requireAuth && !isAuthenticated) {
if (showToast) {
toast.error("برای دسترسی به این صفحه باید وارد شوید");
}
// Save the current location so we can redirect back after login
const currentPath = location.pathname + location.search;
const loginPath =
redirectTo === "/login"
? `${redirectTo}?returnTo=${encodeURIComponent(currentPath)}`
: redirectTo;
navigate(loginPath, { replace: true });
return;
}
// If authentication is required but token is missing/invalid
if (requireAuth && isAuthenticated && !token) {
if (showToast) {
toast.error("جلسه کاری شما منقضی شده است. لطفاً دوباره وارد شوید");
}
// Clear any stored authentication data
localStorage.removeItem("auth_user");
localStorage.removeItem("auth_token");
navigate("/login", { replace: true });
return;
}
// If user is authenticated but trying to access login page
if (!requireAuth && isAuthenticated && location.pathname === "/login") {
navigate("/dashboard", { replace: true });
return;
}
}, [
isLoading,
isAuthenticated,
token,
requireAuth,
redirectTo,
showToast,
navigate,
location.pathname,
location.search,
]);
return {
isAuthenticated,
isLoading,
token,
user,
canAccess: requireAuth ? isAuthenticated && !!token?.accessToken : true,
};
}
// Helper hook for protected routes
export function useProtectedRoute(redirectTo?: string) {
return useRouteGuard({
requireAuth: true,
redirectTo,
showToast: true,
});
}
// Helper hook for public routes (like login)
export function usePublicRoute() {
return useRouteGuard({
requireAuth: false,
showToast: false,
});
}
// Hook to check if user has specific permissions
export function usePermissionGuard(
requiredPermissions: string[] = [],
userPermissions: string[] = [],
) {
const { isAuthenticated, token } = useAuth();
const navigate = useNavigate();
const hasPermission = requiredPermissions.every((permission) =>
userPermissions.includes(permission),
);
useEffect(() => {
if (
isAuthenticated &&
token?.accessToken &&
!hasPermission &&
requiredPermissions.length > 0
) {
toast.error("شما دسترسی لازم برای این صفحه را ندارید");
navigate("/dashboard", { replace: true });
}
}, [
isAuthenticated,
token,
hasPermission,
requiredPermissions.length,
navigate,
]);
return {
hasPermission,
canAccess: isAuthenticated && !!token?.accessToken && hasPermission,
};
}