2025-06-04 15:09:28 +05:30

335 lines
15 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import { Eye, EyeOff, User, Lock, Mail, Camera, UserPlus, ArrowLeft, Check } from 'lucide-react';
// Mock navigation function for demo
const mockNavigate = (path) => {
console.log(`Navigating to: ${path}`);
alert(`Would navigate to: ${path}`);
};
const CreateAccountPage = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [reEnterPassword, setReEnterPassword] = useState('');
const [avatarImage, setAvatarImage] = useState(null);
const [showPassword, setShowPassword] = useState(false);
const [showReEnterPassword, setShowReEnterPassword] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [mounted, setMounted] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const [passwordStrength, setPasswordStrength] = useState(0);
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
// Calculate password strength
let strength = 0;
if (password.length >= 8) strength++;
if (/[A-Z]/.test(password)) strength++;
if (/[0-9]/.test(password)) strength++;
if (/[^A-Za-z0-9]/.test(password)) strength++;
setPasswordStrength(strength);
}, [password]);
const handleCreateAccount = async (e) => {
e.preventDefault();
setErrorMessage('');
setIsLoading(true);
if (!email || !password || !reEnterPassword) {
setErrorMessage('All fields are required.');
setIsLoading(false);
return;
}
if (password !== reEnterPassword) {
setErrorMessage('Passwords do not match.');
setIsLoading(false);
return;
}
if (password.length < 8) {
setErrorMessage('Password must be at least 8 characters long.');
setIsLoading(false);
return;
}
// Simulate API call
setTimeout(() => {
console.log('Account created successfully!');
alert('Account created successfully!');
mockNavigate('/login');
setIsLoading(false);
}, 2000);
};
const handleAvatarChange = (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
setAvatarImage(reader.result);
};
reader.readAsDataURL(file);
}
};
const getPasswordStrengthColor = () => {
if (passwordStrength === 0) return 'bg-gray-300';
if (passwordStrength === 1) return 'bg-red-400';
if (passwordStrength === 2) return 'bg-yellow-400';
if (passwordStrength === 3) return 'bg-blue-400';
return 'bg-green-400';
};
const getPasswordStrengthText = () => {
if (passwordStrength === 0) return 'Enter password';
if (passwordStrength === 1) return 'Weak';
if (passwordStrength === 2) return 'Fair';
if (passwordStrength === 3) return 'Good';
return 'Strong';
};
return (
<div className="min-h-screen bg-gradient-to-br from-purple-50 via-white to-purple-100 relative overflow-hidden">
{/* Background Elements */}
<div className="absolute inset-0">
{/* Subtle geometric shapes */}
<div className="absolute top-20 left-20 w-32 h-32 bg-purple-200 rounded-full opacity-20 animate-pulse"></div>
<div className="absolute bottom-20 right-20 w-24 h-24 bg-purple-300 rounded-full opacity-20 animate-pulse" style={{ animationDelay: '1s' }}></div>
<div className="absolute top-1/2 right-10 w-16 h-16 bg-purple-400 rounded-full opacity-15 animate-pulse" style={{ animationDelay: '2s' }}></div>
{/* Grid pattern */}
<div className="absolute inset-0 opacity-5" style={{
backgroundImage: `url("data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 40 40' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%236B46C1' fill-opacity='0.4'%3E%3Cpath d='M20 20h20v20H20V20zm-20 0h20v20H0V20z'/%3E%3C/g%3E%3C/svg%3E")`
}}></div>
</div>
{/* Main Content */}
<div className="relative z-10 min-h-screen flex items-center justify-center p-4">
{/* Background Logo */}
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
<div className={`text-center transition-all duration-2000 ${mounted ? 'opacity-5 scale-100' : 'opacity-0 scale-95'}`}>
</div>
</div>
{/* Create Account Card */}
<div className={`relative w-full max-w-lg transition-all duration-1000 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
{/* Card Background */}
<div className="bg-white rounded-3xl shadow-2xl border border-purple-100 overflow-hidden">
{/* Header Section */}
<div className="bg-gradient-to-r from-purple-600 to-purple-700 p-8 text-center relative">
<div className="absolute top-4 left-4">
<button
onClick={() => mockNavigate('/login')}
className="p-2 text-white hover:bg-white hover:bg-opacity-20 rounded-xl transition-all duration-200"
>
<ArrowLeft className="w-5 h-5" />
</button>
</div>
<div className="space-y-4">
<div className="inline-flex items-center justify-center w-16 h-16 bg-white bg-opacity-20 rounded-2xl">
<UserPlus className="w-8 h-8 text-white" />
</div>
<div>
<h1 className="text-3xl font-bold text-white mb-2">Create Account</h1>
<p className="text-purple-100">Join our community today</p>
</div>
</div>
</div>
{/* Form Section */}
<div className="p-8 space-y-6">
{/* Error Message */}
{errorMessage && (
<div className="bg-red-50 border border-red-200 rounded-xl p-4 text-red-700 text-sm">
{errorMessage}
</div>
)}
{/* Avatar Upload */}
<div className="text-center">
<div className="relative inline-block">
<input
accept="image/*"
id="avatar-input"
type="file"
className="hidden"
onChange={handleAvatarChange}
/>
<label htmlFor="avatar-input" className="cursor-pointer group">
<div className="relative">
<img
alt="Avatar"
src={avatarImage || 'https://via.placeholder.com/120/E5E7EB/6B7280?text=Photo'}
className="w-28 h-28 rounded-full border-4 border-purple-100 group-hover:border-purple-300 transition-all duration-200 object-cover"
/>
<div className="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-30 rounded-full transition-all duration-200 flex items-center justify-center">
<Camera className="w-6 h-6 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-200" />
</div>
</div>
</label>
</div>
<p className="text-sm text-gray-500 mt-2">Click to upload your photo</p>
</div>
{/* Form Fields */}
<div className="space-y-5">
{/* Email Field */}
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">Email Address</label>
<div className="relative group">
<div className="absolute left-4 top-1/2 transform -translate-y-1/2">
<Mail className="w-5 h-5 text-gray-400 group-focus-within:text-purple-500 transition-colors" />
</div>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full pl-12 pr-4 py-4 bg-gray-50 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200"
placeholder="Enter your email"
/>
</div>
</div>
{/* Password Field */}
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">Password</label>
<div className="relative group">
<div className="absolute left-4 top-1/2 transform -translate-y-1/2">
<Lock className="w-5 h-5 text-gray-400 group-focus-within:text-purple-500 transition-colors" />
</div>
<input
type={showPassword ? 'text' : 'password'}
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full pl-12 pr-12 py-4 bg-gray-50 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200"
placeholder="Create a strong password"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-4 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 transition-colors"
>
{showPassword ? <EyeOff className="w-5 h-5" /> : <Eye className="w-5 h-5" />}
</button>
</div>
{/* Password Strength Indicator */}
{password && (
<div className="space-y-2">
<div className="flex items-center space-x-2">
<div className="flex-1 bg-gray-200 rounded-full h-2">
<div
className={`h-2 rounded-full transition-all duration-300 ${getPasswordStrengthColor()}`}
style={{ width: `${(passwordStrength / 4) * 100}%` }}
></div>
</div>
<span className="text-xs font-medium text-gray-600">
{getPasswordStrengthText()}
</span>
</div>
<div className="text-xs text-gray-500 space-y-1">
<div className="flex items-center space-x-2">
<div className={`w-2 h-2 rounded-full ${password.length >= 8 ? 'bg-green-400' : 'bg-gray-300'}`}></div>
<span>At least 8 characters</span>
</div>
<div className="flex items-center space-x-2">
<div className={`w-2 h-2 rounded-full ${/[A-Z]/.test(password) ? 'bg-green-400' : 'bg-gray-300'}`}></div>
<span>One uppercase letter</span>
</div>
<div className="flex items-center space-x-2">
<div className={`w-2 h-2 rounded-full ${/[0-9]/.test(password) ? 'bg-green-400' : 'bg-gray-300'}`}></div>
<span>One number</span>
</div>
</div>
</div>
)}
</div>
{/* Re-enter Password Field */}
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">Confirm Password</label>
<div className="relative group">
<div className="absolute left-4 top-1/2 transform -translate-y-1/2">
<Lock className="w-5 h-5 text-gray-400 group-focus-within:text-purple-500 transition-colors" />
</div>
<input
type={showReEnterPassword ? 'text' : 'password'}
value={reEnterPassword}
onChange={(e) => setReEnterPassword(e.target.value)}
className={`w-full pl-12 pr-12 py-4 bg-gray-50 border rounded-xl focus:outline-none focus:ring-2 focus:border-transparent transition-all duration-200 ${
reEnterPassword && password !== reEnterPassword
? 'border-red-300 focus:ring-red-500'
: reEnterPassword && password === reEnterPassword
? 'border-green-300 focus:ring-green-500'
: 'border-gray-200 focus:ring-purple-500'
}`}
placeholder="Confirm your password"
/>
<button
type="button"
onClick={() => setShowReEnterPassword(!showReEnterPassword)}
className="absolute right-4 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 transition-colors"
>
{showReEnterPassword ? <EyeOff className="w-5 h-5" /> : <Eye className="w-5 h-5" />}
</button>
{reEnterPassword && password === reEnterPassword && (
<div className="absolute right-12 top-1/2 transform -translate-y-1/2">
<Check className="w-5 h-5 text-green-500" />
</div>
)}
</div>
{reEnterPassword && password !== reEnterPassword && (
<p className="text-xs text-red-500">Passwords do not match</p>
)}
</div>
</div>
{/* Create Account Button */}
<button
type="button"
onClick={handleCreateAccount}
disabled={isLoading || !email || !password || !reEnterPassword || password !== reEnterPassword}
className="w-full py-4 px-6 bg-gradient-to-r from-purple-600 to-purple-700 text-white font-semibold rounded-xl shadow-lg hover:shadow-xl transform hover:scale-105 transition-all duration-200 disabled:opacity-50 disabled:transform-none disabled:cursor-not-allowed"
>
<div className="flex items-center justify-center space-x-2">
{isLoading ? (
<>
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
<span>Creating Account...</span>
</>
) : (
<>
<UserPlus className="w-5 h-5" />
<span>Create Account</span>
</>
)}
</div>
</button>
{/* Login Link */}
<div className="text-center pt-4 border-t border-gray-100">
<p className="text-gray-600 mb-3">Already have an account?</p>
<button
type="button"
onClick={() => mockNavigate('/login')}
className="inline-flex items-center space-x-2 text-purple-600 hover:text-purple-700 font-semibold transition-colors"
>
<User className="w-4 h-4" />
<span>Sign In</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default CreateAccountPage;