From 81ee11f80ad04fa8a2c232990b3cce5b8b0cf89c Mon Sep 17 00:00:00 2001 From: Sandra Hoang Date: Thu, 11 Dec 2025 13:29:51 -0500 Subject: [PATCH 01/11] make useDocumentTitle into fn and clean useHrefParam --- src/app.tsx | 6 ++++-- src/hooks/document-title.ts | 12 ------------ src/hooks/href-param.ts | 15 +++++++++------ src/utils/utilities.ts | 11 +++++++++++ 4 files changed, 24 insertions(+), 20 deletions(-) delete mode 100644 src/hooks/document-title.ts create mode 100644 src/utils/utilities.ts diff --git a/src/app.tsx b/src/app.tsx index c44bbbb..027b5ba 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import { Box, Container, FileUpload, useFileUpload } from "@chakra-ui/react"; import type { StacCollection, StacItem } from "stac-ts"; import { Toaster } from "./components/ui/toaster"; -import useDocumentTitle from "./hooks/document-title"; +import setDocumentTitle from "./utils/utilities"; import useHrefParam from "./hooks/href-param"; import useStacChildren from "./hooks/stac-children"; import useStacFilters from "./hooks/stac-filters"; @@ -66,7 +66,9 @@ export default function App() { }); // Effects - useDocumentTitle(value); + useEffect(() => { + document.title = setDocumentTitle(value); + }, [value]) useEffect(() => { setPicked(undefined); diff --git a/src/hooks/document-title.ts b/src/hooks/document-title.ts deleted file mode 100644 index 8bb999d..0000000 --- a/src/hooks/document-title.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { useEffect } from "react"; -import type { StacValue } from "../types/stac"; - -export default function useDocumentTitle(value: StacValue | undefined) { - useEffect(() => { - if (value && (value.title || value.id)) { - document.title = "stac-map | " + (value.title || value.id); - } else { - document.title = "stac-map"; - } - }, [value]); -} diff --git a/src/hooks/href-param.ts b/src/hooks/href-param.ts index c7fa69c..490dadf 100644 --- a/src/hooks/href-param.ts +++ b/src/hooks/href-param.ts @@ -1,7 +1,11 @@ import { useEffect, useState } from "react"; +function getCurrentHref(): string { + return new URLSearchParams(location.search).get("href") || ""; +} + function getInitialHref(): string | undefined { - const href = new URLSearchParams(location.search).get("href") || ""; + const href = getCurrentHref(); try { new URL(href); } catch { @@ -15,7 +19,7 @@ export default function useHrefParam() { // Sync href with URL params useEffect(() => { - if (href && new URLSearchParams(location.search).get("href") != href) { + if (href && getCurrentHref() != href) { history.pushState(null, "", "?href=" + href); } else if (href === "") { history.pushState(null, "", location.pathname); @@ -25,14 +29,13 @@ export default function useHrefParam() { // Handle browser back/forward useEffect(() => { function handlePopState() { - setHref(new URLSearchParams(location.search).get("href") ?? ""); + setHref(getCurrentHref() ?? ""); } window.addEventListener("popstate", handlePopState); - const href = new URLSearchParams(location.search).get("href"); - if (href) { + if (getCurrentHref()) { try { - new URL(href); + new URL(getCurrentHref()); } catch { history.pushState(null, "", location.pathname); } diff --git a/src/utils/utilities.ts b/src/utils/utilities.ts new file mode 100644 index 0000000..47c8f52 --- /dev/null +++ b/src/utils/utilities.ts @@ -0,0 +1,11 @@ +import type { StacValue } from "../types/stac"; + +// @NOTE-SANDRA: Turn this into a simple function instead +// the useEffect isn't really needed at this level because only app.tsx needs to subscribe to it +export default function setDocumentTitle(value: StacValue | undefined) { + let title = "stac-map"; + if (value && (value.title || value.id)) { + title = "stac-map | " + (value.title || value.id); + } + return title; +} From 8db5866d24152f4576996d68ac2c8dcdfe3e6aad Mon Sep 17 00:00:00 2001 From: Sandra Hoang Date: Thu, 11 Dec 2025 15:27:27 -0500 Subject: [PATCH 02/11] Update useStacFilters hook and remove passing in separate prop for filtered --- src/app.tsx | 9 +++------ src/components/sections/collections.tsx | 10 ++++------ src/components/sections/items.tsx | 12 ++++++------ src/components/value.tsx | 9 +++------ src/hooks/stac-filters.ts | 20 ++++++++++---------- src/layers/map.tsx | 4 +--- src/layers/overlay.tsx | 2 -- 7 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/app.tsx b/src/app.tsx index 027b5ba..04c09dd 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -101,8 +101,7 @@ export default function App() { table={table} collections={collections} filteredCollections={filteredCollections} - items={items} - filteredItems={filteredItems} + items={filteredItems} fillColor={fillColor} lineColor={lineColor} setBbox={setBbox} @@ -132,15 +131,13 @@ export default function App() { error={error} catalogs={catalogs} setCollections={setCollections} - collections={collections} - filteredCollections={filteredCollections} + collections={filteredCollections} filter={filter} setFilter={setFilter} bbox={bbox} setPicked={setPicked} picked={picked} - items={items} - filteredItems={filteredItems} + items={filteredItems} setItems={setItems} setDatetimeBounds={setDatetimeBounds} cogTileHref={cogTileHref} diff --git a/src/components/sections/collections.tsx b/src/components/sections/collections.tsx index 7192d80..682eb6e 100644 --- a/src/components/sections/collections.tsx +++ b/src/components/sections/collections.tsx @@ -11,21 +11,19 @@ interface CollectionsProps { export default function CollectionsSection({ collections, - filteredCollections, numberOfCollections, setHref, }: { - filteredCollections: StacCollection[] | undefined; numberOfCollections: number | undefined; } & CollectionsProps) { - const parenthetical = filteredCollections - ? `${filteredCollections.length}/${numberOfCollections || collections.length}` - : collections.length; + const parenthetical = collections.length !== numberOfCollections + ? `${collections.length}/${numberOfCollections || collections.length}` + : collections.length; const title = `Collections (${parenthetical})`; return (
diff --git a/src/components/sections/items.tsx b/src/components/sections/items.tsx index fb02ef2..b704952 100644 --- a/src/components/sections/items.tsx +++ b/src/components/sections/items.tsx @@ -9,17 +9,17 @@ interface ItemsProps { } export default function ItemsSection({ - filteredItems, + totalNumOfItems, items, ...props -}: { filteredItems: StacItem[] | undefined } & ItemsProps) { - const parenthetical = filteredItems - ? `${filteredItems.length}/${items.length}` - : items.length; +}: {totalNumOfItems: number | undefined} & ItemsProps) { + const parenthetical = items.length !== totalNumOfItems + ? `${items.length}/${totalNumOfItems}` + : items.length; const title = `Items (${parenthetical})`; return (
- +
); } diff --git a/src/components/value.tsx b/src/components/value.tsx index b592e92..3f755ac 100644 --- a/src/components/value.tsx +++ b/src/components/value.tsx @@ -46,9 +46,7 @@ export interface SharedValueProps { catalogs: StacCatalog[] | undefined; setCollections: (collections: StacCollection[] | undefined) => void; collections: StacCollection[] | undefined; - filteredCollections: StacCollection[] | undefined; items: StacItem[] | undefined; - filteredItems: StacItem[] | undefined; setHref: (href: string | undefined) => void; filter: boolean; setFilter: (filter: boolean) => void; @@ -70,10 +68,8 @@ export function Value({ value, catalogs, collections, - filteredCollections, setCollections, items, - filteredItems, setItems, filter, setFilter, @@ -135,6 +131,8 @@ export function Value({ return collectionsResult.data?.pages.at(0)?.numberMatched; }, [collectionsResult.data]); + const totalNumOfItems = items?.length; + useEffect(() => { setCollections( collectionsResult.data?.pages.flatMap((page) => page?.collections || []) @@ -275,7 +273,6 @@ export function Value({ )} @@ -316,7 +313,7 @@ export function Value({ {items && ( )} diff --git a/src/hooks/stac-filters.ts b/src/hooks/stac-filters.ts index 3bfdba2..3f8a256 100644 --- a/src/hooks/stac-filters.ts +++ b/src/hooks/stac-filters.ts @@ -23,31 +23,31 @@ export default function useStacFilters({ filter, bbox, datetimeBounds, -}: UseStacFiltersProps) { +}: UseStacFiltersProps): ({ filteredCollections: StacCollection[] | undefined, filteredItems: StacItem[] | undefined }) { const filteredCollections = useMemo(() => { if (filter && collections) { - return collections.filter( + const filtered = collections.filter( (collection) => (!bbox || isCollectionInBbox(collection, bbox)) && (!datetimeBounds || isCollectionInDatetimeBounds(collection, datetimeBounds)) ); - } else { - return undefined; - } + return filtered; + } + return collections; }, [collections, filter, bbox, datetimeBounds]); const filteredItems = useMemo(() => { if (filter && items) { - return items.filter( + const filtered = items.filter( (item) => (!bbox || isItemInBbox(item, bbox)) && (!datetimeBounds || isItemInDatetimeBounds(item, datetimeBounds)) ); - } else { - return undefined; - } + return filtered; + } + return items; }, [items, filter, bbox, datetimeBounds]); return { filteredCollections, filteredItems }; -} +} \ No newline at end of file diff --git a/src/layers/map.tsx b/src/layers/map.tsx index 38dcb83..faa4d3d 100644 --- a/src/layers/map.tsx +++ b/src/layers/map.tsx @@ -24,7 +24,6 @@ export default function Map({ collections, filteredCollections, items, - filteredItems, fillColor, lineColor, setBbox, @@ -38,7 +37,6 @@ export default function Map({ collections: StacCollection[] | undefined; filteredCollections: StacCollection[] | undefined; items: StacItem[] | undefined; - filteredItems: StacItem[] | undefined; fillColor: Color; lineColor: Color; setBbox: (bbox: BBox2D | undefined) => void; @@ -135,7 +133,7 @@ export default function Map({ }), new GeoJsonLayer({ id: "items", - data: (filteredItems || items) as Feature[] | undefined, + data: (items) as Feature[] | undefined, filled: true, getFillColor: fillColor, getLineColor: lineColor, diff --git a/src/layers/overlay.tsx b/src/layers/overlay.tsx index bbf46e0..5e038a5 100644 --- a/src/layers/overlay.tsx +++ b/src/layers/overlay.tsx @@ -29,7 +29,6 @@ export default function Overlay({ picked, setPicked, items, - filteredItems, ...props }: OverlayProps) { return ( @@ -63,7 +62,6 @@ export default function Overlay({ value={picked || value} fileUpload={fileUpload} items={picked ? undefined : items} - filteredItems={picked ? undefined : filteredItems} {...props} /> From 4f2db2a4588c9c9ce77fc191ed294fd90de471df Mon Sep 17 00:00:00 2001 From: Sandra Hoang Date: Thu, 11 Dec 2025 16:22:57 -0500 Subject: [PATCH 03/11] fix error in collection count --- src/app.tsx | 1 + src/components/panel.tsx | 2 +- src/components/sections/collections.tsx | 10 ++++++---- src/components/value.tsx | 8 +++++--- src/layers/overlay.tsx | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/app.tsx b/src/app.tsx index 04c09dd..b2679f8 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -132,6 +132,7 @@ export default function App() { catalogs={catalogs} setCollections={setCollections} collections={filteredCollections} + totalNumOfCollections={collections?.length} filter={filter} setFilter={setFilter} bbox={bbox} diff --git a/src/components/panel.tsx b/src/components/panel.tsx index 58b64a3..d395809 100644 --- a/src/components/panel.tsx +++ b/src/components/panel.tsx @@ -21,7 +21,7 @@ export default function Panel({ error, fileUpload, ...props -}: PanelProps) { +}: { totalNumOfCollections: number | undefined } & PanelProps) { if (error) return ( diff --git a/src/components/sections/collections.tsx b/src/components/sections/collections.tsx index 682eb6e..695b9dd 100644 --- a/src/components/sections/collections.tsx +++ b/src/components/sections/collections.tsx @@ -11,13 +11,15 @@ interface CollectionsProps { export default function CollectionsSection({ collections, - numberOfCollections, + collectionsNumberMatched, + totalNumOfCollections, setHref, }: { - numberOfCollections: number | undefined; + collectionsNumberMatched: number | undefined; + totalNumOfCollections: number | undefined; } & CollectionsProps) { - const parenthetical = collections.length !== numberOfCollections - ? `${collections.length}/${numberOfCollections || collections.length}` + const parenthetical = collections.length !== collectionsNumberMatched + ? `${collections.length}/${collectionsNumberMatched || totalNumOfCollections}` : collections.length; const title = `Collections (${parenthetical})`; return ( diff --git a/src/components/value.tsx b/src/components/value.tsx index 3f755ac..ba3425d 100644 --- a/src/components/value.tsx +++ b/src/components/value.tsx @@ -77,7 +77,8 @@ export function Value({ setDatetimeBounds, cogTileHref, setCogTileHref, -}: ValueProps) { + totalNumOfCollections +}: { totalNumOfCollections: number | undefined } & ValueProps) { const [search, setSearch] = useState(); const [fetchAllCollections, setFetchAllCollections] = useState(false); const [thumbnailError, setThumbnailError] = useState(false); @@ -127,7 +128,7 @@ export function Value({ ); }, [assets]); - const numberOfCollections = useMemo(() => { + const collectionsNumberMatched = useMemo(() => { return collectionsResult.data?.pages.at(0)?.numberMatched; }, [collectionsResult.data]); @@ -272,7 +273,8 @@ export function Value({ {collections && collections.length && ( )} diff --git a/src/layers/overlay.tsx b/src/layers/overlay.tsx index 5e038a5..e853b21 100644 --- a/src/layers/overlay.tsx +++ b/src/layers/overlay.tsx @@ -30,7 +30,7 @@ export default function Overlay({ setPicked, items, ...props -}: OverlayProps) { +}: { totalNumOfCollections: number | undefined | undefined } & OverlayProps) { return ( From 4ddc28fd2063c933ca57ebd413894f910589cad1 Mon Sep 17 00:00:00 2001 From: Sandra Hoang Date: Thu, 11 Dec 2025 16:43:08 -0500 Subject: [PATCH 04/11] run prettier --- src/app.tsx | 4 ++-- src/components/sections/collections.tsx | 12 +++++------- src/components/sections/items.tsx | 9 +++++---- src/components/value.tsx | 2 +- src/hooks/href-param.ts | 2 +- src/hooks/stac-filters.ts | 11 +++++++---- src/layers/map.tsx | 2 +- src/utils/utilities.ts | 2 +- 8 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/app.tsx b/src/app.tsx index b2679f8..beecb53 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -2,7 +2,6 @@ import { useEffect, useState } from "react"; import { Box, Container, FileUpload, useFileUpload } from "@chakra-ui/react"; import type { StacCollection, StacItem } from "stac-ts"; import { Toaster } from "./components/ui/toaster"; -import setDocumentTitle from "./utils/utilities"; import useHrefParam from "./hooks/href-param"; import useStacChildren from "./hooks/stac-children"; import useStacFilters from "./hooks/stac-filters"; @@ -12,6 +11,7 @@ import Overlay from "./layers/overlay"; import type { BBox2D, Color } from "./types/map"; import type { DatetimeBounds, StacValue } from "./types/stac"; import { getCogTileHref } from "./utils/stac"; +import setDocumentTitle from "./utils/utilities"; // TODO make this configurable by the user. const lineColor: Color = [207, 63, 2, 100]; @@ -68,7 +68,7 @@ export default function App() { // Effects useEffect(() => { document.title = setDocumentTitle(value); - }, [value]) + }, [value]); useEffect(() => { setPicked(undefined); diff --git a/src/components/sections/collections.tsx b/src/components/sections/collections.tsx index 695b9dd..20224e1 100644 --- a/src/components/sections/collections.tsx +++ b/src/components/sections/collections.tsx @@ -18,16 +18,14 @@ export default function CollectionsSection({ collectionsNumberMatched: number | undefined; totalNumOfCollections: number | undefined; } & CollectionsProps) { - const parenthetical = collections.length !== collectionsNumberMatched - ? `${collections.length}/${collectionsNumberMatched || totalNumOfCollections}` - : collections.length; + const parenthetical = + collections.length !== collectionsNumberMatched + ? `${collections.length}/${collectionsNumberMatched || totalNumOfCollections}` + : collections.length; const title = `Collections (${parenthetical})`; return (
- +
); } diff --git a/src/components/sections/items.tsx b/src/components/sections/items.tsx index b704952..0c558ac 100644 --- a/src/components/sections/items.tsx +++ b/src/components/sections/items.tsx @@ -12,10 +12,11 @@ export default function ItemsSection({ totalNumOfItems, items, ...props -}: {totalNumOfItems: number | undefined} & ItemsProps) { - const parenthetical = items.length !== totalNumOfItems - ? `${items.length}/${totalNumOfItems}` - : items.length; +}: { totalNumOfItems: number | undefined } & ItemsProps) { + const parenthetical = + items.length !== totalNumOfItems + ? `${items.length}/${totalNumOfItems}` + : items.length; const title = `Items (${parenthetical})`; return (
diff --git a/src/components/value.tsx b/src/components/value.tsx index ba3425d..8f13f76 100644 --- a/src/components/value.tsx +++ b/src/components/value.tsx @@ -77,7 +77,7 @@ export function Value({ setDatetimeBounds, cogTileHref, setCogTileHref, - totalNumOfCollections + totalNumOfCollections, }: { totalNumOfCollections: number | undefined } & ValueProps) { const [search, setSearch] = useState(); const [fetchAllCollections, setFetchAllCollections] = useState(false); diff --git a/src/hooks/href-param.ts b/src/hooks/href-param.ts index 490dadf..686f28a 100644 --- a/src/hooks/href-param.ts +++ b/src/hooks/href-param.ts @@ -5,7 +5,7 @@ function getCurrentHref(): string { } function getInitialHref(): string | undefined { - const href = getCurrentHref(); + const href = getCurrentHref(); try { new URL(href); } catch { diff --git a/src/hooks/stac-filters.ts b/src/hooks/stac-filters.ts index 3f8a256..6d22e02 100644 --- a/src/hooks/stac-filters.ts +++ b/src/hooks/stac-filters.ts @@ -23,7 +23,10 @@ export default function useStacFilters({ filter, bbox, datetimeBounds, -}: UseStacFiltersProps): ({ filteredCollections: StacCollection[] | undefined, filteredItems: StacItem[] | undefined }) { +}: UseStacFiltersProps): { + filteredCollections: StacCollection[] | undefined; + filteredItems: StacItem[] | undefined; +} { const filteredCollections = useMemo(() => { if (filter && collections) { const filtered = collections.filter( @@ -33,7 +36,7 @@ export default function useStacFilters({ isCollectionInDatetimeBounds(collection, datetimeBounds)) ); return filtered; - } + } return collections; }, [collections, filter, bbox, datetimeBounds]); @@ -45,9 +48,9 @@ export default function useStacFilters({ (!datetimeBounds || isItemInDatetimeBounds(item, datetimeBounds)) ); return filtered; - } + } return items; }, [items, filter, bbox, datetimeBounds]); return { filteredCollections, filteredItems }; -} \ No newline at end of file +} diff --git a/src/layers/map.tsx b/src/layers/map.tsx index faa4d3d..049142c 100644 --- a/src/layers/map.tsx +++ b/src/layers/map.tsx @@ -133,7 +133,7 @@ export default function Map({ }), new GeoJsonLayer({ id: "items", - data: (items) as Feature[] | undefined, + data: items as Feature[] | undefined, filled: true, getFillColor: fillColor, getLineColor: lineColor, diff --git a/src/utils/utilities.ts b/src/utils/utilities.ts index 47c8f52..ae1b2e0 100644 --- a/src/utils/utilities.ts +++ b/src/utils/utilities.ts @@ -6,6 +6,6 @@ export default function setDocumentTitle(value: StacValue | undefined) { let title = "stac-map"; if (value && (value.title || value.id)) { title = "stac-map | " + (value.title || value.id); - } + } return title; } From 9637c03a925547ef6181a6b09ff881111396ba6d Mon Sep 17 00:00:00 2001 From: Sandra Hoang Date: Thu, 11 Dec 2025 16:44:50 -0500 Subject: [PATCH 05/11] remove code note --- src/utils/utilities.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/utilities.ts b/src/utils/utilities.ts index ae1b2e0..f293104 100644 --- a/src/utils/utilities.ts +++ b/src/utils/utilities.ts @@ -1,7 +1,5 @@ import type { StacValue } from "../types/stac"; -// @NOTE-SANDRA: Turn this into a simple function instead -// the useEffect isn't really needed at this level because only app.tsx needs to subscribe to it export default function setDocumentTitle(value: StacValue | undefined) { let title = "stac-map"; if (value && (value.title || value.id)) { From b7cfd5b7a0e695fa4963d767766257a6b4884472 Mon Sep 17 00:00:00 2001 From: Sandra Hoang Date: Sun, 14 Dec 2025 19:07:03 -0500 Subject: [PATCH 06/11] update filename --- src/app.tsx | 2 +- src/utils/{utilities.ts => index.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/utils/{utilities.ts => index.ts} (100%) diff --git a/src/app.tsx b/src/app.tsx index beecb53..7184979 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -11,7 +11,7 @@ import Overlay from "./layers/overlay"; import type { BBox2D, Color } from "./types/map"; import type { DatetimeBounds, StacValue } from "./types/stac"; import { getCogTileHref } from "./utils/stac"; -import setDocumentTitle from "./utils/utilities"; +import setDocumentTitle from "./utils"; // TODO make this configurable by the user. const lineColor: Color = [207, 63, 2, 100]; diff --git a/src/utils/utilities.ts b/src/utils/index.ts similarity index 100% rename from src/utils/utilities.ts rename to src/utils/index.ts From 29066413a074a93d381e3f36087f1532e22be378 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Mon, 15 Dec 2025 06:13:05 -0700 Subject: [PATCH 07/11] fix: lint --- src/app.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.tsx b/src/app.tsx index 7184979..2340476 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -10,8 +10,8 @@ import Map from "./layers/map"; import Overlay from "./layers/overlay"; import type { BBox2D, Color } from "./types/map"; import type { DatetimeBounds, StacValue } from "./types/stac"; -import { getCogTileHref } from "./utils/stac"; import setDocumentTitle from "./utils"; +import { getCogTileHref } from "./utils/stac"; // TODO make this configurable by the user. const lineColor: Color = [207, 63, 2, 100]; From a709558cdd834f82e0f62cc5e12b74c7a9b54618 Mon Sep 17 00:00:00 2001 From: Sandra Hoang Date: Mon, 15 Dec 2025 12:00:08 -0500 Subject: [PATCH 08/11] update filename and update tests --- src/app.tsx | 4 ++-- src/utils/{index.ts => title.ts} | 2 +- tests/hooks/document-title.spec.ts | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) rename src/utils/{index.ts => title.ts} (76%) diff --git a/src/app.tsx b/src/app.tsx index 2340476..5268307 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -10,8 +10,8 @@ import Map from "./layers/map"; import Overlay from "./layers/overlay"; import type { BBox2D, Color } from "./types/map"; import type { DatetimeBounds, StacValue } from "./types/stac"; -import setDocumentTitle from "./utils"; import { getCogTileHref } from "./utils/stac"; +import getDocumentTitle from "./utils/title"; // TODO make this configurable by the user. const lineColor: Color = [207, 63, 2, 100]; @@ -67,7 +67,7 @@ export default function App() { // Effects useEffect(() => { - document.title = setDocumentTitle(value); + document.title = getDocumentTitle(value); }, [value]); useEffect(() => { diff --git a/src/utils/index.ts b/src/utils/title.ts similarity index 76% rename from src/utils/index.ts rename to src/utils/title.ts index f293104..0c49f8b 100644 --- a/src/utils/index.ts +++ b/src/utils/title.ts @@ -1,6 +1,6 @@ import type { StacValue } from "../types/stac"; -export default function setDocumentTitle(value: StacValue | undefined) { +export default function getDocumentTitle(value: StacValue | undefined) { let title = "stac-map"; if (value && (value.title || value.id)) { title = "stac-map | " + (value.title || value.id); diff --git a/tests/hooks/document-title.spec.ts b/tests/hooks/document-title.spec.ts index fda04f8..1ac5de2 100644 --- a/tests/hooks/document-title.spec.ts +++ b/tests/hooks/document-title.spec.ts @@ -1,6 +1,7 @@ import type { StacCatalog, StacCollection, StacItem } from "stac-ts"; import { afterEach, beforeEach, describe, expect, test } from "vitest"; import type { StacItemCollection, StacValue } from "../../src/types/stac"; +import getDocumentTitle from "../../src/utils/title"; describe("useDocumentTitle logic", () => { let originalTitle: string; @@ -18,11 +19,9 @@ describe("useDocumentTitle logic", () => { }); function setDocumentTitle(value: StacValue | undefined) { - if (value && (value.title || value.id)) { - document.title = "stac-map | " + (value.title || value.id); - } else { - document.title = "stac-map"; - } + const title = getDocumentTitle(value); + document.title = title; + return; } test("should set default title when value is undefined", () => { From 35e877eb3e64fad81ce9dc235e2a784138a325ed Mon Sep 17 00:00:00 2001 From: Sandra Hoang Date: Tue, 16 Dec 2025 11:11:41 -0500 Subject: [PATCH 09/11] separate datetimes out into fn --- src/app.tsx | 9 +++++- src/components/sections/filter.tsx | 46 ++++-------------------------- src/components/value.tsx | 10 ++++++- src/utils/datetimes.ts | 44 ++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 43 deletions(-) create mode 100644 src/utils/datetimes.ts diff --git a/src/app.tsx b/src/app.tsx index 5268307..e94f9b6 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Box, Container, FileUpload, useFileUpload } from "@chakra-ui/react"; import type { StacCollection, StacItem } from "stac-ts"; import { Toaster } from "./components/ui/toaster"; @@ -10,6 +10,7 @@ import Map from "./layers/map"; import Overlay from "./layers/overlay"; import type { BBox2D, Color } from "./types/map"; import type { DatetimeBounds, StacValue } from "./types/stac"; +import getDateTimes from "./utils/datetimes"; import { getCogTileHref } from "./utils/stac"; import getDocumentTitle from "./utils/title"; @@ -65,6 +66,11 @@ export default function App() { datetimeBounds, }); + const datetimes = useMemo( + () => (value ? getDateTimes(value, items, collections) : null), + [value, items, collections] + ); + // Effects useEffect(() => { document.title = getDocumentTitle(value); @@ -143,6 +149,7 @@ export default function App() { setDatetimeBounds={setDatetimeBounds} cogTileHref={cogTileHref} setCogTileHref={setCogTileHref} + datetimes={datetimes} > diff --git a/src/components/sections/filter.tsx b/src/components/sections/filter.tsx index d22dee7..00e2aa8 100644 --- a/src/components/sections/filter.tsx +++ b/src/components/sections/filter.tsx @@ -4,7 +4,6 @@ import { Checkbox, DataList, Slider, Stack, Text } from "@chakra-ui/react"; import type { StacCollection, StacItem } from "stac-ts"; import type { BBox2D } from "../../types/map"; import type { DatetimeBounds, StacValue } from "../../types/stac"; -import { getItemDatetimes } from "../../utils/stac"; import { SpatialExtent } from "../extent"; import Section from "../section"; @@ -16,6 +15,10 @@ interface FilterProps { value: StacValue; items: StacItem[] | undefined; collections: StacCollection[] | undefined; + datetimes: { + start: Date; + end: Date; + } | null; } export default function FilterSection({ filter, ...props }: FilterProps) { @@ -35,50 +38,11 @@ function Filter({ setFilter, bbox, setDatetimeBounds, - value, - items, - collections, + datetimes, }: FilterProps) { const [filterStart, setFilterStart] = useState(); const [filterEnd, setFilterEnd] = useState(); - const datetimes = useMemo(() => { - let start = - value.start_datetime && typeof value.start_datetime === "string" - ? new Date(value.start_datetime as string) - : null; - let end = - value.end_datetime && typeof value.end_datetime === "string" - ? new Date(value.end_datetime as string) - : null; - - if (items) { - for (const item of items) { - const itemDatetimes = getItemDatetimes(item); - if (itemDatetimes.start && (!start || itemDatetimes.start < start)) - start = itemDatetimes.start; - if (itemDatetimes.end && (!end || itemDatetimes.end > end)) - end = itemDatetimes.end; - } - } - - if (collections) { - for (const collection of collections) { - const extents = collection.extent?.temporal?.interval?.[0]; - if (extents) { - const collectionStart = extents[0] ? new Date(extents[0]) : null; - if (collectionStart && (!start || collectionStart < start)) - start = collectionStart; - const collectionEnd = extents[1] ? new Date(extents[1]) : null; - if (collectionEnd && (!end || collectionEnd > end)) - end = collectionEnd; - } - } - } - - return start && end ? { start, end } : null; - }, [value, items, collections]); - const sliderValue = useMemo(() => { if (!datetimes) return undefined; if (filterStart && filterEnd) { diff --git a/src/components/value.tsx b/src/components/value.tsx index 8f13f76..22bf7ad 100644 --- a/src/components/value.tsx +++ b/src/components/value.tsx @@ -78,7 +78,14 @@ export function Value({ cogTileHref, setCogTileHref, totalNumOfCollections, -}: { totalNumOfCollections: number | undefined } & ValueProps) { + datetimes, +}: { + totalNumOfCollections: number | undefined; + datetimes: { + start: Date; + end: Date; + } | null; +} & ValueProps) { const [search, setSearch] = useState(); const [fetchAllCollections, setFetchAllCollections] = useState(false); const [thumbnailError, setThumbnailError] = useState(false); @@ -309,6 +316,7 @@ export function Value({ value={value} items={items} collections={collections} + datetimes={datetimes} /> )} diff --git a/src/utils/datetimes.ts b/src/utils/datetimes.ts new file mode 100644 index 0000000..91a4893 --- /dev/null +++ b/src/utils/datetimes.ts @@ -0,0 +1,44 @@ +import type { StacCollection, StacItem } from "stac-ts"; +import type { StacValue } from "../types/stac"; +import { getItemDatetimes } from "../utils/stac"; + +const getDateTimes = ( + value: StacValue, + items: StacItem[] | undefined, + collections: StacCollection[] | undefined +) => { + let start = + value.start_datetime && typeof value.start_datetime === "string" + ? new Date(value.start_datetime as string) + : null; + let end = + value.end_datetime && typeof value.end_datetime === "string" + ? new Date(value.end_datetime as string) + : null; + + if (items) { + for (const item of items) { + const itemDatetimes = getItemDatetimes(item); + if (itemDatetimes.start && (!start || itemDatetimes.start < start)) + start = itemDatetimes.start; + if (itemDatetimes.end && (!end || itemDatetimes.end > end)) + end = itemDatetimes.end; + } + } + + if (collections) { + for (const collection of collections) { + const extents = collection.extent?.temporal?.interval?.[0]; + if (extents) { + const collectionStart = extents[0] ? new Date(extents[0]) : null; + if (collectionStart && (!start || collectionStart < start)) + start = collectionStart; + const collectionEnd = extents[1] ? new Date(extents[1]) : null; + if (collectionEnd && (!end || collectionEnd > end)) end = collectionEnd; + } + } + } + return start && end ? { start, end } : null; +}; + +export default getDateTimes; From 4800418aeff94e717fc135aa68a2c1bc1f9c0f32 Mon Sep 17 00:00:00 2001 From: Sandra Hoang Date: Tue, 16 Dec 2025 11:22:16 -0500 Subject: [PATCH 10/11] fix error by adding prop types --- src/components/panel.tsx | 8 +++++++- src/layers/overlay.tsx | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/panel.tsx b/src/components/panel.tsx index d395809..83441a6 100644 --- a/src/components/panel.tsx +++ b/src/components/panel.tsx @@ -21,7 +21,13 @@ export default function Panel({ error, fileUpload, ...props -}: { totalNumOfCollections: number | undefined } & PanelProps) { +}: { + totalNumOfCollections: number | undefined; + datetimes: { + start: Date; + end: Date; + } | null; +} & PanelProps) { if (error) return ( diff --git a/src/layers/overlay.tsx b/src/layers/overlay.tsx index e853b21..0965da1 100644 --- a/src/layers/overlay.tsx +++ b/src/layers/overlay.tsx @@ -30,7 +30,13 @@ export default function Overlay({ setPicked, items, ...props -}: { totalNumOfCollections: number | undefined | undefined } & OverlayProps) { +}: { + totalNumOfCollections: number | undefined | undefined; + datetimes: { + start: Date; + end: Date; + } | null; +} & OverlayProps) { return ( From 9af9112dd484d6e1ba2fa01a4f9ad2c89cc6b2c0 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Tue, 16 Dec 2025 12:13:08 -0700 Subject: [PATCH 11/11] fix: minor tweaks --- src/layers/overlay.tsx | 2 +- tests/hooks/document-title.spec.ts | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/layers/overlay.tsx b/src/layers/overlay.tsx index 0965da1..ea8929c 100644 --- a/src/layers/overlay.tsx +++ b/src/layers/overlay.tsx @@ -31,7 +31,7 @@ export default function Overlay({ items, ...props }: { - totalNumOfCollections: number | undefined | undefined; + totalNumOfCollections: number | undefined; datetimes: { start: Date; end: Date; diff --git a/tests/hooks/document-title.spec.ts b/tests/hooks/document-title.spec.ts index 1ac5de2..4a3316d 100644 --- a/tests/hooks/document-title.spec.ts +++ b/tests/hooks/document-title.spec.ts @@ -19,9 +19,7 @@ describe("useDocumentTitle logic", () => { }); function setDocumentTitle(value: StacValue | undefined) { - const title = getDocumentTitle(value); - document.title = title; - return; + document.title = getDocumentTitle(value); } test("should set default title when value is undefined", () => {