Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(catalog): introduce usePathname hook, remove React Router dependency from the Catalog #1276

Merged
merged 2 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions app/scripts/components/common/catalog/catalog-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,7 +22,6 @@ interface CatalogCardProps {
selectable?: boolean;
selected?: boolean;
onDatasetClick?: () => void;
pathname?: string;
linkProperties?: LinkProperties;
}

Expand Down Expand Up @@ -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);
Expand Down
5 changes: 0 additions & 5 deletions app/scripts/components/common/catalog/catalog-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export interface CatalogContentProps {
taxonomies: Record<string, string[]>;
onAction: (action: FilterActions, value?: any) => void;
linkProperties: LinkProperties;
pathname?: string;
}

const DEFAULT_SORT_OPTION = 'asc';
Expand Down Expand Up @@ -72,7 +71,6 @@ function CatalogContent({
search,
taxonomies,
onAction,
pathname,
linkProperties
}: CatalogContentProps) {
const [exclusiveSourceSelected, setExclusiveSourceSelected] = useState<string | null>(null);
Expand Down Expand Up @@ -215,7 +213,6 @@ function CatalogContent({
exclusiveSourceSelected={exclusiveSourceSelected}
customTopOffset={isSelectable ? 50 : 0}
openByDefault={false}
pathname={pathname}
/>
<Catalog>
<CatalogTagsContainer
Expand Down Expand Up @@ -264,7 +261,6 @@ function CatalogContent({
selectable={true}
selected={selectedIds.includes(datasetLayer.id)}
onDatasetClick={() => onCardSelect(datasetLayer.id, currentDataset)}
pathname={pathname}
/>
</li>
))}
Expand All @@ -280,7 +276,6 @@ function CatalogContent({
dataset={d}
searchTerm={search}
linkProperties={linkProperties}
pathname={pathname}
/>
</li>
))}
Expand Down
5 changes: 3 additions & 2 deletions app/scripts/components/common/catalog/filters-control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -27,7 +28,6 @@ interface FiltersMenuProps {
exclusiveSourceSelected?: string | null;
customTopOffset?: number;
openByDefault?: boolean;
pathname?: string;
}

export default function FiltersControl(props: FiltersMenuProps) {
Expand All @@ -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<HTMLDivElement>(null);
const [controlsHeight, setControlsHeight] = useState<number>(0);
const { isHeaderHidden, wrapperHeight } = useSlidingStickyHeader(pathname);
Expand Down
3 changes: 0 additions & 3 deletions app/scripts/components/common/catalog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,11 @@ export interface CatalogViewProps {
onAction: () => void,
} | any;
linkProperties: LinkProperties;
pathname: string;
}

function CatalogView({
datasets,
onFilterChanges,
pathname,
linkProperties,
}: CatalogViewProps) {

Expand All @@ -72,7 +70,6 @@ function CatalogView({
search={search}
taxonomies={taxonomies}
onAction={onAction}
pathname={pathname}
linkProperties={linkProperties}
/>
</CatalogWrapper>
Expand Down
3 changes: 0 additions & 3 deletions app/scripts/components/data-catalog/container.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 (
Expand All @@ -37,7 +35,6 @@ export default function DataCatalogContainer() {
<CatalogView
datasets={allDatasets}
onFilterChanges={() => controlVars}
pathname={pathname}
linkProperties={{
LinkElement: SmartLink,
pathAttributeKeyName: 'to'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ export function DatasetSelectorModal(props: DatasetSelectorModalProps) {
onAction={onAction}
filterLayers={true}
linkProperties={linkProperties}
pathname={datasetPathName}
emptyStateContent={
<>
<p>There are no datasets to show with the selected filters.</p>
Expand Down
59 changes: 59 additions & 0 deletions app/scripts/utils/use-pathname.ts
Original file line number Diff line number Diff line change
@@ -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 = () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

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;
};
Loading