[frontend]: Prevent user from deselecting all filters in a group
This commit is contained in:
14
frontend/package-lock.json
generated
14
frontend/package-lock.json
generated
@ -23,6 +23,7 @@
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-leaflet-markercluster": "^5.0.0-rc.0",
|
||||
"react-router-dom": "^7.3.0",
|
||||
"react-toastify": "^11.0.5",
|
||||
"recharts": "^2.15.1",
|
||||
"tailwindcss": "^4.0.9"
|
||||
},
|
||||
@ -4459,6 +4460,19 @@
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-toastify": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz",
|
||||
"integrity": "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"clsx": "^2.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18 || ^19",
|
||||
"react-dom": "^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||
|
@ -25,6 +25,7 @@
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-leaflet-markercluster": "^5.0.0-rc.0",
|
||||
"react-router-dom": "^7.3.0",
|
||||
"react-toastify": "^11.0.5",
|
||||
"recharts": "^2.15.1",
|
||||
"tailwindcss": "^4.0.9"
|
||||
},
|
||||
|
@ -2,6 +2,9 @@ import React, { useState, useEffect, useMemo, useRef } from "react";
|
||||
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
import { ToastContainer } from 'react-toastify';
|
||||
import 'react-toastify/dist/ReactToastify.css';
|
||||
|
||||
import Navbar from "./components/Navbar";
|
||||
import Statistics from "./components/Statistics.jsx";
|
||||
import Help from "./components/Help.jsx";
|
||||
@ -441,6 +444,7 @@ function App() {
|
||||
}, [memoizedFilteredMarkers]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Router>
|
||||
<Navbar />
|
||||
<Routes>
|
||||
@ -497,6 +501,8 @@ function App() {
|
||||
<Route path="/help" element={<Help />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
<ToastContainer position="bottom-right"/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
export default App;
|
@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import PropTypes from 'prop-types';
|
||||
import Cookies from "js-cookie";
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
const menuData = [
|
||||
{
|
||||
@ -19,7 +20,7 @@ const menuData = [
|
||||
{ id: "terminated", name: "Terminated", endsec: true },
|
||||
{ id: "early", name: "Early" },
|
||||
{ id: "on-time", name: "On-time" },
|
||||
{ id: "late", name: "Late" },
|
||||
{ id: "late", name: "Late", endsec: true },
|
||||
],
|
||||
},
|
||||
{ id: "irish-rail-stations", name: "Irish Rail Stations" },
|
||||
@ -42,11 +43,22 @@ const menuData = [
|
||||
{ id: "enabled", name: "Enabled" },
|
||||
{ id: "disabled", name: "Disabled", endsec: true },
|
||||
{ id: "park-and-ride", name: "Must be Park & Ride" },
|
||||
{ id: "cycle-and-ride", name: "Must be Cycle & Ride" },
|
||||
{ id: "cycle-and-ride", name: "Must be Cycle & Ride", endsec: true },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const sectionGroups = [
|
||||
["irish-rail", "bus", "luas-stops"],
|
||||
["irish-rail-trains", "irish-rail-stations"],
|
||||
["mainline", "suburban", "dart"],
|
||||
["running", "not-yet-running", "terminated"],
|
||||
["early", "on-time", "late"],
|
||||
["buses", "bus-stops"],
|
||||
["red-line", "green-line"],
|
||||
["enabled", "disabled"],
|
||||
];
|
||||
|
||||
const customDefaultChecked = ["mainline","suburban","dart","running","not-yet-running","terminated","early","on-time","late","disabled","buses","irish-rail-trains","luas-stops","enabled","green-line","red-line","irish-rail","bus"]
|
||||
|
||||
const getAllDefaultCheckedIds = (data) => {
|
||||
@ -66,14 +78,26 @@ const getAllDefaultCheckedIds = (data) => {
|
||||
};
|
||||
|
||||
const CheckboxItem = ({ item, selectedSources, setSelectedSources, enabledSources, setEnabledSources, level = 0, parentChecked = true }) => {
|
||||
console.log("item id: " + item.id);
|
||||
console.log(selectedSources.includes(item.id));
|
||||
|
||||
const isChecked = selectedSources.includes(item.id);
|
||||
const isDisabled = !parentChecked; // Disable if any parent is not checked
|
||||
const isEnabled = isChecked && parentChecked; // Only enabled if checked and parent is checked
|
||||
|
||||
const handleCheckboxChange = () => {
|
||||
if (isChecked) {
|
||||
if (item.id != "park-and-ride" && item.id != "cycle-and-ride") {
|
||||
// Find which section this item is in
|
||||
const section = sectionGroups.find(group => group.includes(item.id));
|
||||
|
||||
if (section.length > 1) {
|
||||
const selectedInSection = section.filter(id => selectedSources.includes(id));
|
||||
if (selectedInSection.length === 1 && selectedInSection[0] === item.id) {
|
||||
toast.warn("At least one item in this section must be selected");
|
||||
return; // Don't allow unchecking the last one
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedSources((prev) =>
|
||||
isChecked
|
||||
? prev.filter((id) => id !== item.id)
|
||||
|
Reference in New Issue
Block a user