Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions src/components/InventoryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import {
IonLabel,
IonList,
IonListHeader,
IonSpinner,
IonThumbnail,
} from "@ionic/react";
import {
bookmarkOutline,
banOutline,
navigate,
swapVerticalOutline,
arrowDownOutline,
Expand All @@ -24,8 +26,13 @@ import { useSettings } from "../context/settings";
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<boolean>(false)

// load the filtered inventory list
const {
filteredInventory,
Expand All @@ -35,6 +42,9 @@ const InventoryList: React.FC = () => {
setSortDirection
} = useData();

// get selection functions
const { addToActiveSelection, removeFromActiveSelection, activeSelection } = useSelection()

// get a history context
const history = useHistory();

Expand Down Expand Up @@ -76,10 +86,23 @@ const InventoryList: React.FC = () => {
};

const addToBookmarksHandler = (
event: React.MouseEvent<HTMLIonButtonElement, MouseEvent>
event: React.MouseEvent<HTMLIonButtonElement, MouseEvent>,
treeId: number
) => {
// set selection processing
setSelectionProcessing(true)

// stop event propagation
event.stopPropagation();
console.log("add to bookmarks");

// check if this treeId is already in the selection
if (activeSelection?.selection.treeIds.includes(treeId)) {
removeFromActiveSelection(treeId).finally(() => setSelectionProcessing(false))
} else {
addToActiveSelection(treeId).finally(() => setSelectionProcessing(false))
}

//console.log("add to bookmarks");
};

return (
Expand Down Expand Up @@ -145,8 +168,13 @@ const InventoryList: React.FC = () => {
{distString(f)}
</p>
</IonLabel>
<IonButton fill="clear" onClick={(e) => addToBookmarksHandler(e)}>
<IonIcon icon={bookmarkOutline}></IonIcon>
<IonButton
fill="clear"
onClick={e => addToBookmarksHandler(e, Number(f.properties.treeid))}
>
{ selectionProcessing ? <IonSpinner name="lines" /> : (
<IonIcon icon={activeSelection?.selection.treeIds.includes(Number(f.properties.treeid)) ? banOutline : bookmarkOutline} />
)}
</IonButton>
</IonItem>
);
Expand Down
8 changes: 8 additions & 0 deletions src/components/TreeDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import {
IonButton,
IonButtons,
IonCard,
IonCardContent,
IonCardHeader,
IonCardSubtitle,
IonCardTitle,
IonCol,
IonGrid,
IonIcon,
IonItem,
IonLabel,
IonNote,
IonRow,
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";

Expand Down Expand Up @@ -61,6 +66,9 @@ const TreeDetails: React.FC<TreeDetailsProps> = ({ 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<InventoryFeature>();
const [currentImg, setCurrentImg] = useState<string>();
Expand Down
10 changes: 0 additions & 10 deletions src/components/map-components/InventorySource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions src/components/map-components/MainMapMaplibre.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -75,6 +76,7 @@ const MainMap: React.FC = () => {
>
<InventorySource />
<BaseLayerSource />
<SelectionSource />
<UserLocationSource />
<LayerInteraction />
</Map>
Expand Down
45 changes: 45 additions & 0 deletions src/components/map-components/SelectionSource.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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<InventoryData | undefined>()

// subscribe to the current active selection
const { activeSelection } = useSelection()

// update component state when activeSelection changes
useEffect(() => {
if (activeSelection) {
setSrc(cloneDeep(activeSelection.geoJSON))
} else {
setSrc(undefined)
}
}, [activeSelection])

// if there is no source, return null
if (!src) {
return (
null
)
} else {
return (
<Source id="selection" type="geojson" data={src}>
<Layer
id="selection"
source="selection"
type="circle"
paint={{
"circle-radius": 10,
"circle-color": "yellow"
}}
/>
</Source>
)
}
}

export default SelectionSource
14 changes: 7 additions & 7 deletions src/context/offline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ interface OfflineState {
remoteChecksums: Checksums | null;
getImageData: (name: string) => Promise<string>
getBaselayer: (name: string) => Promise<string>
createSelection: (treeIds: number[], title?: string) => Promise<string>
updateSelection: (selection: InventorySelection) => Promise<string>
createSelection: (treeIds: number[], title?: string) => Promise<InventorySelection>
updateSelection: (selection: InventorySelection) => Promise<InventorySelection>
dropSelection: (selectionId: string) => Promise<void>
}

Expand Down Expand Up @@ -289,7 +289,7 @@ export const OfflineProvider: React.FC<React.PropsWithChildren> = ({ children })

}

const createSelection = async (treeIds: number[], title?: string): Promise<string> => {
const createSelection = async (treeIds: number[], title?: string): Promise<InventorySelection> => {
// create a random 16 character string as id
const id = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)

Expand All @@ -304,7 +304,7 @@ export const OfflineProvider: React.FC<React.PropsWithChildren> = ({ children })
return updateSelection(selection)
}

const updateSelection = async (selection: InventorySelection): Promise<string> => {
const updateSelection = async (selection: InventorySelection): Promise<InventorySelection> => {
// 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})
Expand All @@ -323,16 +323,16 @@ export const OfflineProvider: React.FC<React.PropsWithChildren> = ({ 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]
newSelections = [{...selection}]
}

// update the selections state variable
setSelections(newSelections)

// return the local path
return path
return selection
})
}

Expand Down
Loading