Spaces:
Running
Running
| 'use client'; | |
| import { useState, useEffect, ReactNode } from 'react'; | |
| // Simple check - in a real app use a more robust auth method | |
| // We will check against the same server action used for sync to "login" | |
| // But for now, since we only have one password in env, we can just ask for it. | |
| // To keep it simple and consistent with `SyncButton`, we will just store a "loggedIn" state | |
| // after successful validation against the server. | |
| // We need a server action to validate the password without running sync. | |
| // I'll assume we can use `triggerSyncAction` but that triggers a sync. | |
| // Let's create a new action or just use a simple client-side check if we could expose the hash? | |
| // No, never expose secrets. | |
| // Let's add a `verifyPassword` action in `app/actions/auth.ts` first? | |
| // Or just let the component manage the input and pass it to children? | |
| // Detailed Plan said: "Checks if user is authenticated (e.g., via simple client-side state/localStorage)". | |
| // Let's use localStorage 'munger_auth_token' = 'true' (simplified) after a successful check. | |
| // Wait, we need to Verify the password against the server. | |
| // I will create a simple server verify action first. | |
| import { verifyPassword } from '../actions/auth'; | |
| export function AuthGuard({ children }: { children: ReactNode }) { | |
| const [isAuthenticated, setIsAuthenticated] = useState(false); | |
| const [loading, setLoading] = useState(true); | |
| const [password, setPassword] = useState(''); | |
| const [error, setError] = useState(''); | |
| useEffect(() => { | |
| const storedAuth = sessionStorage.getItem('munger_is_authenticated'); | |
| if (storedAuth === 'true') { | |
| setIsAuthenticated(true); | |
| } | |
| setLoading(false); | |
| }, []); | |
| const handleLogin = async () => { | |
| setLoading(true); | |
| setError(''); | |
| try { | |
| const isValid = await verifyPassword(password); | |
| if (isValid) { | |
| sessionStorage.setItem('munger_is_authenticated', 'true'); | |
| sessionStorage.setItem('munger_password', password); | |
| setIsAuthenticated(true); | |
| } else { | |
| setError('Invalid Password'); | |
| } | |
| } catch (e) { | |
| setError('Error verifying password'); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| if (loading) return <div className="p-8 text-center text-zinc-500">Loading...</div>; | |
| if (!isAuthenticated) { | |
| return ( | |
| <div className="flex min-h-screen items-center justify-center bg-zinc-50 dark:bg-black p-4"> | |
| <div className="w-full max-w-sm bg-white dark:bg-zinc-900 p-8 rounded-lg shadow-lg border border-zinc-200 dark:border-zinc-800"> | |
| <h1 className="text-xl font-bold mb-6 text-center text-zinc-900 dark:text-zinc-100">Restricted Access</h1> | |
| <input | |
| type="password" | |
| value={password} | |
| onChange={(e) => setPassword(e.target.value)} | |
| placeholder="Enter Admin Password" | |
| className="w-full px-4 py-2 mb-4 border rounded bg-zinc-50 dark:bg-zinc-800 border-zinc-300 dark:border-zinc-700 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:text-white" | |
| onKeyDown={(e) => e.key === 'Enter' && handleLogin()} | |
| /> | |
| {error && <p className="text-red-500 text-sm mb-4 text-center">{error}</p>} | |
| <button | |
| onClick={handleLogin} | |
| className="w-full py-2 bg-blue-600 hover:bg-blue-700 text-white rounded font-medium transition-colors" | |
| > | |
| Access | |
| </button> | |
| <div className="mt-4 text-center"> | |
| <a href="/" className="text-sm text-zinc-500 hover:underline">Return Home</a> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| return <>{children}</>; | |
| } | |