cesjavi commited on
Commit
89a451f
·
1 Parent(s): 0b03358

Feat: Complete Sign In / Sign Up flow with Aubix mascot (Phase 9)

Browse files
Files changed (1) hide show
  1. frontend/src/components/Login.tsx +111 -37
frontend/src/components/Login.tsx CHANGED
@@ -1,13 +1,17 @@
1
  import React, { useState } from 'react';
2
  import { supabase } from '../services/supabase';
3
- import { LogIn, Mail, Lock, Bot, Globe, GitBranch } from 'lucide-react';
4
- import { motion } from 'framer-motion';
 
5
 
6
  const Login: React.FC = () => {
 
7
  const [email, setEmail] = useState('');
8
  const [password, setPassword] = useState('');
 
9
  const [loading, setLoading] = useState(false);
10
  const [error, setError] = useState<string | null>(null);
 
11
 
12
  const handleLogin = async (e: React.FormEvent) => {
13
  e.preventDefault();
@@ -19,20 +23,101 @@ const Login: React.FC = () => {
19
  setLoading(false);
20
  };
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  return (
23
- <div className="login-screen">
 
 
 
 
 
 
 
24
  <motion.div
25
- initial={{ opacity: 0, scale: 0.9 }}
26
- animate={{ opacity: 1, scale: 1 }}
27
  className="glass-panel login-panel"
 
28
  >
29
- <div style={{ marginBottom: 'var(--space-lg)' }}>
30
- <Bot size={48} color="var(--accent)" style={{ marginBottom: 'var(--space-md)' }} />
31
- <h1 style={{ fontSize: '2rem', marginBottom: 'var(--space-xs)' }}>Welcome Back</h1>
32
- <p style={{ color: 'var(--text-dim)' }}>Access the Aubm Orchestrator</p>
 
 
 
 
33
  </div>
34
 
35
- <form onSubmit={handleLogin} style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-md)' }}>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  <div style={{ position: 'relative' }}>
37
  <Mail size={18} style={{ position: 'absolute', left: '12px', top: '50%', transform: 'translateY(-50%)', color: 'var(--text-muted)' }} />
38
  <input
@@ -79,39 +164,28 @@ const Login: React.FC = () => {
79
  type="submit"
80
  className="btn btn-primary"
81
  disabled={loading}
82
- style={{ padding: '0.8rem', marginTop: 'var(--space-sm)' }}
83
  >
84
- {loading ? 'Authenticating...' : (
85
- <>
86
- <LogIn size={18} />
87
- Sign In
88
- </>
89
- )}
90
  </button>
91
  </form>
92
 
93
- {/* Social Login - Hidden for now but code preserved
94
- <div style={{ margin: 'var(--space-lg) 0', display: 'flex', alignItems: 'center', gap: 'var(--space-md)' }}>
95
- <div style={{ flex: 1, height: '1px', background: 'var(--glass-border)' }}></div>
96
- <span style={{ fontSize: '0.8rem', color: 'var(--text-dim)' }}>OR CONTINUE WITH</span>
97
- <div style={{ flex: 1, height: '1px', background: 'var(--glass-border)' }}></div>
98
- </div>
99
-
100
- <div className="auth-provider-grid">
101
- <button className="btn btn-glass" onClick={() => (window as any).handleSSOLogin?.('google')}>
102
- <Globe size={18} />
103
- Google
104
- </button>
105
- <button className="btn btn-glass" onClick={() => (window as any).handleSSOLogin?.('github')}>
106
- <GitBranch size={18} />
107
- GitHub
108
  </button>
109
  </div>
110
- */}
111
-
112
- <div style={{ marginTop: 'var(--space-lg)', fontSize: '0.85rem', color: 'var(--text-dim)' }}>
113
- Enterprise authentication enabled.
114
- </div>
115
  </motion.div>
116
  </div>
117
  );
 
1
  import React, { useState } from 'react';
2
  import { supabase } from '../services/supabase';
3
+ import { LogIn, Mail, Lock, UserPlus, ArrowLeft, RefreshCw, CheckCircle2 } from 'lucide-react';
4
+ import { motion, AnimatePresence } from 'framer-motion';
5
+ import AubixIcon from './AubixIcon';
6
 
7
  const Login: React.FC = () => {
8
+ const [isSignUp, setIsSignUp] = useState(false);
9
  const [email, setEmail] = useState('');
10
  const [password, setPassword] = useState('');
11
+ const [fullName, setFullName] = useState('');
12
  const [loading, setLoading] = useState(false);
13
  const [error, setError] = useState<string | null>(null);
14
+ const [success, setSuccess] = useState<string | null>(null);
15
 
16
  const handleLogin = async (e: React.FormEvent) => {
17
  e.preventDefault();
 
23
  setLoading(false);
24
  };
25
 
26
+ const handleSignUp = async (e: React.FormEvent) => {
27
+ e.preventDefault();
28
+ setLoading(true);
29
+ setError(null);
30
+ setSuccess(null);
31
+
32
+ const { error } = await supabase.auth.signUp({
33
+ email,
34
+ password,
35
+ options: {
36
+ data: {
37
+ full_name: fullName,
38
+ }
39
+ }
40
+ });
41
+
42
+ if (error) {
43
+ setError(error.message);
44
+ } else {
45
+ setSuccess('Account created! You can now sign in.');
46
+ setIsSignUp(false);
47
+ setFullName('');
48
+ }
49
+ setLoading(false);
50
+ };
51
+
52
  return (
53
+ <div className="login-screen" style={{
54
+ minHeight: '100vh',
55
+ display: 'flex',
56
+ alignItems: 'center',
57
+ justifyContent: 'center',
58
+ background: 'radial-gradient(circle at center, #1a1a2e 0%, #0d0d14 100%)',
59
+ padding: 'var(--space-md)'
60
+ }}>
61
  <motion.div
62
+ initial={{ opacity: 0, y: 20 }}
63
+ animate={{ opacity: 1, y: 0 }}
64
  className="glass-panel login-panel"
65
+ style={{ width: '100%', maxWidth: '440px', padding: 'var(--space-xl)', textAlign: 'center' }}
66
  >
67
+ <div style={{ marginBottom: 'var(--space-xl)' }}>
68
+ <AubixIcon size={120} />
69
+ <h1 style={{ fontSize: '2.5rem', marginBottom: 'var(--space-xs)', fontWeight: 800 }}>
70
+ {isSignUp ? 'Join Aubm' : 'Welcome'}
71
+ </h1>
72
+ <p style={{ color: 'var(--text-dim)' }}>
73
+ {isSignUp ? 'Create your agent operator profile' : 'Access the Aubm Orchestrator'}
74
+ </p>
75
  </div>
76
 
77
+ {success && (
78
+ <motion.div
79
+ initial={{ opacity: 0, scale: 0.9 }}
80
+ animate={{ opacity: 1, scale: 1 }}
81
+ style={{ padding: 'var(--space-md)', background: 'rgba(16, 185, 129, 0.1)', border: '1px solid var(--success)', borderRadius: 'var(--radius-md)', color: 'var(--success)', marginBottom: 'var(--space-md)', display: 'flex', alignItems: 'center', gap: 'var(--space-sm)' }}
82
+ >
83
+ <CheckCircle2 size={18} />
84
+ {success}
85
+ </motion.div>
86
+ )}
87
+
88
+ <form onSubmit={isSignUp ? handleSignUp : handleLogin} style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-md)' }}>
89
+ <AnimatePresence mode="wait">
90
+ {isSignUp && (
91
+ <motion.div
92
+ key="signup-fields"
93
+ initial={{ height: 0, opacity: 0 }}
94
+ animate={{ height: 'auto', opacity: 1 }}
95
+ exit={{ height: 0, opacity: 0 }}
96
+ style={{ overflow: 'hidden' }}
97
+ >
98
+ <div style={{ position: 'relative', marginBottom: 'var(--space-md)' }}>
99
+ <UserPlus size={18} style={{ position: 'absolute', left: '12px', top: '50%', transform: 'translateY(-50%)', color: 'var(--text-muted)' }} />
100
+ <input
101
+ type="text"
102
+ placeholder="Full Name"
103
+ value={fullName}
104
+ onChange={(e) => setFullName(e.target.value)}
105
+ required={isSignUp}
106
+ style={{
107
+ width: '100%',
108
+ padding: '0.8rem 1rem 0.8rem 2.5rem',
109
+ background: 'rgba(255,255,255,0.05)',
110
+ border: '1px solid var(--glass-border)',
111
+ borderRadius: 'var(--radius-md)',
112
+ color: 'white',
113
+ outline: 'none'
114
+ }}
115
+ />
116
+ </div>
117
+ </motion.div>
118
+ )}
119
+ </AnimatePresence>
120
+
121
  <div style={{ position: 'relative' }}>
122
  <Mail size={18} style={{ position: 'absolute', left: '12px', top: '50%', transform: 'translateY(-50%)', color: 'var(--text-muted)' }} />
123
  <input
 
164
  type="submit"
165
  className="btn btn-primary"
166
  disabled={loading}
167
+ style={{ padding: '0.85rem', marginTop: 'var(--space-sm)' }}
168
  >
169
+ {loading ? <RefreshCw className="spin" size={18} /> : (isSignUp ? <UserPlus size={18} /> : <LogIn size={18} />)}
170
+ {loading ? (isSignUp ? 'Creating...' : 'Authenticating...') : (isSignUp ? 'Create Account' : 'Sign In')}
 
 
 
 
171
  </button>
172
  </form>
173
 
174
+ <div style={{ marginTop: 'var(--space-xl)', paddingTop: 'var(--space-lg)', borderTop: '1px solid var(--glass-border)' }}>
175
+ <button
176
+ type="button"
177
+ className="btn btn-glass"
178
+ onClick={() => {
179
+ setIsSignUp(!isSignUp);
180
+ setError(null);
181
+ setSuccess(null);
182
+ }}
183
+ style={{ width: '100%' }}
184
+ >
185
+ {isSignUp ? <ArrowLeft size={18} /> : <UserPlus size={18} />}
186
+ {isSignUp ? 'Back to Sign In' : 'Need an account? Sign Up'}
 
 
187
  </button>
188
  </div>
 
 
 
 
 
189
  </motion.div>
190
  </div>
191
  );