'use client'; import { useState, useEffect } from 'react'; import { settingsStore } from '@/lib/store/settings-store'; import { Lock } from 'lucide-react'; const SESSION_KEY = 'kvideo-settings-unlocked'; export function SettingsPasswordGate({ children }: { children: React.ReactNode }) { const [isLocked, setIsLocked] = useState(true); const [password, setPassword] = useState(''); const [error, setError] = useState(false); const [isClient, setIsClient] = useState(false); const [hasEnvSettingsPassword, setHasEnvSettingsPassword] = useState(false); const [isValidating, setIsValidating] = useState(false); useEffect(() => { let mounted = true; const init = async () => { const settings = settingsStore.getSettings(); const sessionUnlocked = sessionStorage.getItem(SESSION_KEY) === 'true'; const isProtected = (settings.settingsPasswordEnabled && settings.settingsPasswords.length > 0); const localLocked = isProtected && !sessionUnlocked; if (mounted) { setIsLocked(localLocked); setIsClient(true); } // Fetch remote config for env settings password try { const res = await fetch('/api/config'); if (!res.ok) throw new Error('Failed to fetch config'); const data = await res.json(); if (mounted) { setHasEnvSettingsPassword(data.hasEnvSettingsPassword); const isProtectedNow = (settings.settingsPasswordEnabled && settings.settingsPasswords.length > 0) || data.hasEnvSettingsPassword; setIsLocked(isProtectedNow && !sessionUnlocked); } } catch (e) { console.error('SettingsPasswordGate init failed:', e); } }; init(); return () => { mounted = false; }; }, []); // Subscribe to settings changes (auto-unlock if all passwords removed) useEffect(() => { const handleSettingsUpdate = () => { const settings = settingsStore.getSettings(); const sessionUnlocked = sessionStorage.getItem(SESSION_KEY) === 'true'; const isProtected = (settings.settingsPasswordEnabled && settings.settingsPasswords.length > 0) || hasEnvSettingsPassword; if (!isProtected) { setIsLocked(false); } else if (!sessionUnlocked) { setIsLocked(true); } }; const unsubscribe = settingsStore.subscribe(handleSettingsUpdate); return () => unsubscribe(); }, [hasEnvSettingsPassword]); const handleUnlock = async (e: React.FormEvent) => { e.preventDefault(); setIsValidating(true); const settings = settingsStore.getSettings(); const setUnlocked = () => { sessionStorage.setItem(SESSION_KEY, 'true'); setIsLocked(false); setError(false); setIsValidating(false); }; // Check local settings passwords first if (settings.settingsPasswords.includes(password)) { setUnlocked(); return; } // Then check env password via API if (hasEnvSettingsPassword) { try { const res = await fetch('/api/config', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ password, type: 'settings' }), }); const data = await res.json(); if (data.valid) { setUnlocked(); return; } } catch { // API error } } // Password didn't match setError(true); setIsValidating(false); const form = document.getElementById('settings-password-form'); form?.classList.add('animate-shake'); setTimeout(() => form?.classList.remove('animate-shake'), 500); }; if (!isClient) return null; if (!isLocked) { return <>{children}>; } return (