mega-plant/lib/clock-access.ts
David 1ec52961ee Cash float card, Office role + Slips tab, job card PDF, manual close/delete
- Cash Floats: ledger card (opening balance, top-ups, slips), manual entries, slip photos
- Office access level; clock app Slips tab (photograph a slip, popup for supplier/cost
  code/comments/amount); only Office sees it; per-role route table in lib/clock-access
- Job cards: Machine Service PDF (with Oil block), JC numbers, manual Close job, Delete
- Hide Expenses > Vehicle Costs and Finance (Bastion) from the menu

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 15:09:57 +02:00

42 lines
2.4 KiB
TypeScript

import type { UserAccess } from "./auth-policy";
/**
* What each access level may reach inside the Plant Clock app (/clock and /api/clock).
*
* full everything in the main app, and Employees / Fuel / Job cards in the clock app (not Slips)
* clock clock-in user: Employees, Fuel, Job cards
* mechanic Fuel and Job cards only — no clock in/out
* office Slips only (photo of a cash-card slip) — and ONLY office sees Slips
*
* Pure and dependency-free so the proxy, the bottom nav and the tests share one rule.
*/
export type ClockTab = { href: string; label: string };
export const CLOCK_TABS: Record<UserAccess, ClockTab[]> = {
full: [{ href: "/clock", label: "Employees" }, { href: "/clock/stock", label: "Fuel" }, { href: "/clock/job-cards", label: "Job cards" }],
clock: [{ href: "/clock", label: "Employees" }, { href: "/clock/stock", label: "Fuel" }, { href: "/clock/job-cards", label: "Job cards" }],
mechanic: [{ href: "/clock/stock", label: "Fuel" }, { href: "/clock/job-cards", label: "Job cards" }],
office: [{ href: "/clock/slips", label: "Slips" }],
};
/** Where a user lands when they open the clock app. */
export const clockHome = (access: UserAccess): string => (access === "mechanic" ? "/clock/job-cards" : access === "office" ? "/clock/slips" : "/clock");
const under = (path: string, base: string) => path === base || path.startsWith(`${base}/`);
// Pages and APIs a restricted role may use, besides the sign-in / password screens.
const ALLOWED: Partial<Record<UserAccess, string[]>> = {
mechanic: ["/clock/stock", "/clock/job-cards", "/api/clock/stock-out", "/api/clock/oil-out", "/api/clock/job-start", "/api/clock/job-finish"],
office: ["/clock/slips", "/api/clock/slip", "/api/clock/cash-float"],
};
// The slip scanner belongs to the Office role alone. (The cash-float opening-balance call is also
// open to full users, because the main Cash Floats page makes it.)
const SLIPS = ["/clock/slips", "/api/clock/slip"];
const ALWAYS = ["/clock/login", "/clock/change-password"];
export function clockPathAllowed(access: UserAccess, path: string): boolean {
if (ALWAYS.some((p) => under(path, p))) return true;
if (access === "full") return !SLIPS.some((p) => under(path, p));
if (access === "clock") return ![...SLIPS, "/api/clock/cash-float"].some((p) => under(path, p));
return (ALLOWED[access] ?? []).some((p) => under(path, p));
}