SarahXia0405 commited on
Commit
c3c70f8
·
verified ·
1 Parent(s): 00072e4

Update web/src/components/LoginScreen.tsx

Browse files
Files changed (1) hide show
  1. web/src/components/LoginScreen.tsx +57 -22
web/src/components/LoginScreen.tsx CHANGED
@@ -1,10 +1,12 @@
1
- import React, { useState } from 'react';
2
- import { Button } from './ui/button';
3
- import { Input } from './ui/input';
4
- import { Label } from './ui/label';
5
- import { Card } from './ui/card';
6
- import clareAvatar from '../assets/dfe44dab3ad8cd93953eac4a3e68bd1a5f999653.png';
7
- import type { User } from '../App';
 
 
8
 
9
  interface LoginScreenProps {
10
  onLogin: (user: User) => void;
@@ -12,13 +14,37 @@ interface LoginScreenProps {
12
 
13
  export function LoginScreen({ onLogin }: LoginScreenProps) {
14
  const [showForm, setShowForm] = useState(false);
15
- const [name, setName] = useState('');
16
- const [email, setEmail] = useState('');
17
 
18
- const handleSubmit = (e: React.FormEvent) => {
 
 
 
19
  e.preventDefault();
20
- if (name.trim() && email.trim()) {
21
- onLogin({ name: name.trim(), email: email.trim() });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  }
23
  };
24
 
@@ -26,12 +52,10 @@ export function LoginScreen({ onLogin }: LoginScreenProps) {
26
  <div className="min-h-screen bg-background flex items-center justify-center p-4">
27
  <Card className="w-full max-w-md p-8">
28
  <div className="flex flex-col items-center space-y-6">
29
- {/* Clare Avatar */}
30
  <div className="w-24 h-24 rounded-full overflow-hidden bg-white flex items-center justify-center">
31
  <img src={clareAvatar} alt="Clare AI" className="w-full h-full object-cover" />
32
  </div>
33
 
34
- {/* Welcome Text */}
35
  <div className="text-center space-y-2">
36
  <h1 className="text-2xl">Welcome to Clare</h1>
37
  <p className="text-sm text-muted-foreground">
@@ -40,11 +64,7 @@ export function LoginScreen({ onLogin }: LoginScreenProps) {
40
  </div>
41
 
42
  {!showForm ? (
43
- <Button
44
- onClick={() => setShowForm(true)}
45
- className="w-full"
46
- size="lg"
47
- >
48
  Sign In
49
  </Button>
50
  ) : (
@@ -57,8 +77,10 @@ export function LoginScreen({ onLogin }: LoginScreenProps) {
57
  onChange={(e) => setName(e.target.value)}
58
  placeholder="Enter your name"
59
  required
 
60
  />
61
  </div>
 
62
  <div className="space-y-2">
63
  <Label htmlFor="login-email">Email / Student ID</Label>
64
  <Input
@@ -68,16 +90,29 @@ export function LoginScreen({ onLogin }: LoginScreenProps) {
68
  onChange={(e) => setEmail(e.target.value)}
69
  placeholder="Enter your email or ID"
70
  required
 
71
  />
72
  </div>
 
 
 
 
 
 
 
73
  <div className="flex gap-2">
74
- <Button type="submit" className="flex-1">
75
- Enter
76
  </Button>
77
  <Button
78
  type="button"
79
  variant="outline"
80
- onClick={() => setShowForm(false)}
 
 
 
 
 
81
  >
82
  Cancel
83
  </Button>
 
1
+ // web/src/components/LoginScreen.tsx
2
+ import React, { useState } from "react";
3
+ import { Button } from "./ui/button";
4
+ import { Input } from "./ui/input";
5
+ import { Label } from "./ui/label";
6
+ import { Card } from "./ui/card";
7
+ import clareAvatar from "../assets/dfe44dab3ad8cd93953eac4a3e68bd1a5f999653.png";
8
+ import type { User } from "../App";
9
+ import { apiLogin } from "../lib/api";
10
 
11
  interface LoginScreenProps {
12
  onLogin: (user: User) => void;
 
14
 
15
  export function LoginScreen({ onLogin }: LoginScreenProps) {
16
  const [showForm, setShowForm] = useState(false);
17
+ const [name, setName] = useState("");
18
+ const [email, setEmail] = useState("");
19
 
20
+ const [submitting, setSubmitting] = useState(false);
21
+ const [err, setErr] = useState<string | null>(null);
22
+
23
+ const handleSubmit = async (e: React.FormEvent) => {
24
  e.preventDefault();
25
+ setErr(null);
26
+
27
+ const n = name.trim();
28
+ const u = email.trim();
29
+ if (!n || !u) return;
30
+
31
+ setSubmitting(true);
32
+ try {
33
+ // backend expects: { name, user_id }
34
+ const resp = await apiLogin({ name: n, user_id: u });
35
+
36
+ // api.ts returns { ok: true/false ... }
37
+ if ((resp as any)?.ok !== true) {
38
+ const msg = (resp as any)?.error || "Login failed";
39
+ setErr(msg);
40
+ return;
41
+ }
42
+
43
+ onLogin({ name: n, email: u });
44
+ } catch (e: any) {
45
+ setErr(e?.message || "Login failed");
46
+ } finally {
47
+ setSubmitting(false);
48
  }
49
  };
50
 
 
52
  <div className="min-h-screen bg-background flex items-center justify-center p-4">
53
  <Card className="w-full max-w-md p-8">
54
  <div className="flex flex-col items-center space-y-6">
 
55
  <div className="w-24 h-24 rounded-full overflow-hidden bg-white flex items-center justify-center">
56
  <img src={clareAvatar} alt="Clare AI" className="w-full h-full object-cover" />
57
  </div>
58
 
 
59
  <div className="text-center space-y-2">
60
  <h1 className="text-2xl">Welcome to Clare</h1>
61
  <p className="text-sm text-muted-foreground">
 
64
  </div>
65
 
66
  {!showForm ? (
67
+ <Button onClick={() => setShowForm(true)} className="w-full" size="lg">
 
 
 
 
68
  Sign In
69
  </Button>
70
  ) : (
 
77
  onChange={(e) => setName(e.target.value)}
78
  placeholder="Enter your name"
79
  required
80
+ disabled={submitting}
81
  />
82
  </div>
83
+
84
  <div className="space-y-2">
85
  <Label htmlFor="login-email">Email / Student ID</Label>
86
  <Input
 
90
  onChange={(e) => setEmail(e.target.value)}
91
  placeholder="Enter your email or ID"
92
  required
93
+ disabled={submitting}
94
  />
95
  </div>
96
+
97
+ {err && (
98
+ <div className="text-sm text-destructive bg-destructive/10 border border-destructive/20 rounded-md p-2">
99
+ {err}
100
+ </div>
101
+ )}
102
+
103
  <div className="flex gap-2">
104
+ <Button type="submit" className="flex-1" disabled={submitting}>
105
+ {submitting ? "Signing in..." : "Enter"}
106
  </Button>
107
  <Button
108
  type="button"
109
  variant="outline"
110
+ onClick={() => {
111
+ if (submitting) return;
112
+ setShowForm(false);
113
+ setErr(null);
114
+ }}
115
+ disabled={submitting}
116
  >
117
  Cancel
118
  </Button>