173 lines
6.1 KiB
TypeScript
173 lines
6.1 KiB
TypeScript
'use client';
|
|
|
|
import { useState, Suspense } from 'react';
|
|
import { useRouter, useSearchParams } from 'next/navigation';
|
|
import Link from 'next/link';
|
|
import { useLanguage } from '@/context/LanguageContext';
|
|
import { useAuth } from '@/context/AuthContext';
|
|
import Card from '@/components/ui/Card';
|
|
import Button from '@/components/ui/Button';
|
|
import Input from '@/components/ui/Input';
|
|
import { authApi } from '@/lib/api';
|
|
import toast from 'react-hot-toast';
|
|
|
|
function ClaimAccountContent() {
|
|
const router = useRouter();
|
|
const searchParams = useSearchParams();
|
|
const { locale: language } = useLanguage();
|
|
const { setAuthData } = useAuth();
|
|
const [loading, setLoading] = useState(false);
|
|
const [formData, setFormData] = useState({
|
|
password: '',
|
|
confirmPassword: '',
|
|
});
|
|
|
|
const token = searchParams.get('token');
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
if (!token) {
|
|
toast.error(language === 'es' ? 'Token no válido' : 'Invalid token');
|
|
return;
|
|
}
|
|
|
|
if (formData.password !== formData.confirmPassword) {
|
|
toast.error(language === 'es' ? 'Las contraseñas no coinciden' : 'Passwords do not match');
|
|
return;
|
|
}
|
|
|
|
if (formData.password.length < 10) {
|
|
toast.error(
|
|
language === 'es'
|
|
? 'La contraseña debe tener al menos 10 caracteres'
|
|
: 'Password must be at least 10 characters'
|
|
);
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
|
|
try {
|
|
const result = await authApi.confirmClaimAccount(token, { password: formData.password });
|
|
setAuthData({ user: result.user, token: result.token });
|
|
toast.success(language === 'es' ? '¡Cuenta activada!' : 'Account activated!');
|
|
router.push('/dashboard');
|
|
} catch (error: any) {
|
|
toast.error(error.message || (language === 'es' ? 'Error' : 'Failed'));
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
if (!token) {
|
|
return (
|
|
<div className="section-padding min-h-[70vh] flex items-center">
|
|
<div className="container-page">
|
|
<div className="max-w-md mx-auto">
|
|
<Card className="p-8 text-center">
|
|
<div className="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
<svg className="w-8 h-8 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</div>
|
|
<h2 className="text-xl font-semibold mb-2">
|
|
{language === 'es' ? 'Enlace Inválido' : 'Invalid Link'}
|
|
</h2>
|
|
<p className="text-gray-600 mb-6">
|
|
{language === 'es'
|
|
? 'Este enlace de activación no es válido o ha expirado.'
|
|
: 'This activation link is invalid or has expired.'}
|
|
</p>
|
|
<Link href="/login">
|
|
<Button>
|
|
{language === 'es' ? 'Ir a Iniciar Sesión' : 'Go to Login'}
|
|
</Button>
|
|
</Link>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="section-padding min-h-[70vh] flex items-center">
|
|
<div className="container-page">
|
|
<div className="max-w-md mx-auto">
|
|
<div className="text-center mb-8">
|
|
<h1 className="text-3xl font-bold">
|
|
{language === 'es' ? 'Activar tu Cuenta' : 'Activate Your Account'}
|
|
</h1>
|
|
<p className="mt-2 text-gray-600">
|
|
{language === 'es'
|
|
? 'Configura una contraseña para acceder a tu cuenta'
|
|
: 'Set a password to access your account'}
|
|
</p>
|
|
</div>
|
|
|
|
<Card className="p-8">
|
|
<div className="mb-6 p-4 bg-blue-50 rounded-lg">
|
|
<p className="text-sm text-blue-800">
|
|
{language === 'es'
|
|
? 'Tu cuenta fue creada durante una reservación. Establece una contraseña para acceder a tu historial de entradas y más.'
|
|
: 'Your account was created during a booking. Set a password to access your ticket history and more.'}
|
|
</p>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-6">
|
|
<Input
|
|
id="password"
|
|
label={language === 'es' ? 'Contraseña' : 'Password'}
|
|
type="password"
|
|
value={formData.password}
|
|
onChange={(e) => setFormData({ ...formData, password: e.target.value })}
|
|
required
|
|
/>
|
|
<p className="text-xs text-gray-500 -mt-4">
|
|
{language === 'es' ? 'Mínimo 10 caracteres' : 'Minimum 10 characters'}
|
|
</p>
|
|
|
|
<Input
|
|
id="confirmPassword"
|
|
label={language === 'es' ? 'Confirmar Contraseña' : 'Confirm Password'}
|
|
type="password"
|
|
value={formData.confirmPassword}
|
|
onChange={(e) => setFormData({ ...formData, confirmPassword: e.target.value })}
|
|
required
|
|
/>
|
|
|
|
<Button type="submit" className="w-full" size="lg" isLoading={loading}>
|
|
{language === 'es' ? 'Activar Cuenta' : 'Activate Account'}
|
|
</Button>
|
|
</form>
|
|
|
|
<p className="mt-6 text-center text-sm text-gray-600">
|
|
{language === 'es' ? '¿Ya tienes acceso?' : 'Already have access?'}{' '}
|
|
<Link href="/login" className="text-secondary-blue hover:underline font-medium">
|
|
{language === 'es' ? 'Iniciar Sesión' : 'Log In'}
|
|
</Link>
|
|
</p>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function LoadingFallback() {
|
|
return (
|
|
<div className="section-padding min-h-[70vh] flex items-center justify-center">
|
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-secondary-blue"></div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default function ClaimAccountPage() {
|
|
return (
|
|
<Suspense fallback={<LoadingFallback />}>
|
|
<ClaimAccountContent />
|
|
</Suspense>
|
|
);
|
|
}
|