diff --git a/pages/login.js b/pages/login.js index 4875493..cb6476f 100644 --- a/pages/login.js +++ b/pages/login.js @@ -1,5 +1,6 @@ import { useState } from 'react'; import { useRouter } from 'next/router'; +import Link from 'next/link'; import AuthLayout from '../components/AuthLayout'; import AnimatedFireLogo from '../components/AnimatedFireLogo'; @@ -165,23 +166,11 @@ export default function Login() {

Quick Login for Testing:

-
- +
- -
-

- Use the quick login buttons above for testing, or enter credentials manually. -

-
- - - {/* Testing Guide */} -
-
-

- ๐Ÿงช Testing Accounts -

-
-

Admin: Full system access

-

Alice: Regular user for testing

-

Bob: Collaborator for testing

+
+

+ Don't have an account?{' '} + + Sign up here + +

-
+
diff --git a/pages/signup.js b/pages/signup.js new file mode 100644 index 0000000..c94530a --- /dev/null +++ b/pages/signup.js @@ -0,0 +1,307 @@ +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import Link from 'next/link'; +import AuthLayout from '../components/AuthLayout'; +import AnimatedFireLogo from '../components/AnimatedFireLogo'; + +export default function Signup() { + const router = useRouter(); + const [formData, setFormData] = useState({ + email: '', + password: '', + confirmPassword: '', + firstName: '', + lastName: '' + }); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + const [validationErrors, setValidationErrors] = useState({}); + + const handleInputChange = (field, value) => { + setFormData(prev => ({ + ...prev, + [field]: value + })); + // Clear errors when user starts typing + if (error) setError(''); + if (validationErrors[field]) { + setValidationErrors(prev => ({ + ...prev, + [field]: '' + })); + } + }; + + const validateForm = () => { + const errors = {}; + + // Email validation + if (!formData.email) { + errors.email = 'Email is required'; + } else if (!/\S+@\S+\.\S+/.test(formData.email)) { + errors.email = 'Please enter a valid email address'; + } + + // Password validation + if (!formData.password) { + errors.password = 'Password is required'; + } else if (formData.password.length < 6) { + errors.password = 'Password must be at least 6 characters'; + } + + // Confirm password validation + if (!formData.confirmPassword) { + errors.confirmPassword = 'Please confirm your password'; + } else if (formData.password !== formData.confirmPassword) { + errors.confirmPassword = 'Passwords do not match'; + } + + // Name validation + if (!formData.firstName.trim()) { + errors.firstName = 'First name is required'; + } + + if (!formData.lastName.trim()) { + errors.lastName = 'Last name is required'; + } + + setValidationErrors(errors); + return Object.keys(errors).length === 0; + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + + if (!validateForm()) { + return; + } + + setLoading(true); + setError(''); + + try { + const response = await fetch('/api/auth/register', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + email: formData.email, + password: formData.password, + firstName: formData.firstName, + lastName: formData.lastName + }) + }); + + const data = await response.json(); + + if (response.ok) { + // Store the JWT token in localStorage + localStorage.setItem('auth_token', data.token); + + // Redirect to dashboard + router.push('/dashboard'); + } else { + setError(data.error || 'Registration failed'); + } + } catch (error) { + console.error('Registration error:', error); + setError('Network error. Please try again.'); + } finally { + setLoading(false); + } + }; + + return ( + +
+
+
+
+
+ +
+

+ Join Deck Hearth +

+

+ Create your account to start building your collection +

+
+
+ +
+
+ {error && ( +
+

{error}

+
+ )} + +
+
+ + handleInputChange('firstName', e.target.value)} + className="w-full px-4 py-3 rounded-lg border transition-all duration-200 focus:ring-2 focus:ring-orange-500 focus:border-transparent backdrop-blur-sm" + style={{ + backgroundColor: 'rgba(var(--bg-primary-rgb), 0.7)', + borderColor: validationErrors.firstName ? '#ef4444' : 'var(--border)', + color: 'var(--text-primary)' + }} + placeholder="John" + /> + {validationErrors.firstName && ( +

{validationErrors.firstName}

+ )} +
+ +
+ + handleInputChange('lastName', e.target.value)} + className="w-full px-4 py-3 rounded-lg border transition-all duration-200 focus:ring-2 focus:ring-orange-500 focus:border-transparent backdrop-blur-sm" + style={{ + backgroundColor: 'rgba(var(--bg-primary-rgb), 0.7)', + borderColor: validationErrors.lastName ? '#ef4444' : 'var(--border)', + color: 'var(--text-primary)' + }} + placeholder="Doe" + /> + {validationErrors.lastName && ( +

{validationErrors.lastName}

+ )} +
+
+ +
+ + handleInputChange('email', e.target.value)} + className="w-full px-4 py-3 rounded-lg border transition-all duration-200 focus:ring-2 focus:ring-orange-500 focus:border-transparent backdrop-blur-sm" + style={{ + backgroundColor: 'rgba(var(--bg-primary-rgb), 0.7)', + borderColor: validationErrors.email ? '#ef4444' : 'var(--border)', + color: 'var(--text-primary)' + }} + placeholder="john@example.com" + /> + {validationErrors.email && ( +

{validationErrors.email}

+ )} +
+ +
+ + handleInputChange('password', e.target.value)} + className="w-full px-4 py-3 rounded-lg border transition-all duration-200 focus:ring-2 focus:ring-orange-500 focus:border-transparent backdrop-blur-sm" + style={{ + backgroundColor: 'rgba(var(--bg-primary-rgb), 0.7)', + borderColor: validationErrors.password ? '#ef4444' : 'var(--border)', + color: 'var(--text-primary)' + }} + placeholder="At least 6 characters" + /> + {validationErrors.password && ( +

{validationErrors.password}

+ )} +
+ +
+ + handleInputChange('confirmPassword', e.target.value)} + className="w-full px-4 py-3 rounded-lg border transition-all duration-200 focus:ring-2 focus:ring-orange-500 focus:border-transparent backdrop-blur-sm" + style={{ + backgroundColor: 'rgba(var(--bg-primary-rgb), 0.7)', + borderColor: validationErrors.confirmPassword ? '#ef4444' : 'var(--border)', + color: 'var(--text-primary)' + }} + placeholder="Confirm your password" + /> + {validationErrors.confirmPassword && ( +

{validationErrors.confirmPassword}

+ )} +
+ +
+ +
+ +
+

+ Already have an account?{' '} + + Sign in here + +

+
+
+
+
+
+
+ ); +} \ No newline at end of file