Skip to content
Snippets Groups Projects
Commit 72c18e6c authored by Bjarke Madsen's avatar Bjarke Madsen
Browse files

Merge branch 'feature/COMP-169-NAVIGATION-SIDEBAR' into 'develop'

Feature/comp 169 navigation sidebar

See merge request !15
parents 418e5f82 588a0d1f
Branches
Tags
1 merge request!15Feature/comp 169 navigation sidebar
Showing
with 462 additions and 303 deletions
Source diff could not be displayed: it is too large. Options to address this: view the blob.
import React, { ReactElement, useState } from "react"; import React, { ReactElement, useState, useContext } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Landing from "./pages/Landing"; import Landing from "./pages/Landing";
import ExternalPageNavBar from "./components/global/ExternalPageNavBar"; import ExternalPageNavBar from "./components/global/ExternalPageNavBar";
import GeantFooter from "./components/global/GeantFooter"; import GeantFooter from "./components/global/GeantFooter";
import DataAnalysis from "./pages/DataAnalysis"; import DataAnalysis from "./pages/DataAnalysis";
import AnnualReport from "./pages/AnnualReport";
import CompendiumData from "./pages/CompendiumData"; import CompendiumData from "./pages/CompendiumData";
import FundingSourcePage from "./pages/FundingSource"; import FundingSourcePage from "./pages/FundingSource";
import ChargingStructurePage from "./pages/ChargingStructure"; import ChargingStructurePage from "./pages/ChargingStructure";
...@@ -13,32 +12,34 @@ import { FilterSelection } from "./Schema"; ...@@ -13,32 +12,34 @@ import { FilterSelection } from "./Schema";
import SubOrganisation from "./pages/SubOrganisation"; import SubOrganisation from "./pages/SubOrganisation";
import ParentOrganisation from "./pages/ParentOrganisation"; import ParentOrganisation from "./pages/ParentOrganisation";
import ECProjects from "./pages/ECProjects"; import ECProjects from "./pages/ECProjects";
import SidebarProvider from "./helpers/SidebarProvider";
function App(): ReactElement { function App(): ReactElement {
const [filterSelection, setFilterSelection] = useState<FilterSelection>({ selectedYears: [], selectedNrens: [] }); const [filterSelection, setFilterSelection] = useState<FilterSelection>({ selectedYears: [], selectedNrens: [] });
return ( return (
<div className="app"> <div className="app">
<Router> <Router>
<ExternalPageNavBar /> <ExternalPageNavBar />
<Routes> <SidebarProvider>
<Route path="/data" element={<CompendiumData />} /> <Routes>
<Route path="/analysis" element={ <Route path="/analysis" element={<DataAnalysis filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
<DataAnalysis 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="/report" element={<AnnualReport />} /> <Route path="/data/roles" element={<StaffGraph roles filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
<Route path="/funding" element={<FundingSourcePage filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} <Route path="/charging" element={<ChargingStructurePage filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
/> <Route path="/suborganisations" element={<SubOrganisation filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
<Route path="/data/employment" element={<StaffGraph filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> <Route path="/parentorganisation" element={<ParentOrganisation filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
<Route path="/data/roles" element={<StaffGraph roles filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> <Route path="/ec-projects" element={<ECProjects filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
<Route path="/charging" element={<ChargingStructurePage filterSelection={filterSelection} setFilterSelection={setFilterSelection}/>} /> <Route path="/data" element={<CompendiumData />} />
<Route path="/suborganisations" element={<SubOrganisation filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> <Route path="*" element={<Landing />} />
<Route path="/parentorganisation" element={<ParentOrganisation filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> </Routes>
<Route path="/ec-projects" element={<ECProjects filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} /> </SidebarProvider>
<Route path="*" element={<Landing />} />
</Routes>
<GeantFooter /> <GeantFooter />
</Router> </Router>
......
import React from 'react';
import { Link } from 'react-router-dom';
import { Row } from 'react-bootstrap';
import Sidebar from './SideBar';
const OrganizationSidebar = () => {
return (
<Sidebar>
<Row>
<Link to="/analysis" className="link-text-underline">
<span>Budget of NRENs per Year</span>
</Link>
</Row>
<Row>
<Link to="/funding" className="link-text-underline">
<span>Income Source of NRENs per Year</span>
</Link>
</Row>
<Row>
<Link to="/charging" className="link-text-underline">
<span>Charging Mechanism of NRENs per Year</span>
</Link>
</Row>
<Row>
<Link to="/data/roles" className="link-text-underline">
<span>Roles of NREN employees</span>
</Link>
</Row>
<Row>
<Link to="/data/employment" className="link-text-underline">
<span>Types of employment for NRENs</span>
</Link>
</Row>
<Row>
<Link to="/suborganisations" className="link-text-underline">
<span>NREN Suborganisations</span>
</Link>
</Row>
<Row>
<Link to="/parentorganisation" className="link-text-underline">
<span>NREN Parent Organisations</span>
</Link>
</Row>
<Row>
<Link to="/ec-projects" className="link-text-underline">
<span>NREN Involvement in European Commission Projects</span>
</Link>
</Row>
</Sidebar>
)
}
export default OrganizationSidebar
\ No newline at end of file
import React, { useContext } from 'react';
import { sidebarContext } from "../helpers/SidebarProvider";
interface Props {
children: React.ReactNode;
}
const Sidebar: React.FC<Props> = ({ children }) => {
const { show, toggle } = useContext(sidebarContext);
return (
<div className="sidebar-wrapper">
<nav className={show ? '' : 'no-sidebar'} id="sidebar">
<div className={`menu-items`}>{children}</div>
</nav>
<button className="toggle-btn" onClick={toggle}>
{show ? 'Hide Sidebar' : 'Show Sidebar'}
</button>
</div>
);
};
export default Sidebar;
\ No newline at end of file
import React, { createContext, useState } from 'react';
interface Props {
children: React.ReactNode;
}
const sidebarContext = createContext<{
show: boolean;
toggle: React.Dispatch<any>;
}>({
show: false,
toggle: () => { }
});
const SidebarProvider: React.FC<Props> = ({ children }) => {
const [show, setShow] = useState<boolean>(false);
const toggle = () => {
setShow(!show);
};
return (
<sidebarContext.Provider value={{ show, toggle }}>
{children}
</sidebarContext.Provider>
);
};
export { sidebarContext };
export default SidebarProvider;
\ No newline at end of file
import React, { ReactElement } from 'react';
function AnnualReport(): ReactElement {
return (
<div>
<h1>Annual Report</h1>
</div>
);
}
export default AnnualReport;
import React, { useEffect, useState } from "react"; import React, { useState } from "react";
import { Container, Row, Col, Table } from "react-bootstrap"; import { Container, Row, Col, Table } from "react-bootstrap";
import Chart, { ChartOptions, Plugin, ChartTypeRegistry, ScatterDataPoint } from 'chart.js'; import { ChargingStructure, FilterSelection } from "../Schema";
import { Bubble, Scatter } from "react-chartjs-2";
import { ChargingStructure, ChargingStructureDataset, FilterSelection } from "../Schema";
import { import {
Chart as ChartJS, Chart as ChartJS,
...@@ -11,12 +9,13 @@ import { ...@@ -11,12 +9,13 @@ import {
BarElement, BarElement,
Title, Title,
Tooltip, Tooltip,
Legend, Legend
scales,
} from 'chart.js'; } from 'chart.js';
import Filter from "../components/graphing/Filter"; import Filter from "../components/graphing/Filter";
import { createChargingStructureDataLookup } from "../helpers/dataconversion"; import { createChargingStructureDataLookup } from "../helpers/dataconversion";
import ColorPill from "../components/ColorPill"; import ColorPill from "../components/ColorPill";
import OrganizationSidebar from "../components/OrganizationSidebar";
ChartJS.register( ChartJS.register(
CategoryScale, CategoryScale,
LinearScale, LinearScale,
...@@ -26,10 +25,6 @@ ChartJS.register( ...@@ -26,10 +25,6 @@ ChartJS.register(
Legend Legend
); );
const EMPTY_DATASET = { datasets: [], labels: [] };
async function getData(): Promise<ChargingStructure[]> { async function getData(): Promise<ChargingStructure[]> {
try { try {
const response = await fetch('/api/charging/'); const response = await fetch('/api/charging/');
...@@ -61,89 +56,90 @@ function ChargingStructurePage({ filterSelection, setFilterSelection }: inputPro ...@@ -61,89 +56,90 @@ function ChargingStructurePage({ filterSelection, setFilterSelection }: inputPro
return ( return (
<> <>
<Container fluid className="p-0"> <OrganizationSidebar />
<Row> <Container fluid className="p-0">
<h1>Charging Structure</h1> <Row>
</Row> <h1>Charging Structure</h1>
<Row> </Row>
<Col xs={9}> <Row>
<Table className="charging-struct-table" striped bordered responsive > <Col xs={9}>
<colgroup> <Table className="charging-struct-table" striped bordered responsive >
<col span={1} style={{ width: "10%" }} /> <colgroup>
<col span={1} style={{ width: "18%" }} /> <col span={1} style={{ width: "10%" }} />
<col span={1} style={{ width: "18%" }} /> <col span={1} style={{ width: "18%" }} />
<col span={1} style={{ width: "18%" }} /> <col span={1} style={{ width: "18%" }} />
<col span={1} style={{ width: "18%" }} /> <col span={1} style={{ width: "18%" }} />
<col span={1} style={{ width: "18%" }} /> <col span={1} style={{ width: "18%" }} />
</colgroup> <col span={1} style={{ width: "18%" }} />
<thead> </colgroup>
<tr > <thead>
<th></th> <tr >
<th>Flat fee based on bandwidth</th> <th></th>
<th>Usage based fee</th> <th>Flat fee based on bandwidth</th>
<th>Combination flat fee & usage basedfee </th> <th>Usage based fee</th>
<th>No Direct Charge</th> <th>Combination flat fee & usage basedfee </th>
<th>Other</th> <th>No Direct Charge</th>
</tr> <th>Other</th>
</thead> </tr>
<tbody> </thead>
{filterSelection.selectedNrens <tbody>
.sort((a, b) => a>b? 1 : -1) {filterSelection.selectedNrens
.map((nren: string) => ( .sort((a, b) => a > b ? 1 : -1)
<tr key={nren}> .map((nren: string) => (
<td>{nren}</td> <tr key={nren}>
<td > <td>{nren}</td>
{filterSelection.selectedYears <td >
.sort((a, b) => a>b? 1 : -1) {filterSelection.selectedYears
.map((year: number, index) => ( .sort((a, b) => a > b ? 1 : -1)
<ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"flat_fee"}/> .map((year: number, index) => (
))} <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"flat_fee"} />
</td> ))}
<td> </td>
{filterSelection.selectedYears <td>
.sort((a, b) => a>b? 1 : -1) {filterSelection.selectedYears
.map((year: number, index) => ( .sort((a, b) => a > b ? 1 : -1)
<ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"usage_based_fee"}/> .map((year: number, index) => (
)) <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"usage_based_fee"} />
} ))
</td> }
<td> </td>
{filterSelection.selectedYears <td>
.sort((a, b) => a>b? 1 : -1) {filterSelection.selectedYears
.map((year: number, index) => ( .sort((a, b) => a > b ? 1 : -1)
<ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"combination"}/> .map((year: number, index) => (
))} <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"combination"} />
</td> ))}
<td> </td>
{filterSelection.selectedYears <td>
.sort((a, b) => a>b? 1 : -1) {filterSelection.selectedYears
.map((year: number, index) => ( .sort((a, b) => a > b ? 1 : -1)
<ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"no_charge"}/> .map((year: number, index) => (
))} <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"no_charge"} />
</td> ))}
<td> </td>
{filterSelection.selectedYears <td>
.sort((a, b) => a>b? 1 : -1) {filterSelection.selectedYears
.map((year: number, index) => ( .sort((a, b) => a > b ? 1 : -1)
<ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"other"}/> .map((year: number, index) => (
))} <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"other"} />
</td> ))}
</tr> </td>
</tr>
))} ))}
</tbody> </tbody>
</Table> </Table>
</Col> </Col>
<Col xs={3}> <Col xs={3}>
<Filter <Filter
filterOptions={{availableYears: [...labelsYear], availableNrens: [...labelsNREN]}} filterOptions={{ availableYears: [...labelsYear], availableNrens: [...labelsNREN] }}
filterSelection={filterSelection} filterSelection={filterSelection}
setFilterSelection={setFilterSelection} setFilterSelection={setFilterSelection}
/> />
</Col> </Col>
</Row> </Row>
</Container> </Container>
</> </>
); );
}; };
......
import React, {ReactElement, useEffect, useState} from 'react'; import React, { ReactElement, useEffect, useState } from 'react';
import { Col, Container, Row } from "react-bootstrap"; import { Col, Container, Row } from "react-bootstrap";
import LineGraph from "../components/graphing/LineGraph"; import LineGraph from "../components/graphing/LineGraph";
import {Budget, FilterSelection} from "../Schema";
import Filter from "../components/graphing/Filter"; import Filter from "../components/graphing/Filter";
import {createBudgetDataset} from "../helpers/dataconversion"; import OrganizationSidebar from "../components/OrganizationSidebar";
import { createBudgetDataset } from "../helpers/dataconversion";
import { Budget, FilterSelection } from "../Schema";
function api<T>(url: string, options: RequestInit | undefined = undefined): Promise<T> { function api<T>(url: string, options: RequestInit | undefined = undefined): Promise<T> {
return fetch(url, options) return fetch(url, options)
...@@ -35,7 +36,6 @@ function DataAnalysis({ filterSelection, setFilterSelection }: inputProps): Reac ...@@ -35,7 +36,6 @@ function DataAnalysis({ filterSelection, setFilterSelection }: inputProps): Reac
budgetData.datasets.forEach(dataset => { budgetData.datasets.forEach(dataset => {
dataset.hidden = !filterSelection.selectedNrens.includes(dataset.label); dataset.hidden = !filterSelection.selectedNrens.includes(dataset.label);
}); });
useEffect(() => { useEffect(() => {
const loadData = async () => { const loadData = async () => {
...@@ -61,6 +61,8 @@ function DataAnalysis({ filterSelection, setFilterSelection }: inputProps): Reac ...@@ -61,6 +61,8 @@ function DataAnalysis({ filterSelection, setFilterSelection }: inputProps): Reac
return ( return (
<div> <div>
<h1>Data Analysis</h1> <h1>Data Analysis</h1>
<OrganizationSidebar />
<Container> <Container>
<Row> <Row>
<Col> <Col>
...@@ -68,15 +70,15 @@ function DataAnalysis({ filterSelection, setFilterSelection }: inputProps): Reac ...@@ -68,15 +70,15 @@ function DataAnalysis({ filterSelection, setFilterSelection }: inputProps): Reac
<LineGraph data={budgetData} /> <LineGraph data={budgetData} />
</Row> </Row>
<Row> <Row>
The numbers are based on 30 NRENs that reported their budgets continuously throughout this The numbers are based on 30 NRENs that reported their budgets continuously throughout this
period. This means that some larger NRENs are not included and therefore the actual total budgets will period. This means that some larger NRENs are not included and therefore the actual total budgets will
have been higher. (For comparison, the total budget according to the 2021 survey results based on the data have been higher. (For comparison, the total budget according to the 2021 survey results based on the data
for all responding NRENs that year is €555 M). The percentage change is based on the previous year&apos;s budget. for all responding NRENs that year is €555 M). The percentage change is based on the previous year&apos;s budget.
</Row> </Row>
</Col> </Col>
<Col xs={3}> <Col xs={3}>
<Filter <Filter
filterOptions={{availableYears: [], availableNrens: [...nrens]}} filterOptions={{ availableYears: [], availableNrens: [...nrens] }}
filterSelection={filterSelection} filterSelection={filterSelection}
setFilterSelection={setFilterSelection} setFilterSelection={setFilterSelection}
/> />
......
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { Col, Container, Row, Table } from "react-bootstrap"; import { Col, Container, Row, Table } from "react-bootstrap";
import Filter from "../components/graphing/Filter" import Filter from "../components/graphing/Filter"
import OrganizationSidebar from '../components/OrganizationSidebar';
import { import {
ECProject, ECProject,
...@@ -123,41 +124,45 @@ function ECProjects({ filterSelection, setFilterSelection }: inputProps) { ...@@ -123,41 +124,45 @@ function ECProjects({ filterSelection, setFilterSelection }: inputProps) {
}, [setFilterSelection]); }, [setFilterSelection]);
return ( return (
<Container> <>
<Row> <OrganizationSidebar />
<Col xs={9}> <Container>
<Row> <Row>
<h3>NREN Involvement in European Commission Projects</h3> <Col xs={9}>
</Row> <Row>
<Row> <h3>NREN Involvement in European Commission Projects</h3>
<Table> </Row>
<thead> <Row>
<tr> <Table>
<th>NREN</th> <thead>
<th>Year</th> <tr>
<th>EC Project Membership</th> <th>NREN</th>
</tr> <th>Year</th>
</thead> <th>EC Project Membership</th>
<tbody className='table-bg-highlighted'> </tr>
{getJSXFromMap(projectDataByYear)} </thead>
</tbody> <tbody className='table-bg-highlighted'>
</Table> {getJSXFromMap(projectDataByYear)}
</Row> </tbody>
</Col> </Table>
<Col xs={3}> </Row>
<div className="sticky-top" style={{ top: '1rem' }}> </Col>
{/* the sticky-top class makes the filter follow the user as they scroll down the page */} <Col xs={3}>
<Filter <div className="sticky-top" style={{ top: '1rem' }}>
filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }} {/* the sticky-top class makes the filter follow the user as they scroll down the page */}
filterSelection={filterSelection} <Filter
setFilterSelection={setFilterSelection} filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
/> filterSelection={filterSelection}
</div> setFilterSelection={setFilterSelection}
/>
</div>
</Col>
</Row>
</Container> </Col>
</Row>
</Container>
</>
); );
} }
export default ECProjects; export default ECProjects;
import React, {useEffect, useMemo, useState} from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import {Col, Container, Row} from "react-bootstrap"; import { Col, Container, Row } from "react-bootstrap";
import { Bar } from 'react-chartjs-2'; import { Bar } from 'react-chartjs-2';
import { createFundingSourceDataset } from "../helpers/dataconversion"; import { createFundingSourceDataset } from "../helpers/dataconversion";
import Filter from "../components/graphing/Filter" import Filter from "../components/graphing/Filter"
import OrganizationSidebar from "../components/OrganizationSidebar";
import { import {
Chart as ChartJS, Chart as ChartJS,
...@@ -19,6 +21,7 @@ import { ...@@ -19,6 +21,7 @@ import {
} from "../Schema"; } from "../Schema";
ChartJS.register( ChartJS.register(
CategoryScale, CategoryScale,
LinearScale, LinearScale,
...@@ -82,7 +85,7 @@ function getYearsAndNrens(sourceData: FundingSource[]) { ...@@ -82,7 +85,7 @@ function getYearsAndNrens(sourceData: FundingSource[]) {
years.add(datapoint.YEAR); years.add(datapoint.YEAR);
nrens.add(datapoint.NREN); nrens.add(datapoint.NREN);
}); });
return {years: years, nrens: nrens}; return { years: years, nrens: nrens };
} }
interface inputProps { interface inputProps {
...@@ -132,30 +135,34 @@ function FundingSourcePage({ filterSelection, setFilterSelection }: inputProps) ...@@ -132,30 +135,34 @@ function FundingSourcePage({ filterSelection, setFilterSelection }: inputProps)
}, [setFilterSelection]); }, [setFilterSelection]);
return ( return (
<Container> <>
<Row> <OrganizationSidebar />
<Col xs={9}> <Container>
<Row> <Row>
<h1>Funding Source</h1> <Col xs={9}>
</Row> <Row>
<Row> <h1>Funding Source</h1>
<div className="chart-container" style={{ 'minHeight': '100vh', 'width': '60vw', }}> </Row>
<Bar <Row>
data={fundingSourceDataset} <div className="chart-container" style={{ 'minHeight': '100vh', 'width': '60vw', }}>
options={chartOptions} <Bar
/> data={fundingSourceDataset}
</div> options={chartOptions}
</Row> />
</Col> </div>
<Col xs={3}> </Row>
<Filter </Col>
filterOptions={{availableYears: [...years], availableNrens: [...nrens]}} <Col xs={3}>
filterSelection={filterSelection} <Filter
setFilterSelection={setFilterSelection} filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
/> filterSelection={filterSelection}
</Col> setFilterSelection={setFilterSelection}
</Row> />
</Container> </Col>
</Row>
</Container>
</>
); );
} }
export default FundingSourcePage; export default FundingSourcePage;
...@@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react'; ...@@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react';
import { Col, Container, Row, Table } from "react-bootstrap"; import { Col, Container, Row, Table } from "react-bootstrap";
import { createOrganisationDataLookup } from "../helpers/dataconversion"; import { createOrganisationDataLookup } from "../helpers/dataconversion";
import Filter from "../components/graphing/Filter" import Filter from "../components/graphing/Filter"
import OrganizationSidebar from '../components/OrganizationSidebar';
import { import {
Organisation, Organisation,
...@@ -69,48 +70,52 @@ function ParentOrganisation({ filterSelection, setFilterSelection }: inputProps) ...@@ -69,48 +70,52 @@ function ParentOrganisation({ filterSelection, setFilterSelection }: inputProps)
} }
return ( return (
<Container> <>
<Row> <OrganizationSidebar />
<Col xs={9}> <Container>
<Row> <Row>
<h3>NREN Parent Organisations</h3> <Col xs={9}>
</Row> <Row>
<Row> <h3>NREN Parent Organisations</h3>
<Table> </Row>
<thead> <Row>
<tr> <Table>
<th>NREN</th> <thead>
<th>Year</th> <tr>
<th>Parent Organisation</th> <th>NREN</th>
</tr> <th>Year</th>
</thead> <th>Parent Organisation</th>
<tbody> </tr>
{Array.from(organisationDataset).sort().map(([_, nrenEntry]) => ( </thead>
Array.from(nrenEntry).sort().map(([_, nrenDataList], yearIndex) => ( <tbody>
nrenDataList.sort(sortOrganisation).map((nrenData, nrenDataIndex) => ( {Array.from(organisationDataset).sort().map(([_, nrenEntry]) => (
<tr key={nrenData.nren + nrenData.year + nrenData.name}> Array.from(nrenEntry).sort().map(([_, nrenDataList], yearIndex) => (
<td>{yearIndex == 0 && nrenDataIndex == 0 && nrenData.nren}</td> nrenDataList.sort(sortOrganisation).map((nrenData, nrenDataIndex) => (
<td>{nrenDataIndex == 0 && nrenData.year}</td> <tr key={nrenData.nren + nrenData.year + nrenData.name}>
<td>{nrenData.name}</td> <td>{yearIndex == 0 && nrenDataIndex == 0 && nrenData.nren}</td>
</tr> <td>{nrenDataIndex == 0 && nrenData.year}</td>
)) <td>{nrenData.name}</td>
) </tr>
) ))
)
)
))}
</tbody>
</Table>
</Row>
</Col>
<Col xs={3}>
<Filter
filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
filterSelection={filterSelection}
setFilterSelection={setFilterSelection}
/>
</Col>
</Row>
</Container>
</>
))}
</tbody>
</Table>
</Row>
</Col>
<Col xs={3}>
<Filter
filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
filterSelection={filterSelection}
setFilterSelection={setFilterSelection}
/>
</Col>
</Row>
</Container>
); );
} }
export default ParentOrganisation; export default ParentOrganisation;
...@@ -3,6 +3,8 @@ import { Col, Container, Row } from "react-bootstrap"; ...@@ -3,6 +3,8 @@ import { Col, Container, Row } from "react-bootstrap";
import { Bar } from 'react-chartjs-2'; import { Bar } from 'react-chartjs-2';
import { createNRENStaffDataset } from "../helpers/dataconversion"; import { createNRENStaffDataset } from "../helpers/dataconversion";
import Filter from "../components/graphing/Filter" import Filter from "../components/graphing/Filter"
import OrganizationSidebar from "../components/OrganizationSidebar";
import { import {
Chart as ChartJS, Chart as ChartJS,
...@@ -141,31 +143,35 @@ function StaffGraph({ filterSelection, setFilterSelection, roles = false }: inpu ...@@ -141,31 +143,35 @@ function StaffGraph({ filterSelection, setFilterSelection, roles = false }: inpu
const text = roles ? "Roles" : "Employment"; const text = roles ? "Roles" : "Employment";
return ( return (
<Container> <>
<Row> <OrganizationSidebar />
<Col xs={9}> <Container>
<Row> <Row>
<h3>NREN Staff {text}</h3> <Col xs={9}>
</Row> <Row>
<Row> <h3>NREN Staff {text}</h3>
<div className="chart-container" style={{ 'minHeight': '60vh', 'width': '60vw', }}> </Row>
<Bar <Row>
data={nrenStaffDataset} <div className="chart-container" style={{ 'minHeight': '60vh', 'width': '60vw', }}>
options={chartOptions} <Bar
/> data={nrenStaffDataset}
</div> options={chartOptions}
</Row> />
</Col> </div>
<Col xs={3}> </Row>
<Filter </Col>
max1year <Col xs={3}>
filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }} <Filter
filterSelection={filterSelection} max1year
setFilterSelection={setFilterSelection} filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
/> filterSelection={filterSelection}
</Col> setFilterSelection={setFilterSelection}
</Row> />
</Container> </Col>
</Row>
</Container>
</>
); );
} }
export default StaffGraph; export default StaffGraph;
...@@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react'; ...@@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react';
import { Col, Container, Row, Table } from "react-bootstrap"; import { Col, Container, Row, Table } from "react-bootstrap";
import { createOrganisationDataLookup } from "../helpers/dataconversion"; import { createOrganisationDataLookup } from "../helpers/dataconversion";
import Filter from "../components/graphing/Filter" import Filter from "../components/graphing/Filter"
import OrganizationSidebar from '../components/OrganizationSidebar';
import { import {
Organisation, Organisation,
...@@ -69,50 +70,54 @@ function SubOrganisation({ filterSelection, setFilterSelection }: inputProps) { ...@@ -69,50 +70,54 @@ function SubOrganisation({ filterSelection, setFilterSelection }: inputProps) {
} }
return ( return (
<Container> <>
<Row> <OrganizationSidebar />
<Col xs={9}> <Container>
<Row> <Row>
<h3>NREN Suborganisations</h3> <Col xs={9}>
</Row> <Row>
<Row> <h3>NREN Suborganisations</h3>
<Table> </Row>
<thead> <Row>
<tr> <Table>
<th>NREN</th> <thead>
<th>Year</th> <tr>
<th>Suborganisation</th> <th>NREN</th>
<th>Role</th> <th>Year</th>
</tr> <th>Suborganisation</th>
</thead> <th>Role</th>
<tbody> </tr>
{Array.from(organisationDataset).sort().map(([_, nrenEntry]) => ( </thead>
Array.from(nrenEntry).sort().map(([_, nrenDataList], yearIndex) => ( <tbody>
nrenDataList.sort(sortOrganisation).map((nrenData, nrenDataIndex) => ( {Array.from(organisationDataset).sort().map(([_, nrenEntry]) => (
<tr key={nrenData.nren + nrenData.year + nrenData.name}> Array.from(nrenEntry).sort().map(([_, nrenDataList], yearIndex) => (
<td>{yearIndex == 0 && nrenDataIndex == 0 && nrenData.nren}</td> nrenDataList.sort(sortOrganisation).map((nrenData, nrenDataIndex) => (
<td>{nrenDataIndex == 0 && nrenData.year}</td> <tr key={nrenData.nren + nrenData.year + nrenData.name}>
<td>{nrenData.name}</td> <td>{yearIndex == 0 && nrenDataIndex == 0 && nrenData.nren}</td>
<td>{nrenData.role}</td> <td>{nrenDataIndex == 0 && nrenData.year}</td>
</tr> <td>{nrenData.name}</td>
)) <td>{nrenData.role}</td>
) </tr>
) ))
)
)
))}
</tbody>
</Table>
</Row>
</Col>
<Col xs={3}>
<Filter
filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
filterSelection={filterSelection}
setFilterSelection={setFilterSelection}
/>
</Col>
</Row>
</Container>
</>
))}
</tbody>
</Table>
</Row>
</Col>
<Col xs={3}>
<Filter
filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
filterSelection={filterSelection}
setFilterSelection={setFilterSelection}
/>
</Col>
</Row>
</Container>
); );
} }
export default SubOrganisation; export default SubOrganisation;
.sidebar-wrapper {
display: flex;
position: fixed;
top: calc(50vh - 10%);
.menu-items {
padding: 10px;
}
}
.sidebar-wrapper>nav {
transition: 0.25s;
// transition-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55);
transition-property: margin-left;
margin-left: 0;
background-color: #fff;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
a {
text-decoration: none;
}
a:hover {
background-color: $yellow-orange;
text-decoration: none;
}
}
nav.no-sidebar {
margin-left: -79%;
}
\ No newline at end of file
@import '../abstracts/variables'; @import '../abstracts/variables';
@import '../layout/Sidebar';
.rounded-border { .rounded-border {
border-radius: 25px; border-radius: 25px;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment