diff --git a/app/page.tsx b/app/page.tsx index b3c556c..e864aee 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -780,7 +780,7 @@ const loadItems = useCallback(async (showLoading = true) => { {searchQuery ? 'No collections match your search.' : statusFilter === 'assigned' - ? 'No assigned collections right now. New pickups will appear here.' + ? 'No pickups for today or yesterday. New ones appear here as the operator schedules them.' : statusFilter === 'collection_pool' ? 'Collection pool is empty — nothing to claim right now.' : 'No problems reported. Nice work.'} diff --git a/lib/pocketbase.ts b/lib/pocketbase.ts index 242fb01..754ef33 100644 --- a/lib/pocketbase.ts +++ b/lib/pocketbase.ts @@ -112,24 +112,61 @@ const hydrateSuppliers = async (items: OrderItem[]): Promise => { // Referencing either in a filter hard-400s the whole query, so any // OR-fallback against them would *break* the Assigned tab rather // than rescue it. -// - item_status = "assigned" is the live, working status. Currently -// 3 rows; the others have moved on in the workflow (e.g. invoiced). +// - item_status = "assigned" is the live, working status. +// - `assigned_at` is set by the operator app to the SCHEDULED pickup +// date (not the moment of assignment). Items assigned "today for +// tomorrow" carry assigned_at = tomorrow's date — the driver app +// surfaces them tomorrow, not today. Live probe shows current +// assigned rows split evenly across Aug 18/19/20 as expected. // -// If the operator app needs items to land here, it must write -// `drv_id = user.id` and `item_status = "assigned"` on the row. +// Assigned-day window: +// The driver app shows items whose `assigned_at` falls within a +// rolling 2-day window: yesterday + today (driver-local time). This +// covers: +// - items scheduled for today (the day's work), and +// - items scheduled for yesterday (carryover that wasn't completed +// — still actionable today). +// Items scheduled for tomorrow or later stay hidden until their day +// arrives, so the driver isn't tempted to "get ahead" of the schedule +// and pickup a PO whose supplier hasn't been told it'll be picked up. +// +// Timezone: the window boundaries are computed in the driver's local +// timezone (this is a browser app, so `new Date()` is local) and then +// converted to UTC ISO strings for the PB filter. This works as long +// as the driver and operator share a timezone — if they diverge, the +// window rolls over at midnight in the driver's locale, not the +// operator's. Acceptable for the current single-region deployment. +const getAssignedDayWindow = (): { fromIso: string; toIso: string } => { + const now = new Date(); + // Today at 00:00 in the driver's local timezone. + const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + // Last millisecond of today (23:59:59.999) — inclusive upper bound. + const todayEnd = new Date(todayStart.getTime() + 24 * 60 * 60 * 1000 - 1); + // Yesterday at 00:00 — inclusive lower bound. + const yesterdayStart = new Date(todayStart.getTime() - 24 * 60 * 60 * 1000); + return { + fromIso: yesterdayStart.toISOString(), + toIso: todayEnd.toISOString(), + }; +}; + export const getMyAssignedItems = async (): Promise => { const user = getCurrentUser(); if (!user) return []; + const { fromIso, toIso } = getAssignedDayWindow(); + const filter = + `drv_id = "${user.id}" && item_status = "assigned" && ` + + `assigned_at >= "${fromIso}" && assigned_at <= "${toIso}"`; try { const items = await pb.collection('order_items').getFullList({ - filter: `drv_id = "${user.id}" && item_status = "assigned"`, + filter, expand: 'supplier,order,purchase_order', sort: 'supplier.suppliername', }); return items; } catch { const items = await pb.collection('order_items').getFullList({ - filter: `drv_id = "${user.id}" && item_status = "assigned"`, + filter, }); return hydrateSuppliers(items); } diff --git a/scripts/check-pb-schema.mjs b/scripts/check-pb-schema.mjs index 212be5c..07422f6 100644 --- a/scripts/check-pb-schema.mjs +++ b/scripts/check-pb-schema.mjs @@ -32,7 +32,11 @@ const PASSWORD = process.env.PB_USER_PASSWORD || '1234567890'; // PB validates identifier names at the parser level and 400s the moment // it hits one it doesn't know, regardless of the value. const FILTERS = [ - { collection: 'order_items', filter: 'drv_id = "placeholder" && item_status = "assigned"' }, + // Assigned-tab filter with the yesterday+today window. The ISO + // timestamps here are placeholders — PB only validates field names + // and operators at parse time, so any well-formed ISO string works. + // Keep in sync with getAssignedDayWindow in lib/pocketbase.ts. + { collection: 'order_items', filter: 'drv_id = "placeholder" && item_status = "assigned" && assigned_at >= "2026-01-01T00:00:00.000Z" && assigned_at <= "2026-12-31T23:59:59.999Z"' }, { collection: 'order_items', filter: 'item_status = "collection_pool"' }, { collection: 'order_items', filter: 'problem_flag = true || item_status = "problem"' }, // Stock pickups live in their own collection — see