diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 3b24897..9af05cd 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,11 +1,12 @@
import { useState } from "react";
import Panel from "./components/Panel";
-import { useQuery } from "@tanstack/react-query";
+import { useQueries } from "@tanstack/react-query";
import "./App.css";
import ArticleSelector from "./components/ArticleSelector";
import CelexSelector from "./components/CelexSelector";
-import { getArticleIds } from "./lib/api";
+import TOC from "./components/TOC";
+import { getArticleIds, getToc } from "./lib/api";
import { Language } from "./lib/types";
function App() {
@@ -16,21 +17,28 @@ function App() {
null
);
- const {
- data: articleIds,
- isPending,
- error,
- } = useQuery({
- queryKey: ["articleIds", celexId],
- queryFn: () => getArticleIds(celexId),
- enabled: !!celexId,
+ const results = useQueries({
+ queries: [
+ {
+ queryKey: ["articleIds", celexId],
+ queryFn: () => getArticleIds(celexId),
+ enabled: !!celexId,
+ },
+ {
+ queryKey: ["toc", celexId],
+ queryFn: () => getToc(celexId, Language.ENG),
+ enabled: !!celexId,
+ },
+ ],
});
+ const isPending = results.some((result) => result.isPending);
+ const error = results.find((result) => result.isError);
if (isPending) {
return
Loading...
;
}
if (error) {
- return Error: {error.message}
;
+ return Error: {error.error?.message}
;
}
const examples = [
@@ -62,7 +70,7 @@ function App() {
@@ -71,6 +79,11 @@ function App() {
+
{Array.from({ length: numPanels }, (_, index) => (
void;
+};
+
+function TOC({ toc, selectedArticleId, onArticleSelected }: TOCProps) {
+ const [isVisible, setIsVisible] = useState(true);
+
+ return (
+
+ );
+}
+export default TOC;
diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts
index b8c4885..a5b839f 100644
--- a/frontend/src/lib/api.ts
+++ b/frontend/src/lib/api.ts
@@ -1,3 +1,6 @@
+import TOC from "../components/TOC";
+import { Language } from "./types";
+
const API_URL = import.meta.env.VITE_API_URL;
async function getArticle(
@@ -20,4 +23,10 @@ async function getArticleIds(celexId: string): Promise {
return await response.json();
}
-export { getArticle, getArticleIds };
+async function getToc(celexId: string, language: Language): Promise {
+ console.debug(`Fetching TOC for CELEX ID ${celexId}`);
+ const response = await fetch(`${API_URL}/${celexId}/toc/${language}`);
+ return await response.json();
+}
+
+export { getArticle, getArticleIds, getToc };
diff --git a/src/formex_viewer/server.py b/src/formex_viewer/server.py
index eb1a2f5..8b45c0f 100644
--- a/src/formex_viewer/server.py
+++ b/src/formex_viewer/server.py
@@ -63,6 +63,49 @@ def article_ids(celex_id: str, language: Language = Language.ENG):
return article_ids
+@app.get("/{celex_id}/toc/{language}")
+def toc(celex_id: str, language: Language = Language.ENG):
+ """
+ Fetch the table of contents from the server.
+ """
+ fmx4_data = _get_fmx4_data(celex_id, language)
+ xml = ET.fromstring(fmx4_data.encode("utf-8"))
+
+ toc = []
+
+ for division in xml.xpath("//DIVISION"):
+ print(division)
+ title = ti_el[0] if (ti_el := division.xpath("TITLE/TI//text()")) else ""
+ subtitle = sti_el[0] if (sti_el := division.xpath("TITLE/STI//text()")) else ""
+ articles = []
+ for article in division.xpath("ARTICLE") or []:
+ art_id = article.get("IDENTIFIER")
+ if not art_id:
+ continue
+ art_title = ti_el[0] if (ti_el := article.xpath("TI.ART//text()")) else ""
+ art_subtitle = (
+ sti_el[0] if (sti_el := article.xpath("STI.ART//text()")) else ""
+ )
+ articles.append(
+ {
+ "id": int(art_id.lstrip("0")),
+ "type": "article",
+ "title": art_title,
+ "subtitle": art_subtitle,
+ }
+ )
+ toc.append(
+ {
+ "title": title,
+ "type": "division",
+ "subtitle": subtitle,
+ "articles": articles,
+ }
+ )
+
+ return toc
+
+
@app.get("/{celex_id}/articles/{article_id}/{language}")
def article(celex_id: str, article_id: int, language: Language = Language.ENG):
"""