// AllBookings.jsx — full history view of every booking, with collapsible // Year → Month → Day sidebar, full-text search, multi-day "Multiple" pill, // and row-click → Modify dialog (reusing the one from Bookings.jsx). function fmtAllDate(iso) { const d = new Date(iso + 'T00:00:00'); return d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', weekday: 'short' }); } function ymOf(iso) { return iso.slice(0, 7); } // "2026-05" function yOf(iso) { return iso.slice(0, 4); } // "2026" function categoryIcon(cat) { if (cat === 'Mobile Crane') return Crane; if (cat === 'Skylift') return Truck; if (cat === 'Scissor Lift') return Activity; if (cat === 'Lorry Crane') return Truck; if (cat === 'Lorry') return Truck; if (cat === 'Boom Lift') return Activity; if (cat === 'Rough Terrain Crane')return Crane; if (cat === 'Cross Rent') return Layers; return Briefcase; } function AllBookingsPage({ role, setPage }) { const [search, setSearch] = React.useState(''); // sidebar selection: { kind: 'all' | 'year' | 'month' | 'day', value: '...' } const [sel, setSel] = React.useState({ kind: 'all' }); // expansion state: which years/months are open in sidebar const [openYears, setOpenYears] = React.useState({ '2026': true }); const [openMonths, setOpenMonths] = React.useState({ '2026-05': true }); const [modifyTarget, setModifyTarget] = React.useState(null); const [, forceRender] = React.useReducer(x => x + 1, 0); const isAdmin = role === 'Admin'; // ===== Build sidebar tree from a CONTINUOUS date range ===== // Show every day from the earliest booking through today + 14 days, so // the sidebar shows every date in the calendar — even those without bookings. const bookingDates = BOOKINGS.map(b => b.date).filter(Boolean); const minDate = bookingDates.length ? bookingDates.reduce((a, b) => a < b ? a : b) : TODAY; // Forward window: today + 14 days, but never earlier than the latest booking. const maxBooking = bookingDates.length ? bookingDates.reduce((a, b) => a > b ? a : b) : TODAY; const todayPlus14 = (() => { const d = new Date(TODAY + 'T00:00:00'); d.setDate(d.getDate() + 14); return d.toISOString().slice(0, 10); })(); const maxDate = maxBooking > todayPlus14 ? maxBooking : todayPlus14; // Generate every ISO date string between minDate and maxDate (inclusive). const allDates = (() => { const out = []; const cur = new Date(minDate + 'T00:00:00'); const end = new Date(maxDate + 'T00:00:00'); while (cur <= end) { const y = cur.getFullYear(); const m = String(cur.getMonth() + 1).padStart(2, '0'); const dd = String(cur.getDate()).padStart(2, '0'); out.push(`${y}-${m}-${dd}`); cur.setDate(cur.getDate() + 1); } return out.reverse(); // newest first })(); const tree = {}; // { year: { month: [days] } } allDates.forEach(d => { const y = yOf(d), mo = ymOf(d); if (!tree[y]) tree[y] = {}; if (!tree[y][mo]) tree[y][mo] = []; tree[y][mo].push(d); }); // ===== Apply filter by sidebar selection ===== let filtered = BOOKINGS.slice(); if (sel.kind === 'year') filtered = filtered.filter(b => yOf(b.date) === sel.value); if (sel.kind === 'month') filtered = filtered.filter(b => ymOf(b.date) === sel.value); if (sel.kind === 'day') filtered = filtered.filter(b => b.date === sel.value); // ===== Apply full-text search across all fields ===== if (search.trim()) { const q = search.trim().toLowerCase(); filtered = filtered.filter(b => Object.values(b).some(v => String(v ?? '').toLowerCase().includes(q)) ); } // ===== Sort newest first by date ===== filtered.sort((a, b) => (b.date || '').localeCompare(a.date || '')); // Selection label for header const selLabel = sel.kind === 'all' ? 'All Bookings' : sel.kind === 'year' ? sel.value : sel.kind === 'month' ? new Date(sel.value + '-01T00:00:00').toLocaleDateString('en-GB', {month: 'long', year: 'numeric'}) : sel.kind === 'day' ? fmtAllDate(sel.value) : 'All Bookings'; const toggleYear = (y) => setOpenYears({ ...openYears, [y]: !openYears[y] }); const toggleMonth = (mo) => setOpenMonths({ ...openMonths, [mo]: !openMonths[mo] }); return (