최초커밋

This commit is contained in:
kjs
2025-08-21 09:41:46 +09:00
commit a0e5b57a24
2454 changed files with 1476904 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
"use client";
import { useEffect, ReactNode } from "react";
import { useRouter } from "next/navigation";
import { useAuth } from "@/hooks/useAuth";
import { LoadingSpinner } from "@/components/common/LoadingSpinner";
interface AuthGuardProps {
children: ReactNode;
requireAuth?: boolean;
requireAdmin?: boolean;
redirectTo?: string;
fallback?: ReactNode;
}
/**
* 인증 보호 컴포넌트
* 로그인 상태 및 권한에 따라 접근을 제어
*/
export function AuthGuard({
children,
requireAuth = true,
requireAdmin = false,
redirectTo = "/login",
fallback,
}: AuthGuardProps) {
const { isLoggedIn, isAdmin, loading, error } = useAuth();
const router = useRouter();
useEffect(() => {
if (loading) return;
// 인증이 필요한데 로그인되지 않은 경우
if (requireAuth && !isLoggedIn) {
router.push(redirectTo);
return;
}
// 관리자 권한이 필요한데 관리자가 아닌 경우
if (requireAdmin && !isAdmin) {
router.push("/dashboard"); // 또는 권한 없음 페이지
return;
}
}, [isLoggedIn, isAdmin, loading, requireAuth, requireAdmin, redirectTo, router]);
// 로딩 중
if (loading) {
return (
fallback || (
<div className="flex min-h-screen items-center justify-center">
<LoadingSpinner size="lg" text="인증 정보를 확인하고 있습니다..." />
</div>
)
);
}
// 에러 발생
if (error && requireAuth) {
return (
<div className="flex min-h-screen items-center justify-center">
<div className="text-center">
<div className="mb-2 text-red-500"></div>
<p className="mb-4 text-gray-600">{error}</p>
<button
onClick={() => router.push("/login")}
className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600"
>
</button>
</div>
</div>
);
}
// 인증 조건을 만족하지 않는 경우
if (requireAuth && !isLoggedIn) {
return fallback || null;
}
if (requireAdmin && !isAdmin) {
return (
<div className="flex min-h-screen items-center justify-center">
<div className="text-center">
<div className="mb-2 text-yellow-500">🔒</div>
<p className="mb-4 text-gray-600"> .</p>
<button
onClick={() => router.push("/dashboard")}
className="rounded bg-gray-500 px-4 py-2 text-white hover:bg-gray-600"
>
</button>
</div>
</div>
);
}
// 모든 조건을 만족하는 경우 자식 컴포넌트 렌더링
return <>{children}</>;
}
/**
* 로그인 여부만 확인하는 간단한 가드
*/
export function RequireAuth({ children }: { children: ReactNode }) {
return <AuthGuard requireAuth={true}>{children}</AuthGuard>;
}
/**
* 관리자 권한을 요구하는 가드
*/
export function RequireAdmin({ children }: { children: ReactNode }) {
return (
<AuthGuard requireAuth={true} requireAdmin={true}>
{children}
</AuthGuard>
);
}
export default AuthGuard;