'use client'; import React, { useState, useEffect } from 'react'; import Link from 'next/link'; import { Radio, Sparkles, RefreshCw, Search, CheckCircle2, XCircle, Plus, Send, Layers, ShoppingBag, ExternalLink, MessageSquare, ShieldCheck, Zap, Filter, CheckSquare, Square, Edit3, Trash2, ArrowUpRight, Eye, } from 'lucide-react'; import { SupplierPost, Product, MonitoredWhatsAppGroup } from '@/types'; import { formatCOP } from '@/lib/pricing-engine'; import { BRANDS, BrandId } from '@/config/brands'; export default function SupplierFeedPage() { const [posts, setPosts] = useState([]); const [monitoredGroups, setMonitoredGroups] = useState([]); const [selectedGroupFilter, setSelectedGroupFilter] = useState('all'); const [tabStatus, setTabStatus] = useState<'pending' | 'published' | 'discarded'>('pending'); const [isLoading, setIsLoading] = useState(false); const [isSyncingLive, setIsSyncingLive] = useState(false); const [actionMessage, setActionMessage] = useState(null); // Multi-selection state const [selectedPostIds, setSelectedPostIds] = useState>(new Set()); // Edit Modal State const [editingPost, setEditingPost] = useState(null); const [editName, setEditName] = useState(''); const [editBrand, setEditBrand] = useState(''); const [editPrice, setEditPrice] = useState(120000); const [editSizes, setEditSizes] = useState(''); // Target brand selector for publishing const [targetBrand, setTargetBrand] = useState('almeira'); // Cargar grupos monitoreados y posts iniciales en vivo const loadInitialData = async () => { setIsLoading(true); try { // 1. Grupos const grpRes = await fetch('/api/whatsapp-groups?fetchLive=true'); const grpData = await grpRes.json(); if (grpData.success && Array.isArray(grpData.groups)) { setMonitoredGroups(grpData.groups); } // 2. Posts en vivo desde los grupos de WhatsApp const feedRes = await fetch('/api/whatsapp-feed?fetchLive=true&limit=50'); const feedData = await feedRes.json(); if (feedData.success && Array.isArray(feedData.posts)) { setPosts(feedData.posts); } } catch (err) { console.error('Error cargando feed:', err); } finally { setIsLoading(false); } }; useEffect(() => { loadInitialData(); }, []); // Cambiar filtro de grupo y recargar mensajes const handleGroupFilterChange = async (groupJid: string) => { setSelectedGroupFilter(groupJid); setIsSyncingLive(true); setActionMessage(null); try { const url = groupJid !== 'all' ? `/api/whatsapp-feed?fetchLive=true&groupJid=${encodeURIComponent(groupJid)}` : '/api/whatsapp-feed?fetchLive=true&limit=50'; const res = await fetch(url); const data = await res.json(); if (data.success && Array.isArray(data.posts)) { setPosts(data.posts); setActionMessage( `✅ Se cargaron ${data.totalFound || data.posts.length} mensajes del grupo.` ); } } catch (err) { console.error(err); setActionMessage('❌ Error cargando mensajes del grupo.'); } finally { setIsSyncingLive(false); } }; // Sincronizar mensajes en vivo desde Evolution API const handleSyncLive = async () => { setIsSyncingLive(true); setActionMessage(null); try { const url = selectedGroupFilter !== 'all' ? `/api/whatsapp-feed?fetchLive=true&groupJid=${encodeURIComponent(selectedGroupFilter)}` : '/api/whatsapp-feed?fetchLive=true&limit=50'; const res = await fetch(url); const data = await res.json(); if (data.success && Array.isArray(data.posts)) { setPosts(data.posts); setActionMessage( `✅ ¡Sincronización completa! Se escanearon ${data.totalFound || data.posts.length} mensajes recientes de WhatsApp.` ); } else { setActionMessage('⚠️ No se encontraron mensajes nuevos en los grupos seleccionados.'); } } catch (err: any) { console.error(err); setActionMessage('❌ Error conectando con Evolution API para traer mensajes.'); } finally { setIsSyncingLive(false); } }; // Publicar un producto a la tienda const handlePublishPost = async ( post: SupplierPost, customData?: { name?: string; brand?: string; retailPrice?: number; sizes?: string[] } ) => { try { const res = await fetch('/api/whatsapp-feed', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'publish', post, customName: customData?.name, customRetailPrice: customData?.retailPrice, customSizes: customData?.sizes, }), }); const data = await res.json(); if (data.success) { setPosts((prev) => prev.map((p) => (p.id === post.id ? { ...p, status: 'published' } : p)) ); setActionMessage(`🚀 ¡"${data.product.name}" ha sido publicado en la App Móvil y Web!`); if (editingPost?.id === post.id) setEditingPost(null); } } catch (e) { console.error(e); setActionMessage('❌ Error al publicar producto.'); } }; // Publicación masiva de los seleccionados const handleBulkPublish = async () => { const selectedPosts = posts.filter( (p) => selectedPostIds.has(p.id) && p.status !== 'published' ); if (selectedPosts.length === 0) return; setIsLoading(true); try { const res = await fetch('/api/whatsapp-feed', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'bulk-publish', posts: selectedPosts, }), }); const data = await res.json(); if (data.success) { setPosts((prev) => prev.map((p) => (selectedPostIds.has(p.id) ? { ...p, status: 'published' } : p)) ); setSelectedPostIds(new Set()); setActionMessage( `🎉 ¡Éxito! Se han publicado ${data.products?.length || selectedPosts.length} zapatillas en la App Móvil y Web.` ); } } catch (e) { console.error(e); setActionMessage('❌ Error en publicación masiva.'); } finally { setIsLoading(false); } }; // Descartar mensaje const handleDiscardPost = async (post: SupplierPost) => { try { await fetch('/api/whatsapp-feed', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'discard', post }), }); setPosts((prev) => prev.map((p) => (p.id === post.id ? { ...p, status: 'discarded' } : p)) ); setSelectedPostIds((prev) => { const next = new Set(prev); next.delete(post.id); return next; }); } catch (e) { console.error(e); } }; // Manejo de Selección const handleToggleSelect = (id: string) => { setSelectedPostIds((prev) => { const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next; }); }; // Filtrado de posts por estado y grupo const filteredPosts = posts.filter((p) => { // Estado if (tabStatus === 'pending' && p.status === 'published') return false; if (tabStatus === 'pending' && p.status === 'discarded') return false; if (tabStatus === 'published' && p.status !== 'published') return false; if (tabStatus === 'discarded' && p.status !== 'discarded') return false; // Grupo if (selectedGroupFilter !== 'all') { return (p as any).channelJid === selectedGroupFilter || p.channelName === selectedGroupFilter; } return true; }); const pendingCount = posts.filter((p) => p.status !== 'published' && p.status !== 'discarded').length; const publishedCount = posts.filter((p) => p.status === 'published').length; const discardedCount = posts.filter((p) => p.status === 'discarded').length; const handleOpenEdit = (post: SupplierPost) => { setEditingPost(post); setEditName(post.extractedProduct?.name || 'Zapatilla Urbana'); setEditBrand(post.extractedProduct?.brand || 'Nike'); setEditPrice( post.extractedProduct?.suggestedRetailPrice || (post.extractedProduct?.supplierPrice ? post.extractedProduct.supplierPrice + 35000 : 125000) ); setEditSizes(post.extractedProduct?.sizes?.join(', ') || '38, 39, 40, 41, 42, 43'); }; return (
{/* Header */}

Feed de Mensajes de WhatsApp

Visualiza los mensajes de tus grupos de proveedores y selecciona los calzados que deseas publicar en la app móvil.

{/* Action Controls */}
Gestionar Grupos
{/* Toast feedback */} {actionMessage && (
{actionMessage}
)} {/* Filter & Tabs Bar */}
{/* Status Tabs */}
{/* Group Selector Filter */}
{/* Multi-Selection Bulk Actions Bar */} {selectedPostIds.size > 0 && tabStatus === 'pending' && (
{selectedPostIds.size} seleccionados Listos para transferir al catálogo de la tienda
)} {/* Posts List / Grid */} {filteredPosts.length === 0 ? (

No hay mensajes en esta bandeja

Haz clic en "Sincronizar WhatsApp en Vivo" para extraer automáticamente las ofertas recientes de tus grupos seleccionados.

) : (
{filteredPosts.map((post) => { const extracted = post.extractedProduct; const isSelected = selectedPostIds.has(post.id); const isPublished = post.status === 'published'; const isDiscarded = post.status === 'discarded'; return (
{/* Header info */}
{tabStatus === 'pending' && ( )}
{post.channelName || 'Grupo WhatsApp'} {post.receivedAt}
{isPublished ? ( Publicado en Tienda ) : isDiscarded ? ( Descartado ) : ( Pendiente de Aprobación )}
{/* Content Grid (Photo + AI extracted info) */}
{/* Sneaker Image & Raw text */}
{post.rawImages && post.rawImages[0] ? ( {extracted?.name ) : (
Sin foto
)}
{/* Raw WhatsApp Message snippet */}

{post.rawMessage}

{/* AI Extraction & Product Info */}
{extracted?.brand || 'Nike'} • {extracted?.category || 'Sneakers'}

{extracted?.name || 'Zapatilla Urbana'}

{/* Pricing breakdown */}
Costo Proveedor: {formatCOP(extracted?.supplierPrice || 90000)}
Venta Sugerida: {formatCOP(extracted?.suggestedRetailPrice || 125000)}
{/* Sizes badge pills */}
Tallas Disponibles:
{extracted?.sizes && extracted.sizes.length > 0 ? ( extracted.sizes.map((s) => ( {s} )) ) : ( 37 a 43 )}
{/* Card Actions */}
{!isPublished ? ( <> ) : (
Disponible para clientes Ver en Tienda
)}
); })}
)} {/* Edit Modal Before Publishing */} {editingPost && (

Personalizar antes de Publicar

setEditName(e.target.value)} className="w-full bg-neutral-950 border border-neutral-800 rounded-xl px-3 py-2 text-white font-bold outline-hidden focus:border-purple-500" />
setEditBrand(e.target.value)} className="w-full bg-neutral-950 border border-neutral-800 rounded-xl px-3 py-2 text-white outline-hidden focus:border-purple-500" />
setEditPrice(Number(e.target.value))} className="w-full bg-neutral-950 border border-neutral-800 rounded-xl px-3 py-2 text-emerald-300 font-black font-mono outline-hidden focus:border-emerald-500" />
setEditSizes(e.target.value)} placeholder="38, 39, 40, 41, 42, 43" className="w-full bg-neutral-950 border border-neutral-800 rounded-xl px-3 py-2 text-white outline-hidden focus:border-purple-500" />
)}
); }