Skip to content

Commit

Permalink
feat: add selected project as a url parameter
Browse files Browse the repository at this point in the history
Ref: #13
  • Loading branch information
stdavis committed Aug 24, 2022
1 parent ff2e04e commit f1e200e
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 30 deletions.
87 changes: 62 additions & 25 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as reactiveUtils from '@arcgis/core/core/reactiveUtils';
import { whenOnce } from '@arcgis/core/core/reactiveUtils';
import Graphic from '@arcgis/core/Graphic';
import Viewpoint from '@arcgis/core/Viewpoint';
import MapView from '@arcgis/core/views/MapView';
Expand All @@ -10,7 +11,7 @@ import LayerSelector from '@ugrc/layer-selector';
import debounce from 'lodash.debounce';
import { useCallback, useEffect, useRef, useState } from 'react';
import 'typeface-montserrat';
import { NumberParam, useQueryParams } from 'use-query-params';
import { NumberParam, StringParam, useQueryParams } from 'use-query-params';
import './App.scss';
import Filter from './components/Filter';
import MapWidget from './components/MapWidget';
Expand All @@ -33,6 +34,10 @@ function App() {
x: NumberParam,
y: NumberParam,
scale: NumberParam,

//🎗️ these configs need to be synced with Details.jsx
selected_id: NumberParam,
selected_layer_id: StringParam,
});
const mapInitialized = useRef(false);

