feat: implement notification center in frontend shell header
This commit is contained in:
parent
4aac3a0a7e
commit
beb64067cf
1 changed files with 59 additions and 1 deletions
|
|
@ -65,7 +65,10 @@ function CartDropdownContent() {
|
|||
export function Shell({ children }: { children: React.ReactNode }) {
|
||||
const { user, logout } = useAuth()
|
||||
const [isProfileOpen, setIsProfileOpen] = useState(false)
|
||||
const [isNotificationsOpen, setIsNotificationsOpen] = useState(false)
|
||||
const [notifications, setNotifications] = useState<any[]>([])
|
||||
const profileMenuRef = useRef<HTMLDivElement | null>(null)
|
||||
const notificationsRef = useRef<HTMLDivElement | null>(null)
|
||||
const { totalItems: cartCount } = useCartStore(selectCartSummary)
|
||||
|
||||
const isOwner = user?.role === 'owner'
|
||||
|
|
@ -78,13 +81,27 @@ export function Shell({ children }: { children: React.ReactNode }) {
|
|||
if (profileMenuRef.current && !profileMenuRef.current.contains(event.target as Node)) {
|
||||
setIsProfileOpen(false)
|
||||
}
|
||||
if (notificationsRef.current && !notificationsRef.current.contains(event.target as Node)) {
|
||||
setIsNotificationsOpen(false)
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside)
|
||||
|
||||
// Simulate loading notifications (In prod, fetch from /api/v1/notifications)
|
||||
if (user) {
|
||||
setNotifications([
|
||||
{ id: 1, title: 'Bem-vindo!', message: 'Explore o marketplace SaveInMed.', date: new Date().toISOString(), read: false },
|
||||
{ id: 2, title: 'Perfil Completo', message: 'Seu cadastro foi verificado com sucesso.', date: new Date().toISOString(), read: true }
|
||||
])
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside)
|
||||
}
|
||||
}, [])
|
||||
}, [user])
|
||||
|
||||
const unreadCount = notifications.filter(n => !n.read).length
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100">
|
||||
|
|
@ -112,6 +129,47 @@ export function Shell({ children }: { children: React.ReactNode }) {
|
|||
<a href="/shipping-settings" className="hover:underline whitespace-nowrap">Config. Entrega</a>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Notifications */}
|
||||
<div className="relative" ref={notificationsRef}>
|
||||
<button
|
||||
onClick={() => setIsNotificationsOpen(!isNotificationsOpen)}
|
||||
className="relative hover:bg-white/10 p-2 rounded-lg transition-colors block"
|
||||
title="Notificações"
|
||||
>
|
||||
<svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
|
||||
</svg>
|
||||
{unreadCount > 0 && (
|
||||
<span className="absolute top-1 right-1 flex h-4 w-4 items-center justify-center rounded-full bg-orange-500 text-[10px] font-bold">
|
||||
{unreadCount}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{isNotificationsOpen && (
|
||||
<div className="absolute right-0 mt-2 w-80 rounded-lg bg-white shadow-xl border border-gray-100 z-[100] text-gray-800">
|
||||
<div className="p-4 border-b flex justify-between items-center">
|
||||
<h3 className="font-bold text-sm">Notificações</h3>
|
||||
<button onClick={() => setNotifications([])} className="text-xs text-blue-600 hover:underline">Limpar tudo</button>
|
||||
</div>
|
||||
<div className="max-h-64 overflow-y-auto">
|
||||
{notifications.length === 0 ? (
|
||||
<div className="p-8 text-center text-gray-400 text-sm italic">Nenhuma notificação</div>
|
||||
) : (
|
||||
notifications.map(n => (
|
||||
<div key={n.id} className={`p-4 border-b hover:bg-gray-50 transition-colors ${!n.read ? 'bg-blue-50/30' : ''}`}>
|
||||
<p className="font-semibold text-xs">{n.title}</p>
|
||||
<p className="text-xs text-gray-600 mt-1">{n.message}</p>
|
||||
<p className="text-[10px] text-gray-400 mt-2">{new Date(n.date).toLocaleDateString()}</p>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="relative group">
|
||||
<a
|
||||
href="/cart"
|
||||
|
|
|
|||
Loading…
Reference in a new issue