Skip to content

Commit 727214c

Browse files
steveohstdavis
authored andcommitted
feat: enable identify
1 parent 2ba1b63 commit 727214c

File tree

5 files changed

+172
-94
lines changed

5 files changed

+172
-94
lines changed

package-lock.json

Lines changed: 13 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@
7676
"@arcgis/core": "^4.30.9",
7777
"@heroicons/react": "^2.1.5",
7878
"@ugrc/layer-selector": "^6.2.7",
79-
"@ugrc/utah-design-system": "^1.2.0",
79+
"@ugrc/utah-design-system": "^1.2.1",
8080
"firebase": "^10.12.4",
8181
"ky": "^1.5.0",
82+
"lodash.startcase": "^4.4.0",
8283
"react": "^18.3.1",
8384
"react-aria": "^3.34.1",
8485
"react-aria-components": "^1.3.1",

src/App.jsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ import {
1212
masqueradeProvider,
1313
} from '@ugrc/utah-design-system';
1414
import PropTypes from 'prop-types';
15-
import { useCallback, useEffect } from 'react';
15+
import { useCallback, useEffect, useState } from 'react';
1616
import { useOverlayTrigger } from 'react-aria';
1717
import { ErrorBoundary } from 'react-error-boundary';
1818
import { useOverlayTriggerState } from 'react-stately';
1919
import { MapContainer, Tip } from './components';
2020
import { useAnalytics, useFirebaseApp } from './components/contexts';
2121
import { useMap } from './components/hooks';
22+
import { IdentifyInformation } from './components/Identify';
2223
import config from './config';
2324

