55 lines
2.1 KiB
TypeScript
55 lines
2.1 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { useRouter, useSearchParams } from "next/navigation";
|
|
import { api, errorText } from "@/lib/api";
|
|
import { readDemoBoards } from "@/lib/demo-workspace";
|
|
import type { Board } from "@/lib/workspace";
|
|
import styles from "./workspace.module.css";
|
|
|
|
export default function GraphPage({ workspaceId, boardId }: { workspaceId: string; boardId: string }) {
|
|
const demo = useSearchParams().get("demo") === "1";
|
|
const router = useRouter();
|
|
const [board, setBoard] = useState<Board | null>(null);
|
|
const [error, setError] = useState("");
|
|
|
|
useEffect(() => {
|
|
setBoard(null);
|
|
setError("");
|
|
if (demo) {
|
|
try {
|
|
const list = readDemoBoards(workspaceId);
|
|
const item = list.find((b) => b.id === boardId);
|
|
if (item) setBoard(item);
|
|
else setError("图谱不存在。");
|
|
} catch { setError("无法读取本地演示图谱。"); }
|
|
return;
|
|
}
|
|
let active = true;
|
|
const controller = new AbortController();
|
|
api<Board>(`workspaces/${encodeURIComponent(workspaceId)}/materials/${encodeURIComponent(boardId)}`, { signal: controller.signal })
|
|
.then((item) => {
|
|
if (!active) return;
|
|
if (item.kind !== "board" || item.workspace_id !== workspaceId) {
|
|
setError("当前页面不是此工作空间的图谱。");
|
|
return;
|
|
}
|
|
setBoard(item);
|
|
})
|
|
.catch((e) => {
|
|
if (!active) return;
|
|
setError(errorText(e));
|
|
if (e.message === "invalid_session") router.replace("/login");
|
|
});
|
|
return () => { active = false; controller.abort(); };
|
|
}, [workspaceId, boardId, demo, router]);
|
|
|
|
return (
|
|
<main className={styles.graph} aria-label={board ? board.title + " · 无限图谱" : "无限图谱"} aria-busy={!board && !error}>
|
|
<div className={styles.graphSurface} aria-label={board ? board.title + "的画布" : "画布"} />
|
|
{error ? <p className={styles.graphStatus} role="alert">{error}</p>
|
|
: !board && <p className={styles.graphStatus} role="status">正在打开图谱…</p>}
|
|
</main>
|
|
);
|
|
}
|