import React, { useEffect, useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
import api from '../utils/api';
import { Card } from '../components/ui/card';
import { Button } from '../components/ui/button';
import { Input } from '../components/ui/input';
import { Label } from '../components/ui/label';
import { Alert, AlertDescription } from '../components/ui/alert';
import { Badge } from '../components/ui/badge';
import { toast } from 'sonner';
import { Loader2, Mail, Shield, CheckCircle, XCircle, Calendar } from 'lucide-react';
const AcceptInvitation = () => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const { login } = useAuth();
const [token, setToken] = useState(null);
const [invitation, setInvitation] = useState(null);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState(null);
const [formData, setFormData] = useState({
password: '',
confirmPassword: '',
first_name: '',
last_name: '',
phone: '',
address: '',
city: '',
state: '',
zipcode: '',
date_of_birth: ''
});
const [formErrors, setFormErrors] = useState({});
useEffect(() => {
const invitationToken = searchParams.get('token');
if (!invitationToken) {
setError('Invalid invitation link. No token provided.');
setLoading(false);
return;
}
setToken(invitationToken);
verifyInvitation(invitationToken);
}, [searchParams]);
const verifyInvitation = async (invitationToken) => {
try {
const response = await api.get(`/invitations/verify/${invitationToken}`);
setInvitation(response.data);
// Pre-fill form with invitation data
setFormData(prev => ({
...prev,
first_name: response.data.first_name || '',
last_name: response.data.last_name || '',
phone: response.data.phone || ''
}));
setLoading(false);
} catch (error) {
setError(error.response?.data?.detail || 'Invalid or expired invitation token');
setLoading(false);
}
};
const handleChange = (field, value) => {
setFormData(prev => ({ ...prev, [field]: value }));
// Clear error when user starts typing
if (formErrors[field]) {
setFormErrors(prev => ({ ...prev, [field]: null }));
}
};
const validate = () => {
const newErrors = {};
if (!formData.password || formData.password.length < 8) {
newErrors.password = 'Password must be at least 8 characters';
}
if (formData.password !== formData.confirmPassword) {
newErrors.confirmPassword = 'Passwords do not match';
}
if (!formData.first_name) {
newErrors.first_name = 'First name is required';
}
if (!formData.last_name) {
newErrors.last_name = 'Last name is required';
}
if (!formData.phone) {
newErrors.phone = 'Phone is required';
}
setFormErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!validate()) {
return;
}
setSubmitting(true);
try {
// Prepare payload
const payload = {
token,
password: formData.password,
first_name: formData.first_name,
last_name: formData.last_name,
phone: formData.phone
};
// Add optional fields if provided
if (formData.address) payload.address = formData.address;
if (formData.city) payload.city = formData.city;
if (formData.state) payload.state = formData.state;
if (formData.zipcode) payload.zipcode = formData.zipcode;
if (formData.date_of_birth) payload.date_of_birth = formData.date_of_birth;
// Accept invitation
const response = await api.post('/invitations/accept', payload);
// Auto-login with returned token
const { access_token, user } = response.data;
localStorage.setItem('token', access_token);
toast.success('Welcome to LOAF! Your account has been created successfully.');
// Call login to update auth context
if (login) {
await login(invitation.email, formData.password);
}
// Redirect based on role
if (user.role === 'admin' || user.role === 'superadmin') {
navigate('/admin/dashboard');
} else {
navigate('/dashboard');
}
} catch (error) {
const errorMessage = error.response?.data?.detail || 'Failed to accept invitation';
toast.error(errorMessage);
} finally {
setSubmitting(false);
}
};
const getRoleBadge = (role) => {
const config = {
superadmin: { label: 'Superadmin', className: 'bg-[#664fa3] text-white' },
admin: { label: 'Admin', className: 'bg-[#81B29A] text-white' },
member: { label: 'Member', className: 'bg-[#DDD8EB] text-[#422268]' }
};
const roleConfig = config[role] || { label: role, className: 'bg-gray-500 text-white' };
return (
Verifying your invitation...
{error}
Complete your profile to accept the invitation
Email Address
{invitation?.email}
Role
{invitation?.expires_at ? new Date(invitation.expires_at).toLocaleString() : 'N/A'}
Already have an account?{' '}