From f99327e5569dd49fa5cf764991730bc2b4391d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Sun, 9 Apr 2023 20:14:33 +0200 Subject: [PATCH 01/13] offline can now return selections --- src/context/offline.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/context/offline.tsx b/src/context/offline.tsx index 67d57ef..11cd9da 100644 --- a/src/context/offline.tsx +++ b/src/context/offline.tsx @@ -41,8 +41,8 @@ interface OfflineState { remoteChecksums: Checksums | null; getImageData: (name: string) => Promise getBaselayer: (name: string) => Promise - createSelection: (treeIds: number[], title?: string) => Promise - updateSelection: (selection: InventorySelection) => Promise + createSelection: (treeIds: number[], title?: string) => Promise + updateSelection: (selection: InventorySelection) => Promise dropSelection: (selectionId: string) => Promise } @@ -289,7 +289,7 @@ export const OfflineProvider: React.FC = ({ children }) } - const createSelection = async (treeIds: number[], title?: string): Promise => { + const createSelection = async (treeIds: number[], title?: string): Promise => { // create a random 16 character string as id const id = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) @@ -304,7 +304,7 @@ export const OfflineProvider: React.FC = ({ children }) return updateSelection(selection) } - const updateSelection = async (selection: InventorySelection): Promise => { + const updateSelection = async (selection: InventorySelection): Promise => { // create the selections folder if it does not exist if (!fileInfos?.map(i => i.name).includes('selections')) { await Filesystem.mkdir({path: '/selections', directory: Directory.Data}) @@ -323,16 +323,16 @@ export const OfflineProvider: React.FC = ({ children }) // create the new array of selections let newSelections: InventorySelection[] = [] if (selections) { - newSelections = cloneDeep([...selections, selection]) + newSelections = cloneDeep([...selections, {...selection}]) } else { - newSelections = [selection] + newSelections = [{...selection}] } // update the selections state variable setSelections(newSelections) // return the local path - return path + return selection }) } From 7c0de16d19f3a85486fec9c1032caa8e3dfdefa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Sun, 9 Apr 2023 20:18:29 +0200 Subject: [PATCH 02/13] create the add function --- src/context/selection.tsx | 86 +++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/src/context/selection.tsx b/src/context/selection.tsx index 1d72ffa..de221fd 100644 --- a/src/context/selection.tsx +++ b/src/context/selection.tsx @@ -1,7 +1,6 @@ import bbox from "@turf/bbox"; import cloneDeep from "lodash.clonedeep"; import { createContext, useContext, useEffect, useState } from "react"; -import { useData } from "./data"; import { InventoryData } from "./data.model"; import { InventorySelection } from "./inventory-selection.model"; import { useOffline } from "./offline"; @@ -15,12 +14,14 @@ interface SelectionState { selections: InventorySelection[]; activeSelection: ActiveSelection | null; setActiveSelection: (selectionId: string | null) => void + addToActiveSelection: (treeId: number) => void } const initialState: SelectionState = { selections: [], activeSelection: null, - setActiveSelection: (selectionId: string | null) => {} + setActiveSelection: (selectionId: string | null) => {}, + addToActiveSelection: (treeId: number) => {} } // add the context @@ -30,11 +31,13 @@ const SelectionContext = createContext(initialState); export const SelectionProvider: React.FC = ({ children }) => { // create the state const [selections, setSelections] = useState(initialState.selections) + const [activeSelectionId, setActiveSelectionId] = useState(null) const [activeSelection, setActiveSelectionState] = useState(initialState.activeSelection) // get a reference to all inventory data - const { filteredInventory } = useData() - const {selections: offlineSelections} = useOffline() + const { inventory } = useOffline() + + const {selections: offlineSelections, createSelection} = useOffline() // subscribe to changes in offline selections useEffect(() => { @@ -45,40 +48,71 @@ export const SelectionProvider: React.FC = ({ children } }, [offlineSelections]) - // define the context functions + // setActiveSelection handler const setActiveSelection = (selectionId: string | null) => { - if (selectionId === null || !filteredInventory) { - setActiveSelectionState(null) + if (!selectionId) { + setActiveSelectionId(null) + } else { + setActiveSelectionId(selectionId) + } + } + + const addToActiveSelection = async (treeId: number) => { + // get the selection representation from the current data or create a new one + let selection: InventorySelection; + if (!activeSelection) { + selection = await createSelection([], `New Selection ${selections.length}`) } else { - const selection = selections.find(s => s.id === selectionId) + selection = activeSelection.selection + } + + // add the tree to selection + selection.treeIds.push(treeId) + + // build the geojson + const newActiveSelection = getSelectionWithGeoJSON(selection) + setActiveSelectionState(newActiveSelection) + } + + const getSelectionWithGeoJSON = (selection: InventorySelection): ActiveSelection => { + // filter the full inventory for any selected tree + const features = inventory?.features.filter(f => selection.treeIds.includes(Number(f.properties.treeid))) || [] + + // create the geojson + const data = { + type: 'FeatureCollection', + features: cloneDeep(features), + } as InventoryData + + // add the bounding box + data.bbox = bbox(data) + + return {selection: cloneDeep(selection), geoJSON: cloneDeep(data)} + } + + // use effect to update the current active selection, when the activeSelectionId or the filteredInventory changes + useEffect(() => { + if (!inventory) return + if (activeSelectionId) { + const selection = selections.find(s => s.id === activeSelectionId) if (selection) { - // extract the features from the inventory data that match the selection - const features = filteredInventory.features.filter(f => selection.treeIds.includes(Number(f.properties.treeid))) - - // create the geojson - const data = { - type: 'FeatureCollection', - features: cloneDeep(features), - } as InventoryData - - // add the bounding box - data.bbox = bbox(data) - - setActiveSelectionState({ - selection: cloneDeep(selection), - geoJSON: cloneDeep(data) - }) + const newActiveSelection = getSelectionWithGeoJSON(selection) + setActiveSelectionState(newActiveSelection) } else { setActiveSelectionState(null) } + } else { + setActiveSelectionState(null) } - } + }, [activeSelectionId, inventory]) + // create the context value const value = { selections, activeSelection, - setActiveSelection + setActiveSelection, + addToActiveSelection } // return the provider From 053483d732272775c93c0e4f3bbb4a619b61a69b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Mon, 10 Apr 2023 07:30:02 +0200 Subject: [PATCH 03/13] fix adding behavior --- src/context/offline.tsx | 2 +- src/context/selection.tsx | 33 +++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/context/offline.tsx b/src/context/offline.tsx index 11cd9da..96fa273 100644 --- a/src/context/offline.tsx +++ b/src/context/offline.tsx @@ -323,7 +323,7 @@ export const OfflineProvider: React.FC = ({ children }) // create the new array of selections let newSelections: InventorySelection[] = [] if (selections) { - newSelections = cloneDeep([...selections, {...selection}]) + newSelections = cloneDeep([...selections.filter(s => s.id !== selection.id), {...selection}]) } else { newSelections = [{...selection}] } diff --git a/src/context/selection.tsx b/src/context/selection.tsx index de221fd..5624d33 100644 --- a/src/context/selection.tsx +++ b/src/context/selection.tsx @@ -1,6 +1,6 @@ import bbox from "@turf/bbox"; import cloneDeep from "lodash.clonedeep"; -import { createContext, useContext, useEffect, useState } from "react"; +import { createContext, useCallback, useContext, useEffect, useState } from "react"; import { InventoryData } from "./data.model"; import { InventorySelection } from "./inventory-selection.model"; import { useOffline } from "./offline"; @@ -37,7 +37,7 @@ export const SelectionProvider: React.FC = ({ children // get a reference to all inventory data const { inventory } = useOffline() - const {selections: offlineSelections, createSelection} = useOffline() + const {selections: offlineSelections, createSelection, updateSelection} = useOffline() // subscribe to changes in offline selections useEffect(() => { @@ -58,23 +58,32 @@ export const SelectionProvider: React.FC = ({ children } const addToActiveSelection = async (treeId: number) => { + // skip if the treeId is already selection + if (activeSelection && activeSelection.selection.treeIds.includes(treeId)) { + return + } // get the selection representation from the current data or create a new one let selection: InventorySelection; if (!activeSelection) { - selection = await createSelection([], `New Selection ${selections.length}`) + // create a new selection + selection = await createSelection([treeId], `New Selection ${selections.length}`) } else { - selection = activeSelection.selection + // update + activeSelection.selection.treeIds.push(treeId) + selection = await updateSelection(activeSelection.selection) } - // add the tree to selection - selection.treeIds.push(treeId) - // build the geojson - const newActiveSelection = getSelectionWithGeoJSON(selection) - setActiveSelectionState(newActiveSelection) + // const newActiveSelection = getSelectionWithGeoJSON(selection) + // setActiveSelectionState(newActiveSelection) + + // set the selection active if it was not + // if (activeSelectionId !== selection.id) { + setActiveSelectionId(selection.id) + // } } - const getSelectionWithGeoJSON = (selection: InventorySelection): ActiveSelection => { + const getSelectionWithGeoJSON = useCallback((selection: InventorySelection): ActiveSelection => { // filter the full inventory for any selected tree const features = inventory?.features.filter(f => selection.treeIds.includes(Number(f.properties.treeid))) || [] @@ -88,7 +97,7 @@ export const SelectionProvider: React.FC = ({ children data.bbox = bbox(data) return {selection: cloneDeep(selection), geoJSON: cloneDeep(data)} - } + }, [selections]) // use effect to update the current active selection, when the activeSelectionId or the filteredInventory changes useEffect(() => { @@ -104,7 +113,7 @@ export const SelectionProvider: React.FC = ({ children } else { setActiveSelectionState(null) } - }, [activeSelectionId, inventory]) + }, [activeSelectionId, inventory, selections]) // create the context value From 976d7eb4b046277ef2b2c5718ad9d7bde0f4c879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Mon, 10 Apr 2023 07:30:34 +0200 Subject: [PATCH 04/13] add a bookmark just somewhere --- src/components/TreeDetails.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/components/TreeDetails.tsx b/src/components/TreeDetails.tsx index b247470..dc9eba2 100644 --- a/src/components/TreeDetails.tsx +++ b/src/components/TreeDetails.tsx @@ -1,4 +1,6 @@ import { + IonButton, + IonButtons, IonCard, IonCardContent, IonCardHeader, @@ -6,6 +8,7 @@ import { IonCardTitle, IonCol, IonGrid, + IonIcon, IonItem, IonLabel, IonNote, @@ -13,12 +16,14 @@ import { IonSegment, IonSegmentButton, } from "@ionic/react"; +import { bookmarkOutline } from "ionicons/icons"; import { Data, Layout } from "plotly.js"; import { useEffect, useState } from "react"; import Plot from "react-plotly.js"; import { useData } from "../context/data"; import { InventoryFeature } from "../context/data.model"; import { useOffline } from "../context/offline"; +import { useSelection } from "../context/selection"; import * as plot from "../util/plot"; import "./TreeDetails.css"; @@ -61,6 +66,9 @@ const TreeDetails: React.FC = ({ treeID }) => { // load all inventory data const { filteredInventory, allInventory } = useData(); + // get selection functions + const { addToActiveSelection } = useSelection() + // compnent state to store this feature const [feature, setFeature] = useState(); const [currentImg, setCurrentImg] = useState(); @@ -137,6 +145,14 @@ const TreeDetails: React.FC = ({ treeID }) => { return ( <> {/* Overview */} + + + addToActiveSelection(treeID)}> + + + + + From 78223f96f120f2bec36a36431134889c67f8231a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Sun, 23 Apr 2023 10:42:39 +0200 Subject: [PATCH 05/13] wire up bookmark button --- src/components/InventoryList.tsx | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/components/InventoryList.tsx b/src/components/InventoryList.tsx index 0e590e5..26d9462 100644 --- a/src/components/InventoryList.tsx +++ b/src/components/InventoryList.tsx @@ -10,6 +10,7 @@ import { } from "@ionic/react"; import { bookmarkOutline, + bookmark, navigate, swapVerticalOutline, arrowDownOutline, @@ -24,6 +25,7 @@ import { useSettings } from "../context/settings"; import { InventoryFeature } from "../context/data.model"; import "./InventoryList.css"; +import { useSelection } from "../context/selection"; const InventoryList: React.FC = () => { // load the filtered inventory list @@ -35,6 +37,9 @@ const InventoryList: React.FC = () => { setSortDirection } = useData(); + // get selection functions + const { addToActiveSelection, activeSelection } = useSelection() + // get a history context const history = useHistory(); @@ -76,10 +81,16 @@ const InventoryList: React.FC = () => { }; const addToBookmarksHandler = ( - event: React.MouseEvent + event: React.MouseEvent, + treeId: number ) => { + // stop event propagation event.stopPropagation(); - console.log("add to bookmarks"); + + // add to active selection + addToActiveSelection(treeId) + + //console.log("add to bookmarks"); }; return ( @@ -145,8 +156,8 @@ const InventoryList: React.FC = () => { {distString(f)}

- addToBookmarksHandler(e)}> - + addToBookmarksHandler(e, f.properties.treeid)} disabled={activeSelection?.selection.treeIds.includes(f.properties.treeid)} > + ); From 3c3a36f457cff86dc58426919632a891a5000815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Sun, 23 Apr 2023 11:04:21 +0200 Subject: [PATCH 06/13] remove function for current selection --- src/context/selection.tsx | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/context/selection.tsx b/src/context/selection.tsx index 5624d33..ac8bf11 100644 --- a/src/context/selection.tsx +++ b/src/context/selection.tsx @@ -14,14 +14,16 @@ interface SelectionState { selections: InventorySelection[]; activeSelection: ActiveSelection | null; setActiveSelection: (selectionId: string | null) => void - addToActiveSelection: (treeId: number) => void + addToActiveSelection: (treeId: number) => Promise + removeFromActiveSelection: (treeID: number) => Promise } const initialState: SelectionState = { selections: [], activeSelection: null, setActiveSelection: (selectionId: string | null) => {}, - addToActiveSelection: (treeId: number) => {} + addToActiveSelection: (treeId: number) => Promise.reject('Not implemented.'), + removeFromActiveSelection: (treeID: number) => Promise.reject('Not implemented.'), } // add the context @@ -57,7 +59,7 @@ export const SelectionProvider: React.FC = ({ children } } - const addToActiveSelection = async (treeId: number) => { + const addToActiveSelection = async (treeId: number): Promise => { // skip if the treeId is already selection if (activeSelection && activeSelection.selection.treeIds.includes(treeId)) { return @@ -83,6 +85,22 @@ export const SelectionProvider: React.FC = ({ children // } } + const removeFromActiveSelection = async (treeId: number): Promise => { + // skip if the treeId is not in selection + if (activeSelection && !activeSelection.selection.treeIds.includes(treeId)) { + return Promise.reject(`Tree ID=${treeId} is not in the active selection.`) + } + + // remove the treeId + const newTreeIds = activeSelection?.selection.treeIds.filter(id => id !== treeId) || [] + + // update the selection + const selection = await updateSelection({...activeSelection!.selection, treeIds: newTreeIds}) + + // set the selection as the new active selection + setActiveSelectionId(selection.id) + } + const getSelectionWithGeoJSON = useCallback((selection: InventorySelection): ActiveSelection => { // filter the full inventory for any selected tree const features = inventory?.features.filter(f => selection.treeIds.includes(Number(f.properties.treeid))) || [] @@ -121,7 +139,8 @@ export const SelectionProvider: React.FC = ({ children selections, activeSelection, setActiveSelection, - addToActiveSelection + addToActiveSelection, + removeFromActiveSelection } // return the provider From b27bfa6f56a405b3f618db274209c3e131543aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Sun, 23 Apr 2023 11:04:39 +0200 Subject: [PATCH 07/13] wire-up remove functions --- src/components/InventoryList.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/components/InventoryList.tsx b/src/components/InventoryList.tsx index 26d9462..fc6599c 100644 --- a/src/components/InventoryList.tsx +++ b/src/components/InventoryList.tsx @@ -10,7 +10,7 @@ import { } from "@ionic/react"; import { bookmarkOutline, - bookmark, + banOutline, navigate, swapVerticalOutline, arrowDownOutline, @@ -38,7 +38,7 @@ const InventoryList: React.FC = () => { } = useData(); // get selection functions - const { addToActiveSelection, activeSelection } = useSelection() + const { addToActiveSelection, removeFromActiveSelection, activeSelection } = useSelection() // get a history context const history = useHistory(); @@ -87,8 +87,12 @@ const InventoryList: React.FC = () => { // stop event propagation event.stopPropagation(); - // add to active selection - addToActiveSelection(treeId) + // check if this treeId is already in the selection + if (activeSelection?.selection.treeIds.includes(treeId)) { + removeFromActiveSelection(treeId) + } else { + addToActiveSelection(treeId) + } //console.log("add to bookmarks"); }; @@ -156,8 +160,11 @@ const InventoryList: React.FC = () => { {distString(f)}

