← back to Watches
src/components/LoginForm.jsx
121 lines
/**
* Login Form Component
* Email/password login with forgot password link
*/
import React, { useState } from 'react';
const LoginForm = ({ onSuccess, onError, onForgotPassword }) => {
const [formData, setFormData] = useState({
email: '',
password: ''
});
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
setError('');
};
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setError('');
try {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(formData)
});
const data = await response.json();
if (data.success) {
onSuccess?.(data.user);
// Reload page to update auth state
window.location.reload();
} else {
setError(data.error);
onError?.(data.error);
}
} catch (error) {
setError('Login failed. Please try again.');
onError?.(error.message);
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
{error && (
<div className="p-3 bg-red-50 border border-red-200 rounded-lg text-red-600 text-sm">
{error}
</div>
)}
<div>
<label htmlFor="login-email" className="block text-sm font-medium text-gray-700 mb-1">
Email
</label>
<input
type="email"
id="login-email"
name="email"
value={formData.email}
onChange={handleChange}
className="w-full px-4 py-2 border border-gray-300 rounded-lg
focus:ring-2 focus:ring-blue-500 focus:border-blue-500
transition-colors"
placeholder="you@example.com"
required
/>
</div>
<div>
<div className="flex justify-between items-center mb-1">
<label htmlFor="login-password" className="block text-sm font-medium text-gray-700">
Password
</label>
<button
type="button"
onClick={onForgotPassword}
className="text-sm text-blue-600 hover:text-blue-700"
>
Forgot password?
</button>
</div>
<input
type="password"
id="login-password"
name="password"
value={formData.password}
onChange={handleChange}
className="w-full px-4 py-2 border border-gray-300 rounded-lg
focus:ring-2 focus:ring-blue-500 focus:border-blue-500
transition-colors"
placeholder="Your password"
required
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full py-3 px-4 bg-blue-600 text-white font-medium rounded-lg
hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
disabled:opacity-50 disabled:cursor-not-allowed
transition-colors"
>
{loading ? 'Signing in...' : 'Sign In'}
</button>
</form>
);
};
export default LoginForm;