import { useState, useEffect, useRef } from 'react'; import { Bell, Menu, Search, LogOut, User, CheckCircle, AlertCircle } from 'lucide-react'; interface TopbarProps { title: string; subtitle: string; onMenuClick: () => void; onNavigate?: (page: string) => void; } const mockNotifications = [ { id: 1, title: 'Novo Agendamento', message: 'João Silva marcou Cabelo às 14:00', type: 'info', time: '10 min atrás', read: false }, { id: 2, title: 'Pagamento Recebido', message: 'Assinatura renovada com sucesso', type: 'success', time: '2 horas atrás', read: true }, { id: 3, title: 'Estoque Baixo', message: 'Pomada modeladora abaixo de 5 unidades', type: 'warning', time: '1 dia atrás', read: true }, ]; export default function Topbar({ title, subtitle, onMenuClick, onNavigate }: TopbarProps) { const [avatarInitials, setAvatarInitials] = useState('AD'); const [tenantName, setTenantName] = useState('Administrador'); const [email, setEmail] = useState('admin@agendapro.com'); const [showNotifications, setShowNotifications] = useState(false); const [showProfile, setShowProfile] = useState(false); const [notifications, setNotifications] = useState([]); const notifRef = useRef(null); const profileRef = useRef(null); const fetchNotifications = async () => { const slug = localStorage.getItem('agendapro_tenant_slug') || 'barbearia-premium'; try { const res = await fetch(`/api/tenant/notifications?slug=${slug}`); if (res.ok) { const data = await res.json(); setNotifications(data); } } catch (err) { console.error('Error fetching notifications:', err); } }; useEffect(() => { const savedName = localStorage.getItem('agendapro_tenant_name'); if (savedName) { setTenantName(savedName); const initials = savedName.split(' ').map(n => n[0]).join('').substring(0, 2).toUpperCase(); setAvatarInitials(initials || 'BJ'); } const savedEmail = localStorage.getItem('agendapro_email'); if (savedEmail) setEmail(savedEmail); fetchNotifications(); const interval = setInterval(fetchNotifications, 15000); // Auto-refresh every 15s const handleClickOutside = (e: MouseEvent) => { if (notifRef.current && !notifRef.current.contains(e.target as Node)) setShowNotifications(false); if (profileRef.current && !profileRef.current.contains(e.target as Node)) setShowProfile(false); }; document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); clearInterval(interval); }; }, []); const playNotificationSound = () => { try { const audioCtx = new (window.AudioContext || (window as any).webkitAudioContext)(); const oscillator = audioCtx.createOscillator(); const gainNode = audioCtx.createGain(); oscillator.type = 'sine'; oscillator.frequency.setValueAtTime(880, audioCtx.currentTime); // A5 oscillator.frequency.exponentialRampToValueAtTime(1760, audioCtx.currentTime + 0.1); // A6 gainNode.gain.setValueAtTime(0.1, audioCtx.currentTime); gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3); oscillator.connect(gainNode); gainNode.connect(audioCtx.destination); oscillator.start(); oscillator.stop(audioCtx.currentTime + 0.3); } catch (e) { console.log('Audio not supported or blocked'); } }; const handleNotificationClick = () => { if (!showNotifications) { const unreadCount = notifications.filter(n => !n.read).length; if (unreadCount > 0) { playNotificationSound(); } } setShowNotifications(!showNotifications); setShowProfile(false); }; const handleProfileClick = () => { setShowProfile(!showProfile); setShowNotifications(false); }; const markAllAsRead = async () => { const slug = localStorage.getItem('agendapro_tenant_slug') || 'barbearia-premium'; setNotifications(notifications.map(n => ({ ...n, read: true }))); try { await fetch('/api/tenant/notifications', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ slug }), }); } catch (err) { console.error(err); } }; const clearAllNotifications = async () => { const slug = localStorage.getItem('agendapro_tenant_slug') || 'barbearia-premium'; setNotifications([]); try { await fetch(`/api/tenant/notifications?slug=${slug}`, { method: 'DELETE', }); } catch (err) { console.error(err); } }; const logout = () => { localStorage.removeItem('agendapro_token'); localStorage.removeItem('agendapro_tenant_slug'); localStorage.removeItem('agendapro_tenant_name'); localStorage.removeItem('agendapro_email'); localStorage.removeItem('agendapro_role'); window.location.href = '/login'; }; const unreadCount = notifications.filter(n => !n.read).length; return (

{title}

{subtitle}

{showNotifications && (

Notificações

{unreadCount > 0 && ( )} {notifications.length > 0 && ( )}
{notifications.map(n => (
{n.type === 'success' ? : n.type === 'warning' ? : }
{n.title}
{n.message}
{n.time}
))}
)}
{avatarInitials}
{showProfile && (
{tenantName}
{email}
)}
); }