|
1 | 1 | import { useState } from 'react'; |
2 | 2 | import { useAuth } from '../contexts/AuthContext'; |
3 | | -import { Keyboard, Mail, Lock, AlertCircle, Github } from 'lucide-react'; |
| 3 | +import { Keyboard, Mail, Lock, AlertCircle, CheckCircle, Github } from 'lucide-react'; // Added CheckCircle |
4 | 4 |
|
5 | 5 | export default function Auth() { |
6 | 6 | const [isLogin, setIsLogin] = useState(true); |
7 | 7 | const [email, setEmail] = useState(''); |
8 | 8 | const [password, setPassword] = useState(''); |
9 | 9 | const [error, setError] = useState(''); |
| 10 | + const [successMessage, setSuccessMessage] = useState(''); |
| 11 | + const [isConfirmationSent, setIsConfirmationSent] = useState(false); // New state |
10 | 12 | const [loading, setLoading] = useState(false); |
11 | 13 | const { signIn, signUp, signInWithGithub } = useAuth(); |
12 | 14 |
|
13 | 15 | const handleSubmit = async (e: React.FormEvent) => { |
14 | 16 | e.preventDefault(); |
15 | 17 | setError(''); |
| 18 | + setSuccessMessage(''); |
16 | 19 | setLoading(true); |
17 | 20 |
|
18 | | - const { error } = isLogin |
| 21 | + const result = isLogin |
19 | 22 | ? await signIn(email, password) |
20 | 23 | : await signUp(email, password); |
21 | 24 |
|
22 | | - if (error) { |
23 | | - setError(error.message); |
| 25 | + if (result.error) { |
| 26 | + setError(result.error.message); |
| 27 | + setIsConfirmationSent(false); |
| 28 | + } else { |
| 29 | + setSuccessMessage(''); |
| 30 | + setIsConfirmationSent(true); // Set flag for confirmation UI |
24 | 31 | } |
25 | 32 |
|
26 | 33 | setLoading(false); |
@@ -48,111 +55,144 @@ export default function Auth() { |
48 | 55 | </div> |
49 | 56 |
|
50 | 57 | <div className="bg-white rounded-2xl shadow-xl p-8"> |
51 | | - <div className="flex gap-2 mb-6"> |
52 | | - <button |
53 | | - onClick={() => setIsLogin(true)} |
54 | | - className={`flex-1 py-2 rounded-lg font-medium transition-all ${ |
55 | | - isLogin |
56 | | - ? 'bg-blue-600 text-white' |
57 | | - : 'bg-gray-100 text-gray-600 hover:bg-gray-200' |
58 | | - }`} |
59 | | - > |
60 | | - Login |
61 | | - </button> |
62 | | - <button |
63 | | - onClick={() => setIsLogin(false)} |
64 | | - className={`flex-1 py-2 rounded-lg font-medium transition-all ${ |
65 | | - !isLogin |
66 | | - ? 'bg-blue-600 text-white' |
67 | | - : 'bg-gray-100 text-gray-600 hover:bg-gray-200' |
68 | | - }`} |
69 | | - > |
70 | | - Sign Up |
71 | | - </button> |
72 | | - </div> |
73 | | - |
74 | | - {error && ( |
75 | | - <div className="mb-4 p-3 bg-red-50 border border-red-200 rounded-lg flex items-center gap-2 text-red-700 text-sm"> |
76 | | - <AlertCircle className="w-4 h-4 flex-shrink-0" /> |
77 | | - <span>{error}</span> |
78 | | - </div> |
79 | | - )} |
80 | | - |
81 | | - {/* GitHub Sign-In Button */} |
82 | | - <button |
83 | | - onClick={handleGithubSignIn} |
84 | | - disabled={loading} |
85 | | - className="w-full py-3 mb-4 bg-gray-900 text-white rounded-lg hover:bg-gray-800 transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" |
86 | | - > |
87 | | - <Github className="w-5 h-5" /> |
88 | | - Sign in with GitHub |
89 | | - </button> |
90 | | - |
91 | | - <div className="relative mb-4"> |
92 | | - <div className="absolute inset-0 flex items-center"> |
93 | | - <div className="w-full border-t border-gray-300"></div> |
94 | | - </div> |
95 | | - <div className="relative flex justify-center text-sm"> |
96 | | - <span className="px-2 bg-white text-gray-500"> |
97 | | - Or continue with email |
98 | | - </span> |
| 58 | + {isConfirmationSent ? ( |
| 59 | + // Confirmation UI |
| 60 | + <div className="text-center"> |
| 61 | + <CheckCircle className="w-16 h-16 text-green-500 mx-auto mb-4" /> |
| 62 | + <h2 className="text-2xl font-bold text-gray-800 mb-2">Check Your Email</h2> |
| 63 | + <p className="text-gray-600 mb-4"> |
| 64 | + We've sent a confirmation link to <strong>{email}</strong>. |
| 65 | + </p> |
| 66 | + <ul className="text-left text-sm text-gray-600 mb-6 space-y-2"> |
| 67 | + <li>1. Open your email inbox.</li> |
| 68 | + <li>2. Click the confirmation link.</li> |
| 69 | + <li>3. Return here and log in.</li> |
| 70 | + </ul> |
| 71 | + <button |
| 72 | + onClick={() => { |
| 73 | + setIsConfirmationSent(false); |
| 74 | + setSuccessMessage(''); |
| 75 | + setIsLogin(true); |
| 76 | + }} |
| 77 | + className="w-full py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium" |
| 78 | + > |
| 79 | + Back to Login |
| 80 | + </button> |
99 | 81 | </div> |
100 | | - </div> |
101 | | - |
102 | | - <form onSubmit={handleSubmit} className="space-y-4"> |
103 | | - <div> |
104 | | - <label className="block text-sm font-medium text-gray-700 mb-2"> |
105 | | - Email |
106 | | - </label> |
107 | | - <div className="relative"> |
108 | | - <Mail className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> |
109 | | - <input |
110 | | - type="email" |
111 | | - value={email} |
112 | | - onChange={(e) => setEmail(e.target.value)} |
113 | | - className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none" |
114 | | - placeholder="you@example.com" |
115 | | - required |
116 | | - /> |
| 82 | + ) : ( |
| 83 | + // Normal Auth UI |
| 84 | + <> |
| 85 | + <div className="flex gap-2 mb-6"> |
| 86 | + <button |
| 87 | + onClick={() => setIsLogin(true)} |
| 88 | + className={`flex-1 py-2 rounded-lg font-medium transition-all ${ |
| 89 | + isLogin |
| 90 | + ? 'bg-blue-600 text-white' |
| 91 | + : 'bg-gray-100 text-gray-600 hover:bg-gray-200' |
| 92 | + }`} |
| 93 | + > |
| 94 | + Login |
| 95 | + </button> |
| 96 | + <button |
| 97 | + onClick={() => setIsLogin(false)} |
| 98 | + className={`flex-1 py-2 rounded-lg font-medium transition-all ${ |
| 99 | + !isLogin |
| 100 | + ? 'bg-blue-600 text-white' |
| 101 | + : 'bg-gray-100 text-gray-600 hover:bg-gray-200' |
| 102 | + }`} |
| 103 | + > |
| 104 | + Sign Up |
| 105 | + </button> |
117 | 106 | </div> |
118 | | - </div> |
119 | 107 |
|
120 | | - <div> |
121 | | - <label className="block text-sm font-medium text-gray-700 mb-2"> |
122 | | - Password |
123 | | - </label> |
124 | | - <div className="relative"> |
125 | | - <Lock className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> |
126 | | - <input |
127 | | - type="password" |
128 | | - value={password} |
129 | | - onChange={(e) => setPassword(e.target.value)} |
130 | | - className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none" |
131 | | - placeholder="••••••••" |
132 | | - required |
133 | | - minLength={6} |
134 | | - /> |
| 108 | + {error && ( |
| 109 | + <div className="mb-4 p-3 bg-red-50 border border-red-200 rounded-lg flex items-center gap-2 text-red-700 text-sm"> |
| 110 | + <AlertCircle className="w-4 h-4 flex-shrink-0" /> |
| 111 | + <span>{error}</span> |
| 112 | + </div> |
| 113 | + )} |
| 114 | + |
| 115 | + {successMessage && ( |
| 116 | + <div className="mb-4 p-3 bg-green-50 border border-green-200 rounded-lg flex items-center gap-2 text-green-700 text-sm"> |
| 117 | + <CheckCircle className="w-4 h-4 flex-shrink-0" /> |
| 118 | + <span>{successMessage}</span> |
| 119 | + </div> |
| 120 | + )} |
| 121 | + |
| 122 | + <button |
| 123 | + onClick={handleGithubSignIn} |
| 124 | + disabled={loading} |
| 125 | + className="w-full py-3 mb-4 bg-gray-900 text-white rounded-lg hover:bg-gray-800 transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" |
| 126 | + > |
| 127 | + <Github className="w-5 h-5" /> |
| 128 | + Sign in with GitHub |
| 129 | + </button> |
| 130 | + |
| 131 | + <div className="relative mb-4"> |
| 132 | + <div className="absolute inset-0 flex items-center"> |
| 133 | + <div className="w-full border-t border-gray-300"></div> |
| 134 | + </div> |
| 135 | + <div className="relative flex justify-center text-sm"> |
| 136 | + <span className="px-2 bg-white text-gray-500">Or continue with email</span> |
| 137 | + </div> |
135 | 138 | </div> |
136 | | - </div> |
137 | 139 |
|
138 | | - <button |
139 | | - type="submit" |
140 | | - disabled={loading} |
141 | | - className="w-full py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed" |
142 | | - > |
143 | | - {loading ? 'Loading...' : isLogin ? 'Login' : 'Sign Up'} |
144 | | - </button> |
145 | | - </form> |
146 | | - |
147 | | - <div className="mt-6 text-center text-sm text-gray-600"> |
148 | | - {isLogin ? "Don't have an account? " : "Already have an account? "} |
149 | | - <button |
150 | | - onClick={() => setIsLogin(!isLogin)} |
151 | | - className="text-blue-600 hover:text-blue-700 font-medium" |
152 | | - > |
153 | | - {isLogin ? 'Sign up' : 'Login'} |
154 | | - </button> |
155 | | - </div> |
| 140 | + <form onSubmit={handleSubmit} className="space-y-4"> |
| 141 | + <div> |
| 142 | + <label className="block text-sm font-medium text-gray-700 mb-2"> |
| 143 | + Email |
| 144 | + </label> |
| 145 | + <div className="relative"> |
| 146 | + <Mail className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> |
| 147 | + <input |
| 148 | + type="email" |
| 149 | + value={email} |
| 150 | + onChange={(e) => setEmail(e.target.value)} |
| 151 | + className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none" |
| 152 | + placeholder="you@example.com" |
| 153 | + required |
| 154 | + /> |
| 155 | + </div> |
| 156 | + </div> |
| 157 | + |
| 158 | + <div> |
| 159 | + <label className="block text-sm font-medium text-gray-700 mb-2"> |
| 160 | + Password |
| 161 | + </label> |
| 162 | + <div className="relative"> |
| 163 | + <Lock className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> |
| 164 | + <input |
| 165 | + type="password" |
| 166 | + value={password} |
| 167 | + onChange={(e) => setPassword(e.target.value)} |
| 168 | + className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none" |
| 169 | + placeholder="••••••••" |
| 170 | + required |
| 171 | + minLength={6} |
| 172 | + /> |
| 173 | + </div> |
| 174 | + </div> |
| 175 | + |
| 176 | + <button |
| 177 | + type="submit" |
| 178 | + disabled={loading} |
| 179 | + className="w-full py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed" |
| 180 | + > |
| 181 | + {loading ? 'Loading...' : isLogin ? 'Login' : 'Sign Up'} |
| 182 | + </button> |
| 183 | + </form> |
| 184 | + |
| 185 | + <div className="mt-6 text-center text-sm text-gray-600"> |
| 186 | + {isLogin ? "Don't have an account? " : "Already have an account? "} |
| 187 | + <button |
| 188 | + onClick={() => setIsLogin(!isLogin)} |
| 189 | + className="text-blue-600 hover:text-blue-700 font-medium" |
| 190 | + > |
| 191 | + {isLogin ? 'Sign up' : 'Login'} |
| 192 | + </button> |
| 193 | + </div> |
| 194 | + </> |
| 195 | + )} |
156 | 196 | </div> |
157 | 197 |
|
158 | 198 | <div className="mt-6 text-center text-sm text-gray-500"> |
|
0 commit comments