103 lines
3.3 KiB
TypeScript
103 lines
3.3 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
|
|
import { AuthView } from "../components/AuthView";
|
|
import { AppShell } from "../components/AppShell";
|
|
import { EmptyState, LoadingState } from "../components/StateViews";
|
|
import type { PageId, PageParams } from "../contracts/page";
|
|
import { pageRegistry } from "../pages/pageRegistry";
|
|
import { canAccessRoute, defaultPageForUser, hashForPage, navigationRoutesForUser } from "../routes/routes";
|
|
import { initialNavigationState, type NavigationState } from "../stores/navigation";
|
|
import { useOperationTracker } from "../stores/operations";
|
|
import { useSession } from "../stores/session";
|
|
|
|
export function App() {
|
|
const session = useSession();
|
|
const user = session.user;
|
|
const [navigation, setNavigation] = useState<NavigationState | undefined>();
|
|
const operations = useOperationTracker();
|
|
|
|
useEffect(() => {
|
|
if (session.loaded && user) {
|
|
const nextNavigation = initialNavigationState(user);
|
|
setNavigation(nextNavigation);
|
|
if (typeof window !== "undefined") {
|
|
const nextHash = hashForPage(nextNavigation.pageId, nextNavigation.params);
|
|
if (window.location.hash !== nextHash) {
|
|
window.history.replaceState(null, "", nextHash);
|
|
}
|
|
}
|
|
}
|
|
}, [session.loaded, user]);
|
|
|
|
useEffect(() => {
|
|
function syncPageFromHash() {
|
|
if (user) {
|
|
setNavigation(initialNavigationState(user));
|
|
}
|
|
}
|
|
|
|
window.addEventListener("hashchange", syncPageFromHash);
|
|
window.addEventListener("popstate", syncPageFromHash);
|
|
return () => {
|
|
window.removeEventListener("hashchange", syncPageFromHash);
|
|
window.removeEventListener("popstate", syncPageFromHash);
|
|
};
|
|
}, [user]);
|
|
|
|
function handleNavigate(pageId: PageId, params: PageParams = {}) {
|
|
if (!user) {
|
|
return;
|
|
}
|
|
const target: NavigationState = canAccessRoute(user, pageId) ? { pageId, params } : { pageId: defaultPageForUser(user), params: {} };
|
|
setNavigation(target);
|
|
if (typeof window !== "undefined") {
|
|
window.history.replaceState(null, "", hashForPage(target.pageId, target.params));
|
|
}
|
|
}
|
|
|
|
if (!session.loaded) {
|
|
return (
|
|
<main className="auth-shell">
|
|
<LoadingState label="正在加载身份状态…" />
|
|
</main>
|
|
);
|
|
}
|
|
|
|
if (!user || !navigation) {
|
|
return <AuthView session={session} />;
|
|
}
|
|
|
|
const navRoutes = navigationRoutesForUser(user);
|
|
const ActivePage = pageRegistry[navigation.pageId];
|
|
const allowed = canAccessRoute(user, navigation.pageId);
|
|
|
|
return (
|
|
<AppShell
|
|
routes={navRoutes}
|
|
currentPage={navigation.pageId}
|
|
session={user}
|
|
operations={operations.operations}
|
|
onNavigate={handleNavigate}
|
|
>
|
|
{allowed ? (
|
|
<ActivePage
|
|
session={user}
|
|
params={navigation.params}
|
|
operations={operations}
|
|
onNavigate={handleNavigate}
|
|
onLogout={session.logout}
|
|
onProfileSave={session.updateProfile}
|
|
onThemePreferenceSave={session.updateThemePreference}
|
|
/>
|
|
) : (
|
|
<EmptyState
|
|
title="没有访问权限"
|
|
description="当前账号无权访问该区域。请返回你的默认工作台,或联系平台管理员调整权限。"
|
|
actionLabel="返回工作台"
|
|
onAction={() => handleNavigate(defaultPageForUser(user))}
|
|
/>
|
|
)}
|
|
</AppShell>
|
|
);
|
|
}
|