Expand Down Expand Up @@ -155,40 +160,72 @@ function App() {
const [selectedGraphics, setSelectedGraphics] = useState([]);
const [highlight, setHighlight] = useState(null);
const [graphic, setGraphic] = useState(null);
const highlightGraphic = async (newGraphic) => {
console.log('App:highlightGraphic', newGraphic);
const highlightGraphic = useCallback(
async (newGraphic) => {
console.log('App:highlightGraphic', newGraphic);

if (highlight) {
highlight.remove();
setHighlight(null);
}
if (highlight) {
highlight.remove();
setHighlight(null);
}

if (graphic) {
mapView.graphics.remove(graphic);
}
if (graphic) {
mapView.graphics.remove(graphic);
}

if (newGraphic) {
try {
const layerView = await mapView.whenLayerView(newGraphic.layer);
setHighlight(layerView.highlight(newGraphic));
} catch {
const symbolizedGraphic = new Graphic({
...newGraphic,
symbol: config.SELECTION_SYMBOLS[newGraphic.geometry.type],
});
if (newGraphic) {
try {
const layerView = await mapView.whenLayerView(newGraphic.layer);
setHighlight(layerView.highlight(newGraphic));
} catch {
const symbolizedGraphic = new Graphic({
...newGraphic,
symbol: config.SELECTION_SYMBOLS[newGraphic.geometry.type],
});

mapView.graphics.add(symbolizedGraphic);
setGraphic(symbolizedGraphic);
}
} else {
setGraphic(null);
}
},
[graphic, highlight, mapView]
);

mapView.graphics.add(symbolizedGraphic);
setGraphic(symbolizedGraphic);
const initialSelectedGraphicLoaded = useRef(false);
useEffect(() => {
const selectGraphic = async () => {
await mapView.map.when();

const layer = mapView.map.findLayerById(urlState.selected_layer_id);
const layerView = await mapView.whenLayerView(layer);
await whenOnce(() => layerView.updating === false);

const featureSet = await layerView.queryFeatures({
where: `OBJECTID = ${urlState.selected_id}`,
});

setSelectedGraphics(featureSet.features);
};

if (!initialSelectedGraphicLoaded.current && mapView) {
if (urlState.selected_id && urlState.selected_layer_id) {
selectGraphic();
}
} else {
setGraphic(null);
initialSelectedGraphicLoaded.current = true;
}
};
}, [urlState, mapView]);

useEffect(() => {
if (mapView) {
mapView.on('click', async (event) => {
const response = await mapView.hitTest(event);
highlightGraphic();
setUrlState({
selected_id: null,
selected_layer_id: null,
});
setSelectedGraphics(response.results.map((result) => result.graphic));

if (response.results.length > 0) {
Expand All @@ -209,7 +246,7 @@ function App() {
}, 100)
);
}
}, [mapView, setUrlState]);
}, [highlightGraphic, mapView, setUrlState]);

const [filterState, filterDispatch] = useFilterReducer();
const [filterIsOpen, setFilterIsOpen] = useState(config.openOnLoad.filter);
Expand Down
38 changes: 34 additions & 4 deletions src/components/Details.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@ import Feature from '@arcgis/core/widgets/Feature';
import PropTypes from 'prop-types';
import { useEffect, useRef, useState } from 'react';
import { Collapse } from 'reactstrap';
import { NumberParam, StringParam, useQueryParams } from 'use-query-params';
import config from '../services/config';
import Comments from './Comments';
import './Details.scss';

export default function Details({ graphic, highlightGraphic }) {
const [collapsed, setCollapsed] = useState(true);
export default function Details({ graphic, highlightGraphic, onlyOne }) {
const [urlState, setUrlState] = useQueryParams({
selected_id: NumberParam,
selected_layer_id: StringParam,
});
const isNotSelected =
urlState.selected_id !== graphic.attributes.OBJECTID || urlState.selected_layer_id !== graphic.layer.id;
const [collapsed, setCollapsed] = useState(isNotSelected);
const containerRef = useRef();
const [title, setTitle] = useState(null);
const [featureWidgetGraphic, setFeatureWidgetGraphic] = useState(null);
Expand All @@ -34,6 +41,10 @@ export default function Details({ graphic, highlightGraphic }) {
containerRef.current.appendChild(feature.container);

setFeatureWidgetGraphic(feature.graphic);

if (onlyOne) {
highlightGraphic(graphic);
}
};

if (graphic) {
Expand All @@ -43,19 +54,37 @@ export default function Details({ graphic, highlightGraphic }) {
return () => {
if (feature) {
feature.destroy();
console.log('destroyed');
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [graphic]);

useEffect(() => {
if (!collapsed) {
setUrlState({
selected_id: graphic.attributes.OBJECTID,
selected_layer_id: graphic.layer.id,
});
} else if (!isNotSelected) {
setUrlState({
selected_id: null,
selected_layer_id: null,
});
}
}, [collapsed, graphic.attributes.OBJECTID, graphic.layer.id, isNotSelected, setUrlState]);

const showComments =
config.projectInformation.commentsEnabled &&
featureWidgetGraphic &&
new Date() < new Date(config.projectInformation.commentsEnabledUntil) &&
Object.keys(featureWidgetGraphic.attributes).some((name) => name === config.projectInformation.fieldNames.globalId);

return (
<div className="details" onMouseEnter={() => highlightGraphic(graphic)} onMouseLeave={() => highlightGraphic()}>
<div
className="details"
onMouseEnter={() => !onlyOne && highlightGraphic(graphic)}
onMouseLeave={() => !onlyOne && highlightGraphic()}
>
<div className="title" onClick={toggle}>
{title}
</div>
Expand All @@ -71,4 +100,5 @@ export default function Details({ graphic, highlightGraphic }) {
Details.propTypes = {
graphic: PropTypes.object,
highlightGraphic: PropTypes.func.isRequired,
onlyOne: PropTypes.bool.isRequired,
};
7 changes: 6 additions & 1 deletion src/components/ProjectInformation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ export default function ProjectInformation({ graphics, showLoader, highlightGrap
</div>
)}
{graphics.map((graphic, index) => (
<Details key={index} graphic={graphic} highlightGraphic={highlightGraphic} />
<Details
key={`${graphic.layer.id}_${graphic.attributes.OBJECTID}_${index}`}
graphic={graphic}
highlightGraphic={highlightGraphic}
onlyOne={graphics.length === 1}
/>
))}
</div>
);
Expand Down

0 comments on commit f1e200e

Please sign in to comment.