diff --git a/package.json b/package.json index a5a602f1e6db0e8dd83a45310798ddc335498c17..02e778171b4975e640c0c4ceea8262be968ea7b6 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "dev:dego": "yarn pre-dev & NEXT_PUBLIC_CONFIG=dego next dev -p 3001", "dev:dego:windows": "yarn pre-dev-windows && set NEXT_PUBLIC_CONFIG=dego && next dev -p 3001", "dev:dook": "yarn pre-dev & NEXT_PUBLIC_CONFIG=dook next dev -p 3001", + "dev:dook:windows": "yarn pre-dev-windows && set NEXT_PUBLIC_CONFIG=dook && next dev -p 3001", "generate-authorizations": "sh generate-authorizations.sh", "build:demo": " cp .env.acc .env.local && next build && next export", "build:acc:dook": "cp .env.acc .env.local && NEXT_PUBLIC_CONFIG=dook next build && next export", diff --git a/src/components/menu-panel/layer/FilterHierarchy/InputBar.tsx b/src/components/menu-panel/layer/FilterHierarchy/InputBar.tsx index c316274f0cc86b87b58908c47c283c0768d39656..2775e008ed30eff9e4f62fe56bd60a85178c6bfc 100644 --- a/src/components/menu-panel/layer/FilterHierarchy/InputBar.tsx +++ b/src/components/menu-panel/layer/FilterHierarchy/InputBar.tsx @@ -6,14 +6,23 @@ import React, { FC, useEffect, useState } from 'react' import Input from '@commonground/design-system/dist/components/Form/TextInput/Input' import ResetIcon from '../../../../../public/images/close.svg' import * as Styled from '../../location-nav-bar/LocationNavBar.styled' -import { debounce } from '../../../../utils/debounce' import { getSbiCodes } from '../../../../services/sbi/get-sbi-codes' +export const debounce = (fn: Function, delay: number) => { + let timer: NodeJS.Timeout + return function debounced(...args: any[]) { + clearTimeout(timer) + timer = setTimeout(() => { + fn.apply(this, args) + }, delay) + } +} + interface InputBarProps { startText: string - setFilterList + setFilterList: Function searchText: string - setSearchText + setSearchText: Function } export const InputBar: FC = ({ @@ -26,7 +35,7 @@ export const InputBar: FC = ({ const handleClear = () => { setSearchText('') - setFilterList([]) + setFilterList(null) setIsValid(true) } @@ -34,34 +43,36 @@ export const InputBar: FC = ({ setSearchText(e.target.value) } - useEffect(() => { - const abortController = new AbortController() - const signal = abortController.signal - - const fetchData = debounce(async (text): Promise => { + const fetchData = debounce(async (signal: AbortSignal, text: string) => { + try { if (text.length) { - try { - const data = await getSbiCodes(text, signal) - - if (!data) { - return - } - - setFilterList(data.data) - setIsValid(true) - } catch (e) { + const data = await getSbiCodes(text, signal) + if (data === null) { if (!signal.aborted) { - setIsValid(false) - setFilterList([]) + setIsValid(false) // invalid search, but not due to abort because the user is still typing } + setFilterList(null) + return } - } else { - setFilterList([]) + setIsValid(true) + setFilterList(data?.data ?? []) + return } - }, 75) + } catch (e) { + if (!signal.aborted) { + setIsValid(false) + setFilterList(null) + } + } - fetchData(searchText) + setIsValid(true) + setFilterList(null) + }, 75) + useEffect(() => { + const abortController = new AbortController() + const signal = abortController.signal + fetchData(signal, searchText) return () => abortController.abort() }, [searchText]) diff --git a/src/components/menu-panel/layer/FilterHierarchy/TreeView.tsx b/src/components/menu-panel/layer/FilterHierarchy/TreeView.tsx index 26f41728b253c9874cdf9e26e2f51badbe96cf72..18ab4d0c7be7ea502ca445eeec71968fa2d0014d 100644 --- a/src/components/menu-panel/layer/FilterHierarchy/TreeView.tsx +++ b/src/components/menu-panel/layer/FilterHierarchy/TreeView.tsx @@ -37,7 +37,7 @@ export const TreeView = ({ id }) => { const [currentTree, setCurrentTree] = useState() const [allActive, setAllActive] = useState(false) - const [filterList, setFilterList] = useState([]) + const [filterList, setFilterList] = useState(null) const [searchText, setSearchText] = useState('') const [amountOfActiveNodes, setAmountOfActiveNodes] = useState(0) @@ -171,7 +171,7 @@ export const TreeView = ({ id }) => { if (currentTreeNode.isActive === 'partialActive') { currentTreeNode.isActive = 'notActive' - } else if (filterList.length > 0 && currentTreeNode.hasChildren) { + } else if (filterList?.length > 0 && currentTreeNode.hasChildren) { if (currentTreeNode.isActive === 'active') { currentTreeNode.isActive = 'notActive' } else if (currentTreeNode.isActive === 'notActive') { @@ -347,7 +347,7 @@ export const TreeView = ({ id }) => { return } // 0. RESET all nodes to being visible TRUE if there is no filter list. (default all on ) - if (filterList.length <= 0) { + if (!filterList) { const updatedTree: Tree = Object.fromEntries( Object.entries(currentTree).map(([key, node]) => [ key, @@ -355,23 +355,42 @@ export const TreeView = ({ id }) => { ]) ) setCurrentTree(updatedTree) + return // only reset, no filterlist } // 1. when there is a filterList: - if (filterList.length > 0) { - Object.entries(currentTree).reduce((prev, [key, treeNode]) => { - const newNode = treeNode - for (let i = 0; i < filterList.length; i++) { - if (treeNode.code?.toString() === filterList[i].code.toString()) { - newNode.isVisible = true - newNode.parentId && setParentsVisible(newNode.parentId, true) - return - } else { - newNode.isVisible = false + if (filterList?.length >= 0) { + const updatedTree: Tree = { ...currentTree } // copy current tree to update + + // set all nodes to not visible first + Object.keys(updatedTree).forEach((key) => { + updatedTree[key] = { ...updatedTree[key], isVisible: false } + }) + + // then set matching nodes and their parents to visible based on filterList + filterList.forEach((filterItem) => { + Object.keys(updatedTree).forEach((key) => { + const treeNode = updatedTree[key] + if (treeNode.code?.toString() === filterItem.code.toString()) { + // set matching node to visible + updatedTree[key] = { ...treeNode, isVisible: true } + + // also set all parent nodes visible too + let parentId = treeNode.parentId + while (parentId) { + const parentNode = updatedTree[parentId] + if (parentNode && !parentNode.isVisible) { + updatedTree[parentId] = { ...parentNode, isVisible: true } + parentId = parentNode.parentId + } else { + break + } + } } - } - return { ...prev, [key]: newNode } - }, {} as any) + }) + }) + + setCurrentTree(updatedTree) } }, [filterList]) @@ -384,12 +403,9 @@ export const TreeView = ({ id }) => { searchText={searchText} /> - {filterList.length > 0 && ( + {filterList?.length > 0 && ( - +

{filterList.length} resultaten tekst filter

)} diff --git a/src/providers/draw-provider.tsx b/src/providers/draw-provider.tsx index e61391fc5d3048d3fe2fa5f55eb5dc28c021d752..366e3f381359bfd734605ac036d6dbdc2078c055 100644 --- a/src/providers/draw-provider.tsx +++ b/src/providers/draw-provider.tsx @@ -8,7 +8,7 @@ import { Dispatch, SetStateAction, FC, createContext, useState } from 'react' export interface DrawContextProps { drawMode: 'initPoint' | 'initPolygons' | 'idle' | null setDrawMode: Dispatch> - featureCollection: Record + featureCollection: Record // TODO: change to GeoJSON.FeatureCollection setFeatureCollection?: Dispatch< SetStateAction > diff --git a/src/utils/debounce.ts b/src/utils/debounce.ts deleted file mode 100644 index 0cdcd15e25eb0ade61580e0ef54cf8892477bf0e..0000000000000000000000000000000000000000 --- a/src/utils/debounce.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright © VNG Realisatie 2023 -// Licensed under the EUPL -// - -type DebounceFunction any> = ( - fn: T, - delay: number -) => T - -export const debounce: DebounceFunction<(...args: any[]) => void> = ( - fn, - delay -) => { - let timeoutId: NodeJS.Timeout - - return function debounced(this: any, ...args: any[]) { - // eslint-disable-next-line @typescript-eslint/no-this-alias - const context = this - - clearTimeout(timeoutId) - - timeoutId = setTimeout(() => { - fn.apply(context, args) - }, delay) - } as any -}