// order-modal.jsx — In-stay room service / F&B / amenities ordering // Opens from the Booking Detail drawer's "Gọi thêm" button const ORDER_CATEGORIES = [ { k: 'food', l: 'Ẩm thực', emoji: '🍴' }, { k: 'drink', l: 'Đồ uống', emoji: '🍷' }, { k: 'amenity', l: 'Tiện nghi & dịch vụ', emoji: '✨' }, ]; function relTime(d) { if (!d) return ''; const date = d instanceof Date ? d : new Date(d); const diff = Math.floor((Date.now() - date.getTime()) / 1000); if (diff < 60) return 'vừa xong'; if (diff < 3600) return `${Math.floor(diff / 60)} phút trước`; if (diff < 86400) return `${Math.floor(diff / 3600)} giờ trước`; return `${Math.floor(diff / 86400)} ngày trước`; } function OrderModal({ booking, onClose, onSubmit }) { const data = window.HotelData; const room = findRoom(data.rooms, booking.roomId); const guest = booking.guestId ? findGuest(data.guests, booking.guestId) : booking._newGuest; const [cat, setCat] = React.useState('food'); const [q, setQ] = React.useState(''); const [cart, setCart] = React.useState({}); // {itemId: qty} const [note, setNote] = React.useState(''); const filteredItems = React.useMemo(() => { return data.inStayMenu.filter(m => { if (m.cat !== cat) return false; if (!q.trim()) return true; const s = q.trim().toLowerCase(); return m.name.toLowerCase().includes(s) || (m.desc || '').toLowerCase().includes(s); }); }, [cat, q, data.inStayMenu]); const catCount = (k) => data.inStayMenu.filter(m => m.cat === k).length; const setQty = (id, qty) => { setCart(c => { const next = { ...c }; if (qty <= 0) delete next[id]; else next[id] = qty; return next; }); }; const cartTotal = Object.entries(cart).reduce((sum, [id, qty]) => { const item = findMenuItem(data.inStayMenu, id); return sum + (item ? item.price * qty : 0); }, 0); const cartCount = Object.values(cart).reduce((s, q) => s + q, 0); const handleSend = () => { const newOrders = Object.entries(cart).map(([itemId, qty]) => ({ id: 'o-' + Date.now() + '-' + itemId, itemId, qty, status: 'pending', staff: 'Lễ tân Hà', note: note || '', orderedAt: new Date(), })); onSubmit(newOrders); }; return (
e.stopPropagation()}>

Gọi thêm dịch vụ

Phòng {room?.number} · {guest?.name || 'Khách'} ·{' '} ● đang lưu trú
{/* Left: menu */}
{ORDER_CATEGORIES.map(c => ( ))}
setQ(e.target.value)} autoFocus />
{filteredItems.map(item => { const qty = cart[item.id] || 0; const inCart = qty > 0; return (
setQty(item.id, qty + 1)} > {inCart && ×{qty}}
{item.icon}
{item.name}
{item.desc}
{item.price === 0 ? 'Miễn phí' : VND(item.price) + (item.unit || '')}
); })} {filteredItems.length === 0 && (
Không tìm thấy "{q}"
)}
{/* Right: cart */}
Phiếu order · Phòng {room?.number}

Giỏ hàng

{cartCount > 0 && {cartCount} món}
{cartCount === 0 ? (
🛎️
Chưa có món nào.
Bấm hoặc kéo món từ menu để thêm.
) : (
{Object.entries(cart).map(([id, qty]) => { const item = findMenuItem(data.inStayMenu, id); if (!item) return null; return (
{item.icon}
{item.name}
{VND(item.price)} × {qty}
{qty}
{VND(item.price * qty)}
); })}
)}