import React, { useEffect, useState, useRef } from 'react'; import './ProfileView.css'; const AVATARS = [ '/avatars/avatar1.png', '/avatars/avatar2.png', '/avatars/avatar3.png', '/avatars/avatar4.png', '/avatars/avatar5.png', '/avatars/avatar6.png', ]; const COLOR_CIRCLES = [ '/avatars/color1.png', '/avatars/color2.png', '/avatars/color3.png', '/avatars/color4.png', '/avatars/color5.png', '/avatars/color6.png', ]; function resolveAvatarUrl(url) { if (!url) return ''; const matchPreset = url.match(/^preset_avatar_(\d+)$/); if (matchPreset) { const idx = parseInt(matchPreset[1], 10); if (idx >= 1 && idx <= 6) return AVATARS[idx - 1]; } const matchColor = url.match(/^color_circle_(\d+)$/); if (matchColor) { const idx = parseInt(matchColor[1], 10); if (idx >= 1 && idx <= 6) return COLOR_CIRCLES[idx - 1]; } return url; } function ProfileView({ currentUser, onProfileSaved, onLogout, onAdminClick }) { const [firstName, setFirstName] = useState(currentUser?.first_name || ''); const [lastName, setLastName] = useState(currentUser?.last_name || ''); const [avatarUrl, setAvatarUrl] = useState(resolveAvatarUrl(currentUser?.avatar_url)); const [searchHistory, setSearchHistory] = useState([]); const [uploading, setUploading] = useState(false); const [uploadError, setUploadError] = useState(''); const fileInputRef = useRef(null); // Avatar modal state const [showAvatarModal, setShowAvatarModal] = useState(false); const [avatarTab, setAvatarTab] = useState('presets'); // Config modal state const [showConfig, setShowConfig] = useState(false); const [configFirstName, setConfigFirstName] = useState(''); const [configLastName, setConfigLastName] = useState(''); const [configEmail, setConfigEmail] = useState(''); const [configCity, setConfigCity] = useState(''); const [configAddress, setConfigAddress] = useState(''); const [configSaving, setConfigSaving] = useState(false); const [configFeedback, setConfigFeedback] = useState(null); // Addresses modal state const [showAddresses, setShowAddresses] = useState(false); const [addresses, setAddresses] = useState([]); const [addressesLoading, setAddressesLoading] = useState(false); const [showAddressForm, setShowAddressForm] = useState(false); const [editingAddressId, setEditingAddressId] = useState(null); const [formAddress, setFormAddress] = useState(''); const [formLabel, setFormLabel] = useState(''); const [formDefault, setFormDefault] = useState(false); const [formSaving, setFormSaving] = useState(false); const [formError, setFormError] = useState(''); useEffect(() => { setFirstName(currentUser?.first_name || ''); setLastName(currentUser?.last_name || ''); setAvatarUrl(resolveAvatarUrl(currentUser?.avatar_url)); loadSearchHistory(); }, [currentUser?.id]); async function loadSearchHistory() { try { const res = await fetch('/api/search-history', { credentials: 'include' }); if (res.ok) { const data = await res.json(); setSearchHistory(data); } } catch (err) { console.error('Error loading search history:', err); } } function openConfig() { setConfigFirstName(currentUser?.first_name || ''); setConfigLastName(currentUser?.last_name || ''); setConfigEmail(currentUser?.email || ''); setConfigCity(currentUser?.city || ''); setConfigAddress(currentUser?.address || ''); setConfigFeedback(null); setShowConfig(true); } async function loadAddresses() { setAddressesLoading(true); try { const res = await fetch('/api/addresses', { credentials: 'include' }); if (res.ok) { const data = await res.json(); setAddresses(data); } } catch (err) { console.error('Error loading addresses:', err); } finally { setAddressesLoading(false); } } function openAddresses() { setShowAddresses(true); loadAddresses(); } function openAddAddressForm() { setEditingAddressId(null); setFormAddress(''); setFormLabel(''); setFormDefault(addresses.length === 0); setFormError(''); setShowAddressForm(true); } function openEditAddressForm(addr) { setEditingAddressId(addr.id); setFormAddress(addr.address); setFormLabel(addr.label || ''); setFormDefault(Boolean(addr.is_default)); setFormError(''); setShowAddressForm(true); } async function handleAddressSave(e) { e?.preventDefault(); const addr = formAddress.trim(); if (!addr) { setFormError('La dirección es obligatoria'); return; } setFormSaving(true); setFormError(''); try { const url = editingAddressId ? `/api/addresses/${editingAddressId}` : '/api/addresses'; const method = editingAddressId ? 'PUT' : 'POST'; const res = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ address: addr, label: formLabel.trim(), is_default: formDefault, }), }); if (!res.ok) { const err = await res.json().catch(() => ({})); throw new Error(err.error || 'Error al guardar la dirección'); } setShowAddressForm(false); setEditingAddressId(null); loadAddresses(); } catch (err) { setFormError(err.message); } finally { setFormSaving(false); } } async function handleDeleteAddress(id) { try { const res = await fetch(`/api/addresses/${id}`, { method: 'DELETE', credentials: 'include', }); if (res.ok) { setAddresses(prev => prev.filter(a => a.id !== id)); } } catch (err) { console.error('Error deleting address:', err); } } async function handleSetDefault(id) { try { const res = await fetch(`/api/addresses/${id}/default`, { method: 'PUT', credentials: 'include', }); if (res.ok) { loadAddresses(); } } catch (err) { console.error('Error setting default address:', err); } } async function handleConfigSave(e) { e?.preventDefault(); setConfigSaving(true); setConfigFeedback(null); try { const res = await fetch('/api/users/me', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ first_name: configFirstName.trim() || null, last_name: configLastName.trim() || null, email: configEmail.trim() || null, city: configCity.trim() || null, address: configAddress.trim() || null, }), }); if (!res.ok) { const err = await res.json().catch(() => ({})); throw new Error(err.error || `Error al guardar (HTTP ${res.status})`); } const updated = await res.json(); onProfileSaved?.(updated); setFirstName(updated.first_name || ''); setLastName(updated.last_name || ''); setConfigFeedback({ type: 'ok', text: 'Perfil guardado.' }); setTimeout(() => setShowConfig(false), 1200); } catch (err) { setConfigFeedback({ type: 'err', text: err.message || 'Error al guardar' }); } finally { setConfigSaving(false); } } async function handleAvatarUpload(e) { const file = e.target.files?.[0]; if (!file) return; setUploadError(''); setShowAvatarModal(false); setUploading(true); if (file.size > 5 * 1024 * 1024) { setUploadError('La imagen no puede superar los 5 MB'); setUploading(false); return; } try { const reader = new FileReader(); reader.onload = async () => { const base64 = reader.result; setAvatarUrl(base64); try { const res = await fetch('/api/users/me', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ avatar_url: base64 }), }); if (res.ok) { const updated = await res.json(); onProfileSaved?.(updated); } else { setAvatarUrl(resolveAvatarUrl(currentUser?.avatar_url)); setUploadError('Error al guardar la imagen. Intenta con otra foto.'); } } catch (err) { setAvatarUrl(resolveAvatarUrl(currentUser?.avatar_url)); setUploadError('Error de conexión al guardar la imagen.'); } setUploading(false); }; reader.readAsDataURL(file); } catch (err) { setUploadError('Error al procesar la imagen.'); setUploading(false); } } async function handleSelectPresetAvatar(index) { const url = AVATARS[index]; setAvatarUrl(url); setShowAvatarModal(false); try { const res = await fetch('/api/users/me', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ avatar_url: `preset_avatar_${index + 1}` }), }); if (res.ok) { const updated = await res.json(); onProfileSaved?.(updated); } } catch (err) { console.error('Error saving avatar:', err); } } async function handleSelectColor(index) { const url = COLOR_CIRCLES[index]; setAvatarUrl(url); setShowAvatarModal(false); try { const res = await fetch('/api/users/me', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ avatar_url: `color_circle_${index + 1}` }), }); if (res.ok) { const updated = await res.json(); onProfileSaved?.(updated); } } catch (err) { console.error('Error saving avatar:', err); } } function handleGalleryUpload() { fileInputRef.current?.click(); } async function handleDeleteSearch(id) { try { const res = await fetch(`/api/search-history/${id}`, { method: 'DELETE', credentials: 'include', }); if (res.ok) { setSearchHistory(prev => prev.filter(item => item.id !== id)); } } catch (err) { console.error('Error deleting search:', err); } } const displayName = [firstName, lastName].filter(Boolean).join(' ') || currentUser?.username || 'Usuario'; return (
{/* Avatar Section */}
setShowAvatarModal(true)} > {avatarUrl ? ( Avatar ) : ( )}
{uploading &&

Subiendo foto...

} {uploadError &&

{uploadError}

}
{/* Read-only Name Section */}

