feat(shifts): /shift→/shifts, clickable activity log (shared event-detail), booth-style full-height layout
Three changes to the shift hub, addressing the report: 1. Route rename /shift → /shifts (matches the plural "Turnet" label and the section). /shift and /setup/shifts both redirect to /shifts; the header link and the operator-landing fallback point at /shifts. 2. The activity-log rows are now CLICKABLE and open the same read-only event-detail modal the booth live feed uses (full signed payload + entry/exit snapshots + chain provenance) — previously they were static rows. Extracted EVENT_STYLE, the feed row, the detail modal, and their helpers out of BoothScreen into a shared apps/web/src/ui/event-detail.tsx imported by both the booth and the shift log, so the two render and behave identically and can't drift. 3. Reworked the /shifts layout to fill the viewport like /booth: a fixed title + filters, then a two-pane area (shift list | activity log) where each pane scrolls independently (min-h-0/flex-1 + overflow-y-auto) instead of the whole page growing. ShiftActivityLog is now a flex column with a fixed header and a scrollable list. Verified at runtime (Playwright): /shift redirects to /shifts, an activity row opens the detail modal, the layout fills height, and the booth still works (0 console errors after the extraction). build+lint 14/14. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -368,7 +368,7 @@ function RootLayout() {
|
||||
<span className="text-sm font-bold uppercase tracking-widest text-term-amber">▮ Parking</span>
|
||||
<nav className="flex items-center gap-1">
|
||||
<NavLink to="/booth" label={t("nav.booth")} />
|
||||
<NavLink to="/shift" label={t("nav.shifts")} />
|
||||
<NavLink to="/shifts" label={t("nav.shifts")} />
|
||||
{/* Subscriptions — a standalone section (Abonimet / Planet / Lab tarife).
|
||||
Shown if the user can reach ANY of its tabs. */}
|
||||
{(show("subscription:read") || show("subscription:plan") || show("tariff:read")) && (
|
||||
@@ -437,10 +437,11 @@ const legacyRedirects = (
|
||||
["/site", "/setup/site"],
|
||||
["/users", "/setup/users"],
|
||||
["/roles", "/setup/roles"],
|
||||
["/shift", "/shifts"],
|
||||
["/setup/subscriptions", "/subscriptions"],
|
||||
["/setup/plans", "/subscriptions/plans"],
|
||||
["/setup/tariff-lab", "/subscriptions/tariff-lab"],
|
||||
["/setup/shifts", "/shift"],
|
||||
["/setup/shifts", "/shifts"],
|
||||
] as const
|
||||
).map(([from, to]) =>
|
||||
createRoute({
|
||||
@@ -454,7 +455,7 @@ const legacyRedirects = (
|
||||
|
||||
const shiftRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: "/shift",
|
||||
path: "/shifts",
|
||||
component: function ShiftRoute() {
|
||||
const { user } = rootRoute.useRouteContext();
|
||||
// The shift hub: list (current/open shift on top + history) + per-shift activity log.
|
||||
@@ -483,14 +484,14 @@ function requirePerm(perm: Permission) {
|
||||
// The Setup tabs in display order, each with the permission its screen needs. Used
|
||||
// to land a user on the FIRST tab they may see when they open /setup without
|
||||
// `site:update` (e.g. an operator who only has shift:read → goes to the standalone
|
||||
// /shift hub, which is no longer a Setup tab).
|
||||
// /shifts hub, which is no longer a Setup tab).
|
||||
const SETUP_TABS: { to: string; perm: Permission }[] = [
|
||||
{ to: "/setup", perm: "site:update" },
|
||||
{ to: "/setup/tariff", perm: "tariff:read" },
|
||||
{ to: "/setup/site", perm: "site:read" },
|
||||
{ to: "/setup/users", perm: "user:read" },
|
||||
{ to: "/setup/roles", perm: "role:read" },
|
||||
{ to: "/shift", perm: "shift:read" },
|
||||
{ to: "/shifts", perm: "shift:read" },
|
||||
{ to: "/setup/logs", perm: "log:read" },
|
||||
];
|
||||
|
||||
@@ -584,8 +585,8 @@ const rolesRoute = createRoute({
|
||||
return <RolesManager user={user} />;
|
||||
},
|
||||
});
|
||||
// (Shift history lives at the standalone /shift route — see shiftRoute. It was
|
||||
// removed as a Setup tab; /setup/shifts redirects there for old bookmarks.)
|
||||
// (Shift history lives at the standalone /shifts route — see shiftRoute. It was
|
||||
// removed as a Setup tab; /setup/shifts and the old /shift both redirect there.)
|
||||
|
||||
// Diagnostic logs. Gated by log:read (an admin/diagnostic permission).
|
||||
const logsRoute = createRoute({
|
||||
|
||||
Reference in New Issue
Block a user