|
@@ -7,6 +7,12 @@ import { useAuth } from "@/components/auth/authContext";
|
|
|
import { getBranches } from "@/lib/frontend/apiClient";
|
|
import { getBranches } from "@/lib/frontend/apiClient";
|
|
|
import { branchPath, searchPath } from "@/lib/frontend/routes";
|
|
import { branchPath, searchPath } from "@/lib/frontend/routes";
|
|
|
import { isValidBranchParam } from "@/lib/frontend/params";
|
|
import { isValidBranchParam } from "@/lib/frontend/params";
|
|
|
|
|
+import {
|
|
|
|
|
+ buildNextUrlForBranchSwitch,
|
|
|
|
|
+ readRouteBranchFromPathname,
|
|
|
|
|
+ safeReadLocalStorageBranch,
|
|
|
|
|
+ safeWriteLocalStorageBranch,
|
|
|
|
|
+} from "@/lib/frontend/quickNav/branchSwitch";
|
|
|
|
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import { Button } from "@/components/ui/button";
|
|
|
import {
|
|
import {
|
|
@@ -28,34 +34,6 @@ const BRANCH_LIST_STATE = Object.freeze({
|
|
|
ERROR: "error",
|
|
ERROR: "error",
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-function readRouteBranchFromPathname(pathname) {
|
|
|
|
|
- if (typeof pathname !== "string" || !pathname.startsWith("/")) return null;
|
|
|
|
|
-
|
|
|
|
|
- const seg = pathname.split("/").filter(Boolean)[0] || null;
|
|
|
|
|
- return seg && isValidBranchParam(seg) ? seg : null;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function safeReadLocalStorageBranch() {
|
|
|
|
|
- if (typeof window === "undefined") return null;
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- const raw = window.localStorage.getItem(STORAGE_KEY_LAST_BRANCH);
|
|
|
|
|
- return raw && isValidBranchParam(raw) ? raw : null;
|
|
|
|
|
- } catch {
|
|
|
|
|
- return null;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function safeWriteLocalStorageBranch(branch) {
|
|
|
|
|
- if (typeof window === "undefined") return;
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- window.localStorage.setItem(STORAGE_KEY_LAST_BRANCH, String(branch));
|
|
|
|
|
- } catch {
|
|
|
|
|
- // ignore
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
export default function QuickNav() {
|
|
export default function QuickNav() {
|
|
|
const { status, user } = useAuth();
|
|
const { status, user } = useAuth();
|
|
|
|
|
|
|
@@ -71,9 +49,6 @@ export default function QuickNav() {
|
|
|
branches: null,
|
|
branches: null,
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- // Determine a good default branch:
|
|
|
|
|
- // - branch users: always their own
|
|
|
|
|
- // - admin/dev: prefer current route branch, else last stored branch, else first fetched branch
|
|
|
|
|
React.useEffect(() => {
|
|
React.useEffect(() => {
|
|
|
if (!isAuthenticated) return;
|
|
if (!isAuthenticated) return;
|
|
|
|
|
|
|
@@ -83,15 +58,13 @@ export default function QuickNav() {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // admin/dev
|
|
|
|
|
const fromRoute = readRouteBranchFromPathname(window.location.pathname);
|
|
const fromRoute = readRouteBranchFromPathname(window.location.pathname);
|
|
|
- const fromStorage = safeReadLocalStorageBranch();
|
|
|
|
|
|
|
+ const fromStorage = safeReadLocalStorageBranch(STORAGE_KEY_LAST_BRANCH);
|
|
|
|
|
|
|
|
const initial = fromRoute || fromStorage || null;
|
|
const initial = fromRoute || fromStorage || null;
|
|
|
if (initial) setSelectedBranch(initial);
|
|
if (initial) setSelectedBranch(initial);
|
|
|
}, [isAuthenticated, isBranchUser, user?.branchId]);
|
|
}, [isAuthenticated, isBranchUser, user?.branchId]);
|
|
|
|
|
|
|
|
- // Fetch branches for admin/dev dropdown (fail-open; used only for convenience).
|
|
|
|
|
React.useEffect(() => {
|
|
React.useEffect(() => {
|
|
|
if (!isAdminDev) return;
|
|
if (!isAdminDev) return;
|
|
|
|
|
|
|
@@ -107,10 +80,9 @@ export default function QuickNav() {
|
|
|
const branches = Array.isArray(res?.branches) ? res.branches : [];
|
|
const branches = Array.isArray(res?.branches) ? res.branches : [];
|
|
|
setBranchList({ status: BRANCH_LIST_STATE.READY, branches });
|
|
setBranchList({ status: BRANCH_LIST_STATE.READY, branches });
|
|
|
|
|
|
|
|
- // If nothing selected yet, pick the first available branch as a convenience default.
|
|
|
|
|
if (!selectedBranch && branches.length > 0) {
|
|
if (!selectedBranch && branches.length > 0) {
|
|
|
setSelectedBranch(branches[0]);
|
|
setSelectedBranch(branches[0]);
|
|
|
- safeWriteLocalStorageBranch(branches[0]);
|
|
|
|
|
|
|
+ safeWriteLocalStorageBranch(STORAGE_KEY_LAST_BRANCH, branches[0]);
|
|
|
}
|
|
}
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
if (cancelled) return;
|
|
if (cancelled) return;
|
|
@@ -126,11 +98,10 @@ export default function QuickNav() {
|
|
|
}, [isAdminDev, selectedBranch]);
|
|
}, [isAdminDev, selectedBranch]);
|
|
|
|
|
|
|
|
React.useEffect(() => {
|
|
React.useEffect(() => {
|
|
|
- // Persist selection for admin/dev convenience.
|
|
|
|
|
if (!isAdminDev) return;
|
|
if (!isAdminDev) return;
|
|
|
if (!selectedBranch) return;
|
|
if (!selectedBranch) return;
|
|
|
|
|
|
|
|
- safeWriteLocalStorageBranch(selectedBranch);
|
|
|
|
|
|
|
+ safeWriteLocalStorageBranch(STORAGE_KEY_LAST_BRANCH, selectedBranch);
|
|
|
}, [isAdminDev, selectedBranch]);
|
|
}, [isAdminDev, selectedBranch]);
|
|
|
|
|
|
|
|
if (!isAuthenticated) return null;
|
|
if (!isAuthenticated) return null;
|
|
@@ -140,7 +111,21 @@ export default function QuickNav() {
|
|
|
effectiveBranch && isValidBranchParam(effectiveBranch)
|
|
effectiveBranch && isValidBranchParam(effectiveBranch)
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- // Keep TopNav clean on small screens.
|
|
|
|
|
|
|
+ function navigateToBranchKeepingContext(nextBranch) {
|
|
|
|
|
+ if (typeof window === "undefined") return;
|
|
|
|
|
+ if (!isValidBranchParam(nextBranch)) return;
|
|
|
|
|
+
|
|
|
|
|
+ const nextUrl = buildNextUrlForBranchSwitch({
|
|
|
|
|
+ pathname: window.location.pathname || "/",
|
|
|
|
|
+ search: window.location.search || "",
|
|
|
|
|
+ nextBranch,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (!nextUrl) return;
|
|
|
|
|
+
|
|
|
|
|
+ window.location.assign(nextUrl);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
<div className="hidden items-center gap-2 md:flex">
|
|
<div className="hidden items-center gap-2 md:flex">
|
|
|
{isAdminDev ? (
|
|
{isAdminDev ? (
|
|
@@ -169,7 +154,12 @@ export default function QuickNav() {
|
|
|
value={canNavigate ? effectiveBranch : ""}
|
|
value={canNavigate ? effectiveBranch : ""}
|
|
|
onValueChange={(value) => {
|
|
onValueChange={(value) => {
|
|
|
if (!value) return;
|
|
if (!value) return;
|
|
|
|
|
+ if (!isValidBranchParam(value)) return;
|
|
|
|
|
+
|
|
|
setSelectedBranch(value);
|
|
setSelectedBranch(value);
|
|
|
|
|
+ safeWriteLocalStorageBranch(STORAGE_KEY_LAST_BRANCH, value);
|
|
|
|
|
+
|
|
|
|
|
+ navigateToBranchKeepingContext(value);
|
|
|
}}
|
|
}}
|
|
|
>
|
|
>
|
|
|
{(Array.isArray(branchList.branches)
|
|
{(Array.isArray(branchList.branches)
|