Nombre

{firstName || '—'}

Apellidos

{lastName || '—'}

{/* Menu Section */}
{searchHistory.length > 0 && (

Tus búsquedas recientes:

{searchHistory.map((item) => (
{item.address}
))}
)} {currentUser?.is_admin && ( )}
{/* Avatar Modal */} {showAvatarModal && (
setShowAvatarModal(false)}>
e.stopPropagation()}>

Cambiar Avatar

{avatarTab === 'presets' && (
{AVATARS.map((src, index) => ( ))}
)} {avatarTab === 'colors' && (
{COLOR_CIRCLES.map((src, index) => ( ))}
)} {avatarTab === 'upload' && (
)}
)} {/* Config Modal */} {showConfig && (
setShowConfig(false)}>
e.stopPropagation()}>

Configuración

setConfigFirstName(e.target.value)} placeholder="Tu nombre" disabled={configSaving} />
setConfigLastName(e.target.value)} placeholder="Tus apellidos" disabled={configSaving} />
setConfigEmail(e.target.value)} placeholder="tu@email.com" disabled={configSaving} />
setConfigCity(e.target.value)} placeholder="Tu ciudad" disabled={configSaving} />
setConfigAddress(e.target.value)} placeholder="Calle Mayor 1, Madrid" disabled={configSaving} />
{configFeedback && (

{configFeedback.text}

)}
)} {/* Addresses Modal */} {showAddresses && (
{ setShowAddresses(false); setShowAddressForm(false); }}>
e.stopPropagation()}>

Mis Direcciones

{showAddressForm && (
setFormAddress(e.target.value)} placeholder="Calle Mayor 1, Madrid" disabled={formSaving} />
setFormLabel(e.target.value)} placeholder="Ej: Casa, Trabajo, Segunda residencia" disabled={formSaving} />
{formError &&

{formError}

}
)} {!showAddressForm && ( <> {addressesLoading ? (

Cargando direcciones...

) : (
{currentUser?.address && (
Dirección principal {currentUser.address} Predeterminada
)} {addresses.map((addr) => (
{addr.label && {addr.label}} {addr.address}
))}
)} )}
)}
); } export default ProfileView;