import React, { useState, useEffect, useRef } from 'react'; 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 { Textarea } from '../components/ui/textarea'; import { toast } from 'sonner'; import Navbar from '../components/Navbar'; import MemberFooter from '../components/MemberFooter'; import { User, Save, Lock, Heart, Users, Mail, BookUser, Camera, Upload, Trash2 } from 'lucide-react'; import { Avatar, AvatarImage, AvatarFallback } from '../components/ui/avatar'; import ChangePasswordDialog from '../components/ChangePasswordDialog'; const Profile = () => { const { user } = useAuth(); const [loading, setLoading] = useState(false); const [profileData, setProfileData] = useState(null); const [passwordDialogOpen, setPasswordDialogOpen] = useState(false); const [profilePhotoUrl, setProfilePhotoUrl] = useState(null); const [previewImage, setPreviewImage] = useState(null); const [uploadingPhoto, setUploadingPhoto] = useState(false); const fileInputRef = useRef(null); const [maxFileSizeMB, setMaxFileSizeMB] = useState(50); // Default 50MB const [maxFileSizeBytes, setMaxFileSizeBytes] = useState(52428800); // Default 50MB in bytes const [formData, setFormData] = useState({ // Personal Information first_name: '', last_name: '', phone: '', address: '', city: '', state: '', zipcode: '', // Partner Information partner_first_name: '', partner_last_name: '', partner_is_member: false, partner_plan_to_become_member: false, // Newsletter Preferences newsletter_publish_name: false, newsletter_publish_photo: false, newsletter_publish_birthday: false, newsletter_publish_none: false, // Volunteer Interests (array) volunteer_interests: [], // Member Directory Settings show_in_directory: false, directory_email: '', directory_bio: '', directory_address: '', directory_phone: '', directory_dob: '', directory_partner_name: '' }); useEffect(() => { fetchConfig(); fetchProfile(); }, []); const fetchConfig = async () => { try { const response = await api.get('/config'); setMaxFileSizeMB(response.data.max_file_size_mb); setMaxFileSizeBytes(response.data.max_file_size_bytes); } catch (error) { console.error('Failed to fetch config, using defaults:', error); // Keep default values if fetch fails } }; const fetchProfile = async () => { try { const response = await api.get('/users/profile'); setProfileData(response.data); setProfilePhotoUrl(response.data.profile_photo_url); setPreviewImage(response.data.profile_photo_url); setFormData({ // Personal Information first_name: response.data.first_name || '', last_name: response.data.last_name || '', phone: response.data.phone || '', address: response.data.address || '', city: response.data.city || '', state: response.data.state || '', zipcode: response.data.zipcode || '', // Partner Information partner_first_name: response.data.partner_first_name || '', partner_last_name: response.data.partner_last_name || '', partner_is_member: response.data.partner_is_member || false, partner_plan_to_become_member: response.data.partner_plan_to_become_member || false, // Newsletter Preferences newsletter_publish_name: response.data.newsletter_publish_name || false, newsletter_publish_photo: response.data.newsletter_publish_photo || false, newsletter_publish_birthday: response.data.newsletter_publish_birthday || false, newsletter_publish_none: response.data.newsletter_publish_none || false, // Volunteer Interests volunteer_interests: response.data.volunteer_interests || [], // Member Directory Settings show_in_directory: response.data.show_in_directory || false, directory_email: response.data.directory_email || '', directory_bio: response.data.directory_bio || '', directory_address: response.data.directory_address || '', directory_phone: response.data.directory_phone || '', directory_dob: response.data.directory_dob || '', directory_partner_name: response.data.directory_partner_name || '' }); } catch (error) { toast.error('Failed to load profile'); } }; const handleInputChange = (e) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); }; const handleCheckboxChange = (e) => { const { name, checked } = e.target; setFormData(prev => ({ ...prev, [name]: checked })); }; const handleVolunteerToggle = (interest) => { setFormData(prev => ({ ...prev, volunteer_interests: prev.volunteer_interests.includes(interest) ? prev.volunteer_interests.filter(i => i !== interest) : [...prev.volunteer_interests, interest] })); }; // Volunteer interest options const volunteerOptions = [ 'Event Planning', 'Social Media', 'Newsletter', 'Fundraising', 'Community Outreach', 'Graphic Design', 'Photography', 'Writing/Editing', 'Tech Support', 'Hospitality' ]; const handlePhotoUpload = async (e) => { const file = e.target.files[0]; if (!file) return; // Validate file type if (!file.type.startsWith('image/')) { toast.error('Please select an image file'); return; } // Validate file size if (file.size > maxFileSizeBytes) { toast.error(`File size must be less than ${maxFileSizeMB}MB`); return; } setUploadingPhoto(true); try { const formData = new FormData(); formData.append('file', file); const response = await api.post('/members/profile/upload-photo', formData, { headers: { 'Content-Type': 'multipart/form-data' } }); setProfilePhotoUrl(response.data.profile_photo_url); setPreviewImage(response.data.profile_photo_url); toast.success('Profile photo updated successfully!'); } catch (error) { toast.error('Failed to upload photo'); } finally { setUploadingPhoto(false); } }; const handlePhotoDelete = async () => { if (!profilePhotoUrl) return; setUploadingPhoto(true); try { await api.delete('/members/profile/delete-photo'); setProfilePhotoUrl(null); setPreviewImage(null); toast.success('Profile photo deleted successfully!'); } catch (error) { toast.error('Failed to delete photo'); } finally { setUploadingPhoto(false); } }; const handleSubmit = async (e) => { e.preventDefault(); setLoading(true); try { await api.put('/users/profile', formData); toast.success('Profile updated successfully!'); fetchProfile(); } catch (error) { toast.error('Failed to update profile'); } finally { setLoading(false); } }; if (!profileData) { return (
Loading profile...
Update your personal information below.
{profileData.email}
Status
{profileData.status.replace('_', ' ')}
Role
{profileData.role}
Date of Birth
{new Date(profileData.date_of_birth).toLocaleDateString()}
Upload a profile photo (Max {maxFileSizeMB}MB)