Saandraahh commited on
Commit
01c8f1f
·
1 Parent(s): 3535722

feat: implement dynamic scoring, webhooks, and resume download

Browse files
src/components/CandidateDrawer.jsx CHANGED
@@ -123,7 +123,7 @@ const CandidateDrawer = ({ isOpen, onClose, candidate }) => {
123
  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start', marginBottom: '2rem' }}>
124
  <div>
125
  <h2 style={{ fontSize: '1.75rem', fontWeight: 'bold', color: 'white' }}>{candidate.name}</h2>
126
- <p style={{ color: '#94a3b8' }}>{candidate.jobTitle || candidate.role} • {candidate.experience} yrs</p>
127
  </div>
128
  <button onClick={onClose} style={{ background: 'none', border: 'none', color: '#94a3b8', cursor: 'pointer' }}>
129
  <X size={24} />
 
123
  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start', marginBottom: '2rem' }}>
124
  <div>
125
  <h2 style={{ fontSize: '1.75rem', fontWeight: 'bold', color: 'white' }}>{candidate.name}</h2>
126
+ <p style={{ color: '#94a3b8' }}>{candidate.jobTitle || candidate.role} • {candidate.experience} </p>
127
  </div>
128
  <button onClick={onClose} style={{ background: 'none', border: 'none', color: '#94a3b8', cursor: 'pointer' }}>
129
  <X size={24} />
src/pages/AdminLogin.jsx CHANGED
@@ -3,20 +3,16 @@ import React, { useState } from 'react';
3
  import { motion } from 'framer-motion';
4
 
5
  // --- SVG Icon Components ---
6
- const UserIcon = () => ( <svg style={{ width: '20px', height: '20px', color: 'rgba(255, 255, 255, 0.7)' }} viewBox="0 0 20 20" fill="currentColor"><path fillRule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clipRule="evenodd" /></svg> );
7
- const LockIcon = () => ( <svg style={{ width: '20px', height: '20px', color: 'rgba(255, 255, 255, 0.7)' }} viewBox="0 0 20 20" fill="currentColor"><path fillRule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clipRule="evenodd" /></svg> );
8
- const SpinnerIcon = () => <motion.svg animate={{ rotate: 360 }} transition={{ duration: 1, repeat: Infinity, ease: "linear" }} style={{ width: '20px', height: '20px' }} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></motion.svg>;
9
-
10
 
11
  export default function AdminLogin({ onNavigate }) {
12
  const [email, setEmail] = useState('');
13
  const [password, setPassword] = useState('');
14
-
15
- // --- STATE UPDATES ---
16
  const [loading, setLoading] = useState(false);
17
- const [error, setError] = useState(''); // Changed to a single string for all errors
18
 
19
- // --- UPDATED LOGIN HANDLER ---
20
  const handleAdminLogin = async (e) => {
21
  e.preventDefault();
22
  setError('');
@@ -29,40 +25,33 @@ export default function AdminLogin({ onNavigate }) {
29
  setLoading(true);
30
 
31
  try {
32
- // 1. Authenticate with Supabase Auth
33
  const { data: { user }, error: authError } = await supabase.auth.signInWithPassword({
34
  email: email,
35
  password: password,
36
  });
37
 
38
  if (authError) throw authError;
39
- if (!user) throw new Error("Login failed, please try again.");
40
 
41
- // 2. ✅ CORRECTED: Check role in 'user_roles' using 'user_id'
42
  const { data: roleData, error: roleError } = await supabase
43
- .from('user_roles') // Correct table name
44
  .select('role')
45
- .eq('user_id', user.id) // ⚠️ CHANGED: was 'id', now 'user_id'
46
  .single();
47
 
48
- // Handle case where no role row exists
49
  if (roleError && roleError.code !== 'PGRST116') {
50
- throw new Error("Could not verify user role.");
51
  }
52
 
53
- // 3. Check role and grant access
54
- // You mentioned checking for 'recruiter' here.
55
- // If this is the ADMIN login page, you should check for 'admin'.
56
- // If this is a general login, checking for 'recruiter' is fine.
57
- if (roleData && roleData.role === 'recruiter') {
58
-
59
- // ✅ Success
60
  if (typeof onNavigate === 'function') {
61
- onNavigate('admin-dashboard');
62
  }
63
-
64
  } else {
65
- // ❌ Access Denied
66
  await supabase.auth.signOut();
67
  throw new Error("Access Denied. Authorized personnel only.");
68
  }
@@ -80,7 +69,32 @@ export default function AdminLogin({ onNavigate }) {
80
  alignItems: 'center', justifyContent: 'center', overflow: 'hidden',
81
  backgroundColor: '#020617', color: 'white', fontFamily: "'Montserrat', sans-serif", padding: '1rem',
82
  }}>
83
- <style>{`@import url('...'); input:-webkit-autofill...`}</style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
  {/* Background Shapes */}
86
  <>
@@ -88,14 +102,14 @@ export default function AdminLogin({ onNavigate }) {
88
  <div style={{ position: 'absolute', borderRadius: '50%', filter: 'blur(80px)', opacity: 0.4, width: '320px', height: '320px', backgroundColor: '#DC2626', bottom: '-80px', right: '-120px' }}></div>
89
  </>
90
 
91
- <motion.div
92
  initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5, ease: "easeOut" }}
93
  style={{
94
  width: '100%', maxWidth: '512px', borderRadius: '1rem', backgroundColor: 'rgba(239, 68, 68, 0.1)',
95
  backdropFilter: 'blur(12px)', WebkitBackdropFilter: 'blur(12px)', border: '1px solid rgba(239, 68, 68, 0.3)',
96
  padding: '2rem', zIndex: 10,
97
  }}>
98
-
99
  <div style={{ textAlign: 'center', marginBottom: '2rem' }}>
100
  <h2 style={{ fontSize: '1.875rem', fontWeight: 'bold' }}>Admin Portal</h2>
101
  <p style={{ color: '#d1d5db', marginTop: '0.25rem' }}>Manage CV submissions and applications</p>
@@ -114,12 +128,10 @@ export default function AdminLogin({ onNavigate }) {
114
  <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} disabled={loading} placeholder="Password" style={{ width: '100%', padding: '0.75rem 1rem 0.75rem 2.5rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid rgba(239, 68, 68, 0.3)`, borderRadius: '0.5rem', color: 'white', boxSizing: 'border-box' }} />
115
  </div>
116
  </div>
117
-
118
- {/* --- UI TO DISPLAY ANY ERROR --- */}
119
  {error && <p style={{ color: '#F87171', fontSize: '0.875rem', marginTop: '-0.5rem', marginBottom: '1.5rem', textAlign: 'center' }}>{error}</p>}
120
 
121
  <motion.button type="submit" disabled={loading} whileHover={{ scale: loading ? 1 : 1.03 }} whileTap={{ scale: loading ? 1 : 0.98 }} style={{ width: '100%', backgroundColor: '#EF4444', color: 'white', fontWeight: 'bold', padding: '0.75rem 0', borderRadius: '0.5rem', border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px', opacity: loading ? 0.7 : 1 }}>
122
- {/* --- UI FEEDBACK FOR LOADING --- */}
123
  {loading && <SpinnerIcon />}
124
  {loading ? 'Verifying...' : 'Continue'}
125
  </motion.button>
 
3
  import { motion } from 'framer-motion';
4
 
5
  // --- SVG Icon Components ---
6
+ const UserIcon = () => (<svg style={{ width: '20px', height: '20px', color: 'rgba(255, 255, 255, 0.7)' }} viewBox="0 0 20 20" fill="currentColor"><path fillRule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clipRule="evenodd" /></svg>);
7
+ const LockIcon = () => (<svg style={{ width: '20px', height: '20px', color: 'rgba(255, 255, 255, 0.7)' }} viewBox="0 0 20 20" fill="currentColor"><path fillRule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clipRule="evenodd" /></svg>);
8
+ const SpinnerIcon = () => <motion.svg animate={{ rotate: 360 }} transition={{ duration: 1, repeat: Infinity, ease: "linear" }} style={{ width: '20px', height: '20px' }} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 12a9 9 0 1 1-6.219-8.56" /></motion.svg>;
 
9
 
10
  export default function AdminLogin({ onNavigate }) {
11
  const [email, setEmail] = useState('');
12
  const [password, setPassword] = useState('');
 
 
13
  const [loading, setLoading] = useState(false);
14
+ const [error, setError] = useState('');
15
 
 
16
  const handleAdminLogin = async (e) => {
17
  e.preventDefault();
18
  setError('');
 
25
  setLoading(true);
26
 
27
  try {
28
+ // 1. Authenticate
29
  const { data: { user }, error: authError } = await supabase.auth.signInWithPassword({
30
  email: email,
31
  password: password,
32
  });
33
 
34
  if (authError) throw authError;
35
+ if (!user) throw new Error("Login failed.");
36
 
37
+ // 2. Check Role
38
  const { data: roleData, error: roleError } = await supabase
39
+ .from('user_roles')
40
  .select('role')
41
+ .eq('user_id', user.id)
42
  .single();
43
 
 
44
  if (roleError && roleError.code !== 'PGRST116') {
45
+ throw new Error("Could not verify user role.");
46
  }
47
 
48
+ // 3. Admin Check
49
+ // Accepts 'admin' or 'recruiter' based on your previous logic
50
+ if (roleData && (roleData.role === 'admin' || roleData.role === 'recruiter')) {
 
 
 
 
51
  if (typeof onNavigate === 'function') {
52
+ onNavigate('admin-dashboard');
53
  }
 
54
  } else {
 
55
  await supabase.auth.signOut();
56
  throw new Error("Access Denied. Authorized personnel only.");
57
  }
 
69
  alignItems: 'center', justifyContent: 'center', overflow: 'hidden',
70
  backgroundColor: '#020617', color: 'white', fontFamily: "'Montserrat', sans-serif", padding: '1rem',
71
  }}>
72
+ <style>{`@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap'); input:-webkit-autofill { -webkit-text-fill-color: #fff !important; -webkit-box-shadow: 0 0 0px 1000px rgba(239, 68, 68, 0.1) inset !important; }`}</style>
73
+
74
+ {/* --- 🔴 FIXED BACK BUTTON --- */}
75
+ <button
76
+ onClick={() => onNavigate('login')}
77
+ style={{
78
+ position: 'fixed', // Fixed to stay on top
79
+ top: '20px',
80
+ left: '20px',
81
+ display: 'flex',
82
+ alignItems: 'center',
83
+ justifyContent: 'center',
84
+ gap: '8px',
85
+ padding: '12px 20px',
86
+ backgroundColor: '#510000', // Red for Admin
87
+ color: '#ffffffbe',
88
+ border: '2px solid #510000',
89
+ borderRadius: '10px',
90
+ fontWeight: '700',
91
+ cursor: 'pointer',
92
+ zIndex: 9999, // High z-index
93
+ boxShadow: '0 4px 10px rgba(0,0,0,0.3)'
94
+ }}
95
+ >
96
+ <span>⬅</span> Back
97
+ </button>
98
 
99
  {/* Background Shapes */}
100
  <>
 
102
  <div style={{ position: 'absolute', borderRadius: '50%', filter: 'blur(80px)', opacity: 0.4, width: '320px', height: '320px', backgroundColor: '#DC2626', bottom: '-80px', right: '-120px' }}></div>
103
  </>
104
 
105
+ <motion.div
106
  initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5, ease: "easeOut" }}
107
  style={{
108
  width: '100%', maxWidth: '512px', borderRadius: '1rem', backgroundColor: 'rgba(239, 68, 68, 0.1)',
109
  backdropFilter: 'blur(12px)', WebkitBackdropFilter: 'blur(12px)', border: '1px solid rgba(239, 68, 68, 0.3)',
110
  padding: '2rem', zIndex: 10,
111
  }}>
112
+
113
  <div style={{ textAlign: 'center', marginBottom: '2rem' }}>
114
  <h2 style={{ fontSize: '1.875rem', fontWeight: 'bold' }}>Admin Portal</h2>
115
  <p style={{ color: '#d1d5db', marginTop: '0.25rem' }}>Manage CV submissions and applications</p>
 
128
  <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} disabled={loading} placeholder="Password" style={{ width: '100%', padding: '0.75rem 1rem 0.75rem 2.5rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid rgba(239, 68, 68, 0.3)`, borderRadius: '0.5rem', color: 'white', boxSizing: 'border-box' }} />
129
  </div>
130
  </div>
131
+
 
132
  {error && <p style={{ color: '#F87171', fontSize: '0.875rem', marginTop: '-0.5rem', marginBottom: '1.5rem', textAlign: 'center' }}>{error}</p>}
133
 
134
  <motion.button type="submit" disabled={loading} whileHover={{ scale: loading ? 1 : 1.03 }} whileTap={{ scale: loading ? 1 : 0.98 }} style={{ width: '100%', backgroundColor: '#EF4444', color: 'white', fontWeight: 'bold', padding: '0.75rem 0', borderRadius: '0.5rem', border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px', opacity: loading ? 0.7 : 1 }}>
 
135
  {loading && <SpinnerIcon />}
136
  {loading ? 'Verifying...' : 'Continue'}
137
  </motion.button>
src/pages/AppliLogin.jsx CHANGED
@@ -2,9 +2,9 @@ import { supabase } from '../supabaseClient';
2
  import React, { useState } from 'react';
3
  import { motion, AnimatePresence } from 'framer-motion';
4
 
5
- // --- SVG Icon Components (no changes) ---
6
- const EyeIcon = () => ( <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg> );
7
- const EyeOffIcon = () => ( <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg> );
8
 
9
  export default function AppliLogin({ onNavigate }) {
10
  const [mode, setMode] = useState('login');
@@ -14,15 +14,15 @@ export default function AppliLogin({ onNavigate }) {
14
  const [isPasswordVisible, setIsPasswordVisible] = useState(false);
15
  const [errors, setErrors] = useState({});
16
  const [loading, setLoading] = useState(false);
17
-
18
- // NEW: State for integrated notifications
19
- const [notification, setNotification] = useState(null); // { type: 'success' | 'error', message: '...' }
20
 
21
  const validate = () => {
22
  const newErrors = {};
23
  if (!email.trim()) newErrors.email = 'Email is required.';
24
  else if (!/\S+@\S+\.\S+/.test(email)) newErrors.email = 'Email is invalid.';
25
-
26
  if (mode !== 'forgot') {
27
  if (!password) newErrors.password = 'Password is required.';
28
  }
@@ -33,7 +33,6 @@ export default function AppliLogin({ onNavigate }) {
33
  return newErrors;
34
  };
35
 
36
- // --- FULLY MODIFIED handleSubmit Function ---
37
  const handleSubmit = async (e) => {
38
  e.preventDefault();
39
  const formErrors = validate();
@@ -41,61 +40,51 @@ export default function AppliLogin({ onNavigate }) {
41
  setErrors(formErrors);
42
  return;
43
  }
44
-
45
  setErrors({});
46
  setLoading(true);
47
- setNotification(null); // Clear previous notifications
48
 
49
  try {
50
  if (mode === 'login') {
51
- const { data, error } = await supabase.auth.signInWithPassword({
52
- email,
53
- password,
54
- });
55
- if (error) throw error;
56
-
57
- // Check user role from Supabase metadata
58
- const role = data.user?.user_metadata?.role;
59
-
60
- if (role === 'applicant') {
61
- onNavigate('dashboard');
62
- } else {
63
- // If role is undefined or invalid
64
- setNotification({ type: 'error', message: 'Unauthorized role detected.' });
65
- await supabase.auth.signOut(); // Log out unauthorized users
66
- }
67
- }
68
- else if (mode === 'register') {
69
- // FIXED: Added options to pass the 'applicant' role to our trigger
70
  const { error } = await supabase.auth.signUp({
71
  email,
72
  password,
73
- options: {
74
- data: {
75
- role: 'applicant'
76
- }
77
- }
78
  });
79
  if (error) throw error;
80
- setNotification({ type: 'success', message: 'Registration successful! Please login to access your account.' });
81
  setMode('login');
82
  } else if (mode === 'forgot') {
83
- // NEW: Added password reset logic
84
  const { error } = await supabase.auth.resetPasswordForEmail(email, {
85
- redirectTo: window.location.origin, // Or a specific password reset page
86
  });
87
  if (error) throw error;
88
  setNotification({ type: 'success', message: 'Password reset link sent! Check your email.' });
89
  setMode('login');
90
  }
91
  } catch (error) {
92
- // FIXED: Using integrated notification instead of alert()
93
  setNotification({ type: 'error', message: error.message });
94
  } finally {
95
  setLoading(false);
96
  }
97
  };
98
-
99
  const formVariants = {
100
  hidden: { opacity: 0, y: 20 },
101
  visible: { opacity: 1, y: 0 },
@@ -103,64 +92,71 @@ export default function AppliLogin({ onNavigate }) {
103
  };
104
 
105
  const notificationStyles = {
106
- padding: '0.75rem 1rem',
107
- marginBottom: '1rem',
108
- borderRadius: '0.5rem',
109
- fontSize: '0.875rem',
110
- textAlign: 'center',
111
- border: '1px solid',
112
- };
113
-
114
- const successStyles = {
115
- ...notificationStyles,
116
- backgroundColor: 'rgba(16, 185, 129, 0.1)',
117
- borderColor: 'rgba(5, 150, 105, 0.3)',
118
- color: '#34D399',
119
- };
120
-
121
- const errorStyles = {
122
- ...notificationStyles,
123
- backgroundColor: 'rgba(239, 68, 68, 0.1)',
124
- borderColor: 'rgba(220, 38, 38, 0.3)',
125
- color: '#F87171',
126
  };
127
 
128
  return (
129
  <div style={{ position: 'relative', minHeight: '100vh', width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '1rem', overflow: 'hidden', backgroundColor: '#020617', color: 'white', fontFamily: "'Montserrat', sans-serif" }}>
130
- <style>{`@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap'); input:-webkit-autofill, input:-webkit-autofill:hover, input:-webkit-autofill:focus, input:-webkit-autofill:active { -webkit-text-fill-color: #fff !important; -webkit-box-shadow: 0 0 0px 1000px rgba(251, 191, 36, 0.1) inset !important; box-shadow: 0 0 0px 1000px rgba(251, 191, 36, 0.1) inset !important; transition: background-color 5000s ease-in-out 0s; }`}</style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  <>
132
  <div style={{ position: 'absolute', borderRadius: '50%', filter: 'blur(80px)', opacity: 0.4, width: '384px', height: '384px', backgroundColor: '#FBBF24', top: '-50px', left: '-100px' }}></div>
133
  <div style={{ position: 'absolute', borderRadius: '50%', filter: 'blur(80px)', opacity: 0.4, width: '320px', height: '320px', backgroundColor: '#F59E0B', bottom: '-80px', right: '-120px' }}></div>
134
  </>
135
- <motion.div
 
136
  initial={{ opacity: 0, scale: 0.95 }}
137
  animate={{ opacity: 1, scale: 1 }}
138
- transition={{ duration: 0.4, ease: "easeOut" }}
139
- style={{ width: '100%', maxWidth: '512px', borderRadius: '1rem', backgroundColor: 'rgba(251, 191, 36, 0.1)', backdropFilter: 'blur(12px)', WebkitBackdropFilter: 'blur(12px)', border: '1px solid rgba(251, 191, 36, 0.3)', boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)', padding: '2rem', zIndex: 10 }}>
140
-
141
- {/* NEW: Render Notification */}
142
  <AnimatePresence>
143
  {notification && (
144
  <motion.div
145
- initial={{ opacity: 0, y: -10 }}
146
- animate={{ opacity: 1, y: 0 }}
147
- exit={{ opacity: 0, y: -10 }}
148
- style={notification.type === 'success' ? successStyles : errorStyles}
 
 
 
149
  >
150
  {notification.message}
151
  </motion.div>
152
  )}
153
  </AnimatePresence>
154
-
155
  <AnimatePresence mode="wait">
156
- <motion.div
157
- key={mode}
158
- variants={formVariants}
159
- initial="hidden"
160
- animate="visible"
161
- exit="exit"
162
- transition={{ duration: 0.3 }}
163
- >
164
  {/* --- Login Form --- */}
165
  {mode === 'login' && (
166
  <div>
@@ -168,74 +164,59 @@ export default function AppliLogin({ onNavigate }) {
168
  <h2 style={{ fontSize: '1.875rem', fontWeight: 'bold', marginBottom: '1.5rem', textAlign: 'center' }}>Applicant Portal</h2>
169
  <form onSubmit={handleSubmit}>
170
  <div style={{ marginBottom: '1rem' }}>
171
- <label htmlFor="email" style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Email</label>
172
- <input type="email" id="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="lead@example.com" disabled={loading} style={{ width: '100%', padding: '0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.email ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white', transition: 'all 0.3s ease', boxSizing: 'border-box' }} />
173
- {errors.email && <p style={{ color: '#F87171', fontSize: '0.75rem', marginTop: '0.5rem', textAlign: 'left' }}>{errors.email}</p>}
174
  </div>
175
  <div style={{ marginBottom: '1.5rem' }}>
176
- <label htmlFor="password" style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Password</label>
177
- <div style={{ position: 'relative', display: 'flex', alignItems: 'center' }}>
178
- <input type={isPasswordVisible ? 'text' : 'password'} id="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="••••••••" disabled={loading} style={{ width: '100%', padding: '0.75rem 3rem 0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.password ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white', transition: 'all 0.3s ease', boxSizing: 'border-box' }} />
179
- <div style={{ position: 'absolute', right: '0.5rem' }}>
180
- <button type="button" onClick={() => setIsPasswordVisible(!isPasswordVisible)} title={isPasswordVisible ? 'Hide Password' : 'Show Password'} style={{ padding: '0.25rem', backgroundColor: 'transparent', border: 'none', cursor: 'pointer', color: '#FCD34D' }}>
181
- {isPasswordVisible ? <EyeOffIcon /> : <EyeIcon />}
182
- </button>
183
- </div>
184
  </div>
185
- {errors.password ? <p style={{ color: '#F87171', fontSize: '0.75rem', marginTop: '0.5rem', textAlign: 'left' }}>{errors.password}</p> : <button type="button" onClick={() => setMode('forgot')} style={{ fontSize: '0.75rem', color: '#FCD34D', textDecoration: 'none', marginTop: '0.5rem', display: 'block', textAlign: 'right', background: 'none', border: 'none', cursor: 'pointer', padding: 0 }}>Forgot Password?</button>}
186
  </div>
187
- <motion.button type="submit" whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.98 }} disabled={loading} style={{ width: '100%', backgroundColor: '#FBBF24', color: '#1a202c', fontWeight: 'bold', padding: '0.75rem 0', borderRadius: '0.5rem', border: 'none', cursor: 'pointer', opacity: loading ? 0.7 : 1 }}>
188
- {loading ? 'Signing In...' : 'Sign In'}
189
- </motion.button>
190
  </form>
191
- <p style={{ fontSize: '0.75rem', textAlign: 'center', color: '#9ca3af', marginTop: '2rem' }}>Don't have an account? <button onClick={() => setMode('register')} style={{ color: '#FCD34D', fontWeight: '600', textDecoration: 'none', background: 'none', border: 'none', cursor: 'pointer', padding: 0 }}>Register for free</button></p>
192
  </div>
193
  )}
194
-
195
  {/* --- Register Form --- */}
196
  {mode === 'register' && (
197
  <div>
198
  <h2 style={{ fontSize: '1.875rem', fontWeight: 'bold', marginBottom: '1.5rem', textAlign: 'center' }}>Create Account</h2>
199
  <form onSubmit={handleSubmit}>
200
  <div style={{ marginBottom: '1rem' }}>
201
- <label htmlFor="email" style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Email</label>
202
- <input type="email" id="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="lead@example.com" disabled={loading} style={{ width: '100%', padding: '0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.email ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white', transition: 'all 0.3s ease', boxSizing: 'border-box' }} />
203
- {errors.email && <p style={{ color: '#F87171', fontSize: '0.75rem', marginTop: '0.5rem', textAlign: 'left' }}>{errors.email}</p>}
204
  </div>
205
  <div style={{ marginBottom: '1rem' }}>
206
- <label htmlFor="password" style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Password</label>
207
- <input type="password" id="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="••••••••" disabled={loading} style={{ width: '100%', padding: '0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.password ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white', transition: 'all 0.3s ease', boxSizing: 'border-box' }} />
208
- {errors.password && <p style={{ color: '#F87171', fontSize: '0.75rem', marginTop: '0.5rem', textAlign: 'left' }}>{errors.password}</p>}
209
  </div>
210
  <div style={{ marginBottom: '1.5rem' }}>
211
- <label htmlFor="confirmPassword" style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Confirm Password</label>
212
- <input type="password" id="confirmPassword" value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} placeholder="••••••••" disabled={loading} style={{ width: '100%', padding: '0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.confirmPassword ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white', transition: 'all 0.3s ease', boxSizing: 'border-box' }} />
213
- {errors.confirmPassword && <p style={{ color: '#F87171', fontSize: '0.75rem', marginTop: '0.5rem', textAlign: 'left' }}>{errors.confirmPassword}</p>}
214
  </div>
215
- <motion.button type="submit" whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.98 }} disabled={loading} style={{ width: '100%', backgroundColor: '#FBBF24', color: '#1a202c', fontWeight: 'bold', padding: '0.75rem 0', borderRadius: '0.5rem', border: 'none', cursor: 'pointer', opacity: loading ? 0.7 : 1 }}>
216
- {loading ? 'Registering...' : 'Register'}
217
- </motion.button>
218
  </form>
219
- <p style={{ fontSize: '0.75rem', textAlign: 'center', color: '#9ca3af', marginTop: '2rem' }}>Already have an account? <button onClick={() => setMode('login')} style={{ color: '#FCD34D', fontWeight: '600', textDecoration: 'none', background: 'none', border: 'none', cursor: 'pointer', padding: 0 }}>Sign In</button></p>
220
  </div>
221
  )}
222
 
223
- {/* --- Forgot Password Form --- */}
224
  {mode === 'forgot' && (
225
  <div>
226
  <h2 style={{ fontSize: '1.875rem', fontWeight: 'bold', marginBottom: '1.5rem', textAlign: 'center' }}>Forgot Password</h2>
227
- <p style={{ color: '#d1d5db', marginBottom: '1.5rem', textAlign: 'center' }}>Enter your email and we'll send you a reset link.</p>
228
  <form onSubmit={handleSubmit}>
229
  <div style={{ marginBottom: '1.5rem' }}>
230
- <label htmlFor="email" style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Email</label>
231
- <input type="email" id="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="your@email.com" disabled={loading} style={{ width: '100%', padding: '0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.email ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white', transition: 'all 0.3s ease', boxSizing: 'border-box' }} />
232
- {errors.email && <p style={{ color: '#F87171', fontSize: '0.75rem', marginTop: '0.5rem', textAlign: 'left' }}>{errors.email}</p>}
233
  </div>
234
- <motion.button type="submit" whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.98 }} disabled={loading} style={{ width: '100%', backgroundColor: '#FBBF24', color: '#1a202c', fontWeight: 'bold', padding: '0.75rem 0', borderRadius: '0.5rem', border: 'none', cursor: 'pointer', opacity: loading ? 0.7 : 1 }}>
235
- {loading ? 'Sending...' : 'Send Reset Link'}
236
- </motion.button>
237
  </form>
238
- <p style={{ fontSize: '0.75rem', textAlign: 'center', color: '#9ca3af', marginTop: '2rem' }}><button onClick={() => setMode('login')} style={{ color: '#FCD34D', fontWeight: '600', textDecoration: 'none', background: 'none', border: 'none', cursor: 'pointer', padding: 0 }}>Back to Sign In</button></p>
239
  </div>
240
  )}
241
  </motion.div>
 
2
  import React, { useState } from 'react';
3
  import { motion, AnimatePresence } from 'framer-motion';
4
 
5
+ // --- SVG Icon Components ---
6
+ const EyeIcon = () => (<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>);
7
+ const EyeOffIcon = () => (<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>);
8
 
9
  export default function AppliLogin({ onNavigate }) {
10
  const [mode, setMode] = useState('login');
 
14
  const [isPasswordVisible, setIsPasswordVisible] = useState(false);
15
  const [errors, setErrors] = useState({});
16
  const [loading, setLoading] = useState(false);
17
+
18
+ // Notification State
19
+ const [notification, setNotification] = useState(null);
20
 
21
  const validate = () => {
22
  const newErrors = {};
23
  if (!email.trim()) newErrors.email = 'Email is required.';
24
  else if (!/\S+@\S+\.\S+/.test(email)) newErrors.email = 'Email is invalid.';
25
+
26
  if (mode !== 'forgot') {
27
  if (!password) newErrors.password = 'Password is required.';
28
  }
 
33
  return newErrors;
34
  };
35
 
 
36
  const handleSubmit = async (e) => {
37
  e.preventDefault();
38
  const formErrors = validate();
 
40
  setErrors(formErrors);
41
  return;
42
  }
43
+
44
  setErrors({});
45
  setLoading(true);
46
+ setNotification(null);
47
 
48
  try {
49
  if (mode === 'login') {
50
+ const { data, error } = await supabase.auth.signInWithPassword({
51
+ email,
52
+ password,
53
+ });
54
+ if (error) throw error;
55
+
56
+ // Check role
57
+ const role = data.user?.user_metadata?.role;
58
+ if (role === 'applicant') {
59
+ onNavigate('dashboard');
60
+ } else {
61
+ setNotification({ type: 'error', message: 'Unauthorized role detected.' });
62
+ await supabase.auth.signOut();
63
+ }
64
+ } else if (mode === 'register') {
 
 
 
 
65
  const { error } = await supabase.auth.signUp({
66
  email,
67
  password,
68
+ options: { data: { role: 'applicant' } }
 
 
 
 
69
  });
70
  if (error) throw error;
71
+ setNotification({ type: 'success', message: 'Registration successful! Please login.' });
72
  setMode('login');
73
  } else if (mode === 'forgot') {
 
74
  const { error } = await supabase.auth.resetPasswordForEmail(email, {
75
+ redirectTo: window.location.origin,
76
  });
77
  if (error) throw error;
78
  setNotification({ type: 'success', message: 'Password reset link sent! Check your email.' });
79
  setMode('login');
80
  }
81
  } catch (error) {
 
82
  setNotification({ type: 'error', message: error.message });
83
  } finally {
84
  setLoading(false);
85
  }
86
  };
87
+
88
  const formVariants = {
89
  hidden: { opacity: 0, y: 20 },
90
  visible: { opacity: 1, y: 0 },
 
92
  };
93
 
94
  const notificationStyles = {
95
+ padding: '0.75rem 1rem', marginBottom: '1rem', borderRadius: '0.5rem',
96
+ fontSize: '0.875rem', textAlign: 'center', border: '1px solid',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  };
98
 
99
  return (
100
  <div style={{ position: 'relative', minHeight: '100vh', width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '1rem', overflow: 'hidden', backgroundColor: '#020617', color: 'white', fontFamily: "'Montserrat', sans-serif" }}>
101
+ <style>{`@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap'); input:-webkit-autofill { -webkit-text-fill-color: #fff !important; -webkit-box-shadow: 0 0 0px 1000px rgba(251, 191, 36, 0.1) inset !important; }`}</style>
102
+
103
+ {/* --- 🔴 FIXED BACK BUTTON (Z-INDEX 999) --- */}
104
+ <button
105
+ onClick={() => onNavigate('login')} // Ensure this matches your prop name
106
+ style={{
107
+ position: 'fixed', // Changed from absolute to fixed
108
+ top: '20px',
109
+ left: '20px',
110
+ display: 'flex',
111
+ alignItems: 'center',
112
+ justifyContent: 'center',
113
+ gap: '8px',
114
+ padding: '12px 20px',
115
+ backgroundColor: '#3a2f04',
116
+ color: '#cebe65',
117
+ border: '2px solid #3a2f04',
118
+ borderRadius: '10px',
119
+ fontWeight: '700',
120
+ cursor: 'pointer',
121
+ zIndex: 9999, // Super high Z-Index
122
+ boxShadow: '0 4px 10px rgba(0,0,0,0.3)'
123
+ }}
124
+ >
125
+ <span>⬅</span> Back
126
+ </button>
127
+
128
+ {/* Background Orbs */}
129
  <>
130
  <div style={{ position: 'absolute', borderRadius: '50%', filter: 'blur(80px)', opacity: 0.4, width: '384px', height: '384px', backgroundColor: '#FBBF24', top: '-50px', left: '-100px' }}></div>
131
  <div style={{ position: 'absolute', borderRadius: '50%', filter: 'blur(80px)', opacity: 0.4, width: '320px', height: '320px', backgroundColor: '#F59E0B', bottom: '-80px', right: '-120px' }}></div>
132
  </>
133
+
134
+ <motion.div
135
  initial={{ opacity: 0, scale: 0.95 }}
136
  animate={{ opacity: 1, scale: 1 }}
137
+ transition={{ duration: 0.4 }}
138
+ style={{ width: '100%', maxWidth: '512px', borderRadius: '1rem', backgroundColor: 'rgba(251, 191, 36, 0.1)', backdropFilter: 'blur(12px)', border: '1px solid rgba(251, 191, 36, 0.3)', padding: '2rem', zIndex: 10 }}>
139
+
140
+ {/* Notification */}
141
  <AnimatePresence>
142
  {notification && (
143
  <motion.div
144
+ initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -10 }}
145
+ style={{
146
+ ...notificationStyles,
147
+ backgroundColor: notification.type === 'success' ? 'rgba(16, 185, 129, 0.1)' : 'rgba(239, 68, 68, 0.1)',
148
+ borderColor: notification.type === 'success' ? 'rgba(5, 150, 105, 0.3)' : 'rgba(220, 38, 38, 0.3)',
149
+ color: notification.type === 'success' ? '#34D399' : '#F87171'
150
+ }}
151
  >
152
  {notification.message}
153
  </motion.div>
154
  )}
155
  </AnimatePresence>
156
+
157
  <AnimatePresence mode="wait">
158
+ <motion.div key={mode} variants={formVariants} initial="hidden" animate="visible" exit="exit" transition={{ duration: 0.3 }}>
159
+
 
 
 
 
 
 
160
  {/* --- Login Form --- */}
161
  {mode === 'login' && (
162
  <div>
 
164
  <h2 style={{ fontSize: '1.875rem', fontWeight: 'bold', marginBottom: '1.5rem', textAlign: 'center' }}>Applicant Portal</h2>
165
  <form onSubmit={handleSubmit}>
166
  <div style={{ marginBottom: '1rem' }}>
167
+ <label style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Email</label>
168
+ <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="lead@example.com" disabled={loading} style={{ width: '100%', padding: '0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.email ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white' }} />
169
+ {errors.email && <p style={{ color: '#F87171', fontSize: '0.75rem', marginTop: '0.5rem' }}>{errors.email}</p>}
170
  </div>
171
  <div style={{ marginBottom: '1.5rem' }}>
172
+ <label style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Password</label>
173
+ <div style={{ position: 'relative' }}>
174
+ <input type={isPasswordVisible ? 'text' : 'password'} value={password} onChange={(e) => setPassword(e.target.value)} placeholder="••••••••" disabled={loading} style={{ width: '100%', padding: '0.75rem 3rem 0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.password ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white' }} />
175
+ <button type="button" onClick={() => setIsPasswordVisible(!isPasswordVisible)} style={{ position: 'absolute', right: '0.5rem', top: '50%', transform: 'translateY(-50%)', background: 'none', border: 'none', color: '#FCD34D', cursor: 'pointer' }}>{isPasswordVisible ? <EyeOffIcon /> : <EyeIcon />}</button>
 
 
 
 
176
  </div>
177
+ {errors.password ? <p style={{ color: '#F87171', fontSize: '0.75rem', marginTop: '0.5rem' }}>{errors.password}</p> : <button type="button" onClick={() => setMode('forgot')} style={{ fontSize: '0.75rem', color: '#FCD34D', background: 'none', border: 'none', cursor: 'pointer', float: 'right', marginTop: '0.5rem' }}>Forgot Password?</button>}
178
  </div>
179
+ <motion.button type="submit" whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.98 }} disabled={loading} style={{ width: '100%', backgroundColor: '#FBBF24', color: '#1a202c', fontWeight: 'bold', padding: '0.75rem 0', borderRadius: '0.5rem', border: 'none', cursor: 'pointer', marginTop: '1rem' }}>{loading ? 'Signing In...' : 'Sign In'}</motion.button>
 
 
180
  </form>
181
+ <p style={{ fontSize: '0.75rem', textAlign: 'center', color: '#9ca3af', marginTop: '2rem' }}>Don't have an account? <button onClick={() => setMode('register')} style={{ color: '#FCD34D', fontWeight: '600', background: 'none', border: 'none', cursor: 'pointer' }}>Register For Free</button></p>
182
  </div>
183
  )}
184
+
185
  {/* --- Register Form --- */}
186
  {mode === 'register' && (
187
  <div>
188
  <h2 style={{ fontSize: '1.875rem', fontWeight: 'bold', marginBottom: '1.5rem', textAlign: 'center' }}>Create Account</h2>
189
  <form onSubmit={handleSubmit}>
190
  <div style={{ marginBottom: '1rem' }}>
191
+ <label style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Email</label>
192
+ <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} disabled={loading} style={{ width: '100%', padding: '0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.email ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white' }} />
 
193
  </div>
194
  <div style={{ marginBottom: '1rem' }}>
195
+ <label style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Password</label>
196
+ <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} disabled={loading} style={{ width: '100%', padding: '0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.password ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white' }} />
 
197
  </div>
198
  <div style={{ marginBottom: '1.5rem' }}>
199
+ <label style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Confirm Password</label>
200
+ <input type="password" value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} disabled={loading} style={{ width: '100%', padding: '0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.confirmPassword ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white' }} />
 
201
  </div>
202
+ <motion.button type="submit" whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.98 }} disabled={loading} style={{ width: '100%', backgroundColor: '#FBBF24', color: '#1a202c', fontWeight: 'bold', padding: '0.75rem 0', borderRadius: '0.5rem', border: 'none', cursor: 'pointer' }}>{loading ? 'Registering...' : 'Register'}</motion.button>
 
 
203
  </form>
204
+ <p style={{ fontSize: '0.75rem', textAlign: 'center', color: '#9ca3af', marginTop: '2rem' }}>Already have an account? <button onClick={() => setMode('login')} style={{ color: '#FCD34D', fontWeight: '600', background: 'none', border: 'none', cursor: 'pointer' }}>Sign In</button></p>
205
  </div>
206
  )}
207
 
208
+ {/* --- Forgot Password --- */}
209
  {mode === 'forgot' && (
210
  <div>
211
  <h2 style={{ fontSize: '1.875rem', fontWeight: 'bold', marginBottom: '1.5rem', textAlign: 'center' }}>Forgot Password</h2>
 
212
  <form onSubmit={handleSubmit}>
213
  <div style={{ marginBottom: '1.5rem' }}>
214
+ <label style={{ display: 'block', fontSize: '0.875rem', fontWeight: '500', marginBottom: '0.5rem', color: '#d1d5db' }}>Email</label>
215
+ <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} disabled={loading} style={{ width: '100%', padding: '0.75rem 1rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid ${errors.email ? '#EF4444' : 'rgba(251, 191, 36, 0.3)'}`, borderRadius: '0.5rem', color: 'white' }} />
 
216
  </div>
217
+ <motion.button type="submit" whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.98 }} disabled={loading} style={{ width: '100%', backgroundColor: '#FBBF24', color: '#1a202c', fontWeight: 'bold', padding: '0.75rem 0', borderRadius: '0.5rem', border: 'none', cursor: 'pointer' }}>{loading ? 'Sending...' : 'Send Reset Link'}</motion.button>
 
 
218
  </form>
219
+ <p style={{ fontSize: '0.75rem', textAlign: 'center', color: '#9ca3af', marginTop: '2rem' }}><button onClick={() => setMode('login')} style={{ color: '#FCD34D', fontWeight: '600', background: 'none', border: 'none', cursor: 'pointer' }}>Back to Sign In</button></p>
220
  </div>
221
  )}
222
  </motion.div>