// Componente Header del directorio de vendedores function Header() { return (

Directorio de Vendedores

Encuentra vendedores de confianza en tu provincia. Explora sus perfiles y descubre sus productos.

); } // Componente de búsqueda y filtros function SearchFilters({ searchTerm, setSearchTerm, selectedProvince, setSelectedProvince, showFavoritesOnly, setShowFavoritesOnly }) { const provinces = [ "Todas", "Álava", "Albacete", "Alicante", "Almería", "Asturias", "Ávila", "Badajoz", "Barcelona", "Burgos", "Cáceres", "Cádiz", "Cantabria", "Castellón", "Ciudad Real", "Córdoba", "Cuenca", "Girona", "Granada", "Guadalajara", "Guipúzcoa", "Huelva", "Huesca", "Islas Baleares", "Jaén", "La Coruña", "La Rioja", "Las Palmas", "León", "Lleida", "Lugo", "Madrid", "Málaga", "Murcia", "Navarra", "Ourense", "Palencia", "Pontevedra", "Salamanca", "Santa Cruz de Tenerife", "Segovia", "Sevilla", "Soria", "Tarragona", "Teruel", "Toledo", "Valencia", "Valladolid", "Vizcaya", "Zamora", "Zaragoza" ]; return (
{/* Búsqueda */}
setSearchTerm(e.target.value)} placeholder="Buscar por nombre o negocio..." className="block w-full pl-3 pr-11 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-1 focus:ring-blue-500 focus:border-blue-500" />
{/* Filtro Provincia */}
{/* Filtro Favoritos */}
); } // Componente para mostrar el contador de resultados function ResultsCount({ count, loading }) { if (loading) { return null; } return (

