// utils.jsx — shared icons + helpers for Sao Mai Hotel UI // ─── Icons (Material-style line icons) ────────────────────── const Icon = ({ name, size = 20, stroke = 1.8, ...rest }) => { const s = { width: size, height: size, display: 'inline-block', flexShrink: 0, ...rest.style }; const common = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: stroke, strokeLinecap: 'round', strokeLinejoin: 'round', ...rest, style: s, }; const paths = { menu: <>, calendar: <>, timeline: <>, list: <>, invoice: <>, bed: <>, chart: <>, chevron_left: , chevron_right: , chevron_down: , plus: <>, minus: , x: <>, search: <>, filter: , settings: <>, user: <>, users: <>, phone: , mail: <>, location: <>, clock: <>, moon: , sun: <>, print: <>, download: <>, edit: <>, trash: <>, check: , check_circle: <>, arrow_right: <>, sparkle: <>, bell: <>, qr: <>, refresh: <>, sidebar: <>, cash: <>, card: <>, bank: <>, later: <>, info: <>, star: , }; return {paths[name] || null}; }; // ─── Date helpers ──────────────────────────────────────────── const DOW_VN = ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7']; const DOW_VN_LONG = ['Chủ nhật', 'Thứ Hai', 'Thứ Ba', 'Thứ Tư', 'Thứ Năm', 'Thứ Sáu', 'Thứ Bảy']; const MONTH_VN = ['Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6', 'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12']; const sameDay = (a, b) => a && b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); const startOfDay = (d) => { const x = new Date(d); x.setHours(0,0,0,0); return x; }; const daysBetween = (a, b) => Math.round((startOfDay(b) - startOfDay(a)) / 86400000); const formatDateVN = (d) => `${DOW_VN_LONG[d.getDay()]}, ${d.getDate()} ${MONTH_VN[d.getMonth()]} ${d.getFullYear()}`; const formatDateShort = (d) => `${String(d.getDate()).padStart(2,'0')}/${String(d.getMonth()+1).padStart(2,'0')}/${d.getFullYear()}`; const formatRange = (a, b) => { if (a.getMonth() === b.getMonth() && a.getFullYear() === b.getFullYear()) { return `${MONTH_VN[a.getMonth()]} ${a.getFullYear()}`; } return `${MONTH_VN[a.getMonth()]} – ${MONTH_VN[b.getMonth()]} ${b.getFullYear()}`; }; // ─── Currency ──────────────────────────────────────────────── const VND = (n) => { if (n == null) return '—'; return new Intl.NumberFormat('de-DE').format(Math.round(n)) + 'đ'; }; const VNDshort = (n) => { if (n == null) return '—'; if (n >= 1_000_000) return (n / 1_000_000).toFixed(n >= 10_000_000 ? 0 : 1).replace(/\.0$/, '') + 'tr'; if (n >= 1_000) return Math.round(n / 1_000) + 'k'; return String(n); }; // ─── Misc ──────────────────────────────────────────────────── const initials = (name) => { if (!name) return '?'; const parts = name.trim().split(/\s+/); if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase(); return (parts[parts.length - 2][0] + parts[parts.length - 1][0]).toUpperCase(); }; const findRoom = (rooms, id) => rooms.find(r => r.id === id); const findGuest = (guests, id) => guests.find(g => g.id === id); const findService = (catalog, id) => catalog.find(s => s.id === id); const findMenuItem = (menu, id) => menu.find(m => m.id === id); const computeBookingTotal = (booking, rooms, catalog, menu) => { const room = findRoom(rooms, booking.roomId); const nights = Math.max(1, daysBetween(booking.checkIn, booking.checkOut)); const roomTotal = room ? room.price * nights : 0; const servicesTotal = (booking.services || []).reduce((sum, s) => { const sv = findService(catalog, s.id); return sum + (sv ? sv.price * s.qty : 0); }, 0); const ordersTotal = menu ? (booking.orders || []) .filter(o => o.status !== 'cancelled') .reduce((sum, o) => { const item = findMenuItem(menu, o.itemId); return sum + (item ? item.price * o.qty : 0); }, 0) : 0; const subtotal = roomTotal + servicesTotal + ordersTotal; const tax = Math.round(subtotal * 0.1); const total = subtotal + tax; return { nights, roomTotal, servicesTotal, ordersTotal, subtotal, tax, total }; }; // Export everything to window Object.assign(window, { Icon, DOW_VN, DOW_VN_LONG, MONTH_VN, sameDay, startOfDay, daysBetween, formatDateVN, formatDateShort, formatRange, VND, VNDshort, initials, findRoom, findGuest, findService, findMenuItem, computeBookingTotal, });