summaryrefslogblamecommitdiff
path: root/makima/frontend/src/routes/login.tsx
blob: ca1ebd07ce58fe3e8f74290ec99acbd816bc00f9 (plain) (tree)
























































                                                                          


                                                                                               

                                                                                                                 
                                                  











                                                                        
                                                   
                                            

                                                                               





                                                              
                                                             



                                                                

                                                              







                                                                

                                                              








                                                               
                                                                              




                                                        
                                                                                                                                                                      



                      
                                                                                 




                                                           
                                                                                                                                                                      










                                                                              
                                                                                                                                                                    








                                                                                
import { useState, type FormEvent } from "react";
import { useNavigate } from "react-router";
import { useAuth } from "../contexts/AuthContext";
import { Masthead } from "../components/Masthead";

type AuthMode = "signin" | "signup";

export default function LoginPage() {
  const navigate = useNavigate();
  const { signIn, signUp, isAuthConfigured, isAuthenticated } = useAuth();

  const [mode, setMode] = useState<AuthMode>("signin");
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);
  const [message, setMessage] = useState<string | null>(null);

  // Redirect if already authenticated
  if (isAuthenticated && isAuthConfigured) {
    navigate("/mesh");
    return null;
  }

  const handleEmailAuth = async (e: FormEvent) => {
    e.preventDefault();
    setError(null);
    setMessage(null);
    setLoading(true);

    try {
      if (mode === "signin") {
        const { error } = await signIn(email, password);
        if (error) {
          setError(error.message);
        } else {
          navigate("/mesh");
        }
      } else if (mode === "signup") {
        const { error } = await signUp(email, password);
        if (error) {
          setError(error.message);
        } else {
          setMessage("Check your email for a confirmation link.");
        }
      }
    } finally {
      setLoading(false);
    }
  };

  // If auth is not configured, show a message
  if (!isAuthConfigured) {
    return (
      <div className="relative z-10 min-h-screen flex flex-col">
        <Masthead />
        <main className="flex-1 flex items-center justify-center p-4">
          <div className="w-full max-w-md text-center panel p-6">
            <h1 className="text-2xl font-bold mb-4 text-[#f0f5ff]">Authentication Required</h1>
            <p className="text-[#9bc3ff] mb-4">
              Authentication is not configured. Please configure Supabase authentication to use this application.
            </p>
            <p className="text-[#597aaa] text-sm">
              For API access, use an API key in request headers instead.
            </p>
          </div>
        </main>
      </div>
    );
  }

  return (
    <div className="relative z-10 min-h-screen flex flex-col">
      <Masthead />
      <main className="flex-1 flex items-center justify-center p-4">
        <div className="w-full max-w-md panel p-6">
          <div className="text-center mb-8">
            <h1 className="text-2xl font-bold mb-2 text-[#f0f5ff]">Sign In</h1>
            <p className="text-[#9bc3ff]">
              {mode === "signin" && "Sign in to your account"}
              {mode === "signup" && "Create a new account"}
            </p>
          </div>

        {/* Mode switcher */}
        <div className="flex border-b border-[#2f476d] mb-6">
          <button
            onClick={() => setMode("signin")}
            className={`flex-1 py-2 text-sm transition-colors ${
              mode === "signin"
                ? "text-[#dbe7ff] border-b-2 border-[#3f6fb3]"
                : "text-[#597aaa] hover:text-[#9bc3ff]"
            }`}
          >
            Sign In
          </button>
          <button
            onClick={() => setMode("signup")}
            className={`flex-1 py-2 text-sm transition-colors ${
              mode === "signup"
                ? "text-[#dbe7ff] border-b-2 border-[#3f6fb3]"
                : "text-[#597aaa] hover:text-[#9bc3ff]"
            }`}
          >
            Sign Up
          </button>
        </div>

        {/* Email/password form */}
        <form onSubmit={handleEmailAuth} className="space-y-4">
          <div>
            <label className="block text-sm text-[#9bc3ff] mb-1">Email</label>
            <input
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              placeholder="you@example.com"
              className="w-full px-3 py-2 bg-[#0f1c2f] border border-[#2f476d] rounded text-[#dbe7ff] placeholder-[#597aaa] focus:outline-none focus:border-[#3f6fb3]"
              required
            />
          </div>
          <div>
            <label className="block text-sm text-[#9bc3ff] mb-1">Password</label>
            <input
              type="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              placeholder="********"
              className="w-full px-3 py-2 bg-[#0f1c2f] border border-[#2f476d] rounded text-[#dbe7ff] placeholder-[#597aaa] focus:outline-none focus:border-[#3f6fb3]"
              required
              minLength={6}
            />
          </div>

          {error && <div className="text-red-400 text-sm">{error}</div>}
          {message && <div className="text-green-400 text-sm">{message}</div>}

          <button
            type="submit"
            disabled={loading}
            className="w-full py-2 bg-[#0f3c78] text-[#dbe7ff] border border-[#3f6fb3] rounded font-medium hover:bg-[#1a4c8a] transition-colors disabled:opacity-50"
          >
            {loading ? "Loading..." : mode === "signin" ? "Sign In" : "Sign Up"}
          </button>
        </form>
        </div>
      </main>
    </div>
  );
}