import { useQueryClient } from "@tanstack/react-query"; import { useCallback, useEffect, useMemo, useRef } from "react"; import { Link, matchPath, useLocation, useNavigate, useRoutes } from "react-router"; import { clearToken } from "../auth/token.ts"; import { CloseAbortContext } from "../issues/closeAbort.ts"; import { IssueModal } from "../issues/IssueModal.tsx"; import { cardState, LIST_BACKGROUND } from "../issues/modal.ts"; import { ErrorBoundary } from "./ErrorBoundary.tsx"; import { PAGE_ROUTES } from "./pages.tsx"; import "./shell.css"; export function Layout() { const qc = useQueryClient(); const location = useLocation(); const navigate = useNavigate(); const issueKey = matchPath("/issues/:key", location.pathname)?.params.key ?? null; const card = issueKey ? cardState(location.state) : null; const bgPath = issueKey ? (card?.background ?? LIST_BACKGROUND).pathname : null; const bgSearch = issueKey ? (card?.background ?? LIST_BACKGROUND).search : ""; // адрес страницы под окном; передаётся в useRoutes всегда (и без окна), чтобы дерево страницы не менялось при // открытии окна и useSearchParams внутри неё видел её собственный адрес (design 10) const bgLocation = useMemo(() => bgPath === null ? null : { pathname: bgPath, search: bgSearch, hash: "", state: null, key: "card-background" }, [bgPath, bgSearch]); const pageLocation = bgLocation ?? location; const page = useRoutes(PAGE_ROUTES, pageLocation); // прямой адрес карточки: запись истории получает state окна поверх списка задач (design 11) useEffect(() => { if (issueKey && !card) { void navigate(location.pathname + location.search, { replace: true, state: { background: LIST_BACKGROUND, depth: 0, direct: true } }); } }, [issueKey, card, location.pathname, location.search, navigate]); // закрытие (design 12): назад на depth записей; запись прямого адреса, на которую вернулись, заменяется списком const closingDirect = useRef(false); useEffect(() => { if (closingDirect.current && card?.direct && card.depth === 0) { closingDirect.current = false; void navigate("/issues", { replace: true }); } }, [card, navigate]); const close = useCallback(() => { if (!card || card.depth === 0) { void navigate("/issues", { replace: true }); return; } closingDirect.current = card.direct; void navigate(-card.depth); }, [card, navigate]); const abortClose = useCallback(() => { closingDirect.current = false; }, []); const at = pageLocation.pathname; const tab = (to: string, label: string) => { const active = at === to || at.startsWith(to + "/"); return {label}; }; return ( <>
Хаб Jira
{page}
{issueKey && } ); }