fix issues
This commit is contained in:
@@ -33,14 +33,17 @@ export function AuthProvider({ initialSession = null, children }: AuthProviderPr
|
||||
const router = useRouter();
|
||||
const { sessionService, authService } = useServices();
|
||||
const [session, setSession] = useState<SessionViewModel | null>(initialSession);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const fetchSession = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const current = await sessionService.getSession();
|
||||
setSession(current);
|
||||
} catch {
|
||||
setSession(null);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [sessionService]);
|
||||
|
||||
|
||||
@@ -32,19 +32,14 @@ export class AuthorizationBlocker extends Blocker {
|
||||
this.currentSession = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user can execute (access admin area)
|
||||
*/
|
||||
canExecute(): boolean {
|
||||
return this.getReason() === 'enabled';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current block reason
|
||||
*/
|
||||
getReason(): AuthorizationBlockReason {
|
||||
if (!this.currentSession) {
|
||||
return 'loading';
|
||||
// Session is null - this means unauthenticated (not loading)
|
||||
// Loading state is handled by AuthContext
|
||||
return 'unauthenticated';
|
||||
}
|
||||
|
||||
if (!this.currentSession.isAuthenticated) {
|
||||
@@ -66,6 +61,14 @@ export class AuthorizationBlocker extends Blocker {
|
||||
return 'enabled'; // Allow access for demo purposes
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user can execute (access admin area)
|
||||
*/
|
||||
canExecute(): boolean {
|
||||
const reason = this.getReason();
|
||||
return reason === 'enabled';
|
||||
}
|
||||
|
||||
/**
|
||||
* Block access (for testing/demo purposes)
|
||||
*/
|
||||
@@ -88,14 +91,12 @@ export class AuthorizationBlocker extends Blocker {
|
||||
const reason = this.getReason();
|
||||
|
||||
switch (reason) {
|
||||
case 'loading':
|
||||
return 'Loading user data...';
|
||||
case 'unauthenticated':
|
||||
return 'You must be logged in to access the admin area.';
|
||||
return 'You must be logged in to access this area.';
|
||||
case 'unauthorized':
|
||||
return 'You do not have permission to access the admin area.';
|
||||
return 'You do not have permission to access this area.';
|
||||
case 'insufficient_role':
|
||||
return `Admin access requires one of: ${this.requiredRoles.join(', ')}`;
|
||||
return `Access requires one of: ${this.requiredRoles.join(', ')}`;
|
||||
case 'enabled':
|
||||
return 'Access granted';
|
||||
default:
|
||||
|
||||
@@ -62,7 +62,9 @@ export class AuthGateway {
|
||||
return {
|
||||
canAccess: this.canAccess(),
|
||||
reason: this.blocker.getBlockMessage(),
|
||||
isLoading: reason === 'loading',
|
||||
// Only show loading if auth context is still loading
|
||||
// If auth context is done but session is null, that's unauthenticated (not loading)
|
||||
isLoading: this.authContext.loading,
|
||||
isAuthenticated: this.authContext.session?.isAuthenticated ?? false,
|
||||
};
|
||||
}
|
||||
@@ -137,4 +139,11 @@ export class AuthGateway {
|
||||
getBlockReason(): string {
|
||||
return this.blocker.getReason();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user-friendly block message
|
||||
*/
|
||||
getBlockMessage(): string {
|
||||
return this.blocker.getBlockMessage();
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import { ReactNode, useEffect, useState } from 'react';
|
||||
import { ReactNode, useEffect, useState, useMemo } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useAuth } from '@/lib/auth/AuthContext';
|
||||
import { AuthGateway, AuthGatewayConfig } from './AuthGateway';
|
||||
@@ -51,41 +51,50 @@ export function RouteGuard({
|
||||
const router = useRouter();
|
||||
const authContext = useAuth();
|
||||
const [gateway] = useState(() => new AuthGateway(authContext, config));
|
||||
const [accessState, setAccessState] = useState(gateway.getAccessState());
|
||||
const [isChecking, setIsChecking] = useState(true);
|
||||
|
||||
// Update gateway when auth context changes
|
||||
useEffect(() => {
|
||||
// Calculate access state
|
||||
const accessState = useMemo(() => {
|
||||
gateway.refresh();
|
||||
setAccessState(gateway.getAccessState());
|
||||
return {
|
||||
canAccess: gateway.canAccess(),
|
||||
reason: gateway.getBlockMessage(),
|
||||
redirectPath: gateway.getUnauthorizedRedirectPath(),
|
||||
};
|
||||
}, [authContext.session, authContext.loading, gateway]);
|
||||
|
||||
// Handle redirects
|
||||
// Handle the loading state and redirects
|
||||
useEffect(() => {
|
||||
if (!accessState.canAccess && !accessState.isLoading) {
|
||||
if (config.redirectOnUnauthorized !== false) {
|
||||
const redirectPath = gateway.getUnauthorizedRedirectPath();
|
||||
|
||||
// Use a small delay to show unauthorized message briefly
|
||||
const timer = setTimeout(() => {
|
||||
router.push(redirectPath);
|
||||
}, 500);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
// If we're loading, stay in checking state
|
||||
if (authContext.loading) {
|
||||
setIsChecking(true);
|
||||
return;
|
||||
}
|
||||
}, [accessState, gateway, router, config.redirectOnUnauthorized]);
|
||||
|
||||
// Done loading, can exit checking state
|
||||
setIsChecking(false);
|
||||
|
||||
// If we can't access and should redirect, do it
|
||||
if (!accessState.canAccess && config.redirectOnUnauthorized !== false) {
|
||||
const timer = setTimeout(() => {
|
||||
router.push(accessState.redirectPath);
|
||||
}, 500);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [authContext.loading, accessState.canAccess, accessState.redirectPath, config.redirectOnUnauthorized, router]);
|
||||
|
||||
// Show loading state
|
||||
if (accessState.isLoading) {
|
||||
if (isChecking || authContext.loading) {
|
||||
return loadingComponent || (
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<LoadingState message="Loading..." className="min-h-screen" />
|
||||
<LoadingState message="Verifying authentication..." className="min-h-screen" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Show unauthorized state
|
||||
if (!accessState.canAccess) {
|
||||
// Show unauthorized state (only if not redirecting)
|
||||
if (!accessState.canAccess && config.redirectOnUnauthorized === false) {
|
||||
return unauthorizedComponent || (
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<div className="bg-iron-gray p-8 rounded-lg border border-charcoal-outline max-w-md text-center">
|
||||
@@ -102,6 +111,15 @@ export function RouteGuard({
|
||||
);
|
||||
}
|
||||
|
||||
// Show redirecting state
|
||||
if (!accessState.canAccess && config.redirectOnUnauthorized !== false) {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<LoadingState message="Redirecting to login..." className="min-h-screen" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Render protected content
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user