arbret/frontend/app/hooks/useRequireAuth.ts

71 lines
2.2 KiB
TypeScript
Raw Normal View History

2025-12-19 11:08:19 +01:00
"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { useAuth, PermissionType, Permission } from "../auth-context";
interface UseRequireAuthOptions {
/** Required permission to access the page */
requiredPermission?: PermissionType;
/** Required role to access the page */
requiredRole?: string;
/** Where to redirect if permission check fails (defaults to best available page) */
fallbackRedirect?: string;
}
interface UseRequireAuthResult {
user: ReturnType<typeof useAuth>["user"];
isLoading: boolean;
isAuthorized: boolean;
}
/**
* Hook that handles authentication and authorization checks.
* Automatically redirects to login if not authenticated,
* or to a fallback page if missing required permissions.
*/
export function useRequireAuth(options: UseRequireAuthOptions = {}): UseRequireAuthResult {
const { requiredPermission, requiredRole, fallbackRedirect } = options;
const { user, isLoading, hasPermission, hasRole } = useAuth();
const router = useRouter();
const isAuthorized = (() => {
if (!user) return false;
if (requiredPermission && !hasPermission(requiredPermission)) return false;
if (requiredRole && !hasRole(requiredRole)) return false;
return true;
})();
useEffect(() => {
if (isLoading) return;
if (!user) {
router.push("/login");
return;
}
if (!isAuthorized) {
// Redirect to the most appropriate page based on permissions
// Use hasPermission/hasRole directly since they're stable callbacks
const redirect =
fallbackRedirect ??
(hasPermission(Permission.VIEW_ALL_EXCHANGES)
? "/admin/trades"
: hasPermission(Permission.CREATE_EXCHANGE)
? "/exchange"
: "/login");
2025-12-19 11:08:19 +01:00
router.push(redirect);
}
// Note: hasPermission and hasRole are stable callbacks from useAuth,
// so they don't need to be in the dependency array. They're only included
// for clarity and to satisfy exhaustive-deps if needed.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoading, user, isAuthorized, router, fallbackRedirect]);
2025-12-19 11:08:19 +01:00
return {
user,
isLoading,
isAuthorized,
};
}