theo-agent-dashboard

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

Setup.tsx (4285B)


      1 import { useState, type FormEvent } from "react";
      2 import { api } from "../../lib/api";
      3 import { useAuthStore } from "../../store/auth";
      4 
      5 export function Setup() {
      6   const { checkStatus } = useAuthStore();
      7   const [password, setPassword] = useState("");
      8   const [confirmPassword, setConfirmPassword] = useState("");
      9   const [apiKey, setApiKey] = useState("");
     10   const [error, setError] = useState<string | null>(null);
     11   const [loading, setLoading] = useState(false);
     12 
     13   const handleSubmit = async (e: FormEvent) => {
     14     e.preventDefault();
     15     setError(null);
     16 
     17     if (password !== confirmPassword) {
     18       setError("Passwords do not match");
     19       return;
     20     }
     21 
     22     if (!password.trim()) {
     23       setError("Password is required");
     24       return;
     25     }
     26 
     27     setLoading(true);
     28     try {
     29       await api.post("/auth/setup", { password, api_key: apiKey || undefined });
     30       await checkStatus();
     31       window.location.href = "/";
     32     } catch (err) {
     33       const message =
     34         err instanceof Error ? err.message : "Setup failed";
     35       setError(message);
     36     } finally {
     37       setLoading(false);
     38     }
     39   };
     40 
     41   return (
     42     <div className="flex min-h-screen items-center justify-center bg-gray-950">
     43       <div className="w-full max-w-sm rounded-xl border border-gray-800 bg-gray-900 p-8 shadow-2xl">
     44         <h1 className="mb-2 text-center text-2xl font-bold text-gray-100">
     45           Initial Setup
     46         </h1>
     47         <p className="mb-6 text-center text-sm text-gray-400">
     48           Create your admin account to get started.
     49         </p>
     50 
     51         <form onSubmit={handleSubmit} className="space-y-4">
     52           <div>
     53             <label
     54               htmlFor="setup-password"
     55               className="mb-1 block text-sm font-medium text-gray-300"
     56             >
     57               Password
     58             </label>
     59             <input
     60               id="setup-password"
     61               type="password"
     62               value={password}
     63               onChange={(e) => setPassword(e.target.value)}
     64               className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-100 placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
     65               placeholder="Choose a password"
     66               autoFocus
     67             />
     68           </div>
     69 
     70           <div>
     71             <label
     72               htmlFor="confirm-password"
     73               className="mb-1 block text-sm font-medium text-gray-300"
     74             >
     75               Confirm Password
     76             </label>
     77             <input
     78               id="confirm-password"
     79               type="password"
     80               value={confirmPassword}
     81               onChange={(e) => setConfirmPassword(e.target.value)}
     82               className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-100 placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
     83               placeholder="Confirm password"
     84             />
     85           </div>
     86 
     87           <div>
     88             <label
     89               htmlFor="api-key"
     90               className="mb-1 block text-sm font-medium text-gray-300"
     91             >
     92               API Key{" "}
     93               <span className="text-gray-500">(optional)</span>
     94             </label>
     95             <input
     96               id="api-key"
     97               type="password"
     98               value={apiKey}
     99               onChange={(e) => setApiKey(e.target.value)}
    100               className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-100 placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
    101               placeholder="LLM API key"
    102             />
    103           </div>
    104 
    105           {error && (
    106             <div className="rounded-lg bg-red-900/50 px-3 py-2 text-sm text-red-300">
    107               {error}
    108             </div>
    109           )}
    110 
    111           <button
    112             type="submit"
    113             disabled={loading || !password.trim() || !confirmPassword.trim()}
    114             className="w-full rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-500 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
    115           >
    116             {loading ? "Setting up..." : "Create Account"}
    117           </button>
    118         </form>
    119       </div>
    120     </div>
    121   );
    122 }