From 820730fd7c1e25e68997b200d31bc4ee27525f7e Mon Sep 17 00:00:00 2001 From: Vitor George Date: Tue, 26 Nov 2024 12:41:51 +0000 Subject: [PATCH 1/2] refactor(catalog): introduce usePathname hook, remove React Router dependency from the Catalog --- .../common/catalog/catalog-card.tsx | 7 ++- .../common/catalog/catalog-content.tsx | 5 -- .../common/catalog/filters-control.tsx | 5 +- .../components/common/catalog/index.tsx | 3 - .../components/data-catalog/container.tsx | 3 - app/scripts/utils/use-pathname.ts | 59 +++++++++++++++++++ 6 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 app/scripts/utils/use-pathname.ts diff --git a/app/scripts/components/common/catalog/catalog-card.tsx b/app/scripts/components/common/catalog/catalog-card.tsx index 944507108..3dc8e3f28 100644 --- a/app/scripts/components/common/catalog/catalog-card.tsx +++ b/app/scripts/components/common/catalog/catalog-card.tsx @@ -13,6 +13,7 @@ import { DatasetData, DatasetLayer } from "$types/veda"; import { getDatasetPath } from "$utils/routes"; import { TAXONOMY_SOURCE, TAXONOMY_TOPICS, getAllTaxonomyValues, getTaxonomy } from "$utils/veda-data/taxonomies"; import { Pill } from "$styles/pill"; +import { usePathname } from "$utils/use-pathname"; interface CatalogCardProps { dataset: DatasetData; @@ -21,7 +22,6 @@ interface CatalogCardProps { selectable?: boolean; selected?: boolean; onDatasetClick?: () => void; - pathname?: string; linkProperties?: LinkProperties; } @@ -102,10 +102,11 @@ export const CatalogCard = (props: CatalogCardProps) => { selectable, selected, onDatasetClick, - linkProperties, - pathname + linkProperties } = props; + const pathname = usePathname(); + const topics = getTaxonomy(dataset, TAXONOMY_TOPICS)?.values; const sources = getTaxonomy(dataset, TAXONOMY_SOURCE)?.values; const allTaxonomyValues = getAllTaxonomyValues(dataset).map((v) => v.name); diff --git a/app/scripts/components/common/catalog/catalog-content.tsx b/app/scripts/components/common/catalog/catalog-content.tsx index dcac02395..1b8e15dbf 100644 --- a/app/scripts/components/common/catalog/catalog-content.tsx +++ b/app/scripts/components/common/catalog/catalog-content.tsx @@ -35,7 +35,6 @@ export interface CatalogContentProps { taxonomies: Record; onAction: (action: FilterActions, value?: any) => void; linkProperties: LinkProperties; - pathname?: string; } const DEFAULT_SORT_OPTION = 'asc'; @@ -72,7 +71,6 @@ function CatalogContent({ search, taxonomies, onAction, - pathname, linkProperties }: CatalogContentProps) { const [exclusiveSourceSelected, setExclusiveSourceSelected] = useState(null); @@ -215,7 +213,6 @@ function CatalogContent({ exclusiveSourceSelected={exclusiveSourceSelected} customTopOffset={isSelectable ? 50 : 0} openByDefault={false} - pathname={pathname} /> onCardSelect(datasetLayer.id, currentDataset)} - pathname={pathname} /> ))} @@ -280,7 +276,6 @@ function CatalogContent({ dataset={d} searchTerm={search} linkProperties={linkProperties} - pathname={pathname} /> ))} diff --git a/app/scripts/components/common/catalog/filters-control.tsx b/app/scripts/components/common/catalog/filters-control.tsx index 4bc667c1b..b82f76819 100644 --- a/app/scripts/components/common/catalog/filters-control.tsx +++ b/app/scripts/components/common/catalog/filters-control.tsx @@ -5,6 +5,7 @@ import { Taxonomy } from '$types/veda'; import SearchField from '$components/common/search-field'; import CheckableFilters, { OptionItem } from '$components/common/form/checkable-filter'; import { useSlidingStickyHeader, HEADER_TRANSITION_DURATION } from '$utils/use-sliding-sticky-header'; +import { usePathname } from '$utils/use-pathname'; const ControlsWrapper = styled.div<{ widthValue?: string; heightValue?: string; topValue: string }>` min-width: 20rem; @@ -27,7 +28,6 @@ interface FiltersMenuProps { exclusiveSourceSelected?: string | null; customTopOffset?: number; openByDefault?: boolean; - pathname?: string; } export default function FiltersControl(props: FiltersMenuProps) { @@ -48,9 +48,10 @@ export default function FiltersControl(props: FiltersMenuProps) { // uses as a reference (the main page header). To avoid changing the reference IDs in the // main logic of the sliding sticky header hook, we provide this custom top offset for more control. customTopOffset = 0, - pathname, } = props; + const pathname = usePathname(); + const controlsRef = useRef(null); const [controlsHeight, setControlsHeight] = useState(0); const { isHeaderHidden, wrapperHeight } = useSlidingStickyHeader(pathname); diff --git a/app/scripts/components/common/catalog/index.tsx b/app/scripts/components/common/catalog/index.tsx index bff33ded7..d065738ba 100644 --- a/app/scripts/components/common/catalog/index.tsx +++ b/app/scripts/components/common/catalog/index.tsx @@ -42,13 +42,11 @@ export interface CatalogViewProps { onAction: () => void, } | any; linkProperties: LinkProperties; - pathname: string; } function CatalogView({ datasets, onFilterChanges, - pathname, linkProperties, }: CatalogViewProps) { @@ -72,7 +70,6 @@ function CatalogView({ search={search} taxonomies={taxonomies} onAction={onAction} - pathname={pathname} linkProperties={linkProperties} /> diff --git a/app/scripts/components/data-catalog/container.tsx b/app/scripts/components/data-catalog/container.tsx index b56655908..4aa3af414 100644 --- a/app/scripts/components/data-catalog/container.tsx +++ b/app/scripts/components/data-catalog/container.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { useLocation } from 'react-router'; import { getString } from 'veda'; import { getAllDatasetsProps } from '$utils/veda-data'; import CatalogView from '$components/common/catalog'; @@ -20,7 +19,6 @@ import SmartLink from '$components/common/smart-link'; export default function DataCatalogContainer() { const allDatasets = getAllDatasetsProps(veda_faux_module_datasets); - const pathname = useLocation().pathname; const controlVars = useFiltersWithQS(); return ( @@ -37,7 +35,6 @@ export default function DataCatalogContainer() { controlVars} - pathname={pathname} linkProperties={{ LinkElement: SmartLink, pathAttributeKeyName: 'to' diff --git a/app/scripts/utils/use-pathname.ts b/app/scripts/utils/use-pathname.ts new file mode 100644 index 000000000..702649e04 --- /dev/null +++ b/app/scripts/utils/use-pathname.ts @@ -0,0 +1,59 @@ +import { useEffect, useState } from 'react'; + +/** + * usePathname + * * + * This hook is implemented to work in both client-side rendering + * and server-side rendering environments. During SSR, it initializes the + * `pathname` as an empty string, ensuring the application remains stable in + * non-browser environments. + * + * @returns {string} The current `pathname`. Returns an empty string during SSR + * or if the `window` object is unavailable. + */ +export const usePathname = () => { + const [pathname, setPathname] = useState( + typeof window !== 'undefined' ? window.location.pathname : '' + ); + + useEffect(() => { + if (typeof window === 'undefined') return; + + const updatePathname = () => { + setPathname(window.location.pathname); + }; + + // Listen to popstate events (back/forward navigation) + window.addEventListener('popstate', updatePathname); + + // Detect programmatic navigation by dispatching a custom event + const originalPushState = history.pushState; + const originalReplaceState = history.replaceState; + + const customEvent = new Event('pathnamechange'); + const dispatchPathnameChange = () => { + window.dispatchEvent(customEvent); + }; + + history.pushState = function (...args) { + originalPushState.apply(this, args); + dispatchPathnameChange(); + }; + + history.replaceState = function (...args) { + originalReplaceState.apply(this, args); + dispatchPathnameChange(); + }; + + window.addEventListener('pathnamechange', updatePathname); + + return () => { + window.removeEventListener('popstate', updatePathname); + window.removeEventListener('pathnamechange', updatePathname); + history.pushState = originalPushState; + history.replaceState = originalReplaceState; + }; + }, []); + + return pathname; +}; From 2807db683aa95d18005c3b43d74b10a0499adfb8 Mon Sep 17 00:00:00 2001 From: Vitor George Date: Tue, 26 Nov 2024 15:14:44 +0000 Subject: [PATCH 2/2] Remove deprecated prop --- .../exploration/components/dataset-selector-modal/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/scripts/components/exploration/components/dataset-selector-modal/index.tsx b/app/scripts/components/exploration/components/dataset-selector-modal/index.tsx index 6ba6cd34b..171d08059 100644 --- a/app/scripts/components/exploration/components/dataset-selector-modal/index.tsx +++ b/app/scripts/components/exploration/components/dataset-selector-modal/index.tsx @@ -127,7 +127,6 @@ export function DatasetSelectorModal(props: DatasetSelectorModalProps) { onAction={onAction} filterLayers={true} linkProperties={linkProperties} - pathname={datasetPathName} emptyStateContent={ <>

There are no datasets to show with the selected filters.