diff --git a/src/App.tsx b/src/App.tsx index c1bee1d..1f0b475 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,16 +6,13 @@ import StringFilter from "./components/StringFilter/StringFilter"; import useGlossary from "./hooks/useGlossary"; function App() { - const { glossary, citations, isLoading, isError } = useGlossary(); + const { glossary, citations } = useGlossary(); const [alphabeticalFilter, setAlphabeticalFilter] = useState(""); const [stringFilter, setStringFilter] = useState(""); const [selectedCitation, setSelectedCitation] = useState(null); - if (isLoading) return
Loading...
; - if (isError) return
Error while fetching
; - - const entries = glossary! + const entries = glossary .filter((entry) => { if (!stringFilter) { return true; @@ -40,7 +37,7 @@ function App() { {selectedCitation && ( citation.key === selectedCitation)! + citations.find((citation) => citation.key === selectedCitation)! } onClose={() => setSelectedCitation(null)} /> diff --git a/src/components/ErrorBoundary/ErrorBoundary.css b/src/components/ErrorBoundary/ErrorBoundary.css new file mode 100644 index 0000000..5d3bf3a --- /dev/null +++ b/src/components/ErrorBoundary/ErrorBoundary.css @@ -0,0 +1,9 @@ +.error-boundary { + color: red; + font-size: 1.2rem; + text-align: center; + + pre { + color: var(--color-text); + } +} diff --git a/src/components/ErrorBoundary/ErrorBoundary.tsx b/src/components/ErrorBoundary/ErrorBoundary.tsx new file mode 100644 index 0000000..dc58999 --- /dev/null +++ b/src/components/ErrorBoundary/ErrorBoundary.tsx @@ -0,0 +1,43 @@ +import type { ReactNode } from "react"; +import React, { Component } from "react"; + +import "./ErrorBoundary.css"; + +interface ErrorBoundaryProps { + children: ReactNode; +} + +interface ErrorBoundaryState { + hasError: boolean; + error: Error | null; +} + +class ErrorBoundary extends Component { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { hasError: false, error: null }; + } + + static getDerivedStateFromError(error: Error) { + return { hasError: true, error }; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + componentDidCatch(_: Error, __: React.ErrorInfo) { + // You can log the error to an error reporting service here + } + + render() { + if (this.state.hasError) { + return ( +
+

Something went wrong.

+
{this.state.error?.message}
+
+ ); + } + return this.props.children; + } +} + +export default ErrorBoundary; diff --git a/src/hooks/useGlossary.ts b/src/hooks/useGlossary.ts index 54e416b..629ef66 100644 --- a/src/hooks/useGlossary.ts +++ b/src/hooks/useGlossary.ts @@ -1,13 +1,13 @@ -import { useQuery } from "@tanstack/react-query"; +import { useSuspenseQuery } from "@tanstack/react-query"; import { fetchCitations, fetchDefinitions } from "../lib/nist-api"; const useGlossary = () => { - const definitionsQuery = useQuery({ + const definitionsQuery = useSuspenseQuery({ queryKey: ["definitions"], queryFn: fetchDefinitions, staleTime: 1000 * 60 * 60, // 1 hour }); - const citationsQuery = useQuery({ + const citationsQuery = useSuspenseQuery({ queryKey: ["citations"], queryFn: fetchCitations, staleTime: 1000 * 60 * 60, // 1 hour @@ -16,8 +16,6 @@ const useGlossary = () => { return { glossary: definitionsQuery.data, citations: citationsQuery.data, - isLoading: definitionsQuery.isLoading || citationsQuery.isLoading, - isError: definitionsQuery.isError || citationsQuery.isError, }; }; diff --git a/src/lib/nist-api.ts b/src/lib/nist-api.ts index 26a71be..a8b5bb8 100644 --- a/src/lib/nist-api.ts +++ b/src/lib/nist-api.ts @@ -38,6 +38,7 @@ const citationGid = "2053825396"; const makeClient = () => { const client = new Axios({ baseURL: baseUrl, + timeout: 2500, }); return client; }; @@ -62,18 +63,6 @@ export const fetchDefinitions = async () => { return parseDefinitions(resp.data); }; -export const parseGlossary = ( - glossaryData: string, - citationData: string -): Glossary => { - const glossary: Glossary = { - definitions: parseDefinitions(glossaryData), - citations: parseCitations(citationData), - }; - - return glossary; -}; - const parseDefinitions = (glossaryData: string): GlossaryTerm[] => { const terms: GlossaryTerm[] = []; const parsed = Papa.parse(glossaryData, { diff --git a/src/main.tsx b/src/main.tsx index 28cc10d..f625fd2 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,15 +1,26 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; -import { StrictMode } from "react"; +import { StrictMode, Suspense } from "react"; import { createRoot } from "react-dom/client"; import App from "./App.tsx"; +import ErrorBoundary from "./components/ErrorBoundary/ErrorBoundary"; import "./index.css"; const queryClient = new QueryClient(); createRoot(document.getElementById("root")!).render( - + + + Loading... + + } + > + + +