Skip to content

Commit 56a6382

Browse files
authored
refactor: state (#131)
1 parent 4132eab commit 56a6382

20 files changed

+605
-449
lines changed

src/app.tsx

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ import {
22
Alert,
33
Box,
44
Container,
5+
FileUpload,
56
Flex,
67
GridItem,
78
SimpleGrid,
89
useBreakpointValue,
10+
useFileUpload,
911
} from "@chakra-ui/react";
1012
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
13+
import { useEffect, useState } from "react";
1114
import { ErrorBoundary } from "react-error-boundary";
1215
import { MapProvider } from "react-map-gl/dist/esm/exports-maplibre";
1316
import Header from "./components/header";
@@ -17,31 +20,75 @@ import { Toaster } from "./components/ui/toaster";
1720
import { StacMapProvider } from "./provider";
1821

1922
export default function App() {
23+
const [href, setHref] = useState<string | undefined>(getInitialHref());
24+
const fileUpload = useFileUpload({ maxFiles: 1 });
2025
const queryClient = new QueryClient({});
2126
const isHeaderAboveMap = useBreakpointValue({ base: true, md: false });
2227

28+
useEffect(() => {
29+
function handlePopState() {
30+
setHref(new URLSearchParams(location.search).get("href") ?? "");
31+
}
32+
33+
window.addEventListener("popstate", handlePopState);
34+
return () => {
35+
window.removeEventListener("popstate", handlePopState);
36+
};
37+
}, []);
38+
39+
useEffect(() => {
40+
if (href && new URLSearchParams(location.search).get("href") != href) {
41+
history.pushState(null, "", "?href=" + href);
42+
}
43+
}, [href]);
44+
45+
useEffect(() => {
46+
// It should never be more than 1.
47+
if (fileUpload.acceptedFiles.length == 1) {
48+
setHref(fileUpload.acceptedFiles[0].name);
49+
}
50+
}, [fileUpload.acceptedFiles]);
51+
52+
const header = (
53+
<Header href={href} setHref={setHref} fileUpload={fileUpload}></Header>
54+
);
55+
2356
return (
2457
<QueryClientProvider client={queryClient}>
2558
<MapProvider>
26-
<StacMapProvider>
59+
<StacMapProvider
60+
href={href}
61+
fileUpload={fileUpload}
62+
temporalFilter={undefined} // TODO re-add temporal filtering: https://github.com/developmentseed/stac-map/issues/123
63+
>
2764
<Box zIndex={0} position={"absolute"} top={0} left={0}>
28-
<ErrorBoundary FallbackComponent={MapFallback}>
29-
<Map></Map>
30-
</ErrorBoundary>
65+
<FileUpload.RootProvider value={fileUpload} unstyled={true}>
66+
<FileUpload.Dropzone
67+
disableClick={true}
68+
style={{
69+
height: "100dvh",
70+
width: "100dvw",
71+
}}
72+
>
73+
<ErrorBoundary FallbackComponent={MapFallback}>
74+
<Map></Map>
75+
</ErrorBoundary>
76+
</FileUpload.Dropzone>
77+
</FileUpload.RootProvider>
3178
</Box>
3279
<Container zIndex={1} fluid h={"dvh"} py={4} pointerEvents={"none"}>
3380
<SimpleGrid columns={{ base: 1, md: 3 }} gap={4}>
34-
{isHeaderAboveMap && (
35-
<GridItem colSpan={1}>
36-
<Header></Header>
37-
</GridItem>
38-
)}
81+
{isHeaderAboveMap && <GridItem colSpan={1}>{header}</GridItem>}
3982
<GridItem colSpan={1}>
40-
<Panel></Panel>
83+
<Panel
84+
href={href}
85+
setHref={setHref}
86+
fileUpload={fileUpload}
87+
></Panel>
4188
</GridItem>
4289
{!isHeaderAboveMap && (
4390
<GridItem colSpan={2} hideBelow={"md"}>
44-
<Header></Header>
91+
{header}
4592
</GridItem>
4693
)}
4794
</SimpleGrid>
@@ -68,3 +115,13 @@ function MapFallback({ error }: { error: Error }) {
68115
</Flex>
69116
);
70117
}
118+
119+
function getInitialHref() {
120+
const href = new URLSearchParams(location.search).get("href") || "";
121+
try {
122+
new URL(href);
123+
} catch {
124+
return undefined;
125+
}
126+
return href;
127+
}

src/components/catalog.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
import { Stack } from "@chakra-ui/react";
22
import type { StacCatalog } from "stac-ts";
3+
import type { SetHref } from "../types/app";
34
import { Children } from "./children";
45
import Value from "./value";
56

6-
export function Catalog({ catalog }: { catalog: StacCatalog }) {
7+
export function Catalog({
8+
catalog,
9+
setHref,
10+
}: {
11+
catalog: StacCatalog;
12+
setHref: SetHref;
13+
}) {
714
return (
815
<Stack>
916
<Value value={catalog}></Value>
10-
<Children value={catalog}></Children>
17+
<Children value={catalog} setHref={setHref}></Children>
1118
</Stack>
1219
);
1320
}

src/components/children.tsx

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,74 @@ import { LuFolderPlus, LuFolderSearch } from "react-icons/lu";
44
import { MarkdownHooks } from "react-markdown";
55
import type { StacCatalog, StacCollection } from "stac-ts";
66
import useStacMap from "../hooks/stac-map";
7+
import { useChildren } from "../hooks/stac-value";
8+
import type { SetHref } from "../types/app";
79
import { CollectionSearch } from "./search/collection";
810
import Section from "./section";
911

10-
export function Children({ value }: { value: StacCatalog | StacCollection }) {
11-
const { catalogs, collections } = useStacMap();
12+
export function Children({
13+
value,
14+
setHref,
15+
}: {
16+
value: StacCatalog | StacCollection;
17+
setHref: SetHref;
18+
}) {
19+
const { collections } = useStacMap();
20+
const children = useChildren(value, !!collections);
1221
const selfHref = value?.links?.find((link) => link.rel === "self")?.href;
1322

1423
return (
1524
<>
1625
{collections && collections?.length > 0 && (
17-
<Section
18-
title={
19-
<HStack>
20-
<Icon>
21-
<LuFolderSearch></LuFolderSearch>
22-
</Icon>{" "}
23-
Collection search
24-
</HStack>
25-
}
26-
>
27-
<CollectionSearch
28-
href={selfHref}
29-
collections={collections}
30-
></CollectionSearch>
31-
</Section>
32-
)}
26+
<>
27+
<Section
28+
title={
29+
<HStack>
30+
<Icon>
31+
<LuFolderSearch></LuFolderSearch>
32+
</Icon>{" "}
33+
Collection search
34+
</HStack>
35+
}
36+
>
37+
<CollectionSearch
38+
href={selfHref}
39+
setHref={setHref}
40+
collections={collections}
41+
></CollectionSearch>
42+
</Section>
3343

34-
{catalogs && catalogs.length > 0 && (
35-
<Section title="Catalogs">
36-
<Stack>
37-
{catalogs.map((catalog) => (
38-
<ChildCard
39-
child={catalog}
40-
key={"catalog-" + catalog.id}
41-
></ChildCard>
42-
))}
43-
</Stack>
44-
</Section>
44+
<Section
45+
title={
46+
<HStack>
47+
<Icon>
48+
<LuFolderPlus></LuFolderPlus>
49+
</Icon>{" "}
50+
Collections ({collections.length})
51+
</HStack>
52+
}
53+
>
54+
<Stack>
55+
{collections.map((collection) => (
56+
<ChildCard
57+
child={collection}
58+
setHref={setHref}
59+
key={"collection-" + collection.id}
60+
></ChildCard>
61+
))}
62+
</Stack>
63+
</Section>
64+
</>
4565
)}
4666

47-
{collections && collections.length > 0 && (
48-
<Section
49-
title={
50-
<HStack>
51-
<Icon>
52-
<LuFolderPlus></LuFolderPlus>
53-
</Icon>{" "}
54-
Collections ({collections.length})
55-
</HStack>
56-
}
57-
>
67+
{children && children.length > 0 && (
68+
<Section title="Children">
5869
<Stack>
59-
{collections.map((collection) => (
70+
{children.map((child) => (
6071
<ChildCard
61-
child={collection}
62-
key={"collection-" + collection.id}
72+
child={child}
73+
setHref={setHref}
74+
key={"child-" + child.id}
6375
></ChildCard>
6476
))}
6577
</Stack>
@@ -72,11 +84,12 @@ export function Children({ value }: { value: StacCatalog | StacCollection }) {
7284
export function ChildCard({
7385
child,
7486
footer,
87+
setHref,
7588
}: {
7689
child: StacCatalog | StacCollection;
7790
footer?: ReactNode;
91+
setHref: SetHref;
7892
}) {
79-
const { setHref } = useStacMap();
8093
const selfHref = child.links.find((link) => link.rel === "self")?.href;
8194

8295
return (

src/components/collection.tsx

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,34 @@ import {
88
Text,
99
} from "@chakra-ui/react";
1010
import { LuFileSearch } from "react-icons/lu";
11-
import type { StacCollection } from "stac-ts";
12-
import useStacMap from "../hooks/stac-map";
11+
import type { StacCollection, StacLink } from "stac-ts";
12+
import { useStacLinkContainer } from "../hooks/stac-value";
13+
import type { SetHref } from "../types/app";
14+
import type { StacSearch } from "../types/stac";
1315
import { ChildCard, Children } from "./children";
1416
import { SpatialExtent, TemporalExtent } from "./extents";
1517
import ItemSearch from "./search/item";
1618
import Section from "./section";
1719
import Value from "./value";
1820

19-
export function Collection({ collection }: { collection: StacCollection }) {
20-
const { root } = useStacMap();
21+
export function Collection({
22+
collection,
23+
setHref,
24+
search,
25+
setSearch,
26+
setSearchLink,
27+
autoLoad,
28+
setAutoLoad,
29+
}: {
30+
collection: StacCollection;
31+
setHref: SetHref;
32+
search: StacSearch | undefined;
33+
setSearch: (search: StacSearch | undefined) => void;
34+
setSearchLink: (link: StacLink | undefined) => void;
35+
autoLoad: boolean;
36+
setAutoLoad: (autoLoad: boolean) => void;
37+
}) {
38+
const root = useStacLinkContainer(collection, "root");
2139
const searchLinks =
2240
(root && root.links?.filter((link) => link.rel == "search")) || [];
2341

@@ -39,25 +57,36 @@ export function Collection({ collection }: { collection: StacCollection }) {
3957
</HStack>
4058
}
4159
>
42-
<ItemSearch collection={collection} links={searchLinks}></ItemSearch>
60+
<ItemSearch
61+
collection={collection}
62+
links={searchLinks}
63+
search={search}
64+
setSearch={setSearch}
65+
setSearchLink={setSearchLink}
66+
autoLoad={autoLoad}
67+
setAutoLoad={setAutoLoad}
68+
></ItemSearch>
4369
</Section>
4470
)}
4571

46-
<Children value={collection}></Children>
72+
<Children value={collection} setHref={setHref}></Children>
4773
</Stack>
4874
);
4975
}
5076

5177
export function CollectionCard({
5278
collection,
79+
setHref,
5380
explanation,
5481
}: {
5582
collection: StacCollection;
83+
setHref: SetHref;
5684
explanation?: string;
5785
}) {
5886
return (
5987
<ChildCard
6088
child={collection}
89+
setHref={setHref}
6190
footer={
6291
<Stack>
6392
<HStack>

0 commit comments

Comments
 (0)