// ============================================================================== // SHIFT ERP - MODULO INDEPENDIENTE BANDEJA & CHAT WHATSAPP WEB // ============================================================================== const formatWhatsAppChatTime = (timestamp) => { if (!timestamp) return ''; const date = new Date(Number(timestamp)); if (isNaN(date.getTime())) return ''; const now = new Date(); const diffMs = now.getTime() - date.getTime(); if (diffMs < 0) return 'Ahora'; const diffSec = Math.floor(diffMs / 1000); const diffMin = Math.floor(diffSec / 60); const diffHours = Math.floor(diffMin / 60); const diffDays = Math.floor(diffHours / 24); // Menos de 1 minuto if (diffMin < 1) return 'Ahora'; // Menos de 60 minutos if (diffMin < 60) return `Hace ${diffMin} min`; // Mismo día calendario const isToday = now.toDateString() === date.toDateString(); if (isToday) { if (diffHours < 12) return `Hace ${diffHours} h`; return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } // Ayer const yesterday = new Date(now); yesterday.setDate(yesterday.getDate() - 1); if (yesterday.toDateString() === date.toDateString()) { return 'Ayer'; } // De 2 a 30 días atrás if (diffDays >= 2 && diffDays <= 30) { return `Hace ${diffDays} días`; } // Más de 30 días: fecha corta DD/MM/YY const d = String(date.getDate()).padStart(2, '0'); const m = String(date.getMonth() + 1).padStart(2, '0'); const y = String(date.getFullYear()).slice(-2); return `${d}/${m}/${y}`; }; window.AdminWhatsAppModal = function({ isOpen, onClose, activeClientId, adminAlerts = { unread_count: 0, alerts: [] }, fetchAdminAlerts = () => {}, showToast = () => {}, initialSelectedUser = null }) { if (!isOpen) return null; const [conversations, setConversations] = React.useState([]); const [chatSearchQuery, setChatSearchQuery] = React.useState(''); const [selectedChatUser, setSelectedChatUser] = React.useState(initialSelectedUser); const [chatHistory, setChatHistory] = React.useState([]); const [adminReplyText, setAdminReplyText] = React.useState(''); const [isSendingReply, setIsSendingReply] = React.useState(false); const chatEndRef = React.useRef(null); const fetchConversations = React.useCallback(async () => { try { const res = await window.apiCall('get_chat_conversations', {}, activeClientId); if (res && res.success) { setConversations(res.conversations || []); } } catch (e) {} }, [activeClientId]); const handleLoadChatHistory = React.useCallback(async (userObj) => { if (!userObj) return; setSelectedChatUser(userObj); try { const res = await window.apiCall('get_chat_history', { user_id: userObj.user_id || userObj.id || 0, phone: userObj.phone || userObj.sender_phone || '' }, activeClientId); if (res && res.success) { setChatHistory(res.messages || []); if (typeof fetchAdminAlerts === 'function') fetchAdminAlerts(); setConversations(prev => prev.map(c => { const match = (userObj.user_id && c.user_id === userObj.user_id) || (userObj.phone && c.phone === userObj.phone); return match ? { ...c, unread_count: 0 } : c; })); } } catch (e) {} }, [activeClientId, fetchAdminAlerts]); React.useEffect(() => { if (isOpen) { fetchConversations(); fetchAdminAlerts(); if (initialSelectedUser) { handleLoadChatHistory(initialSelectedUser); } } }, [isOpen, fetchConversations, fetchAdminAlerts, initialSelectedUser, handleLoadChatHistory]); // Polling en vivo mientras el modal está abierto React.useEffect(() => { if (!isOpen) return; const interval = setInterval(() => { fetchConversations(); fetchAdminAlerts(); if (selectedChatUser) { handleLoadChatHistory(selectedChatUser); } }, 3500); return () => clearInterval(interval); }, [isOpen, fetchConversations, fetchAdminAlerts, selectedChatUser, handleLoadChatHistory]); // Auto-scroll al fondo al actualizar historial React.useEffect(() => { if (chatEndRef.current) { chatEndRef.current.scrollIntoView({ behavior: 'smooth' }); } }, [chatHistory]); const handleMarkAlertRead = async (alertId = 0) => { try { await window.apiCall('mark_alert_read', { alert_id: alertId }, activeClientId); await fetchAdminAlerts(); await fetchConversations(); } catch (e) {} }; const handleSendAdminReply = async () => { if (!selectedChatUser || !adminReplyText.trim()) return; setIsSendingReply(true); try { const res = await window.apiCall('send_admin_chat_reply', { user_id: selectedChatUser.user_id || selectedChatUser.id || 0, phone: selectedChatUser.phone || selectedChatUser.sender_phone || '', message: adminReplyText.trim() }, activeClientId); if (res && res.success) { if (typeof showToast === 'function') showToast("✅ Respuesta enviada vía WhatsApp."); setAdminReplyText(''); await handleLoadChatHistory(selectedChatUser); await fetchConversations(); } else { if (typeof showToast === 'function') showToast("⚠️ Error: " + (res?.error || "Fallo de envío")); } } catch (e) { if (typeof showToast === 'function') showToast("Error de conexión al responder."); } finally { setIsSendingReply(false); } }; return (
Conversaciones & Alertas
{conv.direction === 'outgoing' && ✓✓} {conv.last_message}
{m.message_text || m.message_body || m.message || ''}
{!isIncoming && (Selecciona un colaborador del buzón de la izquierda para abrir su chat en vivo, revisar el historial de mensajes y enviar notificaciones o respuestas por WhatsApp.