diff --git a/app/scripts/components/common/card-sources.tsx b/app/scripts/components/common/card-sources.tsx
index d592a1c68..9d9cf6cca 100644
--- a/app/scripts/components/common/card-sources.tsx
+++ b/app/scripts/components/common/card-sources.tsx
@@ -1,8 +1,7 @@
import React from 'react';
import styled from 'styled-components';
-import { Link } from 'react-router-dom';
import { listReset } from '@devseed-ui/theme-provider';
-import { TaxonomyItem } from '$types/veda';
+import { LinkProperties, TaxonomyItem } from '$types/veda';
import { FilterActions } from '$components/common//catalog/utils';
const SourcesUl = styled.ul`
@@ -23,11 +22,12 @@ interface SourcesListProps {
sources?: TaxonomyItem[];
onSourceClick?: (v: string) => void;
rootPath?: string;
+ linkProperties?: LinkProperties;
}
export function CardSourcesList(props: SourcesListProps) {
- const { sources, onSourceClick, rootPath } = props;
-
+ const { sources, onSourceClick, linkProperties, rootPath } = props;
+ const { LinkElement, pathAttributeKeyName } = linkProperties as { LinkElement: React.ElementType, pathAttributeKeyName: string };
if (!sources?.length) return null;
// No link rendering
@@ -50,19 +50,19 @@ export function CardSourcesList(props: SourcesListProps) {
{sources.map((source) => (
- {
e.preventDefault();
onSourceClick(source.id);
}}
>
{source.name}
-
+
))}
diff --git a/app/scripts/components/common/card/index.tsx b/app/scripts/components/common/card/index.tsx
index ce98fac0b..74e705cd1 100644
--- a/app/scripts/components/common/card/index.tsx
+++ b/app/scripts/components/common/card/index.tsx
@@ -1,6 +1,6 @@
-import React, { lazy, MouseEventHandler, ComponentType } from 'react';
+import React, { lazy, MouseEventHandler } from 'react';
import styled, { css } from 'styled-components';
-import { format } from 'date-fns';
+import format from 'date-fns/format';
import { CollecticonExpandTopRight } from '@devseed-ui/collecticons';
import {
glsp,
@@ -25,6 +25,7 @@ import HorizontalInfoCard, {
import { variableBaseType, variableGlsp } from '$styles/variable-utils';
import { ElementInteractive } from '$components/common/element-interactive';
import { Figure } from '$components/common/figure';
+import { LinkProperties } from '$types/veda';
type CardType = 'classic' | 'cover' | 'featured' | 'horizontal-info';
@@ -230,12 +231,6 @@ export function ExternalLinkFlag() {
);
}
-export interface LinkProperties {
- LinkElement: string | ComponentType | undefined;
- pathAttributeKeyName: string;
- onLinkClick?: MouseEventHandler;
-}
-
export interface LinkWithPathProperties extends LinkProperties {
linkTo: string;
}
@@ -255,16 +250,17 @@ export interface CardComponentBaseProps {
footerContent?: JSX.Element;
hideExternalLinkBadge?: boolean;
onCardClickCapture?: MouseEventHandler;
+ onClick?: MouseEventHandler;
}
-// @TODO: Consolidate these props when the instance adapts the new syntax
+// @TODO: Created because GHG uses the card component directly and passes in "linkTo" prop. Consolidate these props when the instance adapts the new syntax
// Specifically: https://github.com/US-GHG-Center/veda-config-ghg/blob/develop/custom-pages/news-and-events/component.tsx#L108
export interface CardComponentPropsDeprecated extends CardComponentBaseProps {
linkTo: string;
- onLinkClick?: MouseEventHandler;
}
+
export interface CardComponentProps extends CardComponentBaseProps {
- linkProperties: LinkWithPathProperties;
+ linkProperties?: LinkWithPathProperties;
}
type CardComponentPropsType = CardComponentProps | CardComponentPropsDeprecated;
@@ -291,40 +287,37 @@ function CardComponent(props: CardComponentPropsType) {
parentTo,
footerContent,
hideExternalLinkBadge,
- onCardClickCapture
+ onCardClickCapture,
+ onClick,
} = props;
// @TODO: This process is not necessary once all the instances adapt the linkProperties syntax
// Consolidate them to use LinkProperties only
- let linkProperties: LinkWithPathProperties;
+ let linkProperties: LinkWithPathProperties | undefined;
if (hasLinkProperties(props)) {
// Handle new props with linkProperties
const { linkProperties: linkPropertiesProps } = props;
linkProperties = linkPropertiesProps;
} else {
- const { linkTo, onLinkClick } = props;
- linkProperties = {
+ const { linkTo } = props;
+ linkProperties = linkTo ? {
linkTo,
- onLinkClick,
pathAttributeKeyName: 'to',
LinkElement: SmartLink
- };
+ } : undefined;
}
- const isExternalLink = /^https?:\/\//.test(linkProperties.linkTo);
+ const isExternalLink = linkProperties ? /^https?:\/\//.test(linkProperties.linkTo) : false;
return (
{cardType !== 'horizontal-info' && (
<>
@@ -340,7 +333,7 @@ function CardComponent(props: CardComponentPropsType) {
parentTo &&
tagLabels.map((label) => (
diff --git a/app/scripts/components/common/catalog/catalog-card.tsx b/app/scripts/components/common/catalog/catalog-card.tsx
index e9a85a751..944507108 100644
--- a/app/scripts/components/common/catalog/catalog-card.tsx
+++ b/app/scripts/components/common/catalog/catalog-card.tsx
@@ -1,27 +1,18 @@
-import React from 'react';
-import styled, { css } from 'styled-components';
-import {
- CollecticonPlus,
- CollecticonTickSmall,
- iconDataURI
-} from '@devseed-ui/collecticons';
-import { glsp, themeVal } from '@devseed-ui/theme-provider';
-
-import { Card, LinkProperties } from '../card';
-import { CardMeta, CardTopicsList } from '../card/styles';
-import { DatasetClassification } from '../dataset-classification';
-import { CardSourcesList } from '../card-sources';
-import TextHighlight from '../text-highlight';
+import React from "react";
+import styled, { css } from "styled-components";
+import { CollecticonPlus, CollecticonTickSmall, iconDataURI } from "@devseed-ui/collecticons";
+import { glsp, themeVal } from "@devseed-ui/theme-provider";
+import { Card } from "../card";
+import { CardMeta, CardTopicsList } from "../card/styles";
+import { DatasetClassification } from "../dataset-classification";
+import { CardSourcesList } from "../card-sources";
+import TextHighlight from "../text-highlight";
import { getDatasetDescription, getMediaProperty } from './utils';
-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 { LinkProperties } from '$types/veda';
+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";
interface CatalogCardProps {
dataset: DatasetData;
@@ -31,7 +22,7 @@ interface CatalogCardProps {
selected?: boolean;
onDatasetClick?: () => void;
pathname?: string;
- linkProperties: LinkProperties;
+ linkProperties?: LinkProperties;
}
const CardSelectable = styled(Card)<{
@@ -142,10 +133,11 @@ export const CatalogCard = (props: CatalogCardProps) => {
overline={
-
+
}
linkLabel='View dataset'
+ onClick={handleClick}
title={
{title}
@@ -179,11 +171,7 @@ export const CatalogCard = (props: CatalogCardProps) => {
) : null}
>
}
- linkProperties={{
- ...linkProperties,
- linkTo: linkTo,
- onLinkClick: handleClick
- }}
+ {...(linkProperties ? {linkProperties: {...linkProperties, linkTo: linkTo}} : {})}
/>
);
};
diff --git a/app/scripts/components/common/catalog/catalog-content.tsx b/app/scripts/components/common/catalog/catalog-content.tsx
index 6240116f8..dcac02395 100644
--- a/app/scripts/components/common/catalog/catalog-content.tsx
+++ b/app/scripts/components/common/catalog/catalog-content.tsx
@@ -3,13 +3,13 @@ import styled from 'styled-components';
import { glsp, themeVal } from '@devseed-ui/theme-provider';
import TextHighlight from '../text-highlight';
import { CollecticonDatasetLayers } from '../icons/dataset-layers';
-import { LinkProperties } from '../card';
import { prepareDatasets } from './prepare-datasets';
import FiltersControl from './filters-control';
import { CatalogCard } from './catalog-card';
import CatalogTagsContainer from './catalog-tags';
import { FilterActions } from './utils';
+import { LinkProperties } from '$types/veda';
import { DatasetData, DatasetDataWithEnhancedLayers } from '$types/veda';
import { CardList } from '$components/common/card/styles';
import EmptyHub from '$components/common/empty-hub';
@@ -264,7 +264,6 @@ function CatalogContent({
selectable={true}
selected={selectedIds.includes(datasetLayer.id)}
onDatasetClick={() => onCardSelect(datasetLayer.id, currentDataset)}
- linkProperties={linkProperties}
pathname={pathname}
/>
diff --git a/app/scripts/components/common/catalog/index.tsx b/app/scripts/components/common/catalog/index.tsx
index f4dddfc52..bff33ded7 100644
--- a/app/scripts/components/common/catalog/index.tsx
+++ b/app/scripts/components/common/catalog/index.tsx
@@ -1,9 +1,8 @@
import React from 'react';
import styled from 'styled-components';
import { themeVal } from '@devseed-ui/theme-provider';
-import { LinkProperties } from '../card';
import CatalogContent from './catalog-content';
-import { DatasetData } from '$types/veda';
+import { DatasetData, LinkProperties } from '$types/veda';
import {
useSlidingStickyHeaderProps
} from '$components/common/layout-root/useSlidingStickyHeaderProps';
diff --git a/app/scripts/components/common/element-interactive.js b/app/scripts/components/common/element-interactive.js
index 497679951..6deebd1f8 100644
--- a/app/scripts/components/common/element-interactive.js
+++ b/app/scripts/components/common/element-interactive.js
@@ -73,7 +73,13 @@ const InteractiveLink = styled.a`
*/
export const ElementInteractive = React.forwardRef(
function ElementInteractiveFwd(props, ref) {
- const { linkProps = {}, linkLabel = 'View', children, ...rest } = props;
+ const {
+ linkProps = {},
+ linkLabel = 'View',
+ children,
+ onClick,
+ ...rest
+ } = props;
const [isStateOver, setStateOver] = useState(false);
const [isStateActive, setStateActive] = useState(false);
const [isStateFocus, setStateFocus] = useState(false);
@@ -92,6 +98,7 @@ export const ElementInteractive = React.forwardRef(
setStateOver(false);
setStateActive(false);
}, [])}
+ onClick={onClick}
>
{children}
{
const date = new Date(d[dateProperty ?? '']);
const topics = getTaxonomy(d, TAXONOMY_TOPICS)?.values;
-
+ const linkProperties = {
+ pathAttributeKeyName: 'to',
+ LinkElement: SmartLink
+ };
return (
)}
diff --git a/app/scripts/components/common/map/controls/aoi/custom-aoi-control.tsx b/app/scripts/components/common/map/controls/aoi/custom-aoi-control.tsx
index 9d5a5ae18..9f2a7814d 100644
--- a/app/scripts/components/common/map/controls/aoi/custom-aoi-control.tsx
+++ b/app/scripts/components/common/map/controls/aoi/custom-aoi-control.tsx
@@ -76,15 +76,25 @@ function CustomAoI({
const [selectedState, setSelectedState] = useState('');
const [presetIds, setPresetIds] = useState([]);
const [fileUploadedIds, setFileUplaodedIds] = useState([]);
+ const [updated, forceUpdate] = useState(0); // @NOTE: Needed so that this component re-renders to when the draw selection changes from feature to point.
+ const [isAreaSelected, setAreaSelected] = useState(false);
+ const [isPointSelected, setPointSelected] = useState(false);
const [selectedForEditing, setSelectedForEditing] = useAtom(selectedForEditingAtom);
const { onUpdate, isDrawing, setIsDrawing, features } = useAois();
const aoiDeleteAll = useSetAtom(aoiDeleteAllAtom);
- // Needed so that this component re-renders to when the draw selection changes
- // from feature to point.
- const [, forceUpdate] = useState(0);
+ // @NOTE: map?._drawControl?.getSelected() needs access to mapboxgl draw context store,
+ // but the function gets called before mapboxdraw store is initialized (before being added to map) resulting in an error
+ useEffect(() => {
+ if (!map) return;
+
+ const mbDraw = map?._drawControl;
+ setAreaSelected(!!(mbDraw?.getSelected().features.length));
+ setPointSelected(!!(mbDraw?.getSelectedPoints()?.features.length));
+ }, [map, updated]);
+
useEffect(() => {
const mbDraw = map?._drawControl;
if (!mbDraw) return;
@@ -220,6 +230,7 @@ function CustomAoI({
// selected, the trash method doesn't do anything. So, in this case, we
// trigger the delete for the whole feature.
const selectedFeatures = mbDraw.getSelected()?.features;
+
if (
mbDraw.getMode() === DIRECT_SELECT &&
selectedFeatures.length &&
@@ -248,9 +259,6 @@ function CustomAoI({
mbDraw.trash();
}, [features, aoiDeleteAll, map]);
- const isAreaSelected = !!map?._drawControl?.getSelected().features.length;
- const isPointSelected =
- !!map?._drawControl.getSelectedPoints().features.length;
const hasFeatures = !!features.length;
return (
@@ -330,21 +338,19 @@ export default function CustomAoIControl({
disableReason?: React.ReactNode;
}) {
const { main } = useMaps();
-
const { isDrawing } = useAois();
- // Start/stop the drawing.
+ // Start the drawing mode when isDrawing is true
+ // There's no need to switch back to 'simple_select' mode when !isDrawing
+ // as Mapbox Draw handles this internally when the drawing is completed
useEffect(() => {
- // Property was added to access draw control.
- const mbDraw = main?._drawControl;
+ if (!main) return;
+ const mbDraw = main._drawControl;
+
if (!mbDraw) return;
if (isDrawing) {
mbDraw.changeMode(DRAW_POLYGON);
- } else {
- mbDraw.changeMode(SIMPLE_SELECT, {
- featureIds: mbDraw.getSelectedIds()
- });
}
}, [main, isDrawing]);
@@ -354,5 +360,7 @@ export default function CustomAoIControl({
position: 'top-left'
}
);
+
return null;
}
+
diff --git a/app/scripts/components/common/map/controls/aoi/index.tsx b/app/scripts/components/common/map/controls/aoi/index.tsx
index 3f8a4b2da..808cc9164 100644
--- a/app/scripts/components/common/map/controls/aoi/index.tsx
+++ b/app/scripts/components/common/map/controls/aoi/index.tsx
@@ -2,14 +2,18 @@ import MapboxDraw from '@mapbox/mapbox-gl-draw';
import StaticMode from '@mapbox/mapbox-gl-draw-static-mode';
import { useTheme } from 'styled-components';
import { useAtomValue } from 'jotai';
-import { useRef } from 'react';
import { useControl } from 'react-map-gl';
+import type { MapRef } from 'react-map-gl';
import useAois from '../hooks/use-aois';
import { aoisFeaturesAtom } from './atoms';
import { computeDrawStyles } from './style';
type DrawControlProps = MapboxDraw.DrawOptions;
+interface ExtendedMapRef extends MapRef {
+ _drawControl?: MapboxDraw;
+}
+
export const STATIC_MODE = 'static_mode';
export const SIMPLE_SELECT = 'simple_select';
export const DIRECT_SELECT = 'direct_select';
@@ -30,13 +34,12 @@ const customDirectSelect = {
export default function DrawControl(props: DrawControlProps) {
const theme = useTheme();
- const control = useRef();
const aoisFeatures = useAtomValue(aoisFeaturesAtom);
const { onUpdate, onDelete, onSelectionChange, onDrawModeChange } = useAois();
- useControl(
+ const drawControl = useControl(
() => {
- control.current = new MapboxDraw({
+ const control = new MapboxDraw({
displayControlsDefault: false,
styles: computeDrawStyles(theme),
modes: {
@@ -47,23 +50,25 @@ export default function DrawControl(props: DrawControlProps) {
},
...props
});
- return control.current;
+ return control;
},
- ({ map }: { map: any }) => {
- map._drawControl = control.current;
+ ({ map }) => {
+ // We're making the controls available on the map instance for later use throughout
+ // the app (e.g in the CustomAoIControl)
+ (map as ExtendedMapRef)._drawControl = drawControl;
map.on('draw.create', onUpdate);
map.on('draw.update', onUpdate);
map.on('draw.delete', onDelete);
map.on('draw.selectionchange', onSelectionChange);
map.on('draw.modechange', onDrawModeChange);
map.on('load', () => {
- control.current?.set({
+ drawControl.set({
type: 'FeatureCollection',
features: aoisFeatures
});
});
},
- ({ map }: { map: any }) => {
+ ({ map }) => {
map.off('draw.create', onUpdate);
map.off('draw.update', onUpdate);
map.off('draw.delete', onDelete);
@@ -76,4 +81,4 @@ export default function DrawControl(props: DrawControlProps) {
);
return null;
-}
+}
\ No newline at end of file
diff --git a/app/scripts/components/common/map/controls/hooks/use-themed-control.tsx b/app/scripts/components/common/map/controls/hooks/use-themed-control.tsx
index ff50f88a6..925e8d1b6 100644
--- a/app/scripts/components/common/map/controls/hooks/use-themed-control.tsx
+++ b/app/scripts/components/common/map/controls/hooks/use-themed-control.tsx
@@ -54,4 +54,4 @@ export default function useThemedControl(
useControl(() => new ThemedControl(), opts);
return null;
-}
+}
\ No newline at end of file
diff --git a/app/scripts/components/common/map/style-generators/basemap.tsx b/app/scripts/components/common/map/style-generators/basemap.tsx
index b5e037b98..ad866f7f5 100644
--- a/app/scripts/components/common/map/style-generators/basemap.tsx
+++ b/app/scripts/components/common/map/style-generators/basemap.tsx
@@ -33,7 +33,6 @@ export function Basemap({
boundariesOption = true
}: BasemapProps) {
const { updateStyle } = useMapStyle();
-
const [baseStyle, setBaseStyle] = useState