diff --git a/compendium-frontend/src/App.tsx b/compendium-frontend/src/App.tsx index 8133fb96f8a53eb547cf72dd7c9bb4e26799a38e..56e412d763f61ebf70b0ab8a08564d27b537c266 100644 --- a/compendium-frontend/src/App.tsx +++ b/compendium-frontend/src/App.tsx @@ -1,5 +1,5 @@ -import React, { ReactElement, useState } from "react"; -import { BrowserRouter as Router, Routes, Route,} from "react-router-dom"; +import React, { ReactElement } from "react"; +import { createBrowserRouter, RouterProvider } from "react-router-dom"; import Landing from "./pages/Landing"; import ExternalPageNavBar from "./shared/ExternalPageNavBar"; import GeantFooter from "./components/global/GeantFooter"; @@ -8,42 +8,40 @@ import CompendiumData from "./pages/CompendiumData"; import FundingSourcePage from "./pages/FundingSource"; import ChargingStructurePage from "./pages/ChargingStructure"; import StaffGraph from "./pages/StaffGraph"; -import { FilterSelection } from "./Schema"; import SubOrganisation from "./pages/SubOrganisation"; import ParentOrganisation from "./pages/ParentOrganisation"; import ECProjects from "./pages/ECProjects"; import Providers from "./Providers"; import PolicyPage from "./pages/Policy"; + +const router = createBrowserRouter([ + { path: "/budget", element: <BudgetPage />}, + { path: "/funding", element: <FundingSourcePage />}, + { path: "/data/employment", element: <StaffGraph />}, + { path: "/data/roles", element: <StaffGraph roles />}, + { path: "/charging", element: <ChargingStructurePage />}, + { path: "/suborganisations", element: <SubOrganisation />}, + { path: "/parentorganisation", element: <ParentOrganisation />}, + { path: "/ec-projects", element: <ECProjects />}, + { path: "/policy", element: <PolicyPage />}, + { path: "/data", element: <CompendiumData />}, + { path: "*", element: <Landing />}, +]); + + function App(): ReactElement { - const [filterSelection, setFilterSelection] = useState<FilterSelection>({ selectedYears: [], selectedNrens: [] }); if (process.env.NODE_ENV === 'production') { window.location.replace('/survey') return <></>; } return ( <div className="app"> - <Router> - <Providers> - <ExternalPageNavBar /> - <Routes> - <Route path="/budget" element={<BudgetPage filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> - <Route path="/funding" element={<FundingSourcePage filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> - <Route path="/data/employment" element={<StaffGraph filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> - <Route path="/data/roles" element={<StaffGraph roles filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> - <Route path="/charging" element={<ChargingStructurePage filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> - <Route path="/suborganisations" element={<SubOrganisation filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> - <Route path="/parentorganisation" element={<ParentOrganisation filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> - <Route path="/ec-projects" element={<ECProjects filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> - <Route path="/policy" element={<PolicyPage filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> - <Route path="/data" element={<CompendiumData />} /> - <Route path="*" element={<Landing />} /> - </Routes> - </Providers> - - - <GeantFooter /> - </Router> + <Providers> + <ExternalPageNavBar /> + <RouterProvider router={router} /> + </Providers> + <GeantFooter /> </div> ); diff --git a/compendium-frontend/src/Providers.tsx b/compendium-frontend/src/Providers.tsx index 072f5cededfd9728fb7af0b97ea60b30d59e5bc8..622d9b1608c27dbd51d30c0b9eff340d8b19283e 100644 --- a/compendium-frontend/src/Providers.tsx +++ b/compendium-frontend/src/Providers.tsx @@ -2,13 +2,16 @@ import React, { ReactElement } from "react"; import SidebarProvider from "./helpers/SidebarProvider"; import UserProvider from "./shared/UserProvider"; +import FilterSelectionProvider from "./helpers/FilterSelectionProvider"; function Providers({ children }): ReactElement { return ( <SidebarProvider> <UserProvider> - {children} + <FilterSelectionProvider> + {children} + </FilterSelectionProvider> </UserProvider> </SidebarProvider> ); diff --git a/compendium-frontend/src/helpers/FilterSelectionProvider.tsx b/compendium-frontend/src/helpers/FilterSelectionProvider.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c1ec0a760d1208fd951c024ac9665d40cd4bef4d --- /dev/null +++ b/compendium-frontend/src/helpers/FilterSelectionProvider.tsx @@ -0,0 +1,28 @@ +import React, { Dispatch, SetStateAction, createContext, useState } from 'react'; +import { FilterSelection } from '../Schema'; + +interface Props { + children: React.ReactNode; +} + +const FilterSelectionContext = createContext<{ + filterSelection: FilterSelection; + setFilterSelection: Dispatch<SetStateAction<FilterSelection>>; // (filterSelection: FilterSelection) => void; +}>({ + filterSelection: { selectedYears: [], selectedNrens: [] }, + setFilterSelection: () => { } +}); + + +const FilterSelectionProvider: React.FC<Props> = ({ children }) => { + const [filterSelection, setFilterSelection] = useState<FilterSelection>({ selectedYears: [], selectedNrens: [] }); + + return ( + <FilterSelectionContext.Provider value={{ filterSelection, setFilterSelection }}> + {children} + </FilterSelectionContext.Provider> + ); +}; + +export { FilterSelectionContext }; +export default FilterSelectionProvider; \ No newline at end of file diff --git a/compendium-frontend/src/pages/Budget.tsx b/compendium-frontend/src/pages/Budget.tsx index f5cd8d8dd8f6bf812604c376d596b4fa7483d1b1..08ea1e7e8d242e6df09e4ae85a0d8c29d356cf8b 100644 --- a/compendium-frontend/src/pages/Budget.tsx +++ b/compendium-frontend/src/pages/Budget.tsx @@ -1,22 +1,19 @@ -import React, { ReactElement, useEffect, useMemo, useState } from 'react'; +import React, { ReactElement, useContext, useEffect, useMemo, useState } from 'react'; import { Row } from "react-bootstrap"; -import { Budget, FilterSelection } from "../Schema"; +import { Budget } from "../Schema"; import { createBudgetDataset, getYearsAndNrens, loadDataWithFilterNrenSelectionFallback } from "../helpers/dataconversion"; import DataPage from '../components/DataPage'; import Filter from "../components/graphing/Filter"; import LineGraph from "../components/graphing/LineGraph"; import { Sections } from '../helpers/constants'; import DownloadCSVButton from "../components/DownloadCSVButton"; +import { FilterSelectionContext } from '../helpers/FilterSelectionProvider'; -interface inputProps { - filterSelection: FilterSelection - setFilterSelection: React.Dispatch<React.SetStateAction<FilterSelection>> -} - -function BudgetPage({ filterSelection, setFilterSelection }: inputProps): ReactElement { +function BudgetPage(): ReactElement { const [budgetResponse, setBudget] = useState<Budget[]>([]); + const {filterSelection, setFilterSelection } = useContext(FilterSelectionContext); const { nrens } = useMemo( () => getYearsAndNrens(budgetResponse), diff --git a/compendium-frontend/src/pages/ChargingStructure.tsx b/compendium-frontend/src/pages/ChargingStructure.tsx index d23de5f233669b91f1235d340728629f9956dab4..c3caf300153fff5df15acda3059d9c508d0e2d76 100644 --- a/compendium-frontend/src/pages/ChargingStructure.tsx +++ b/compendium-frontend/src/pages/ChargingStructure.tsx @@ -1,14 +1,15 @@ -import React, { useMemo, useState } from "react"; +import React, { useContext, useMemo, useState } from "react"; import {Row, Table} from "react-bootstrap"; import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend } from 'chart.js'; -import { ChargingStructure, FilterSelection } from "../Schema"; +import { ChargingStructure } from "../Schema"; import { createChargingStructureDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion"; import ColorPill from "../components/ColorPill"; import DataPage from "../components/DataPage"; import Filter from "../components/graphing/Filter"; import { Sections } from "../helpers/constants"; import DownloadCSVButton from "../components/DownloadCSVButton"; +import { FilterSelectionContext } from "../helpers/FilterSelectionProvider"; ChartJS.register( @@ -20,13 +21,9 @@ ChartJS.register( Legend ); -interface inputProps { - filterSelection: FilterSelection - setFilterSelection: React.Dispatch<React.SetStateAction<FilterSelection>> -} - -function ChargingStructurePage({ filterSelection, setFilterSelection }: inputProps): React.ReactElement { +function ChargingStructurePage(): React.ReactElement { const [chargingStructureData, setChargingStructureData] = useState<ChargingStructure[]>([]); + const {filterSelection, setFilterSelection } = useContext(FilterSelectionContext); const { years, nrens } = useMemo( () => getYearsAndNrens(chargingStructureData), diff --git a/compendium-frontend/src/pages/ECProjects.tsx b/compendium-frontend/src/pages/ECProjects.tsx index 18f3e40668ddf5d5a3f18650b00c775c1c3163c6..5dcb883820014eee58d67a3f5437710b5c4a1b17 100644 --- a/compendium-frontend/src/pages/ECProjects.tsx +++ b/compendium-frontend/src/pages/ECProjects.tsx @@ -1,19 +1,15 @@ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useMemo, useState } from 'react'; import {Row, Table} from "react-bootstrap"; -import { ECProject, FilterSelection } from "../Schema"; +import { ECProject } from "../Schema"; import { createECProjectsDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from '../helpers/dataconversion'; import DataPage from '../components/DataPage'; import Filter from "../components/graphing/Filter" import { Sections } from '../helpers/constants'; import DownloadCSVButton from "../components/DownloadCSVButton"; +import { FilterSelectionContext } from '../helpers/FilterSelectionProvider'; -interface inputProps { - filterSelection: FilterSelection - setFilterSelection: React.Dispatch<React.SetStateAction<FilterSelection>> -} - function getJSXFromMap(data: Map<string, Map<number, ECProject[]>>) { return Array.from(data.entries()).map(([nren, nrenMap]) => { return Array.from(nrenMap.entries()).map(([year, projects], yearIndex) => ( @@ -32,8 +28,9 @@ function getJSXFromMap(data: Map<string, Map<number, ECProject[]>>) { }) } -function ECProjects({ filterSelection, setFilterSelection }: inputProps) { +function ECProjects() { const [projectData, setProjectData] = useState<ECProject[]>([]); + const {filterSelection, setFilterSelection } = useContext(FilterSelectionContext); const { years, nrens } = useMemo( () => getYearsAndNrens(projectData), diff --git a/compendium-frontend/src/pages/FundingSource.tsx b/compendium-frontend/src/pages/FundingSource.tsx index 898dc367c4582f1988de7c64f26e18a0b17d338e..61e6e6a8a88469617e5e97f2ffe8b675a1238662 100644 --- a/compendium-frontend/src/pages/FundingSource.tsx +++ b/compendium-frontend/src/pages/FundingSource.tsx @@ -1,16 +1,17 @@ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useMemo, useState } from 'react'; import { Bar } from 'react-chartjs-2'; import { Col, Row } from "react-bootstrap"; import { Chart as ChartJS } from 'chart.js'; import ChartDataLabels from 'chartjs-plugin-datalabels'; -import { FundingSource, FilterSelection } from "../Schema"; +import { FundingSource } from "../Schema"; import { createFundingSourceDataset, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion"; import DataPage from '../components/DataPage'; import Filter from "../components/graphing/Filter" import { Sections } from '../helpers/constants'; import ColorBadge from '../components/ColorBadge'; import DownloadCSVButton from "../components/DownloadCSVButton"; +import { FilterSelectionContext } from '../helpers/FilterSelectionProvider'; export const chartOptions = { maintainAspectRatio: false, @@ -104,14 +105,9 @@ function FundingSourceLegend() { ); } - -interface inputProps { - filterSelection: FilterSelection - setFilterSelection: React.Dispatch<React.SetStateAction<FilterSelection>> -} - -function FundingSourcePage({ filterSelection, setFilterSelection }: inputProps) { +function FundingSourcePage() { const [fundingSourceData, setFundingSourceData] = useState<FundingSource[]>([]); + const {filterSelection, setFilterSelection } = useContext(FilterSelectionContext); const { years, nrens } = useMemo( () => getYearsAndNrens(fundingSourceData), diff --git a/compendium-frontend/src/pages/ParentOrganisation.tsx b/compendium-frontend/src/pages/ParentOrganisation.tsx index 47d2d5c3faae5369aae79d6077ed1fe4ef209979..624fa9bb911719bb90c92d5070b366b7e7a4c5a2 100644 --- a/compendium-frontend/src/pages/ParentOrganisation.tsx +++ b/compendium-frontend/src/pages/ParentOrganisation.tsx @@ -1,12 +1,13 @@ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useMemo, useState } from 'react'; import {Row, Table} from "react-bootstrap"; -import { Organisation, FilterSelection } from "../Schema"; +import { Organisation } from "../Schema"; import { createOrganisationDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion"; import DataPage from '../components/DataPage'; import Filter from "../components/graphing/Filter" import { Sections } from '../helpers/constants'; import DownloadCSVButton from "../components/DownloadCSVButton"; +import { FilterSelectionContext } from '../helpers/FilterSelectionProvider'; function getJSXFromMap(data: Map<string, Map<number, Organisation[]>>) { @@ -20,14 +21,9 @@ function getJSXFromMap(data: Map<string, Map<number, Organisation[]>>) { )) }) } - -interface inputProps { - filterSelection: FilterSelection - setFilterSelection: React.Dispatch<React.SetStateAction<FilterSelection>> -} - -function ParentOrganisation({ filterSelection, setFilterSelection }: inputProps) { +function ParentOrganisation() { const [organisationData, setOrganisationData] = useState<Organisation[]>([]); + const {filterSelection, setFilterSelection } = useContext(FilterSelectionContext); const { years, nrens } = useMemo( () => getYearsAndNrens(organisationData), diff --git a/compendium-frontend/src/pages/Policy.tsx b/compendium-frontend/src/pages/Policy.tsx index ed6bc0a7f91fc13681338abb28f91e57cc63c5b0..6f1362e4b2dabcbe2ea60e347331d551d6f16f29 100644 --- a/compendium-frontend/src/pages/Policy.tsx +++ b/compendium-frontend/src/pages/Policy.tsx @@ -1,16 +1,12 @@ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useMemo, useState } from 'react'; import { Table } from "react-bootstrap"; -import { Policy, FilterSelection } from "../Schema"; +import { Policy } from "../Schema"; import { createPolicyDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from '../helpers/dataconversion'; import DataPage from '../components/DataPage'; import Filter from "../components/graphing/Filter" import { Sections } from '../helpers/constants'; - -interface inputProps { - filterSelection: FilterSelection - setFilterSelection: React.Dispatch<React.SetStateAction<FilterSelection>> -} +import { FilterSelectionContext } from '../helpers/FilterSelectionProvider'; function getJSXFromMap(data: Map<string, Map<number, Policy>>) { const policies = [ @@ -46,8 +42,9 @@ function getJSXFromMap(data: Map<string, Map<number, Policy>>) { }) } -function PolicyPage({ filterSelection, setFilterSelection }: inputProps) { +function PolicyPage() { const [policyData, setProjectData] = useState<Policy[]>([]); + const {filterSelection, setFilterSelection } = useContext(FilterSelectionContext); const { years, nrens } = useMemo( () => getYearsAndNrens(policyData), diff --git a/compendium-frontend/src/pages/StaffGraph.tsx b/compendium-frontend/src/pages/StaffGraph.tsx index 6c82d571eabcc0ab055f999f8e6b4fd8654f0857..c1ac1da3b7f98b1f57e77566dedecc4f6ac1785e 100644 --- a/compendium-frontend/src/pages/StaffGraph.tsx +++ b/compendium-frontend/src/pages/StaffGraph.tsx @@ -1,8 +1,8 @@ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useMemo, useState } from 'react'; import { Bar } from 'react-chartjs-2'; import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend } from 'chart.js'; -import { NrenStaff, FilterSelection } from "../Schema"; +import { NrenStaff } from "../Schema"; import { createNRENStaffDataset, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion"; import DataPage from '../components/DataPage'; import Filter from "../components/graphing/Filter" @@ -11,6 +11,7 @@ import WithLegend from '../components/WithLegend'; import htmlLegendPlugin from '../plugins/HTMLLegendPlugin'; import {Row} from "react-bootstrap"; import DownloadCSVButton from "../components/DownloadCSVButton"; +import { FilterSelectionContext } from '../helpers/FilterSelectionProvider'; ChartJS.register( CategoryScale, @@ -101,13 +102,12 @@ const chartOptions = { }; interface inputProps { - filterSelection: FilterSelection - setFilterSelection: React.Dispatch<React.SetStateAction<FilterSelection>> roles?: boolean } -function StaffGraph({ filterSelection, setFilterSelection, roles = false }: inputProps) { +function StaffGraph({ roles = false }: inputProps) { const [staffData, setStaffData] = useState<NrenStaff[]>([]); + const {filterSelection, setFilterSelection } = useContext(FilterSelectionContext); const { years, nrens } = useMemo( () => getYearsAndNrens(staffData), diff --git a/compendium-frontend/src/pages/SubOrganisation.tsx b/compendium-frontend/src/pages/SubOrganisation.tsx index b57d5d0ad7efe04903fb2431ffa0609007812219..e2fb705eb020d07c951b0f73b71a4a5d187d1f42 100644 --- a/compendium-frontend/src/pages/SubOrganisation.tsx +++ b/compendium-frontend/src/pages/SubOrganisation.tsx @@ -1,12 +1,13 @@ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useMemo, useState } from 'react'; import {Row, Table} from "react-bootstrap"; -import { Organisation, FilterSelection } from "../Schema"; +import { Organisation } from "../Schema"; import { createOrganisationDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion"; import DataPage from '../components/DataPage'; import Filter from "../components/graphing/Filter" import { Sections } from '../helpers/constants'; import DownloadCSVButton from "../components/DownloadCSVButton"; +import { FilterSelectionContext } from '../helpers/FilterSelectionProvider'; function getJSXFromMap(data: Map<string, Map<number, Organisation[]>>) { @@ -27,13 +28,9 @@ function getJSXFromMap(data: Map<string, Map<number, Organisation[]>>) { }) } -interface inputProps { - filterSelection: FilterSelection - setFilterSelection: React.Dispatch<React.SetStateAction<FilterSelection>> -} - -function SubOrganisation({ filterSelection, setFilterSelection }: inputProps) { +function SubOrganisation() { const [organisationData, setOrganisationData] = useState<Organisation[]>([]); + const {filterSelection, setFilterSelection } = useContext(FilterSelectionContext); const { years, nrens } = useMemo( () => getYearsAndNrens(organisationData), diff --git a/survey-frontend/src/App.tsx b/survey-frontend/src/App.tsx index 2851cda7e33a6f22abdd0a3073417bc260bdf14b..19e3831154be5a68e694a695913512d10392e657 100644 --- a/survey-frontend/src/App.tsx +++ b/survey-frontend/src/App.tsx @@ -1,5 +1,5 @@ import React, { ReactElement } from "react"; -import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; +import { createBrowserRouter, RouterProvider } from "react-router-dom"; import SurveyManagementComponent from './SurveyManagementComponent'; import UserManagementComponent from './UserManagementComponent'; @@ -8,22 +8,22 @@ import ExternalPageNavBar from "shared/ExternalPageNavBar" import UserProvider from "./providers/UserProvider"; import Landing from "./Landing"; +const router = createBrowserRouter([ + { path: "survey/admin/surveys", element: <SurveyManagementComponent /> }, + { path: "survey/admin/users", element: <UserManagementComponent /> }, + { path: "survey/admin/inspect/:year", element: <SurveyContainerComponent loadFrom={'/api/response/inspect/'} /> }, + { path: "survey/admin/try/:year", element: <SurveyContainerComponent loadFrom={'/api/response/try/'} /> }, + { path: "survey/response/:year/:nren", element: <SurveyContainerComponent loadFrom={'/api/response/load/'} />}, + { path: "*", element: <Landing /> } +]); + function App(): ReactElement { return ( <div className="app"> - <Router> - <UserProvider> - <ExternalPageNavBar /> - <Routes> - <Route path="survey/admin/surveys" element={<SurveyManagementComponent />} /> - <Route path="survey/admin/users" element={<UserManagementComponent />} /> - <Route path="survey/admin/inspect/:year" element={<SurveyContainerComponent loadFrom={'/api/response/inspect/'} />} /> - <Route path="survey/admin/try/:year" element={<SurveyContainerComponent loadFrom={'/api/response/try/'} />} /> - <Route path="survey/response/:year/:nren" element={<SurveyContainerComponent loadFrom={'/api/response/load/'} />} /> - <Route path="*" element={<Landing />} /> - </Routes> - </UserProvider> - </Router> + <UserProvider> + <ExternalPageNavBar /> + <RouterProvider router={router} /> + </UserProvider> </div> ); }