summaryrefslogtreecommitdiff
path: root/makima/frontend/src/routes/login.tsx
blob: 0725a2d921c3c38fb0f3fc82a4e3d4a164c722c0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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("/exec");
    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("/exec");
        }
      } 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">
            <h1 className="text-2xl font-bold mb-4">Authentication Required</h1>
            <p className="text-zinc-400 mb-4">
              Authentication is not configured. Please configure Supabase authentication to use this application.
            </p>
            <p className="text-zinc-500 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">
          <div className="text-center mb-8">
            <h1 className="text-2xl font-bold mb-2">Sign In</h1>
            <p className="text-zinc-400">
              {mode === "signin" && "Sign in to your account"}
              {mode === "signup" && "Create a new account"}
            </p>
          </div>

        {/* Mode switcher */}
        <div className="flex border-b border-zinc-800 mb-6">
          <button
            onClick={() => setMode("signin")}
            className={`flex-1 py-2 text-sm transition-colors ${
              mode === "signin"
                ? "text-white border-b-2 border-white"
                : "text-zinc-500 hover:text-zinc-300"
            }`}
          >
            Sign In
          </button>
          <button
            onClick={() => setMode("signup")}
            className={`flex-1 py-2 text-sm transition-colors ${
              mode === "signup"
                ? "text-white border-b-2 border-white"
                : "text-zinc-500 hover:text-zinc-300"
            }`}
          >
            Sign Up
          </button>
        </div>

        {/* Email/password form */}
        <form onSubmit={handleEmailAuth} className="space-y-4">
          <div>
            <label className="block text-sm text-zinc-400 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-zinc-900 border border-zinc-800 rounded text-white placeholder-zinc-600 focus:outline-none focus:border-zinc-600"
              required
            />
          </div>
          <div>
            <label className="block text-sm text-zinc-400 mb-1">Password</label>
            <input
              type="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              placeholder="********"
              className="w-full px-3 py-2 bg-zinc-900 border border-zinc-800 rounded text-white placeholder-zinc-600 focus:outline-none focus:border-zinc-600"
              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-white text-black rounded font-medium hover:bg-zinc-200 transition-colors disabled:opacity-50"
          >
            {loading ? "Loading..." : mode === "signin" ? "Sign In" : "Sign Up"}
          </button>
        </form>
        </div>
      </main>
    </div>
  );
}