/** * Oveyo PWA V7.8.1 — Page Assistant (fix scroll iOS + safe-area) * ================================================================= * Même fix que FAQ : paddingBottom suffisante + scroll iOS fluide. */ const AssistantPage = ({ state, onClose, onOpenSheet }) => { const { Send, Bot, User: UserIcon, Loader, Sparkles, ArrowLeft } = window.LucideReact || {}; const flash = window.OveyoUI?.useFlash ? window.OveyoUI.useFlash() : { show: () => {} }; const [messages, setMessages] = React.useState([]); const [input, setInput] = React.useState(''); const [busy, setBusy] = React.useState(false); const [historyLoaded, setHistoryLoaded] = React.useState(false); const messagesEndRef = React.useRef(null); const inputRef = React.useRef(null); const token = state.user?.session_token; const isLoggedIn = !!token; React.useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); React.useEffect(() => { if (!isLoggedIn || historyLoaded) return; const loadHistory = async () => { try { const r = await fetch('/api/pwa/assistant/history?limit=20', { headers: { 'Authorization': 'Bearer ' + token }, }); if (r.ok) { const data = await r.json(); const list = (data.history || []).map((h) => ({ id: h.id, from: h.direction === 'in' ? 'user' : 'bot', text: h.content, time: h.created_at, })); setMessages(list); } } catch (e) { console.error('History load failed:', e); } finally { setHistoryLoaded(true); } }; loadHistory(); }, [isLoggedIn, token, historyLoaded]); const sendMessage = async (forcedText) => { const text = (forcedText || input).trim(); if (!text || busy || !isLoggedIn) return; const userMsg = { id: 'temp-' + Date.now(), from: 'user', text, time: new Date().toISOString() }; setMessages((prev) => [...prev, userMsg]); setInput(''); setBusy(true); try { const r = await fetch('/api/pwa/assistant/chat', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token, }, body: JSON.stringify({ message: text }), }); if (r.status === 429) { flash.show('error', 'Trop de messages — attends 1 minute'); setBusy(false); return; } if (!r.ok) { const errData = await r.json().catch(() => ({})); flash.show('error', errData.detail || 'Erreur du bot'); setBusy(false); return; } const data = await r.json(); // V7.8 : si bot désactivé, afficher un message + bouton WhatsApp if (data.disabled) { const botMsg = { id: 'bot-' + Date.now(), from: 'bot', text: data.reply, time: new Date().toISOString(), }; setMessages((prev) => [...prev, botMsg]); setBusy(false); return; } const botMsg = { id: 'bot-' + Date.now(), from: 'bot', text: data.reply, intent: data.intent, time: new Date().toISOString(), }; setMessages((prev) => [...prev, botMsg]); } catch (e) { console.error('Send failed:', e); flash.show('error', 'Erreur de connexion'); } finally { setBusy(false); setTimeout(() => inputRef.current?.focus(), 100); } }; const handleKeyDown = (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }; const SUGGESTIONS = [ "Combien le pain à Plateau ?", "Prix moyen du gaz", "Pharmacie de garde Dakar", "Quel est le prix officiel du sucre ?", ]; if (!isLoggedIn) { return (

Assistant Oveyo

Connecte-toi pour utiliser l'assistant.

); } return (

Assistant Oveyo

Propulsé par Claude AI

{messages.length === 0 && historyLoaded && (

Pose ta première question 👇

{SUGGESTIONS.map((s, i) => ( ))}
)} {messages.map((m) => (
{m.from === 'user' ? : }
{m.text}
))} {busy && (
)}
setInput(e.target.value)} onKeyDown={handleKeyDown} placeholder="Pose ta question…" disabled={busy} maxLength={500} className="flex-1 px-4 py-3 rounded-2xl text-sm outline-none" style={{ background: '#F1F4F9', border: '1px solid #EAEEF4' }} />

Le bot peut se tromper — vérifie les prix critiques

); }; window.AssistantPage = AssistantPage;