feat(marketplace): add cart hover dropdown preview
- Add CartDropdownContent component showing cart items on hover - Show 'carrinho vazio' message when empty - Display up to 4 items with name, quantity, price - Add remove button for each item in dropdown - Show total and 'Ver carrinho completo' link - Badge only shows when cart has items (already implemented)
This commit is contained in:
parent
299001d8bc
commit
8ec820c383
1 changed files with 92 additions and 10 deletions
|
|
@ -2,6 +2,66 @@ import { useEffect, useRef, useState } from 'react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { useAuth } from '../context/AuthContext'
|
import { useAuth } from '../context/AuthContext'
|
||||||
import { useCartStore, selectCartSummary } from '../stores/cartStore'
|
import { useCartStore, selectCartSummary } from '../stores/cartStore'
|
||||||
|
import { formatCurrency } from '../utils/format'
|
||||||
|
|
||||||
|
// Cart dropdown content component
|
||||||
|
function CartDropdownContent() {
|
||||||
|
const items = useCartStore((state) => state.items)
|
||||||
|
const removeItem = useCartStore((state) => state.removeItem)
|
||||||
|
const { totalValue } = useCartStore(selectCartSummary)
|
||||||
|
|
||||||
|
// Show max 4 items in preview
|
||||||
|
const displayItems = items.slice(0, 4)
|
||||||
|
const hiddenCount = items.length - displayItems.length
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="p-3 border-b border-gray-100">
|
||||||
|
<p className="text-sm font-semibold text-gray-700">Carrinho</p>
|
||||||
|
</div>
|
||||||
|
<div className="max-h-64 overflow-y-auto">
|
||||||
|
{displayItems.map((item) => (
|
||||||
|
<div key={item.id} className="flex items-center gap-3 p-3 hover:bg-gray-50 border-b border-gray-50">
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<p className="text-sm font-medium text-gray-800 truncate">{item.name}</p>
|
||||||
|
<p className="text-xs text-gray-500">{item.quantity}x • R$ {formatCurrency(item.unitPrice)}</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
removeItem(item.id)
|
||||||
|
}}
|
||||||
|
className="text-red-500 hover:text-red-700 p-1"
|
||||||
|
title="Remover"
|
||||||
|
>
|
||||||
|
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{hiddenCount > 0 && (
|
||||||
|
<div className="p-2 text-center text-xs text-gray-500">
|
||||||
|
+{hiddenCount} {hiddenCount === 1 ? 'item' : 'itens'}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="p-3 border-t border-gray-100 bg-gray-50">
|
||||||
|
<div className="flex justify-between items-center mb-3">
|
||||||
|
<span className="text-sm text-gray-600">Total:</span>
|
||||||
|
<span className="text-lg font-bold text-medicalBlue">R$ {formatCurrency(totalValue)}</span>
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
to="/cart"
|
||||||
|
className="block w-full text-center bg-medicalBlue text-white py-2 rounded-lg text-sm font-semibold hover:bg-blue-700 transition-colors"
|
||||||
|
>
|
||||||
|
Ver carrinho completo
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function Shell({ children }: { children: React.ReactNode }) {
|
export function Shell({ children }: { children: React.ReactNode }) {
|
||||||
const { user, logout } = useAuth()
|
const { user, logout } = useAuth()
|
||||||
|
|
@ -58,16 +118,38 @@ export function Shell({ children }: { children: React.ReactNode }) {
|
||||||
</Link>
|
</Link>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Link to="/cart" className="relative hover:bg-white/10 p-2 rounded-lg transition-colors" title="Carrinho">
|
{/* Cart with hover dropdown */}
|
||||||
<svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<div className="relative group">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
|
<Link
|
||||||
</svg>
|
to="/cart"
|
||||||
{cartCount > 0 && (
|
className="relative hover:bg-white/10 p-2 rounded-lg transition-colors block"
|
||||||
<span className="absolute -top-1 -right-1 flex h-5 w-5 items-center justify-center rounded-full bg-red-500 text-xs font-bold">
|
title="Carrinho"
|
||||||
{cartCount > 99 ? '99+' : cartCount}
|
>
|
||||||
</span>
|
<svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
)}
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||||
</Link>
|
</svg>
|
||||||
|
{cartCount > 0 && (
|
||||||
|
<span className="absolute -top-1 -right-1 flex h-5 w-5 items-center justify-center rounded-full bg-red-500 text-xs font-bold">
|
||||||
|
{cartCount > 99 ? '99+' : cartCount}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Dropdown on hover */}
|
||||||
|
<div className="invisible group-hover:visible opacity-0 group-hover:opacity-100 transition-all duration-200 absolute right-0 top-full z-50 mt-2 w-80 rounded-lg bg-white shadow-xl border border-gray-100">
|
||||||
|
{cartCount === 0 ? (
|
||||||
|
<div className="p-6 text-center">
|
||||||
|
<svg className="mx-auto h-12 w-12 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||||
|
</svg>
|
||||||
|
<p className="mt-2 text-sm font-medium text-gray-600">Seu carrinho está vazio</p>
|
||||||
|
<p className="text-xs text-gray-400">Adicione produtos para começar</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<CartDropdownContent />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{user && (
|
{user && (
|
||||||
<div className="relative flex items-center" ref={profileMenuRef}>
|
<div className="relative flex items-center" ref={profileMenuRef}>
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue