- Workforce: Employees register, per-employee dashboards, Attendance table - Plant Clock: scan-only clock, bottom tab bar (Employees / Oil & Diesel / Job cards) - Oil & Diesel stock: diesel tank (650 L, opening 589 L), level overwrite dialog, QR on each card, book-out screen with searchable vehicle picker, filterable "Booked out" table (today/week/month/all/range) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
47 lines
2 KiB
TypeScript
47 lines
2 KiB
TypeScript
/** Date filtering for the oil/diesel "Booked out" table. Days are South African calendar days. */
|
|
export type LogPreset = "today" | "week" | "month" | "all" | "range";
|
|
|
|
const dayFmt = new Intl.DateTimeFormat("en-CA", { timeZone: "Africa/Johannesburg" });
|
|
|
|
/** "2026-10-22" for an instant, in SA time. PocketBase stamps look like "2026-10-22 08:15:00.000Z". */
|
|
export function saDay(stamp: string): string {
|
|
if (!stamp || Number.isNaN(new Date(stamp.replace(" ", "T")).getTime())) return "";
|
|
return dayFmt.format(new Date(stamp.replace(" ", "T")));
|
|
}
|
|
|
|
function addDays(day: string, n: number): string {
|
|
const d = new Date(`${day}T00:00:00Z`);
|
|
d.setUTCDate(d.getUTCDate() + n);
|
|
return d.toISOString().slice(0, 10);
|
|
}
|
|
|
|
/** Inclusive [from, to] day bounds for a preset; null bound = open. Weeks start Monday. */
|
|
export function presetBounds(preset: LogPreset, today: string, from = "", to = ""): [string | null, string | null] {
|
|
switch (preset) {
|
|
case "today": return [today, today];
|
|
case "week": {
|
|
const dow = (new Date(`${today}T00:00:00Z`).getUTCDay() + 6) % 7; // Mon=0
|
|
return [addDays(today, -dow), today];
|
|
}
|
|
case "month": return [`${today.slice(0, 7)}-01`, today];
|
|
case "range": return [from || null, to || null];
|
|
default: return [null, null];
|
|
}
|
|
}
|
|
|
|
export function inBounds(day: string, [from, to]: [string | null, string | null]): boolean {
|
|
if (!day) return !from && !to; // undated rows only show when no period is applied
|
|
return (!from || day >= from) && (!to || day <= to);
|
|
}
|
|
|
|
/**
|
|
* When a movement happened. `created` is NOT reliable on oil_stock_movements (the collection
|
|
* was made through the API, so the field never auto-fills), so book-outs store a full ISO
|
|
* instant in `occurred_on`. Older rows hold a bare date. Returns "" when neither is usable.
|
|
*/
|
|
export function movementAt(m: { [k: string]: any }): string {
|
|
for (const v of [m.occurred_on, m.created] as (string | undefined)[]) {
|
|
if (v && !Number.isNaN(new Date(v.replace(" ", "T")).getTime())) return v;
|
|
}
|
|
return "";
|
|
}
|