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): """