munger-engine / app /components /AuthGuard.tsx
dromerosm's picture
feat: Add authentication, charting, and dark mode
21ac82a
'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}</>;
}