Mostrando {count} vendedor{count !== 1 ? 'es' : ''}

); } // Componente de tarjeta individual de vendedor function VendorCard({ vendor, isFavorite, onToggleFavorite }) { // Función para generar slug const generateSlug = (text) => { if (!text) return 'vendedor'; return text .toLowerCase() .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') // Remover acentos .replace(/[^a-z0-9]+/g, '-') .replace(/^-+|-+$/g, ''); }; const vendorSlug = generateSlug(vendor.businessName); const profileUrl = `/vendedores/${vendorSlug}`; return (
{/* Header de la tarjeta */}
{/* Avatar */}
{vendor.image ? ( {`Perfil { e.target.style.display = 'none'; e.target.nextElementSibling.style.display = 'flex'; }} /> ) : null}
{/* Información del vendedor */}

{vendor.businessName}

{/* Botón de favoritos */}
{/* Descripción */}

{vendor.description}

{/* Información de contacto */}
{/* Ubicación */}
{vendor.location}
{/* Teléfono */}
{vendor.phone}
{/* Email */}
{vendor.email}
{/* Botón Ver Perfil */}
Ver Perfil
); } // Componente de grid de vendedores function VendorGrid({ vendors, loading, favorites, onToggleFavorite }) { if (loading) { return (

Cargando vendedores...

); } if (vendors.length === 0) { return (

No se encontraron vendedores

Intenta ajustar los filtros de búsqueda

); } return (
{vendors.map((vendor, index) => ( ))}
); } // Componente principal de la aplicación Vendedores function VendedoresApp() { const [searchTerm, setSearchTerm] = React.useState(''); const [selectedProvince, setSelectedProvince] = React.useState('Todas'); const [showFavoritesOnly, setShowFavoritesOnly] = React.useState(false); const [vendors, setVendors] = React.useState([]); const [loading, setLoading] = React.useState(false); const [allVendors, setAllVendors] = React.useState([]); const [favorites, setFavorites] = React.useState([]); // Cargar favoritos al inicializar React.useEffect(() => { loadFavorites(); }, []); // Función para cargar favoritos const loadFavorites = async () => { try { const form = new URLSearchParams(); form.append('action', 'vendedores_get_favorites'); form.append('nonce', (window.vendedoresPlugin && window.vendedoresPlugin.nonce) || ''); const res = await fetch((window.vendedoresPlugin && window.vendedoresPlugin.ajax_url) || '/wp-admin/admin-ajax.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, body: form.toString() }); const json = await res.json(); if (json && json.success && Array.isArray(json.data.favorites)) { // Convertir a strings para asegurar consistencia const favoritesAsStrings = json.data.favorites.map(id => String(id)); setFavorites(favoritesAsStrings); } } catch (e) { console.error('Error loading favorites:', e); } }; // Función para toggle favoritos con actualización optimista const handleToggleFavorite = async (vendorId) => { const isFavorite = favorites.includes(vendorId); // Actualización optimista: cambiar el estado inmediatamente if (isFavorite) { setFavorites(prev => prev.filter(id => id !== vendorId)); } else { setFavorites(prev => [...prev, vendorId]); } const action = isFavorite ? 'vendedores_remove_favorite' : 'vendedores_add_favorite'; try { const form = new URLSearchParams(); form.append('action', action); form.append('vendor_id', vendorId); form.append('nonce', (window.vendedoresPlugin && window.vendedoresPlugin.nonce) || ''); const res = await fetch((window.vendedoresPlugin && window.vendedoresPlugin.ajax_url) || '/wp-admin/admin-ajax.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, body: form.toString() }); const json = await res.json(); if (json && json.success && Array.isArray(json.data.favorites)) { // Sincronizar con el servidor const favoritesAsStrings = json.data.favorites.map(id => String(id)); setFavorites(favoritesAsStrings); } else if (json && !json.success) { // Revertir cambio optimista si hay error if (isFavorite) { setFavorites(prev => [...prev, vendorId]); } else { setFavorites(prev => prev.filter(id => id !== vendorId)); } if (json.data && json.data.message) { alert(json.data.message); } } } catch (e) { // Revertir cambio optimista si hay error de red if (isFavorite) { setFavorites(prev => [...prev, vendorId]); } else { setFavorites(prev => prev.filter(id => id !== vendorId)); } console.error('Error toggling favorite:', e); alert('Error al procesar favoritos. Por favor, inténtalo de nuevo.'); } }; // Cargar vendedores desde AJAX de WP (que proxy a la API) React.useEffect(() => { let abort = false; async function loadVendors() { try { setLoading(true); const form = new URLSearchParams(); form.append('action', 'vendedores_list'); form.append('nonce', (window.vendedoresPlugin && window.vendedoresPlugin.nonce) || ''); const res = await fetch((window.vendedoresPlugin && window.vendedoresPlugin.ajax_url) || '/wp-admin/admin-ajax.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, body: form.toString() }); const json = await res.json(); if (!abort) { if (json && json.success && json.data && Array.isArray(json.data.items)) { // Mapear a formato de UI const mapped = json.data.items.map((item) => ({ id: String(item.id), // Asegurar que sea string businessName: item.nombre || 'Sin nombre', vendorName: item.nombre || 'Sin nombre', category: 'General', description: `${item.ciudad || ''}${item.ciudad && item.provincia ? ', ' : ''}${item.provincia || ''}`.trim() || 'Sin descripción', location: `${item.ciudad || ''}${item.ciudad && item.provincia ? ', ' : ''}${item.provincia || ''}`.trim(), phone: item.telefono || item.whatsapp || '', email: item.email || '', rating: '-', views: '-', image: item.imagen || '' })); setAllVendors(mapped); } else { setAllVendors([]); } } } catch (e) { if (!abort) setAllVendors([]); } finally { if (!abort) setLoading(false); } } loadVendors(); return () => { abort = true; }; }, []); // Función para filtrar vendedores const filterVendors = React.useCallback(() => { return allVendors.filter(vendor => { const matchesSearch = !searchTerm || vendor.businessName.toLowerCase().includes(searchTerm.toLowerCase()) || vendor.vendorName.toLowerCase().includes(searchTerm.toLowerCase()); const matchesProvince = selectedProvince === 'Todas' || vendor.location.includes(selectedProvince); const matchesFavorites = !showFavoritesOnly || favorites.includes(vendor.id); return matchesSearch && matchesProvince && matchesFavorites; }); }, [searchTerm, selectedProvince, showFavoritesOnly, allVendors, favorites]); // Efecto para aplicar filtros React.useEffect(() => { const filteredVendors = filterVendors(); setVendors(filteredVendors); }, [filterVendors]); return (
{/* Header */}
{/* Búsqueda y filtros */} {/* Contador de resultados */} {/* Grid de vendedores */}
); } // Renderizar la aplicación function initReactApp() { const container = document.getElementById('vendedores-container'); if (container) { const root = ReactDOM.createRoot(container); root.render(React.createElement(VendedoresApp)); } } // Inicializar aplicación if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initReactApp); } else { initReactApp(); }