diff --git a/package-lock.json b/package-lock.json index 86f3a0b1..712f57a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "utopia-ui", - "version": "3.0.86", + "version": "3.0.93", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "utopia-ui", - "version": "3.0.86", + "version": "3.0.93", "license": "GPL-3.0-only", "dependencies": { "@heroicons/react": "^2.0.17", diff --git a/package.json b/package.json index b8309549..aa2efef2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "utopia-ui", - "version": "3.0.86", + "version": "3.0.93", "description": "Reuseable React Components to build mapping apps for real life communities and networks", "repository": "https://github.com/utopia-os/utopia-ui", "homepage": "https://utopia-os.org/", diff --git a/src/Components/Map/Subcomponents/Controls/LayerControl.tsx b/src/Components/Map/Subcomponents/Controls/LayerControl.tsx index 64d60b95..10180de0 100644 --- a/src/Components/Map/Subcomponents/Controls/LayerControl.tsx +++ b/src/Components/Map/Subcomponents/Controls/LayerControl.tsx @@ -5,8 +5,8 @@ import LayerSVG from '#assets/layer.svg' import { useIsLayerVisible, useToggleVisibleLayer } from '#components/Map/hooks/useFilter' import { useLayers } from '#components/Map/hooks/useLayers' -export function LayerControl() { - const [open, setOpen] = useState(false) +export function LayerControl({ expandLayerControl = false }: { expandLayerControl: boolean }) { + const [open, setOpen] = useState(expandLayerControl) const layers = useLayers() diff --git a/src/Components/Map/Subcomponents/ItemFormPopup.tsx b/src/Components/Map/Subcomponents/ItemFormPopup.tsx index d37d1fe6..572bfa58 100644 --- a/src/Components/Map/Subcomponents/ItemFormPopup.tsx +++ b/src/Components/Map/Subcomponents/ItemFormPopup.tsx @@ -101,9 +101,7 @@ export function ItemFormPopup(props: Props) { setSpinner(false) map.closePopup() } else { - const item = items.find( - (i) => i.user_created?.id === user?.id && i.layer?.id === popupForm.layer.id, - ) + const item = items.find((i) => i.user_created?.id === user?.id && i.layer === popupForm.layer) const uuid = crypto.randomUUID() let success = false diff --git a/src/Components/Map/Tags.tsx b/src/Components/Map/Tags.tsx index fb435f1a..11de83b7 100644 --- a/src/Components/Map/Tags.tsx +++ b/src/Components/Map/Tags.tsx @@ -1,8 +1,6 @@ import { useEffect } from 'react' -import { useLocation } from 'react-router-dom' -import { useAddFilterTag, useFilterTags, useResetFilterTags } from './hooks/useFilter' -import { useSetTagData, useSetTagApi, useTags } from './hooks/useTags' +import { useSetTagData, useSetTagApi } from './hooks/useTags' import type { ItemsApi } from '#types/ItemsApi' import type { Tag } from '#types/Tag' @@ -42,36 +40,5 @@ export function Tags({ data, api }: { data?: Tag[]; api?: ItemsApi }) { // eslint-disable-next-line react-hooks/exhaustive-deps }, [api, data]) - const location = useLocation() - const addFilterTag = useAddFilterTag() - const resetFilterTags = useResetFilterTags() - const tags = useTags() - const filterTags = useFilterTags() - - useEffect(() => { - const params = new URLSearchParams(location.search) - const urlTags = params.get('tags') - const decodedTags = urlTags ? decodeURIComponent(urlTags) : '' - const decodedTagsArray = decodedTags.split(';') - if ( - decodedTagsArray.some( - (ut) => !filterTags.find((ft) => ut.toLocaleLowerCase() === ft.name.toLocaleLowerCase()), - ) || - filterTags.some( - (ft) => - !decodedTagsArray.find((ut) => ut.toLocaleLowerCase() === ft.name.toLocaleLowerCase()), - ) - ) { - resetFilterTags() - decodedTagsArray.map((urlTag) => { - const tag = tags.find((t) => t.name.toLocaleLowerCase() === urlTag.toLocaleLowerCase()) - tag && addFilterTag(tag) - return null - }) - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [location, tags]) - return <> } diff --git a/src/Components/Map/UtopiaMap.tsx b/src/Components/Map/UtopiaMap.tsx index 19f81152..da909e3b 100644 --- a/src/Components/Map/UtopiaMap.tsx +++ b/src/Components/Map/UtopiaMap.tsx @@ -55,6 +55,7 @@ function UtopiaMap({ showThemeControl = false, defaultTheme, donationWidget, + expandLayerControl, }: { /** height of the map (default '500px') */ height?: string @@ -82,6 +83,8 @@ function UtopiaMap({ defaultTheme?: string /** ask to donate to the Utopia Project OpenCollective campaign (default false) */ donationWidget?: boolean + /** open layer control on map initialisation */ + expandLayerControl?: boolean }) { return ( @@ -100,6 +103,7 @@ function UtopiaMap({ donationWidget={donationWidget} showThemeControl={showThemeControl} defaultTheme={defaultTheme} + expandLayerControl={expandLayerControl} > {children} diff --git a/src/Components/Map/UtopiaMapInner.tsx b/src/Components/Map/UtopiaMapInner.tsx index 64860a1a..c099915d 100644 --- a/src/Components/Map/UtopiaMapInner.tsx +++ b/src/Components/Map/UtopiaMapInner.tsx @@ -17,7 +17,13 @@ import { useTheme } from '#components/AppShell/hooks/useTheme' import { containsUUID } from '#utils/ContainsUUID' import { useClusterRef, useSetClusterRef } from './hooks/useClusterRef' -import { useAddVisibleLayer } from './hooks/useFilter' +import { + useAddFilterTag, + useAddVisibleLayer, + useFilterTags, + useResetFilterTags, + useToggleVisibleLayer, +} from './hooks/useFilter' import { useLayers } from './hooks/useLayers' import { useLeafletRefs } from './hooks/useLeafletRefs' import { usePopupForm } from './hooks/usePopupForm' @@ -26,6 +32,7 @@ import { useSetMapClicked, useSetSelectPosition, } from './hooks/useSelectPosition' +import { useTags } from './hooks/useTags' import AddButton from './Subcomponents/AddButton' import { Control } from './Subcomponents/Controls/Control' import { FilterControl } from './Subcomponents/Controls/FilterControl' @@ -47,6 +54,7 @@ export function UtopiaMapInner({ showThemeControl = false, defaultTheme = '', donationWidget, + expandLayerControl, }: { children?: React.ReactNode geo?: GeoJsonObject @@ -56,6 +64,7 @@ export function UtopiaMapInner({ donationWidget?: boolean showThemeControl?: boolean defaultTheme?: string + expandLayerControl?: boolean }) { const selectNewItemPosition = useSelectPosition() const setSelectNewItemPosition = useSetSelectPosition() @@ -198,6 +207,63 @@ export function UtopiaMapInner({ } } + const addFilterTag = useAddFilterTag() + const resetFilterTags = useResetFilterTags() + const tags = useTags() + const filterTags = useFilterTags() + + useEffect(() => { + const params = new URLSearchParams(location.search) + const urlTags = params.get('tags') + const decodedTags = urlTags ? decodeURIComponent(urlTags) : '' + const decodedTagsArray = decodedTags.split(';').filter(Boolean) + + const urlDiffersFromState = + decodedTagsArray.some( + (ut) => !filterTags.find((ft) => ut.toLowerCase() === ft.name.toLowerCase()), + ) || + filterTags.some( + (ft) => !decodedTagsArray.find((ut) => ut.toLowerCase() === ft.name.toLowerCase()), + ) + + if (urlDiffersFromState) { + resetFilterTags() + decodedTagsArray.forEach((urlTag) => { + const match = tags.find((t) => t.name.toLowerCase() === urlTag.toLowerCase()) + if (match) addFilterTag(match) + }) + } + }, [location, tags, filterTags, addFilterTag, resetFilterTags]) + + const toggleVisibleLayer = useToggleVisibleLayer() + const allLayers = useLayers() + + const initializedRef = useRef(false) + + useEffect(() => { + if (initializedRef.current || allLayers.length === 0) return + + const params = new URLSearchParams(location.search) + const urlLayersParam = params.get('layers') + if (!urlLayersParam) { + initializedRef.current = true + return + } + + const urlLayerNames = urlLayersParam.split(',').filter(Boolean) + + const layerNamesToHide = allLayers + .map((l) => l.name) + .filter((name) => !urlLayerNames.includes(name)) + + layerNamesToHide.forEach((name) => { + const match = allLayers.find((l) => l.name === name) + if (match) toggleVisibleLayer(match) + }) + + initializedRef.current = true + }, [location, allLayers, toggleVisibleLayer]) + return (
@@ -207,7 +273,7 @@ export function UtopiaMapInner({ {showFilterControl && } - {showLayerControl && } + {showLayerControl && } {showGratitudeControl && } { + if (allLayers.length === 0) return + + const visibleNames = visibleLayers.map((l) => l.name) + const allNames = allLayers.map((l) => l.name) + const params = new URLSearchParams(location.search) + + const allVisible = + visibleNames.length === allNames.length && + visibleNames.every((name) => allNames.includes(name)) + + if (allVisible) { + params.delete('layers') + } else { + params.set('layers', visibleNames.join(',')) + } + + navigate(`${location.pathname}?${params.toString()}`, { replace: true }) + }, [visibleLayers, allLayers, navigate]) + const [visibleGroupTypes, dispatchGroupTypes] = useReducer( (state: string[], action: ActionType) => { switch (action.type) { diff --git a/src/types/UtopiaMapProps.d.ts b/src/types/UtopiaMapProps.d.ts index 664bdac6..3d85374e 100644 --- a/src/types/UtopiaMapProps.d.ts +++ b/src/types/UtopiaMapProps.d.ts @@ -17,4 +17,5 @@ export interface UtopiaMapProps { infoText?: string donationWidget?: boolean defaultTheme?: string + expandLayerControl?: boolean }