feat: implement auth flow and app initialization

This commit is contained in:
2026-06-15 18:41:27 +05:30
parent 9de65d0ce6
commit 8d4ff49633
29 changed files with 551 additions and 535 deletions

30
src/guards/AuthGuard.tsx Normal file
View 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
View 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;
}

View 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
View File

@@ -0,0 +1,3 @@
export * from './AuthGuard';
export * from './GuestGuard';
export * from './PermissionGuard';