From bcae60190a0153b2d8ba365c4d0ad8e3f44abdf9 Mon Sep 17 00:00:00 2001
From: Remco Tukker <remco.tukker@geant.org>
Date: Fri, 21 Apr 2023 11:18:26 +0200
Subject: [PATCH] the filter component now returns two styled dropdown boxes
 instead of a long list of checkboxes

---
 webapp/src/components/graphing/Filter.tsx | 88 +++++++++++++++--------
 webapp/src/scss/layout/_components.scss   | 32 ++++++++-
 2 files changed, 88 insertions(+), 32 deletions(-)

diff --git a/webapp/src/components/graphing/Filter.tsx b/webapp/src/components/graphing/Filter.tsx
index 3391b9f7..3440c0e5 100644
--- a/webapp/src/components/graphing/Filter.tsx
+++ b/webapp/src/components/graphing/Filter.tsx
@@ -1,14 +1,15 @@
 import React, {ReactElement} from 'react';
-import {Button, Row} from 'react-bootstrap';
+import {Button, Dropdown, ButtonToolbar} from 'react-bootstrap';
 import {FilterSelection} from "../../Schema";
 
 interface inputProps {
     filterOptions: { availableNrens: string[], availableYears: number[] }
     filterSelection: FilterSelection
     setFilterSelection: React.Dispatch<React.SetStateAction<FilterSelection>>
+    max1year?: boolean
 }
 
-function Filter({ filterOptions, filterSelection, setFilterSelection }: inputProps): ReactElement {
+function Filter({ filterOptions, filterSelection, setFilterSelection, max1year = false }: inputProps): ReactElement {
 
     const handleNrenClick = (nren: string) => {
         if (filterSelection.selectedNrens.includes(nren)) {
@@ -32,7 +33,7 @@ function Filter({ filterOptions, filterSelection, setFilterSelection }: inputPro
             });
         } else {
             setFilterSelection({
-                selectedYears: [...filterSelection.selectedYears, year],
+                selectedYears: max1year ? [year] : [...filterSelection.selectedYears, year],
                 selectedNrens: [...filterSelection.selectedNrens]
             });
         }
@@ -52,37 +53,62 @@ function Filter({ filterOptions, filterSelection, setFilterSelection }: inputPro
         });
     }
 
+    // flex wrap in the column direction causes issues so we prepare the columns ourselves:
+    const nrOfColumns = 2;
+    const nrOfRows = Math.ceil(filterOptions.availableNrens.length / nrOfColumns);
+    const grid: string[][] = Array.from(Array(nrOfColumns), () => []);
+    filterOptions.availableNrens.sort().forEach((nren, idx) => {
+        const col = Math.floor(idx / nrOfRows);
+        grid[col].push(nren);
+    });
+
     return (
-        <>
-            <Row>
-                {filterOptions.availableYears.sort().map((year) => (
-                    <div key={year} onClick={() => (handleYearClick(year))}>
-                        <input
-                            type="checkbox"
-                            checked={filterSelection.selectedYears.includes(year)}
-                            readOnly
-                        />
-                        {year}
+        <ButtonToolbar className="d-flex justify-content-end gap-2 m-2">
+
+            <Dropdown autoClose="outside">
+                <Dropdown.Toggle id="nren-dropdown-toggle" variant="compendium">Select NRENs</Dropdown.Toggle>
+                <Dropdown.Menu>
+                    <div className="d-flex fit-max-content">
+                        {grid.map((column, columnIndex) => (
+                            <div key={columnIndex} className="flex-fill">
+                                {column.map((nren) => (
+                                    <div className="filter-dropdown-item flex-fill" key={nren} onClick={() => (handleNrenClick(nren))}>
+                                        <input
+                                            type="checkbox"
+                                            checked={filterSelection.selectedNrens.includes(nren)}
+                                            readOnly
+                                        /> {nren}
+                                    </div>
+                                ))}
+                            </div>
+                        ))}
                     </div>
-                ))}
-            </Row>
-            <Row>
-                {filterOptions.availableNrens.sort().map((nren) => (
-                    <div key={nren} onClick={() => (handleNrenClick(nren))}>
-                        <input
-                            type="checkbox"
-                            checked={filterSelection.selectedNrens.includes(nren)}
-                            readOnly
-                        />
-                        {nren}
+                    <div className="d-flex fit-max-content gap-2 mx-2 mt-3">
+                        <Button variant="compendium" className="flex-fill" onClick={handleSelectAllNrensClick}>Select all NRENs</Button>
+                        <Button variant="compendium" className="flex-fill" onClick={handleDeselectAllNrensClick}>Unselect all NRENs</Button>
                     </div>
-                ))}
-            </Row>
-            <Row>
-                <Button onClick={handleSelectAllNrensClick}>Select all NRENs</Button>
-                <Button onClick={handleDeselectAllNrensClick}>Deselect all NRENs</Button>
-            </Row>
-        </>
+                </Dropdown.Menu>
+            </Dropdown>
+
+            { filterOptions.availableYears.length > 0 &&
+                <Dropdown autoClose="outside">
+                    <Dropdown.Toggle id="year-dropdown-toggle" variant="compendium">Select years</Dropdown.Toggle>
+                    <Dropdown.Menu>
+                        {filterOptions.availableYears.sort().map((year) => (
+                            <div className="filter-dropdown-item" key={year} onClick={() => (handleYearClick(year))}>
+                                <input
+                                    type="checkbox"
+                                    checked={filterSelection.selectedYears.includes(year)}
+                                    readOnly
+                                /> {year}
+                            </div>
+                        ))}
+                    </Dropdown.Menu>
+                </Dropdown>
+            }
+
+        </ButtonToolbar>
+
     );
 }
 
diff --git a/webapp/src/scss/layout/_components.scss b/webapp/src/scss/layout/_components.scss
index 607885d9..58a20fb6 100644
--- a/webapp/src/scss/layout/_components.scss
+++ b/webapp/src/scss/layout/_components.scss
@@ -113,4 +113,34 @@
   align-items: center;
   padding-top: 20px;
   background-color: #3b536b;
-}
\ No newline at end of file
+}
+
+.filter-dropdown-item {
+  padding-left: 1rem;
+  cursor: pointer;
+}
+
+.filter-dropdown-item:hover {
+  background-color: var(--bs-dropdown-link-hover-bg);
+}
+
+.btn-compendium {
+  --bs-btn-color:#fff;
+  --bs-btn-bg:#003753;
+  --bs-btn-border-color:#003753;
+  --bs-btn-hover-color:#fff;
+  --bs-btn-hover-bg:#3b536b;
+  --bs-btn-hover-border-color:#3b536b;
+  --bs-btn-focus-shadow-rgb:49,132,253;
+  --bs-btn-active-color:#f5f5f5;
+  --bs-btn-active-bg:#3b536b;
+  --bs-btn-active-border-color:#003753;
+  --bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);
+  --bs-btn-disabled-color:#fff;
+  --bs-btn-disabled-bg:#0d6efd;
+  --bs-btn-disabled-border-color:#0d6efd
+}
+
+.fit-max-content {
+  min-width: max-content;
+}
-- 
GitLab