The selected Space used to live in sessionStorage and ride along invisibly with every collection route. It now lives in the URL: collection pages exist both globally and beneath /spaces/:spaceUid, and the Space context derives its scope from the current location. - Add a Space route branch (Home, Explore, Calendar, Attachments) guarded by a SpaceRoute that shows loading, unavailable, and retry states. - Resolve collection routes through one matchPath-based helper built from the route constants; build Space-scoped paths with buildCollectionPath. - Fetch the route Space directly, seeded from the switcher list so pages are not held behind a second round-trip. - Turn the Space switcher into plain links that preserve the current collection view and query. - Drop the remembered-Space machinery: clearSelectedSpace/selectMemos, the compose-placement policy, routeSupportsCollectionScope, and the quick-find switchToAll flag are all implied by the URL now. - Return from memo details to the full origin URL, including its Space. - Add space.unavailable and space.back-to-memos strings; align the Azerbaijani catalog with English.
42 lines
1.7 KiB
TypeScript
42 lines
1.7 KiB
TypeScript
import { Code } from "@connectrpc/connect";
|
|
import { LoaderCircleIcon } from "lucide-react";
|
|
import { Link, Outlet } from "react-router-dom";
|
|
import { Button, buttonVariants } from "@/components/ui/button";
|
|
import { useSpaceContext } from "@/contexts/SpaceContext";
|
|
import { hasConnectCode } from "@/lib/error";
|
|
import NotFound from "@/pages/NotFound";
|
|
import { useTranslate } from "@/utils/i18n";
|
|
import { ROUTES } from "./routes";
|
|
|
|
/** Keeps inaccessible or unresolved Space content out of the page and composer. */
|
|
export const SpaceRoute = () => {
|
|
const t = useTranslate();
|
|
const { selectedSpaceName, isSpaceReady, spaceError, retrySpace } = useSpaceContext();
|
|
if (!selectedSpaceName) return <NotFound />;
|
|
if (isSpaceReady) return <Outlet />;
|
|
const unavailable = hasConnectCode(spaceError, Code.NotFound, Code.PermissionDenied);
|
|
return (
|
|
<section className="flex min-h-[50vh] w-full flex-col items-center justify-center gap-4 px-4 text-center" role="status">
|
|
{!spaceError ? (
|
|
<>
|
|
<LoaderCircleIcon className="size-5 animate-spin text-muted-foreground" />
|
|
<p>{t("space.loading")}</p>
|
|
</>
|
|
) : (
|
|
<>
|
|
<p className="text-sm text-muted-foreground">{t(unavailable ? "space.unavailable" : "space.load-error")}</p>
|
|
<div className="flex items-center gap-2">
|
|
{!unavailable && (
|
|
<Button variant="outline" onClick={retrySpace}>
|
|
{t("search.retry")}
|
|
</Button>
|
|
)}
|
|
<Link className={buttonVariants({ variant: "outline" })} to={ROUTES.HOME}>
|
|
{t("space.back-to-memos")}
|
|
</Link>
|
|
</div>
|
|
</>
|
|
)}
|
|
</section>
|
|
);
|
|
};
|