feat: implement auth flow and app initialization
This commit is contained in:
30
src/guards/AuthGuard.tsx
Normal file
30
src/guards/AuthGuard.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
'use client';
|
||||
|
||||
import { useAppStore } from '@/store/app.store';
|
||||
import { useAuthStore } from '@/store/auth.store';
|
||||
import { ROUTES } from '@/utils/routes';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export function AuthGuard({ children }: { children: ReactNode }) {
|
||||
const router = useRouter();
|
||||
const accessToken = useAuthStore((state) => state.accessToken);
|
||||
const isInitialized = useAppStore((state) => state.isInitialized);
|
||||
const user = useAppStore((state) => state.user);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isInitialized) return;
|
||||
|
||||
if (!accessToken) {
|
||||
console.debug('[auth] guard:redirect-login');
|
||||
router.replace(ROUTES.LOGIN);
|
||||
}
|
||||
}, [accessToken, isInitialized, router]);
|
||||
|
||||
if (!isInitialized || !accessToken || !user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
26
src/guards/GuestGuard.tsx
Normal file
26
src/guards/GuestGuard.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
'use client';
|
||||
|
||||
import { useAppStore } from '@/store/app.store';
|
||||
import { useAuthStore } from '@/store/auth.store';
|
||||
import { ROUTES } from '@/utils/routes';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export function GuestGuard({ children }: { children: ReactNode }) {
|
||||
const router = useRouter();
|
||||
const accessToken = useAuthStore((state) => state.accessToken);
|
||||
const isInitialized = useAppStore((state) => state.isInitialized);
|
||||
const user = useAppStore((state) => state.user);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialized && accessToken && user) {
|
||||
console.debug('[auth] guest-guard:redirect-dashboard');
|
||||
router.replace(ROUTES.DASHBOARD);
|
||||
}
|
||||
}, [accessToken, isInitialized, router, user]);
|
||||
|
||||
if (!isInitialized || (accessToken && user)) return null;
|
||||
|
||||
return children;
|
||||
}
|
||||
29
src/guards/PermissionGuard.tsx
Normal file
29
src/guards/PermissionGuard.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
'use client';
|
||||
|
||||
import { useAppStore } from '@/store/app.store';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
type PermissionGuardProps = {
|
||||
children: ReactNode;
|
||||
permissions: string[];
|
||||
mode?: 'all' | 'any';
|
||||
fallback?: ReactNode;
|
||||
};
|
||||
|
||||
export function PermissionGuard({
|
||||
children,
|
||||
permissions,
|
||||
mode = 'all',
|
||||
fallback = null,
|
||||
}: PermissionGuardProps) {
|
||||
const grantedPermissions = useAppStore((state) => state.permissions);
|
||||
const normalizedPermissions = grantedPermissions.map((permission) => permission.toLowerCase());
|
||||
const hasPermission =
|
||||
mode === 'all'
|
||||
? permissions.every((permission) => normalizedPermissions.includes(permission.toLowerCase()))
|
||||
: permissions.some((permission) => normalizedPermissions.includes(permission.toLowerCase()));
|
||||
|
||||
if (!hasPermission) return fallback;
|
||||
|
||||
return children;
|
||||
}
|
||||
3
src/guards/index.ts
Normal file
3
src/guards/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './AuthGuard';
|
||||
export * from './GuestGuard';
|
||||
export * from './PermissionGuard';
|
||||
Reference in New Issue
Block a user