diff --git a/src/Components/Chart.js b/src/Components/Chart.js
index ca3fc66..525606d 100644
--- a/src/Components/Chart.js
+++ b/src/Components/Chart.js
@@ -22,6 +22,7 @@ const url =
"api/dashboards.json?paging=false&fields=id,name,favorite,displayDescription,dashboardItems[id,resources[id, name],type,shape,x,y,width,height,text,visualization[id,displayName],map[id,displayName],eventReport[id,displayName],eventChart[id,displayName]]";
export default function Chart({
+ settings,
savedReports,
setSavedReports,
selectedSavedChart,
@@ -179,7 +180,10 @@ export default function Chart({
-
+
diff --git a/src/Components/Dashboard.js b/src/Components/Dashboard.js
index fb491c2..d915b89 100644
--- a/src/Components/Dashboard.js
+++ b/src/Components/Dashboard.js
@@ -8,6 +8,7 @@ import ReactGA from "react-ga4";
// import MapChart from "./MapChart";
import Footer from "./Footer";
import NavBar from "./AppBar";
+import useSettings from "../hooks/useSettings";
const chartData = {
headers: [
@@ -49,6 +50,9 @@ export default function Dashboard() {
const [savedReports, setSavedReports] = React.useState(
JSON.parse(localStorage.getItem("saved_reports"))
);
+
+ const settings = useSettings();
+
return (
{/* Chart */}
({
const OrgUnitFilter = (props) => {
const [expanded, setExpanded] = useState([]);
- const { selected, setSelected } = props;
+ const { selected, setSelected, settings } = props;
const [data, setData] = useState({ ...props.data });
const apiBase = process.env.REACT_APP_BASE_URI;
@@ -39,16 +39,25 @@ const OrgUnitFilter = (props) => {
return dataCache[nodeId];
}
- console.log("fetching...");
-
- const url = `${apiBase}api/organisationUnits/${nodeId}?fields=displayName,path,id,children%5Bid%2Cpath%2CdisplayName%5D`;
+ const url = `${apiBase}api/organisationUnits/${nodeId}?fields=displayName,level,path,id,children%5Bid%2Cpath%2CdisplayName%5D ${
+ settings?.orgUnitLimit?.level
+ ? `&filter=children.level:lt:${settings?.orgUnitLimit?.level}&filter=level:lt:${settings?.orgUnitLimit?.level}`
+ : ""
+ }`;
const response = await fetch(url);
if (!response.ok) {
throw new Error("Failed to fetch data");
}
- const fetchedData = await response.json();
- dataCache[nodeId] = fetchedData; // Cache the fetched data
- return fetchedData;
+ const dataLoaded = await response.text();
+
+ if ("" === dataLoaded) {
+ dataCache[nodeId] = {};
+ return dataCache[nodeId];
+ } else {
+ const fetchedData = JSON.parse(dataLoaded);
+ dataCache[nodeId] = fetchedData; // Cache the fetched data
+ return fetchedData;
+ }
};
const handleToggle = async (event, nodeIds) => {
@@ -56,11 +65,19 @@ const OrgUnitFilter = (props) => {
const nodeId = nodeIds;
const fetchedData = await fetchData(nodeId);
- const updatedDataChildren = await hasChildren(fetchedData.children);
- const updatedData = { ...fetchedData, children: updatedDataChildren };
- const paths = updatedData.path.split("/").slice(2);
- const newData = updateData(paths, updatedData);
- setData(newData);
+
+ if (
+ fetchedData &&
+ fetchedData?.children &&
+ fetchedData?.children?.length > 0
+ ) {
+ const updatedDataChildren = await hasChildren(fetchedData.children);
+ const updatedData = { ...fetchedData, children: updatedDataChildren };
+ const paths = updatedData?.path?.split("/")?.slice(2);
+ const newData = updateData(paths, updatedData);
+
+ setData(newData);
+ }
};
const updateData = (path, updatedData) => {
@@ -71,7 +88,7 @@ const OrgUnitFilter = (props) => {
return { ...node, children: updatedData.children };
}
- if (!node.children) {
+ if (!node.children || node.hasChildren === false) {
return node;
}
@@ -90,16 +107,31 @@ const OrgUnitFilter = (props) => {
};
const hasChildren = async (nodes) => {
+ const updatedNodes = [];
+
for (const node of nodes) {
- const urlChildren = `${apiBase}api/organisationUnits/${node.id}?fields=path,children%3A%3Asize`;
+ const urlChildren = `${apiBase}api/organisationUnits/${node.id}?fields=path,level,children%3A%3Asize`;
const response = await fetch(urlChildren);
+
if (!response.ok) {
throw new Error("Failed to fetch data");
}
- const data = await response.json();
- node.hasChildren = parseInt(data.children) > 0;
+
+ const dataLoaded = await response.text();
+
+ const updatedNode = { ...node };
+ if ("" === dataLoaded) {
+ updatedNode.hasChildren = false;
+ } else {
+ const data = JSON.parse(dataLoaded);
+ updatedNode.hasChildren =
+ parseInt(data.children) > 0 &&
+ data.level < settings?.orgUnitLimit?.level - 1;
+ }
+
+ updatedNodes.push(updatedNode);
}
- return nodes;
+ return updatedNodes;
};
const handleSelect = (event, nodeId) => {
diff --git a/src/Components/OrgUnitFilterModal.js b/src/Components/OrgUnitFilterModal.js
index 8cd4f45..f883277 100644
--- a/src/Components/OrgUnitFilterModal.js
+++ b/src/Components/OrgUnitFilterModal.js
@@ -12,8 +12,9 @@ import FilterListIcon from "@mui/icons-material/FilterList";
import IconButton from "@mui/material/IconButton";
import Badge from "@mui/material/Badge";
import Tooltip from "@mui/material/Tooltip";
+import useSetting from "../hooks/useSettings";
-const OrgUnitFilterModal = ({ onConfirmed }) => {
+const OrgUnitFilterModal = ({ onConfirmed, settings }) => {
const [open, setOpen] = useState(false);
const [data, setData] = useState(null);
const [orgUnitGroups, setOrgUnitGroups] = useState([]);
@@ -25,7 +26,11 @@ const OrgUnitFilterModal = ({ onConfirmed }) => {
const [hideEmptyCharts, setHideEmptyCharts] = useState(false);
const fetchData = async () => {
- const url = `${apiBase}api/organisationUnits/b3aCK1PTn5S?fields=displayName, path, id, children%5Bid%2Cpath%2CdisplayName%5D`;
+ const url = `${apiBase}api/organisationUnits/b3aCK1PTn5S?fields=displayName, path, id, children%5Bid%2Cpath%2CdisplayName%5D ${
+ settings?.orgUnitLimit?.level
+ ? `&filter=children.level:lt:${settings?.orgUnitLimit?.level}&filter=level:lt:${settings?.orgUnitLimit?.level}`
+ : ""
+ }`;
const response = await fetch(url);
if (!response.ok) {
throw new Error("Failed to fetch data");
@@ -47,36 +52,57 @@ const OrgUnitFilterModal = ({ onConfirmed }) => {
};
const fetchOrgUnitLevels = async () => {
- const url = `${apiBase}api/organisationUnitLevels?paging=false`;
+ console.log("settings loaded: ", settings);
+ const url = `${apiBase}api/organisationUnitLevels?paging=false${
+ settings?.orgUnitLimit?.level
+ ? `&filter=level:lt:${settings?.orgUnitLimit?.level}`
+ : ""
+ }`;
const response = await fetch(url);
if (!response.ok) {
throw new Error("Failed to fetch data");
}
-
const data = await response.json();
+
setOrgUnitLevels(data.organisationUnitLevels);
};
const hasChildren = async (nodes) => {
+ console.log("nodes:", nodes);
for (const node of nodes) {
- const urlChildren = `${apiBase}api/organisationUnits/${node.id}?fields=path,children%3A%3Asize`;
+ const urlChildren = `${apiBase}api/organisationUnits/${
+ node.id
+ }?fields=path,children%3A%3Asize${
+ settings?.orgUnitLimit?.level
+ ? `&filter=children.level:lt:${settings?.orgUnitLimit?.level}&filter=level:lt:${settings?.orgUnitLimit?.level}`
+ : ""
+ }`;
+
const response = await fetch(urlChildren);
if (!response.ok) {
throw new Error("Failed to fetch data");
}
- const data = await response.json();
- if (parseInt(data.children) > 0) {
- node.hasChildren = true;
+
+ let dataLoaded = await response.text();
+
+ if ("" === dataLoaded) {
+ node.hasChildren = false;
+ } else {
+ const data = JSON.parse(dataLoaded);
+ if (parseInt(data.children) > 0) {
+ node.hasChildren = true;
+ }
}
}
return nodes;
};
useEffect(() => {
+ if (settings === null) return;
fetchData();
fetchOrgUnitGroups();
fetchOrgUnitLevels();
- }, []);
+ }, [settings]);
const handleClickOpen = () => {
setOpen(true);
@@ -200,6 +226,7 @@ const OrgUnitFilterModal = ({ onConfirmed }) => {
setSelectedOrgUnitLevel={setSelectedOrgUnitLevel}
hideEmptyCharts={hideEmptyCharts}
setHideEmptyCharts={setHideEmptyCharts}
+ settings={settings}
/>
) : (
diff --git a/src/hooks/useSettings.js b/src/hooks/useSettings.js
new file mode 100644
index 0000000..66d7ccf
--- /dev/null
+++ b/src/hooks/useSettings.js
@@ -0,0 +1,29 @@
+// a hook to load settings from server dhis2 object store
+
+import { useEffect, useState } from "react";
+
+const apiBase = process.env.REACT_APP_BASE_URI;
+const useSettings = () => {
+ const [settings, setSettings] = useState(null);
+
+ useEffect(() => {
+ const fetchSettings = async () => {
+ try {
+ const response = await fetch(
+ apiBase + "api/dataStore/public-dashboard/settings"
+ );
+ const data = await response.json();
+ setSettings(data);
+ } catch (error) {
+ setSettings({});
+ console.error("Error fetching settings:", error);
+ }
+ };
+
+ fetchSettings();
+ }, []);
+
+ return settings;
+};
+
+export default useSettings;