280 lines
10 KiB
TypeScript
280 lines
10 KiB
TypeScript
import { useState } from 'react';
|
|
import { Link, useNavigate } from 'react-router-dom';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { useAuth } from '@/contexts/AuthContext';
|
|
import { useLanguage } from '@/contexts/LanguageContext';
|
|
import { Apple, Eye, EyeOff } from 'lucide-react';
|
|
import { FaGoogle } from 'react-icons/fa';
|
|
|
|
const SignUp = () => {
|
|
const [formData, setFormData] = useState({
|
|
fullName: '',
|
|
email: '',
|
|
password: '',
|
|
confirmPassword: '',
|
|
userType: 'tourist' as 'tourist' | 'business'
|
|
});
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
|
const [agreeToTerms, setAgreeToTerms] = useState(false);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState('');
|
|
|
|
const { register } = useAuth();
|
|
const { t } = useLanguage();
|
|
const navigate = useNavigate();
|
|
|
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
|
|
setFormData({
|
|
...formData,
|
|
[e.target.name]: e.target.value
|
|
});
|
|
};
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setError('');
|
|
|
|
if (formData.password !== formData.confirmPassword) {
|
|
setError('Las contraseñas no coinciden');
|
|
return;
|
|
}
|
|
|
|
if (!agreeToTerms) {
|
|
setError('Debes aceptar los términos de servicio');
|
|
return;
|
|
}
|
|
|
|
setIsLoading(true);
|
|
|
|
try {
|
|
await register({
|
|
name: formData.fullName,
|
|
email: formData.email,
|
|
password: formData.password,
|
|
type: formData.userType,
|
|
location: { lat: 18.4861, lng: -69.9312 }, // Default to Santo Domingo
|
|
preferences: { language: 'es' }
|
|
});
|
|
navigate('/dashboard');
|
|
} catch (err: any) {
|
|
setError(err.message);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleSocialLogin = (provider: string) => {
|
|
console.log(`Register with ${provider}`);
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen flex">
|
|
{/* Left Side - Form */}
|
|
<div className="flex-1 flex items-center justify-center p-8 bg-white">
|
|
<div className="w-full max-w-md space-y-8">
|
|
{/* Header */}
|
|
<div className="text-center">
|
|
<h1 className="text-3xl font-bold text-gray-900 mb-2">
|
|
{t('welcomeSignUp')} <span className="text-primary italic">{t('signUp')}</span> {t('toContinue')}
|
|
</h1>
|
|
<p className="text-gray-600 text-sm leading-relaxed">
|
|
{t('unlockContent')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Social Login Buttons */}
|
|
<div className="space-y-3">
|
|
<Button
|
|
variant="outline"
|
|
onClick={() => handleSocialLogin('apple')}
|
|
className="w-full h-12 bg-gray-900 text-white hover:bg-gray-800 border-gray-900"
|
|
>
|
|
<Apple className="w-5 h-5 mr-3" />
|
|
{t('signUpWithApple')}
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outline"
|
|
onClick={() => handleSocialLogin('google')}
|
|
className="w-full h-12 bg-gray-100 text-gray-700 hover:bg-gray-200"
|
|
>
|
|
<FaGoogle className="w-5 h-5 mr-3" />
|
|
{t('signUpWithGoogle')}
|
|
</Button>
|
|
|
|
<p className="text-xs text-gray-500 text-center">
|
|
{t('privacyNotice')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Divider */}
|
|
<div className="relative">
|
|
<div className="absolute inset-0 flex items-center">
|
|
<div className="w-full border-t border-gray-300" />
|
|
</div>
|
|
<div className="relative flex justify-center text-sm">
|
|
<span className="px-4 bg-white text-gray-500">Or</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Registration Form */}
|
|
<form onSubmit={handleSubmit} className="space-y-6">
|
|
{error && (
|
|
<div className="bg-red-50 text-red-500 p-3 rounded-lg text-sm">
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<div className="space-y-4">
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
{t('fullName')} <span className="text-red-500">*</span>
|
|
</label>
|
|
<Input
|
|
type="text"
|
|
name="fullName"
|
|
value={formData.fullName}
|
|
onChange={handleChange}
|
|
placeholder="Ingresa tu nombre completo"
|
|
className="h-12"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
Tipo de Usuario <span className="text-red-500">*</span>
|
|
</label>
|
|
<select
|
|
name="userType"
|
|
value={formData.userType}
|
|
onChange={handleChange}
|
|
className="w-full h-12 px-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary"
|
|
required
|
|
>
|
|
<option value="tourist">Turista</option>
|
|
<option value="business">Comercio</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
{t('enterEmail')} <span className="text-red-500">*</span>
|
|
</label>
|
|
<Input
|
|
type="email"
|
|
name="email"
|
|
value={formData.email}
|
|
onChange={handleChange}
|
|
placeholder={t('enterValidEmail')}
|
|
className="h-12"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
{t('password')} <span className="text-red-500">*</span>
|
|
</label>
|
|
<div className="relative">
|
|
<Input
|
|
type={showPassword ? 'text' : 'password'}
|
|
name="password"
|
|
value={formData.password}
|
|
onChange={handleChange}
|
|
placeholder={t('enterPassword')}
|
|
className="h-12 pr-12"
|
|
required
|
|
/>
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowPassword(!showPassword)}
|
|
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
|
>
|
|
{showPassword ? <EyeOff className="w-5 h-5" /> : <Eye className="w-5 h-5" />}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
{t('confirmPassword')} <span className="text-red-500">*</span>
|
|
</label>
|
|
<div className="relative">
|
|
<Input
|
|
type={showConfirmPassword ? 'text' : 'password'}
|
|
name="confirmPassword"
|
|
value={formData.confirmPassword}
|
|
onChange={handleChange}
|
|
placeholder="Confirma tu contraseña"
|
|
className="h-12 pr-12"
|
|
required
|
|
/>
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
|
|
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
|
>
|
|
{showConfirmPassword ? <EyeOff className="w-5 h-5" /> : <Eye className="w-5 h-5" />}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-start">
|
|
<input
|
|
type="checkbox"
|
|
id="terms"
|
|
checked={agreeToTerms}
|
|
onChange={(e) => setAgreeToTerms(e.target.checked)}
|
|
className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mt-1"
|
|
/>
|
|
<label htmlFor="terms" className="ml-2 text-sm text-gray-700">
|
|
By signing up, you agree to the{' '}
|
|
<Link to="/terms" className="text-primary hover:underline">
|
|
terms of service
|
|
</Link>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<Button
|
|
type="submit"
|
|
disabled={isLoading}
|
|
className="w-full h-12 bg-primary hover:bg-primary-dark text-white font-semibold"
|
|
>
|
|
{isLoading ? t('loading') : t('signUp')}
|
|
</Button>
|
|
|
|
<div className="text-center">
|
|
<p className="text-sm text-gray-600">
|
|
Already have an account?{' '}
|
|
<Link to="/sign-in" className="text-primary hover:underline font-medium">
|
|
{t('signIn')}
|
|
</Link>
|
|
</p>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right Side - Image & Content */}
|
|
<div className="hidden lg:flex flex-1 bg-gray-100 items-center justify-center p-8">
|
|
<div className="text-center max-w-md">
|
|
<h2 className="text-4xl font-bold text-gray-900 mb-4 leading-tight">
|
|
Effortlessly organize your workspace with ease.
|
|
</h2>
|
|
<p className="text-gray-600 mb-8">
|
|
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.
|
|
</p>
|
|
<div className="bg-gray-300 rounded-lg h-64 flex items-center justify-center">
|
|
<span className="text-6xl font-bold text-gray-500">698x609</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default SignUp; |