PHP Rebuild
CI / ci (push) Canceled after 0s

Initial PHP rebuild of the app
This commit is contained in:
Stefan Lazic committed 2026-09-05 08:21:33 +01:00
1 parent 8a2b211069
commit 2ef3654841
690 files changed
+33944 -12046

No files matched your search

-50
View File
@@ -1,50 +0,0 @@
import type { BottomNavItem } from "@/components/navigation/bottom-nav";
/**
* Single source of truth for the merged staff/owner/super-admin bottom nav
* and desktop sidebar (see docs/implementation-plan.md and the Phase 11
* "merged navigation" brief). Owner is a permission on a staff account, not
* a separate app — Owner and SuperAdmin nav reuse the exact same personal
* routes (`/staff/current`, `/staff/clients`, `/staff/settings`) a barber
* uses, rather than duplicating them under `/owner`. This is what lets
* owners reach barber tools and business tools from one menu with zero new
* routes.
*
* A Super Administrator has no StaffProfile by construction (see
* isSuperAdmin/getActingBusinessContext) — they get no "Now" tab, since
* there is no personal schedule to show, per the brief's explicit "do not
* fabricate a personal barber schedule for the Super Administrator".
*/
export type NavRole = "staff" | "owner" | "superadmin";
const CALENDAR: BottomNavItem = { href: "/staff", label: "Calendar", icon: "calendar-days" };
const OWNER_CALENDAR: BottomNavItem = { href: "/owner/calendar", label: "Calendar", icon: "calendar-days" };
const NOW: BottomNavItem = { href: "/staff/current", label: "Now", icon: "scissors" };
const CLIENTS: BottomNavItem = { href: "/staff/clients", label: "Clients", icon: "users" };
const MANAGE: BottomNavItem = { href: "/owner", label: "Manage", icon: "briefcase" };
const SETTINGS: BottomNavItem = { href: "/staff/settings", label: "Settings", icon: "settings" };
const NAV_ITEMS_BY_ROLE: Record<NavRole, BottomNavItem[]> = {
staff: [CALENDAR, NOW, CLIENTS, SETTINGS],
owner: [OWNER_CALENDAR, NOW, CLIENTS, MANAGE, SETTINGS],
superadmin: [OWNER_CALENDAR, CLIENTS, MANAGE, SETTINGS],
};
export function getNavItems(role: NavRole): BottomNavItem[] {
return NAV_ITEMS_BY_ROLE[role];
}
/**
* Longest-matching-href wins, rather than "every item whose href is a
* pathname prefix" (the previous per-component logic) — that scheme let
* `/staff/current` mark both "Calendar" (href `/staff`) and "Now" active at
* once, since `/staff/current` also starts with `/staff`. Sorting by href
* length and taking the first match makes only the most specific item win,
* which is what makes nested routes (e.g. `/owner/settings/loyalty`,
* `/staff/clients/[id]`) activate exactly one, correct primary tab.
*/
export function resolveActiveHref(pathname: string, items: BottomNavItem[]): string | null {
const matches = items.filter((item) => pathname === item.href || pathname.startsWith(`${item.href}/`));
if (matches.length === 0) return null;
return matches.reduce((longest, item) => (item.href.length > longest.href.length ? item : longest)).href;
}