AI_Agent_V4 / web /src /components /LoginScreen.tsx
SarahXia0405's picture
Update web/src/components/LoginScreen.tsx
507f3f7 verified
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 { toast } from 'sonner';
import clareAvatar from '../assets/dfe44dab3ad8cd93953eac4a3e68bd1a5f999653.png';
import type { User } from '../App';
interface LoginScreenProps {
onLogin: (user: User) => void;
}
export function LoginScreen({ onLogin }: LoginScreenProps) {
const [showForm, setShowForm] = useState(false);
const [name, setName] = useState('');
const [emailOrId, setEmailOrId] = useState('');
const [submitting, setSubmitting] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const n = name.trim();
const uid = emailOrId.trim();
if (!n || !uid) return;
setSubmitting(true);
try {
// HF Space: same-origin call is correct (your FastAPI serves the SPA)
const resp = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: n, user_id: uid }),
});
const data = await resp.json().catch(() => ({}));
if (!resp.ok || !data?.ok) {
const msg = data?.error || `Login failed (HTTP ${resp.status})`;
throw new Error(msg);
}
// Keep your existing App flow: user = { name, email }
onLogin({ name: data.user?.name ?? n, email: data.user?.user_id ?? uid });
toast.success('Signed in');
} catch (err: any) {
toast.error(err?.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">
{/* Clare Avatar */}
<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>
{/* Welcome Text */}
<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-userid">Email / Student ID</Label>
<Input
id="login-userid"
// IMPORTANT: allow non-email IDs
type="text"
value={emailOrId}
onChange={(e) => setEmailOrId(e.target.value)}
placeholder="Enter your email or ID"
required
disabled={submitting}
/>
</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={() => setShowForm(false)}
disabled={submitting}
>
Cancel
</Button>
</div>
<div className="text-xs text-muted-foreground">
This sign-in is for session identification only (name + ID), used to personalize tutoring and log events.
</div>
</form>
)}
</div>
</Card>
</div>
);
}