- addToBookmarksHandler(e, f.properties.treeid)} disabled={activeSelection?.selection.treeIds.includes(f.properties.treeid)} > - + addToBookmarksHandler(e, f.properties.treeid)} + > + ); From 29fb8e04995feaecc5356a7efdf4c9f3b55221fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Sun, 23 Apr 2023 13:17:49 +0200 Subject: [PATCH 08/13] fix string type treeIds --- src/context/selection.tsx | 42 ++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/context/selection.tsx b/src/context/selection.tsx index ac8bf11..02fe23d 100644 --- a/src/context/selection.tsx +++ b/src/context/selection.tsx @@ -14,16 +14,16 @@ interface SelectionState { selections: InventorySelection[]; activeSelection: ActiveSelection | null; setActiveSelection: (selectionId: string | null) => void - addToActiveSelection: (treeId: number) => Promise - removeFromActiveSelection: (treeID: number) => Promise + addToActiveSelection: (treeId: number | string) => Promise + removeFromActiveSelection: (treeID: number | string) => Promise } const initialState: SelectionState = { selections: [], activeSelection: null, setActiveSelection: (selectionId: string | null) => {}, - addToActiveSelection: (treeId: number) => Promise.reject('Not implemented.'), - removeFromActiveSelection: (treeID: number) => Promise.reject('Not implemented.'), + addToActiveSelection: (treeId: number | string) => Promise.reject('Not implemented.'), + removeFromActiveSelection: (treeID: number | string) => Promise.reject('Not implemented.'), } // add the context @@ -59,35 +59,35 @@ export const SelectionProvider: React.FC = ({ children } } - const addToActiveSelection = async (treeId: number): Promise => { + const addToActiveSelection = async (treeId: number | string): Promise => { // skip if the treeId is already selection - if (activeSelection && activeSelection.selection.treeIds.includes(treeId)) { - return + if (activeSelection && activeSelection.selection.treeIds.includes(Number(treeId))) { + return Promise.reject(`The tree ID=${treeId} is already part of the current selection`) } // get the selection representation from the current data or create a new one let selection: InventorySelection; if (!activeSelection) { // create a new selection - selection = await createSelection([treeId], `New Selection ${selections.length}`) + selection = await createSelection([Number(treeId)], `New Selection ${selections.length}`) } else { // update - activeSelection.selection.treeIds.push(treeId) + activeSelection.selection.treeIds.push(Number(treeId)) selection = await updateSelection(activeSelection.selection) } // build the geojson - // const newActiveSelection = getSelectionWithGeoJSON(selection) - // setActiveSelectionState(newActiveSelection) + const newActiveSelection = getSelectionWithGeoJSON(selection) + setActiveSelectionState(newActiveSelection) // set the selection active if it was not - // if (activeSelectionId !== selection.id) { + if (activeSelectionId !== selection.id) { setActiveSelectionId(selection.id) - // } + } } - const removeFromActiveSelection = async (treeId: number): Promise => { + const removeFromActiveSelection = async (treeId: number | string): Promise => { // skip if the treeId is not in selection - if (activeSelection && !activeSelection.selection.treeIds.includes(treeId)) { + if (activeSelection && !activeSelection.selection.treeIds.includes(Number(treeId))) { return Promise.reject(`Tree ID=${treeId} is not in the active selection.`) } @@ -97,8 +97,14 @@ export const SelectionProvider: React.FC = ({ children // update the selection const selection = await updateSelection({...activeSelection!.selection, treeIds: newTreeIds}) + // build the geoJSON + const newActiveSelection = getSelectionWithGeoJSON(selection) + setActiveSelectionState(newActiveSelection) + // set the selection as the new active selection - setActiveSelectionId(selection.id) + if (activeSelectionId !== selection.id) { + setActiveSelectionId(selection.id) + } } const getSelectionWithGeoJSON = useCallback((selection: InventorySelection): ActiveSelection => { @@ -115,7 +121,7 @@ export const SelectionProvider: React.FC = ({ children data.bbox = bbox(data) return {selection: cloneDeep(selection), geoJSON: cloneDeep(data)} - }, [selections]) + }, [inventory]) // use effect to update the current active selection, when the activeSelectionId or the filteredInventory changes useEffect(() => { @@ -131,7 +137,7 @@ export const SelectionProvider: React.FC = ({ children } else { setActiveSelectionState(null) } - }, [activeSelectionId, inventory, selections]) + }, [activeSelectionId, inventory, selections, getSelectionWithGeoJSON]) // create the context value From 6e01a33bc91684172db245138bd7786e734a69b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Sun, 23 Apr 2023 13:17:58 +0200 Subject: [PATCH 09/13] cleanup --- src/components/map-components/InventorySource.tsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/components/map-components/InventorySource.tsx b/src/components/map-components/InventorySource.tsx index 235a2eb..bb22419 100644 --- a/src/components/map-components/InventorySource.tsx +++ b/src/components/map-components/InventorySource.tsx @@ -6,18 +6,8 @@ import { Source, Layer, useMap } from "react-map-gl"; import { useData } from "../../context/data"; import { InventoryData, InventoryFeature } from "../../context/data.model"; import { useLayers } from "../../context/layers"; -import { - IonCard, - IonCardContent, - IonCardHeader, - IonCardTitle, - IonItem, - IonLabel, - IonPopover, -} from "@ionic/react"; import { useHistory } from "react-router"; import { useOffline } from "../../context/offline"; -import bbox from "@turf/bbox"; const InventoryLayer: React.FC = () => { const { From 809f7cce047b46fe5e61c45102c2d206d055a2fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Sun, 23 Apr 2023 13:18:09 +0200 Subject: [PATCH 10/13] add processing state --- src/components/InventoryList.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/components/InventoryList.tsx b/src/components/InventoryList.tsx index fc6599c..26e31d3 100644 --- a/src/components/InventoryList.tsx +++ b/src/components/InventoryList.tsx @@ -6,6 +6,7 @@ import { IonLabel, IonList, IonListHeader, + IonSpinner, IonThumbnail, } from "@ionic/react"; import { @@ -26,8 +27,12 @@ import { InventoryFeature } from "../context/data.model"; import "./InventoryList.css"; import { useSelection } from "../context/selection"; +import { useState } from "react"; const InventoryList: React.FC = () => { + // add a state for processing selections + const [selectionProcessing, setSelectionProcessing] = useState(false) + // load the filtered inventory list const { filteredInventory, @@ -84,14 +89,17 @@ const InventoryList: React.FC = () => { event: React.MouseEvent, treeId: number ) => { + // set selection processing + setSelectionProcessing(true) + // stop event propagation event.stopPropagation(); // check if this treeId is already in the selection if (activeSelection?.selection.treeIds.includes(treeId)) { - removeFromActiveSelection(treeId) + removeFromActiveSelection(treeId).finally(() => setSelectionProcessing(false)) } else { - addToActiveSelection(treeId) + addToActiveSelection(treeId).finally(() => setSelectionProcessing(false)) } //console.log("add to bookmarks"); @@ -162,9 +170,11 @@ const InventoryList: React.FC = () => { addToBookmarksHandler(e, f.properties.treeid)} + onClick={e => addToBookmarksHandler(e, Number(f.properties.treeid))} > - + { selectionProcessing ? : ( + + )} ); From 09afce8c12ea2c6d3935defcff238cc3f5833558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Sun, 23 Apr 2023 13:18:18 +0200 Subject: [PATCH 11/13] add a selection source --- .../map-components/SelectionSource.tsx | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/components/map-components/SelectionSource.tsx diff --git a/src/components/map-components/SelectionSource.tsx b/src/components/map-components/SelectionSource.tsx new file mode 100644 index 0000000..5f8c347 --- /dev/null +++ b/src/components/map-components/SelectionSource.tsx @@ -0,0 +1,47 @@ +import cloneDeep from "lodash.clonedeep" +import { useEffect, useState } from "react" +import { Layer, Source } from "react-map-gl" +import { InventoryData } from "../../context/data.model" +import { useSelection } from "../../context/selection" + +const SelectionSource: React.FC = () => { + // define a component state for the selection GeoJSON + const [src, setSrc] = useState() + + // subscribe to the current active selection + const { activeSelection } = useSelection() + + // update component state when activeSelection changes + useEffect(() => { + if (activeSelection) { + console.log(activeSelection) + setSrc(cloneDeep(activeSelection.geoJSON)) + } else { + setSrc(undefined) + } + }, [activeSelection]) + + // if there is no source, return null + console.log(src) + if (!src) { + return ( + null + ) + } else { + return ( + + + + ) + } +} + +export default SelectionSource \ No newline at end of file From cc520cbca8de15771a6a6733f8cb7a6deba53c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Sun, 23 Apr 2023 13:18:25 +0200 Subject: [PATCH 12/13] enabled selection source --- src/components/map-components/MainMapMaplibre.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/map-components/MainMapMaplibre.tsx b/src/components/map-components/MainMapMaplibre.tsx index 3b82c2a..7154127 100644 --- a/src/components/map-components/MainMapMaplibre.tsx +++ b/src/components/map-components/MainMapMaplibre.tsx @@ -8,6 +8,7 @@ import InventorySource from "./InventorySource"; import BaseLayerSource from "./BaseLayerSource"; import UserLocationSource from "./UserLocationSource"; import LayerInteraction from "./LayerInteraction"; +import SelectionSource from "./SelectionSource"; const MainMap: React.FC = () => { // onload callback handler @@ -75,6 +76,7 @@ const MainMap: React.FC = () => { > + From dae0730fcefbc85ce304d3deca536a40d0a8c2b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Sun, 23 Apr 2023 13:19:01 +0200 Subject: [PATCH 13/13] remove old console.log --- src/components/map-components/SelectionSource.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/map-components/SelectionSource.tsx b/src/components/map-components/SelectionSource.tsx index 5f8c347..2e28cf1 100644 --- a/src/components/map-components/SelectionSource.tsx +++ b/src/components/map-components/SelectionSource.tsx @@ -14,7 +14,6 @@ const SelectionSource: React.FC = () => { // update component state when activeSelection changes useEffect(() => { if (activeSelection) { - console.log(activeSelection) setSrc(cloneDeep(activeSelection.geoJSON)) } else { setSrc(undefined) @@ -22,7 +21,6 @@ const SelectionSource: React.FC = () => { }, [activeSelection]) // if there is no source, return null - console.log(src) if (!src) { return ( null