2425
const apiKey = import.meta.env.VITE_WEB_API;
@@ -58,6 +59,8 @@ const wkid = 26912;
5859
export default function App() {
5960
const app = useFirebaseApp();
6061
const logEvent = useAnalytics();
62+
const { zoom, placeGraphic } = useMap();
63+
const [initialIdentifyLocation, setInitialIdentifyLocation] = useState();
6164
const sideBarState = useOverlayTriggerState({ defaultOpen: true });
6265
const sideBarTriggerProps = useOverlayTrigger(
6366
{
@@ -74,8 +77,6 @@ export default function App() {
7477
trayState,
7578
);
7679

77-
const { zoom, placeGraphic } = useMap();
78-
7980
// initialize firebase performance metrics
8081
useEffect(() => {
8182
async function initPerformance() {
@@ -135,7 +136,7 @@ export default function App() {
135136

136137
const onClick = useCallback(
137138
(event) => {
138-
console.log('map click', event.mapPoint);
139+
setInitialIdentifyLocation(event.mapPoint);
139140
trayState.open(true);
140141
},
141142
[trayState],
@@ -178,20 +179,17 @@ export default function App() {
178179
</Drawer>
179180
<div className="relative flex flex-col flex-1 rounded">
180181
<div className="relative flex-1 dark:rounded overflow-hidden">
181-
<MapContainer />
182+
<MapContainer onIdentifyClick={onClick} />
182183
<Drawer
183184
type="tray"
184185
className="shadow-inner dark:shadow-white/20"
185186
allowFullScreen
186187
state={trayState}
187188
{...trayTriggerProps}
188189
>
189-
<section className="px-6 pt-2 grid gap-2">
190+
<section className="px-7 pt-2 grid gap-2">
190191
<h2 className="text-center">What&#39;s there?</h2>
191-
<p>
192-
First, explore the map to find your desired location. Then, click on it to reveal additional details
193-
about the area.
194-
</p>
192+
<IdentifyInformation apiKey={apiKey} location={initialIdentifyLocation} />
195193
</section>
196194
</Drawer>
197195
</div>

src/components/ExternalLink.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { ReactNode } from 'react';
2+
3+
export const ExternalLink = ({ href, children }: { href: URL; children: ReactNode }) => (
4+
<a
5+
href={href}
6+
target="_blank"
7+
rel="noopener noreferrer nofollow"
8+
className="inline-flex items-center gap-x-1 flex-wrap m-0"
9+
>
10+
{children}
11+
<span aria-hidden="true">
12+
<svg
13+
xmlns="http://www.w3.org/2000/svg"
14+
fill="none"
15+
viewBox="0 0 24 24"
16+
strokeWidth="1.5"
17+
stroke="currentColor"
18+
className="size-4"
19+
>
20+
<path
21+
strokeLinecap="round"
22+
strokeLinejoin="round"
23+
d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"
24+
></path>
25+
</svg>
26+
</span>
27+
<span className="sr-only">opens in a new window</span>
28+
</a>
29+
);

src/components/Identify.jsx

Lines changed: 120 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import PropTypes from 'prop-types';
2-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3-
41
import { isLoaded, load, project } from '@arcgis/core/geometry/projection';
5-
6-
import { toQueryString } from '@ugrc/utilities/src';
7-
2+
import { Label } from '@ugrc/utah-design-system';
3+
import { toQueryString } from '@ugrc/utilities';
84
import ky from 'ky';
9-
import './Identify.css';
5+
import startCase from 'lodash.startcase';
6+
import PropTypes from 'prop-types';
7+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
8+
import { Text } from 'react-aria-components';
9+
import { ExternalLink } from './ExternalLink';
1010

1111
const featureClassNames = {
1212
counties: 'boundaries.county_boundaries',
@@ -50,7 +50,7 @@ const projectPoint = async (mapPoint, srid) => {
5050
return project(mapPoint, { wkid: srid });
5151
};
5252

53-
const IdentifyInformation = ({ apiKey, wkid = 3857, location }) => {
53+
export const IdentifyInformation = ({ apiKey, wkid = 3857, location }) => {
5454
const [spatial, setSpatial] = useState({
5555
x: 0,
5656
y: 0,
@@ -296,92 +296,136 @@ const IdentifyInformation = ({ apiKey, wkid = 3857, location }) => {
296296
return () => controller.current?.abort();
297297
}, [location, get, requests]);
298298

299+
if (!location) {
300+
return (
301+
<p>
302+
First, explore the map to find your desired location. Then, click on it to reveal additional details about the
303+
area.
304+
</p>
305+
);
306+
}
307+
299308
return (
300-
<dev className="identify">
301-
<div>
302-
<h4>What&apos;s here?</h4>
303-
<hr />
304-
</div>
305-
<div>
306-
<strong>Approximate Street Address</strong>
307-
<p className="identify--muted">
308-
<span className="d-block">{address}</span>
309-
<a href={spatial.googleMapsLink} className="text-info" target="_blank" rel="noopener noreferrer">
309+
<div className="grid grid-cols-2 lg:grid-cols-5 lg:gap-4 gap-10 mx-auto">
310+
<div
311+
className="flex flex-col gap-1 px-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded"
312+
role="presentation"
313+
>
314+
<Label>Approximate Street Address</Label>
315+
<Text className="block text-sm pl-1">
316+
<Text className="block text-sm pl-1">{address}</Text>
317+
<ExternalLink href={spatial.googleMapsLink} className="pl-1">
310318
Google Street View
311-
</a>
312-
</p>
319+
</ExternalLink>
320+
</Text>
321+
<Text className="text-xs block grow content-end">
322+
Provided by{' '}
323+
<ExternalLink href="https://gis.utah.gov/products/sgid/transportation/road-centerlines/">roads</ExternalLink>
324+
</Text>
313325
</div>
314-
<div>
315-
<strong>City</strong>
316-
<p className="identify--muted">{city}</p>
326+
<div
327+
className="flex flex-col gap-1 px-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded"
328+
role="presentation"
329+
>
330+
<Label>City</Label>
331+
<Text className="block text-sm pl-1">{city}</Text>
332+
<Text className="text-xs block grow content-end">
333+
Provided by{' '}
334+
<ExternalLink href="https://gis.utah.gov/products/sgid/boundaries/municipal/">
335+
municipal boundaries
336+
</ExternalLink>
337+
</Text>
317338
</div>
318-
<div>
319-
<strong>Zip Code</strong>
320-
<p className="identify--muted">{zip}</p>
339+
<div
340+
className="flex flex-col gap-1 px-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded"
341+
role="presentation"
342+
>
343+
<Label>Zip code</Label>
344+
<Text className="block text-sm pl-1">{zip}</Text>
345+
<Text className="text-xs block grow content-end">
346+
Provided by{' '}
347+
<ExternalLink href="https://gis.utah.gov/products/sgid/boundaries/zip-codes/">zip code areas</ExternalLink>
348+
</Text>
321349
</div>
322-
<div>
323-
<strong>County</strong>
324-
<p className="identify--muted">{county}</p>
350+
<div
351+
className="flex flex-col gap-1 px-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded"
352+
role="presentation"
353+
>
354+
<Label>County</Label>
355+
<Text className="block text-sm pl-1">{startCase(county.toLowerCase())}</Text>
356+
<Text className="text-xs block grow content-end">
357+
Provided by{' '}
358+
<ExternalLink href="https://gis.utah.gov/products/sgid/boundaries/county/">county boundaries</ExternalLink>
359+
</Text>
325360
</div>
326-
<div>
327-
<strong>UTM 12 NAD83 Coordinates</strong>
328-
<p className="identify--muted">
329-
{spatial.x}, {spatial.y} meters
330-
</p>
361+
<div
362+
className="flex flex-col gap-1 px-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded"
363+
role="presentation"
364+
>
365+
<Label>UTM 12 NAD83 coordinates</Label>
366+
<Text className="block text-sm pl-1">
367+
{spatial.x}, {spatial.y} m
368+
</Text>
331369
</div>
332-
<div>
333-
<strong>WGS84 Coordinates</strong>
334-
<p className="identify--muted">
370+
<div
371+
className="flex flex-col gap-1 px-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded"
372+
role="presentation"
373+
>
374+
<Label>WGS84 coordinates</Label>
375+
<Text className="block text-sm pl-1">
335376
{spatial.lat}, {spatial.lon}
336-
</p>
337-
</div>
338-
<div>
339-
<strong>Elevation Meters</strong>
340-
<p className="identify--muted">{elevation.meters}</p>
377+
</Text>
341378
</div>
342-
<div>
343-
<strong>Elevation Feet</strong>
344-
<p className="identify--muted">{elevation.feet}</p>
379+
<div
380+
className="flex flex-col gap-1 px-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded"
381+
role="presentation"
382+
>
383+
<Label>Elevation</Label>
384+
<Text className="block text-sm pl-1">{elevation.meters} m</Text>
385+
<Text className="block text-sm pl-1">{elevation.feet} ft</Text>
386+
<Text className="text-xs block grow content-end">
387+
Provided by <ExternalLink href="https://elevation.nationalmap.gov/">The National Map</ExternalLink>
388+
</Text>
345389
</div>
346-
<div>
347-
<strong>Land Administration Category</strong>
348-
<p className="identify--muted">{ownership}</p>
390+
<div
391+
className="flex flex-col gap-1 px-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded"
392+
role="presentation"
393+
>
394+
<Label>Land administration category</Label>
395+
<Text className="block text-sm pl-1">{ownership}</Text>
396+
<Text className="text-xs block grow content-end">
397+
Provided by{' '}
398+
<ExternalLink href="https://gis.utah.gov/products/sgid/cadastre/land-ownership/">land ownership</ExternalLink>
399+
</Text>
349400
</div>
350-
<div>
351-
<strong>US National Grid</strong>
352-
<p className="identify--muted">{grid}</p>
401+
<div
402+
className="flex flex-col gap-1 px-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded"
403+
role="presentation"
404+
>
405+
<Label>US National Grid</Label>
406+
<Text className="block text-sm pl-1">{grid}</Text>
407+
<Text className="text-xs block grow content-end">
408+
Provided by the{' '}
409+
<ExternalLink href="https://gis.utah.gov/products/sgid/indices/national-grid-index/">
410+
national grid
411+
</ExternalLink>
412+
</Text>
353413
</div>
354-
<div>
355-
<strong>Imagery Flight Data</strong>
356-
<p className="identify--muted">{flightDate.date && `${flightDate.resolution} on ${flightDate.date}`}</p>
414+
<div
415+
className="flex flex-col gap-1 px-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded"
416+
role="presentation"
417+
>
418+
<Label>Imagery flight metadata</Label>
419+
<Text className="block text-sm pl-1">
420+
{flightDate.date && `${flightDate.resolution} on ${flightDate.date}`}
421+
</Text>
357422
</div>
358-
</dev>
359-
);
360-
};
361-
362-
IdentifyInformation.propTypes = {
363-
location: PropTypes.object,
364-
};
365-
366-
const IdentifyContainer = function ({ show, children }) {
367-
return (
368-
<div className="identify__container side-bar side-bar--with-border side-bar--open">
369-
<button type="button" className="identify__close" aria-label="Close" onClick={() => show(false)}>
370-
<span aria-hidden="true">&times;</span>
371-
</button>
372-
{children}
373423
</div>
374424
);
375425
};
376426

377-
IdentifyContainer.propTypes = {
378-
show: PropTypes.func.isRequired,
379-
children: PropTypes.node.isRequired,
380-
};
381-
382-
export { IdentifyContainer, IdentifyInformation };
383-
384427
IdentifyInformation.propTypes = {
428+
location: PropTypes.object,
385429
apiKey: PropTypes.string.isRequired,
386430
wkid: PropTypes.number,
387431
};

0 commit comments

Comments
 (0)