Files

186 lines
7.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import Link from 'next/link';
import { Heart, ShoppingBag } from 'lucide-react';
import { useWishlist } from '@/presentation/providers/wishlist-provider';
import { useCart } from '@/presentation/providers/cart-provider';
import { useLanguage } from '@/presentation/providers/language-provider';
import { getTranslation } from '@/presentation/i18n/translations';
import { getMenuPosterSrc, applyNextImageFallback, getMenuPosterCandidates } from '@/lib/assets';
import { useMenu } from '@/presentation/providers/menu-provider';
import { getMenuItemName } from '@/application/i18n/menu-localization';
import { buildCartLineFromMenuItem } from '@/application/cart/cart-line-builder';
export default function WishlistDrawer() {
const {
items,
isOpen,
closeWishlist,
removeFromWishlist,
clearWishlist,
} = useWishlist();
const { addToCart } = useCart();
const { getItemById } = useMenu();
const { language, isRtl } = useLanguage();
const t = getTranslation(language);
if (!isOpen) return null;
const handleAddToCart = (item: (typeof items)[number]) => {
const menuItem = getItemById(item.id);
addToCart(menuItem ? buildCartLineFromMenuItem(menuItem) : {
id: item.id,
name: item.name,
price: item.price,
image: item.image,
pricingMode: 'standard',
});
};
return (
<>
<div
className="fixed inset-0 bg-black/40 z-[985]"
onClick={closeWishlist}
/>
<div
className={`fixed top-0 h-full w-full max-w-md bg-[#F8F5F0] z-[985] shadow-2xl flex flex-col ${
isRtl ? 'left-0 border-r border-[#EDE6D9]' : 'right-0 border-l border-[#EDE6D9]'
}`}
>
<div className="flex items-center justify-between p-6 border-b border-[#EDE6D9]">
<div className="flex items-center gap-3">
<Heart className="h-5 w-5 text-[#c99a2e] fill-[#c99a2e]/20" />
<h2 className="text-2xl tracking-[-0.5px] text-[#101724]">{t.wishlistDrawer.title}</h2>
{items.length > 0 && (
<span className="text-xs px-2.5 py-0.5 rounded-full bg-[#EDE6D9] text-[#6B665F]">
{items.length} {items.length === 1 ? t.wishlistDrawer.item : t.wishlistDrawer.items}
</span>
)}
</div>
<div className="flex items-center gap-3">
{items.length > 0 && (
<button
onClick={clearWishlist}
className="text-xs text-[#B38B4D] hover:underline"
>
{t.wishlistDrawer.clear}
</button>
)}
<button
onClick={closeWishlist}
className="text-[#6B665F] hover:text-[#2C2A26] text-2xl leading-none pl-1"
aria-label="Close wishlist"
>
×
</button>
</div>
</div>
<div className="flex-1 overflow-y-auto p-6">
{items.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-center">
<Heart className="h-16 w-16 text-[#c99a2e]/30 mb-4" />
<p className="text-lg text-[#6B665F]">{t.wishlistDrawer.empty}</p>
<Link
href="/menu"
onClick={closeWishlist}
className="mt-6 text-[#B38B4D] hover:underline"
>
{t.wishlistDrawer.browseMenu}
</Link>
</div>
) : (
<div className="space-y-5">
{items.map((item) => {
const menuItem = getItemById(item.id);
const displayName = getMenuItemName(language, {
id: item.id,
name: menuItem?.name ?? item.name,
});
return (
<div
key={item.id}
className="flex gap-4 rounded-2xl border border-[#EDE6D9] bg-white p-4"
>
<div className="h-20 w-20 shrink-0 overflow-hidden rounded-xl bg-[#F2EDE4]">
<img
src={getMenuPosterSrc(item)}
alt={displayName}
className="h-full w-full object-cover"
loading="lazy"
onError={(e) => {
applyNextImageFallback(
e.target as HTMLImageElement,
getMenuPosterCandidates(item),
(e.target as HTMLImageElement).src
);
}}
/>
</div>
<div className="flex-1 min-w-0">
<div className="flex justify-between gap-2">
<h4 className="font-medium tracking-[-0.3px] text-[#101724] truncate">
{displayName}
</h4>
<span className="shrink-0 text-right font-medium text-[#B38B4D] tabular-nums text-sm leading-tight">
{(() => {
const menuItem = getItemById(item.id);
if (menuItem?.pricing === 'weight') {
return (
<>
<span className="block">{menuItem.pricePerHalfKg} kr / ½ kg</span>
<span className="block text-xs text-[#8A8478]">{menuItem.pricePerKg} {t.menu.perKg}</span>
</>
);
}
return <span>{item.price} kr</span>;
})()}
</span>
</div>
<div className="flex items-center gap-2 mt-3">
<button
onClick={() => handleAddToCart(item)}
className="inline-flex items-center gap-1.5 rounded-full bg-gradient-to-r from-[#c99a2e] to-[#d4a73d] px-4 py-2 text-xs font-bold text-[#241806] transition-all hover:scale-[1.02] active:scale-[0.98]"
>
<ShoppingBag className="h-3.5 w-3.5" />
{t.wishlistDrawer.addToCart}
</button>
<button
onClick={() => removeFromWishlist(item.id)}
className="text-xs text-[#B38B4D] hover:underline ml-auto"
>
{t.wishlistDrawer.remove}
</button>
</div>
</div>
</div>
);
})}
</div>
)}
</div>
{items.length > 0 && (
<div className="p-6 pb-[max(1.5rem,env(safe-area-inset-bottom))] border-t border-[#EDE6D9] bg-white">
<p className="text-xs text-center text-[#6B665F] mb-4">
{t.wishlistDrawer.hint}
</p>
<Link
href="/menu"
onClick={closeWishlist}
className="block w-full text-center text-sm text-[#B38B4D] hover:underline"
>
{t.wishlistDrawer.continueBrowsing}
</Link>
</div>
)}
</div>
</>
);
}