From f66832c7f3d724f30603e5e78b65f591f1589904 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 13 Oct 2024 22:45:34 +0100 Subject: [PATCH] retain toggle in dashboard, refresh when new devices loaded --- interface/src/app/main/Dashboard.tsx | 21 +++++++++++---------- interface/src/utils/index.ts | 1 + interface/src/utils/usePersistState.ts | 26 ++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 interface/src/utils/usePersistState.ts diff --git a/interface/src/app/main/Dashboard.tsx b/interface/src/app/main/Dashboard.tsx index dda4a907f..a2892d55c 100644 --- a/interface/src/app/main/Dashboard.tsx +++ b/interface/src/app/main/Dashboard.tsx @@ -24,7 +24,7 @@ import { useRequest } from 'alova/client'; import { FormLoader, SectionContent, useLayoutTitle } from 'components'; import { AuthenticatedContext } from 'contexts/authentication'; import { useI18nContext } from 'i18n/i18n-react'; -import { useInterval } from 'utils'; +import { useInterval, usePersistState } from 'utils'; import { readDashboard, writeDeviceValue } from '../../api/app'; import DeviceIcon from './DeviceIcon'; @@ -44,11 +44,10 @@ const Dashboard = () => { useLayoutTitle(LL.DASHBOARD()); - const [firstLoad, setFirstLoad] = useState(true); - const [showAll, setShowAll] = useState(true); + const [showAll, setShowAll] = usePersistState(true, 'showAll'); const [deviceValueDialogOpen, setDeviceValueDialogOpen] = useState(false); - + const [parentNodes, setParentNodes] = useState(0); const [selectedDashboardItem, setSelectedDashboardItem] = useState(); @@ -59,6 +58,10 @@ const Dashboard = () => { loading } = useRequest(readDashboard, { initialData: [] + }).onSuccess((event) => { + if (event.data.length > parentNodes) { + setParentNodes(event.data.length); // count number of parents/devices + } }); const { loading: submitting, send: sendDeviceValue } = useRequest( @@ -145,13 +148,11 @@ const Dashboard = () => { } }, 3000); - // auto expand on first load useEffect(() => { - if (firstLoad && Array.isArray(data) && data.length && !tree.state.ids.length) { - tree.fns.onToggleAll({}); - setFirstLoad(false); - } - }, [loading]); + showAll + ? tree.fns.onAddAll(data.map((item: DashboardItem) => item.id)) // expand tree + : tree.fns.onRemoveAll(); // collapse tree + }, [parentNodes]); const showType = (n?: string, t?: number) => { // if we have a name show it diff --git a/interface/src/utils/index.ts b/interface/src/utils/index.ts index e704f66e5..87fdbc07c 100644 --- a/interface/src/utils/index.ts +++ b/interface/src/utils/index.ts @@ -6,3 +6,4 @@ export * from './useRest'; export * from './useInterval'; export * from './props'; export * from './file'; +export * from './usePersistState'; diff --git a/interface/src/utils/usePersistState.ts b/interface/src/utils/usePersistState.ts new file mode 100644 index 000000000..d8cb8a19a --- /dev/null +++ b/interface/src/utils/usePersistState.ts @@ -0,0 +1,26 @@ +import { useEffect, useMemo, useState } from 'react'; + +export const usePersistState = ( + initial_value: T, + id: string +): [T, (new_state: T) => void] => { + // Set initial value + const _initial_value = useMemo(() => { + const local_storage_value_str = localStorage.getItem('state:' + id); + // If there is a value stored in localStorage, use that + if (local_storage_value_str) { + return JSON.parse(local_storage_value_str); + } + // Otherwise use initial_value that was passed to the function + return initial_value; + }, []); + + const [state, setState] = useState(_initial_value); + + useEffect(() => { + const state_str = JSON.stringify(state); // Stringified state + localStorage.setItem('state:' + id, state_str); // Set stringified state as item in localStorage + }, [state]); + + return [state, setState]; +};