Spaces:
Runtime error
Runtime error
File size: 9,022 Bytes
2070fe3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | import React, { useState } from 'react';
import { useAuth } from '../context/AuthContext';
import { useNavigate } from 'react-router-dom';
// Icons
const CloseIcon = ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
);
const GoogleIcon = ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className={className}>
<path d="M12.479,14.265v-3.279h11.049c0.108,0.571,0.164,1.247,0.164,1.979c0,2.46-0.672,5.502-2.84,7.669 C18.744,22.829,16.051,24,12.483,24C5.869,24,0.308,18.613,0.308,12S5.869,0,12.483,0c3.659,0,6.265,1.436,8.223,3.307L18.392,5.62 c-1.404-1.317-3.307-2.341-5.913-2.341C7.65,3.279,3.873,7.171,3.873,12s3.777,8.721,8.606,8.721c3.132,0,4.916-1.258,6.059-2.401 c0.927-0.927,1.537-2.251,1.777-4.059L12.479,14.265z" />
</svg>
);
const AtSignIcon = ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}><circle cx="12" cy="12" r="4"/><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-3.92 7.94"/></svg>
);
const UserIcon = ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
);
const LockIcon = ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
);
const SignupModal = ({ onClose, onLogin }) => {
const [formData, setFormData] = useState({
username: '',
email: '',
password: '',
});
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const { register, googleLogin } = useAuth();
const navigate = useNavigate();
const handleChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
const handleSubmit = async (e) => {
e.preventDefault();
setError('');
if (formData.password.length < 6) {
setError('Password must be at least 6 characters');
return;
}
setLoading(true);
try {
await register(formData);
onClose();
navigate('/dashboard');
} catch (err) {
setError(err.response?.data?.message || 'Registration failed');
} finally {
setLoading(false);
}
};
const handleGoogleLogin = () => {
googleLogin();
};
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm p-4">
{/* Container echoing the AuthPage styling */}
<div className="relative w-full max-w-md bg-black border border-gray-800 rounded-xl overflow-hidden shadow-2xl">
{/* Background Gradients */}
<div className="absolute inset-0 pointer-events-none opacity-40">
<div className="absolute top-0 right-0 h-[300px] w-[300px] bg-purple-900/20 blur-[100px] rounded-full translate-x-1/3 -translate-y-1/3" />
<div className="absolute bottom-0 left-0 h-[300px] w-[300px] bg-blue-900/10 blur-[100px] rounded-full -translate-x-1/3 translate-y-1/3" />
</div>
{/* Close Button */}
<button onClick={onClose} className="absolute top-4 right-4 text-gray-400 hover:text-white transition z-20">
<CloseIcon className="w-5 h-5" />
</button>
<div className="relative z-10 p-8">
{/* Header */}
<div className="flex flex-col space-y-1 mb-6 text-center md:text-left">
<h1 className="text-2xl font-bold tracking-wide text-white">Create Account</h1>
<p className="text-gray-400 text-sm">
Sign up to start your journey.
</p>
</div>
{/* Google Button */}
<div className="space-y-2 mb-6">
<button
onClick={handleGoogleLogin}
type="button"
className="w-full flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium h-10 px-4 py-2 border border-gray-700 bg-gray-900 hover:bg-gray-800 hover:text-white text-gray-200 transition-colors"
>
<GoogleIcon className="w-4 h-4 mr-2" />
Continue with Google
</button>
</div>
{/* Separator */}
<div className="flex w-full items-center justify-center mb-6">
<div className="bg-gray-800 h-px w-full" />
<span className="text-gray-500 px-2 text-xs uppercase">OR</span>
<div className="bg-gray-800 h-px w-full" />
</div>
{/* Error Message */}
{error && (
<div className="mb-4 p-3 bg-red-500/10 border border-red-500/50 rounded-md text-red-500 text-sm">
{error}
</div>
)}
{/* Signup Form */}
<form onSubmit={handleSubmit} className="space-y-4">
{/* Username */}
<div className="space-y-2">
<div className="relative">
<input
type="text"
name="username"
placeholder="Username"
value={formData.username}
onChange={handleChange}
required
className="flex h-10 w-full rounded-md border border-gray-700 bg-black px-3 py-2 pl-9 text-sm text-white placeholder:text-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent transition-all"
/>
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3 text-gray-500">
<UserIcon className="w-4 h-4" />
</div>
</div>
</div>
{/* Email */}
<div className="space-y-2">
<div className="relative">
<input
type="email"
name="email"
placeholder="name@example.com"
value={formData.email}
onChange={handleChange}
required
className="flex h-10 w-full rounded-md border border-gray-700 bg-black px-3 py-2 pl-9 text-sm text-white placeholder:text-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent transition-all"
/>
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3 text-gray-500">
<AtSignIcon className="w-4 h-4" />
</div>
</div>
</div>
{/* Password */}
<div className="space-y-2">
<div className="relative">
<input
type="password"
name="password"
placeholder="Password (min 6 chars)"
value={formData.password}
onChange={handleChange}
required
className="flex h-10 w-full rounded-md border border-gray-700 bg-black px-3 py-2 pl-9 text-sm text-white placeholder:text-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent transition-all"
/>
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3 text-gray-500">
<LockIcon className="w-4 h-4" />
</div>
</div>
</div>
<button
type="submit"
disabled={loading}
className="w-full inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium h-10 px-4 py-2 bg-purple-600 text-white hover:bg-purple-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? 'Creating account...' : 'Create Account'}
</button>
</form>
{/* Footer */}
<p className="mt-6 text-center text-sm text-gray-400">
Already have an account?{' '}
<button
onClick={onLogin}
className="text-purple-400 hover:text-purple-300 font-medium underline underline-offset-4"
>
Log In
</button>
</p>
</div>
</div>
</div>
);
};
export default SignupModal; |