Features: - Image generation (OpenAI, Gemini, Leonardo, Bria, Stability, Flux) - Nano Banana iterative editing - Video generation and upscaling - Audio TTS, STT, sound effects (ElevenLabs) - Text prompt studio and alt text - User authentication with JWT/cookies - Admin panel with voice management - Job queue with Celery - PostgreSQL + Redis backend - Next.js 15 + FastAPI architecture 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
59 lines
1.5 KiB
TypeScript
59 lines
1.5 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import { useStore } from '@/lib/store';
|
|
import { isAdmin } from '@/lib/auth';
|
|
import { ShieldX, Loader2 } from 'lucide-react';
|
|
|
|
interface AdminGuardProps {
|
|
children: React.ReactNode;
|
|
fallback?: React.ReactNode;
|
|
}
|
|
|
|
export default function AdminGuard({ children, fallback }: AdminGuardProps) {
|
|
const { user } = useStore();
|
|
const router = useRouter();
|
|
const [checking, setChecking] = useState(true);
|
|
|
|
useEffect(() => {
|
|
// Small delay to allow store to hydrate
|
|
const timer = setTimeout(() => {
|
|
setChecking(false);
|
|
}, 100);
|
|
|
|
return () => clearTimeout(timer);
|
|
}, []);
|
|
|
|
if (checking) {
|
|
return (
|
|
<div className="flex items-center justify-center h-64">
|
|
<Loader2 className="w-8 h-8 text-forge-yellow animate-spin" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!isAdmin(user as any)) {
|
|
if (fallback) {
|
|
return <>{fallback}</>;
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-col items-center justify-center h-64 text-center">
|
|
<ShieldX className="w-16 h-16 text-red-400 mb-4" />
|
|
<h2 className="text-xl font-bold text-white mb-2">Access Denied</h2>
|
|
<p className="text-gray-400 mb-6">
|
|
You don't have permission to access this area.
|
|
</p>
|
|
<button
|
|
onClick={() => router.push('/')}
|
|
className="btn-secondary"
|
|
>
|
|
Go to Dashboard
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return <>{children}</>;
|
|
}
|