Files
shahikitchen-prod/components/CartDrawer.tsx
T

247 lines
9.4 KiB
TypeScript
Raw 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 { useState } from 'react';
import Link from 'next/link';
import { MessageCircle } from 'lucide-react';
import {
buildDeliveryInquiryMessage,
buildPickupInquiryMessage,
} from '@/application/messaging/whatsapp-message-builder';
import type { FulfillmentMode } from '@/domain/cart/inquiry';
import type { DeliveryInquiryDetails, PickupInquiryDetails } from '@/domain/cart/inquiry';
import {
calculateLineTotal,
formatLineQuantityLabel,
} from '@/domain/shared/order-line';
import { RESTAURANT_CONTACT } from '@/domain/shared/constants';
import { container } from '@/infrastructure/di/container';
import { useCart } from '@/presentation/providers/cart-provider';
import { useLanguage } from '@/presentation/providers/language-provider';
import { getTranslation } from '@/presentation/i18n/translations';
import CartInquiryModal from '@/components/CartInquiryModal';
export default function CartDrawer() {
const {
items,
isOpen,
closeCart,
totalPrice,
removeFromCart,
updateQuantity,
clearCart,
} = useCart();
const { language } = useLanguage();
const t = getTranslation(language);
const [inquiryMode, setInquiryMode] = useState<FulfillmentMode | null>(null);
const inquiryCopy = {
pickupIntro: t.cartDrawer.inquiryPickupIntro,
deliveryIntro: t.cartDrawer.inquiryDeliveryIntro,
messageTotal: t.cartDrawer.messageTotal,
messageName: t.cartDrawer.messageName,
messagePhone: t.cartDrawer.messagePhone,
messageAddress: t.cartDrawer.messageAddress,
messagePreferredTime: t.cartDrawer.messagePreferredTime,
deliverySwishNote: t.cartDrawer.deliverySwishNote,
};
const openWhatsApp = (message: string | null) => {
if (!message) return;
container.messagingGateway.openWhatsApp(message);
setInquiryMode(null);
};
const handlePickupSubmit = (details: PickupInquiryDetails) => {
openWhatsApp(buildPickupInquiryMessage(items, details, inquiryCopy));
};
const handleDeliverySubmit = (details: DeliveryInquiryDetails) => {
openWhatsApp(buildDeliveryInquiryMessage(items, details, inquiryCopy));
};
if (!isOpen) return null;
return (
<>
<div
className="fixed inset-0 bg-black/40 z-[980]"
onClick={closeCart}
/>
<div className="fixed top-0 right-0 h-full w-full max-w-md bg-[#F8F5F0] z-[990] shadow-2xl flex flex-col">
<div className="flex items-center justify-between p-6 border-b border-[#EDE6D9]">
<div className="flex items-center gap-3">
<h2 className="text-2xl tracking-[-0.5px]">{t.cartDrawer.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.cartDrawer.item : t.cartDrawer.items}
</span>
)}
</div>
<div className="flex items-center gap-3">
{items.length > 0 && (
<button
onClick={clearCart}
className="text-xs text-[#B38B4D] hover:underline"
>
{t.cartDrawer.clear}
</button>
)}
<button
onClick={closeCart}
className="text-[#6B665F] hover:text-[#2C2A26] text-2xl leading-none pl-1"
>
×
</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">
<div className="text-6xl mb-4">🛒</div>
<p className="text-lg text-[#6B665F]">{t.cartDrawer.empty}</p>
<Link
href="/menu"
onClick={closeCart}
className="mt-6 text-[#B38B4D] hover:underline"
>
{t.cartDrawer.browseMenu}
</Link>
</div>
) : (
<div className="space-y-6">
{items.map((item) => (
<div key={item.id} className="flex gap-4 border-b border-[#EDE6D9] pb-6">
<div className="flex-1">
<div className="flex justify-between">
<div>
<h4 className="font-medium tracking-[-0.3px]">{item.name}</h4>
<p className="text-sm text-[#6B665F]">
{item.pricingMode === 'weight'
? `${item.pricePerHalfKg ?? item.price} kr / ½ kg`
: `${item.price} kr × ${item.quantity}`}
</p>
</div>
<div className="text-right font-medium">
{calculateLineTotal(item)} kr
</div>
</div>
<div className="flex items-center gap-3 mt-3">
<button
onClick={() => updateQuantity(item.id, item.quantity - 1)}
className="w-8 h-8 flex items-center justify-center border border-[#EDE6D9] rounded hover:bg-white transition"
>
</button>
<span className="min-w-12 text-center font-medium tabular-nums">
{formatLineQuantityLabel(item)}
</span>
<button
onClick={() => updateQuantity(item.id, item.quantity + 1)}
className="w-8 h-8 flex items-center justify-center border border-[#EDE6D9] rounded hover:bg-white transition"
>
+
</button>
<button
onClick={() => removeFromCart(item.id)}
className="ml-auto text-xs text-[#B38B4D] hover:underline"
>
{t.cartDrawer.remove}
</button>
</div>
</div>
</div>
))}
</div>
)}
</div>
{items.length > 0 && (
<div className="p-6 border-t border-[#EDE6D9] bg-white">
<button
onClick={clearCart}
className="text-xs text-[#8A8478] hover:text-[#B38B4D] mb-3 underline"
>
{t.cartDrawer.clearBasket}
</button>
<div className="flex justify-between text-lg font-medium mb-4">
<span>{t.cartDrawer.total}</span>
<span>{totalPrice.toFixed(0)} kr</span>
</div>
<p className="text-xs text-center text-[#6B665F] mb-4">
{t.cartDrawer.inquiryHint}
</p>
<button
type="button"
onClick={() => setInquiryMode('pickup')}
className="btn-primary w-full py-4 rounded-full text-base tracking-[0.5px] font-medium mb-2 flex items-center justify-center gap-2"
>
<MessageCircle className="h-5 w-5" aria-hidden />
{t.cartDrawer.pickupInquiry}
</button>
<button
type="button"
onClick={() => setInquiryMode('delivery')}
className="btn-outline w-full py-4 rounded-full text-base tracking-[0.5px] font-medium mb-2 flex items-center justify-center gap-2 border-[#25D366] text-[#128C7E] hover:bg-[#25D366]/10"
>
<MessageCircle className="h-5 w-5" aria-hidden />
{t.cartDrawer.deliveryInquiry}
</button>
<button
onClick={() => window.open(`tel:${RESTAURANT_CONTACT.phonePrimary}`, '_self')}
className="btn-outline w-full py-3 rounded-full text-sm tracking-[0.5px] font-medium mb-3"
>
{t.cartDrawer.call}
</button>
<button
onClick={closeCart}
className="w-full text-sm text-[#6B665F] hover:text-[#2C2A26] pt-1"
>
{t.cartDrawer.continueBrowsing}
</button>
</div>
)}
</div>
{inquiryMode && (
<CartInquiryModal
mode={inquiryMode}
isOpen={!!inquiryMode}
onClose={() => setInquiryMode(null)}
onSubmitPickup={handlePickupSubmit}
onSubmitDelivery={handleDeliverySubmit}
labels={{
titlePickup: t.cartDrawer.inquiryModalTitlePickup,
titleDelivery: t.cartDrawer.inquiryModalTitleDelivery,
nameLabel: t.cartDrawer.nameLabel,
namePlaceholder: t.cartDrawer.namePlaceholder,
phoneLabel: t.cartDrawer.phoneLabel,
phonePlaceholder: t.cartDrawer.phonePlaceholder,
addressLabel: t.cartDrawer.addressLabel,
addressPlaceholder: t.cartDrawer.addressPlaceholder,
preferredTimeLabel: t.cartDrawer.preferredTimeLabel,
preferredTimePlaceholder: t.cartDrawer.preferredTimePlaceholder,
submitPickup: t.cartDrawer.submitPickup,
submitDelivery: t.cartDrawer.submitDelivery,
cancel: t.cartDrawer.inquiryCancel,
close: t.cartDrawer.inquiryClose,
nameRequired: t.cartDrawer.nameRequired,
phoneRequired: t.cartDrawer.phoneRequired,
addressRequired: t.cartDrawer.addressRequired,
timeRequired: t.cartDrawer.timeRequired,
}}
/>
)}
</>
);
}