summaryrefslogtreecommitdiff
path: root/makima/frontend/src/routes/login.tsx
blob: ca1ebd07ce58fe3e8f74290ec99acbd816bc00f9 (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("/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>
  );
}