branch crud and intergration
This commit is contained in:
@@ -9,10 +9,53 @@ import { createContext, useContext, useEffect, useState } from "react"
|
||||
import { authApi } from "@/lib/api/auth"
|
||||
import { MeResponse } from "@/types/rbac"
|
||||
|
||||
interface ActiveBranch {
|
||||
id: number | null
|
||||
name: string | null
|
||||
}
|
||||
|
||||
/** Admin's last-picked header branch, kept per-browser (docs/BRANCH_ISOLATION_PLAN.md
|
||||
* §Frontend impact: "a current branch selector... persisted per session"). Purely a
|
||||
* display/filter convenience — never trusted server-side. */
|
||||
const ACTIVE_BRANCH_KEY = "erpcore.activeBranch"
|
||||
|
||||
function readStoredActiveBranch(): ActiveBranch | null {
|
||||
if (typeof window === "undefined") return null
|
||||
const raw = window.localStorage.getItem(ACTIVE_BRANCH_KEY)
|
||||
if (!raw) return null
|
||||
try {
|
||||
return JSON.parse(raw) as ActiveBranch
|
||||
} catch {
|
||||
window.localStorage.removeItem(ACTIVE_BRANCH_KEY)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
interface AuthContextValue {
|
||||
roleCode: string | null
|
||||
roleName: string | null
|
||||
navCodes: string[]
|
||||
/** True for the Admin role — the only role that may pick any branch (others are locked to their own). */
|
||||
isAdmin: boolean
|
||||
/** The caller's own branch, via their linked Employee record — null if unlinked. */
|
||||
branchId: number | null
|
||||
branchName: string | null
|
||||
/**
|
||||
* The branch currently being "worked in": for non-admins this always mirrors their own
|
||||
* branch; for an Admin it's whichever branch they last picked in the header (null = "All
|
||||
* Branches"), persisted per-browser. Screens that want to filter by "the branch the user
|
||||
* is currently viewing" should read this, not `branchId`.
|
||||
*/
|
||||
activeBranchId: number | null
|
||||
activeBranchName: string | null
|
||||
/** Admin-only — switches the header's active branch. A no-op for any other role. */
|
||||
setActiveBranch: (id: number | null, name: string | null) => void
|
||||
/**
|
||||
* The deployment-wide toggle (Settings → Configuration → Branch Configuration). False
|
||||
* means this deployment doesn't use branches at all — every branch picker/badge in the
|
||||
* app should be hidden entirely, not merely restricted by role.
|
||||
*/
|
||||
branchingEnabled: boolean
|
||||
/** True until the first `/auth/me` response lands. */
|
||||
loading: boolean
|
||||
}
|
||||
@@ -21,11 +64,19 @@ const AuthContext = createContext<AuthContextValue>({
|
||||
roleCode: null,
|
||||
roleName: null,
|
||||
navCodes: [],
|
||||
isAdmin: false,
|
||||
branchId: null,
|
||||
branchName: null,
|
||||
activeBranchId: null,
|
||||
activeBranchName: null,
|
||||
setActiveBranch: () => {},
|
||||
branchingEnabled: true,
|
||||
loading: true,
|
||||
})
|
||||
|
||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
const [me, setMe] = useState<MeResponse | null>(null)
|
||||
const [activeBranch, setActiveBranchState] = useState<ActiveBranch | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
@@ -37,19 +88,39 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
.catch(() => {
|
||||
// Unauthenticated/unreachable — fall back to "no permissions" rather than
|
||||
// crash the shell; proxy.ts already redirects unauthenticated users to /login.
|
||||
if (!cancelled) setMe({ roleCode: null, roleName: null, navCodes: [] })
|
||||
if (!cancelled) setMe({ roleCode: null, roleName: null, navCodes: [], isAdmin: false, branchId: null, branchName: null, branchingEnabled: true })
|
||||
})
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (me === null) return
|
||||
// Non-admins are always pinned to their own branch — never their own past picks.
|
||||
setActiveBranchState(me.isAdmin ? (readStoredActiveBranch() ?? { id: null, name: null }) : { id: me.branchId, name: me.branchName })
|
||||
}, [me])
|
||||
|
||||
function setActiveBranch(id: number | null, name: string | null) {
|
||||
if (!me?.isAdmin) return
|
||||
const next = { id, name }
|
||||
setActiveBranchState(next)
|
||||
if (typeof window !== "undefined") window.localStorage.setItem(ACTIVE_BRANCH_KEY, JSON.stringify(next))
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthContext.Provider
|
||||
value={{
|
||||
roleCode: me?.roleCode ?? null,
|
||||
roleName: me?.roleName ?? null,
|
||||
navCodes: me?.navCodes ?? [],
|
||||
isAdmin: me?.isAdmin ?? false,
|
||||
branchId: me?.branchId ?? null,
|
||||
branchName: me?.branchName ?? null,
|
||||
activeBranchId: activeBranch?.id ?? null,
|
||||
activeBranchName: activeBranch?.name ?? null,
|
||||
setActiveBranch,
|
||||
branchingEnabled: me?.branchingEnabled ?? true,
|
||||
loading: me === null,
|
||||
}}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user