Spaces:
Sleeping
Sleeping
File size: 4,116 Bytes
c3c70f8 0ef5c60 c3c70f8 0ef5c60 c3c70f8 0ef5c60 c3c70f8 0ef5c60 c3c70f8 0ef5c60 c3c70f8 0ef5c60 c3c70f8 0ef5c60 c3c70f8 0ef5c60 c3c70f8 0ef5c60 c3c70f8 0ef5c60 c3c70f8 0ef5c60 |
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 |
// web/src/components/LoginScreen.tsx
import React, { useState } from "react";
import { Button } from "./ui/button";
import { Input } from "./ui/input";
import { Label } from "./ui/label";
import { Card } from "./ui/card";
import clareAvatar from "../assets/dfe44dab3ad8cd93953eac4a3e68bd1a5f999653.png";
import type { User } from "../App";
import { apiLogin } from "../lib/api";
interface LoginScreenProps {
onLogin: (user: User) => void;
}
export function LoginScreen({ onLogin }: LoginScreenProps) {
const [showForm, setShowForm] = useState(false);
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [submitting, setSubmitting] = useState(false);
const [err, setErr] = useState<string | null>(null);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setErr(null);
const n = name.trim();
const u = email.trim();
if (!n || !u) return;
setSubmitting(true);
try {
// backend expects: { name, user_id }
const resp = await apiLogin({ name: n, user_id: u });
// api.ts returns { ok: true/false ... }
if ((resp as any)?.ok !== true) {
const msg = (resp as any)?.error || "Login failed";
setErr(msg);
return;
}
onLogin({ name: n, email: u });
} catch (e: any) {
setErr(e?.message || "Login failed");
} finally {
setSubmitting(false);
}
};
return (
<div className="min-h-screen bg-background flex items-center justify-center p-4">
<Card className="w-full max-w-md p-8">
<div className="flex flex-col items-center space-y-6">
<div className="w-24 h-24 rounded-full overflow-hidden bg-white flex items-center justify-center">
<img src={clareAvatar} alt="Clare AI" className="w-full h-full object-cover" />
</div>
<div className="text-center space-y-2">
<h1 className="text-2xl">Welcome to Clare</h1>
<p className="text-sm text-muted-foreground">
Your AI teaching assistant for personalized learning
</p>
</div>
{!showForm ? (
<Button onClick={() => setShowForm(true)} className="w-full" size="lg">
Sign In
</Button>
) : (
<form onSubmit={handleSubmit} className="w-full space-y-4">
<div className="space-y-2">
<Label htmlFor="login-name">Name</Label>
<Input
id="login-name"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter your name"
required
disabled={submitting}
/>
</div>
<div className="space-y-2">
<Label htmlFor="login-email">Email / Student ID</Label>
<Input
id="login-email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email or ID"
required
disabled={submitting}
/>
</div>
{err && (
<div className="text-sm text-destructive bg-destructive/10 border border-destructive/20 rounded-md p-2">
{err}
</div>
)}
<div className="flex gap-2">
<Button type="submit" className="flex-1" disabled={submitting}>
{submitting ? "Signing in..." : "Enter"}
</Button>
<Button
type="button"
variant="outline"
onClick={() => {
if (submitting) return;
setShowForm(false);
setErr(null);
}}
disabled={submitting}
>
Cancel
</Button>
</div>
</form>
)}
</div>
</Card>
</div>
);
}
|