Skip to content

Commit

Permalink
Adding support for seasonal cdi; COUNTRY=jordan (#1301)
Browse files Browse the repository at this point in the history
* Updating to use month range

* Fix date propagation in CDI

* Update composite_data.ts

* Use getFormattedDate

* Update composite_data.ts

* Update composite_data.ts

* add mozambique cdi for testing

* Update index.tsx

* Dynamic error cdi; COUNTRY=jordan (#1259)

* Updating to use local hip service

* no console

* Clean up

* Clean up readme

---------

Co-authored-by: Christopher J Lowrie <[email protected]>
Co-authored-by: ericboucher <[email protected]>
Co-authored-by: Amit Wadhwa <[email protected]>
Co-authored-by: Will Gislason <[email protected]>

* Removing local hip service env var

* Error handling fixes and end date support form the lyer

* Initial support for seasonal CDI

* Remove console log, update configs for tests to pass

* Appease eslint

* Fixing seasonal fetch - using first of next season as 'end'

* Support for validity areas in composite layers

* Reducing date deduping

* Clean up

* refactor datesAreEqualWithoutTime

* Fix datesAreEqualWithoutTime

* Adding 'season' validity

* Skip the tests

* Fixing query date for seasonal range

* Updating CDI config in cambodia and mozambique

* Update tests

* undo log update

* update mozambique CDI for testing

* Update composite monthly date range

* Handling overlap selection for dates without overlapping validity

* fix test

* rename scale to period

* Updates to date picking

* Allow composite layers with validity or without

* Update the query display matching to be more flexible

* Updating event handlers in time selection

* Test fic

* Better test fix

* Break out visible layer dates and selectable layer dates

* don't fetch CDI for invalid dates

* fix tests

* Fixing availability date indicator

* Ensuring messaging fires

* fix lint

* Reuse clickDate for draggable item

* Update index.tsx

* Update datasetStateSlice.ts

* Update index.tsx

* Adding back no date overlapping handling

* Ensuring that date selection warning is displayed when the date jumps to valid date

* Remove check intersection, leveraging logic in layer-utils

* using in datesAreEqualWithoutTime in findDateIndex

* Update layers-utils.tsx

* Only remove non-boundary layers

* Handling AA dates with fewer limitations

* Add comment to code

* Fix extra visible dates for AA

* Update logic in useLayer's useEffect to ensure we don't exit early

* Fix AA parseFloat

* Ensuring group is writable in formatLayersCategories

* fixing eslint

---------

Co-authored-by: Christopher J Lowrie <[email protected]>
Co-authored-by: ericboucher <[email protected]>
Co-authored-by: Amit Wadhwa <[email protected]>
Co-authored-by: Chris Lowrie <[email protected]>
  • Loading branch information
5 people authored Jul 29, 2024
1 parent 47c05e5 commit 7e7cd86
Show file tree
Hide file tree
Showing 23 changed files with 853 additions and 332 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { createStyles, makeStyles } from '@material-ui/core';
import React, { memo } from 'react';
import React, { memo, useMemo } from 'react';
import 'react-datepicker/dist/react-datepicker.css';
import { DateItem, DateRangeType } from 'config/types';
import { binaryFind } from 'utils/date-utils';
import { datesAreEqualWithoutTime } from 'utils/date-utils';

const TimelineItem = memo(
({
Expand All @@ -13,14 +13,35 @@ const TimelineItem = memo(
}: TimelineItemProps) => {
// Pre-compute the matching indices for all layers
const classes = useStyles();
const layerMatches = concatenatedLayers.map(layerDates =>
binaryFind<DateItem>(
layerDates,
new Date(currentDate.value).setUTCHours(0, 0, 0, 0),
(i: DateItem) => new Date(i.displayDate).setUTCHours(0, 0, 0, 0),
),

const displayDateMatches = useMemo(
() =>
concatenatedLayers.map(layerDates =>
layerDates.findIndex(i =>
datesAreEqualWithoutTime(i.displayDate, currentDate.value),
),
),
[concatenatedLayers, currentDate.value],
);

const layerMatches = useMemo(() => {
const queryDateMatches = concatenatedLayers.map(layerDates =>
layerDates.findIndex(i =>
datesAreEqualWithoutTime(i.queryDate, currentDate.value),
),
);

return displayDateMatches.map((displayDateMatch, layerIndex) =>
queryDateMatches[layerIndex] > -1 &&
!datesAreEqualWithoutTime(
concatenatedLayers[layerIndex][displayDateMatch].queryDate,
currentDate.value,
)
? queryDateMatches[layerIndex]
: displayDateMatch,
);
}, [concatenatedLayers, currentDate.value, displayDateMatches]);

const hasNextItemDirectionForward = (
_matchingDate: DateItem,
_layerDates: DateItem[],
Expand All @@ -32,7 +53,7 @@ const TimelineItem = memo(
): boolean => false;

const isQueryDate = (date: DateItem): boolean =>
date.queryDate === date.displayDate;
datesAreEqualWithoutTime(date.queryDate, date.displayDate);

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { Provider } from 'react-redux';
import TimelineItems from '.';

const props = {
selectedLayers: [],
orderedLayers: [],
truncatedLayers: [],
selectedLayerTitles: [],
availableDates: [],
dateRange: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ import {
TIMELINE_ITEM_WIDTH,
} from 'components/MapView/DateSelector/utils';
import { datesAreEqualWithoutTime, getFormattedDate } from 'utils/date-utils';
import { useSelector } from 'react-redux';
import { AAAvailableDatesSelector } from 'context/anticipatoryActionStateSlice';
import { dateRangeSelector } from 'context/mapStateSlice/selectors';
import { getRequestDate } from 'utils/server-utils';
import TimelineItem from './TimelineItem';
import TimelineLabel from './TimelineLabel';
import TooltipItem from './TooltipItem';
Expand All @@ -43,54 +39,15 @@ const TimelineItems = memo(
dateRange,
clickDate,
locale,
selectedLayers,
orderedLayers,
truncatedLayers,
availableDates,
}: TimelineItemsProps) => {
const classes = useStyles();
const { t } = useSafeTranslation();
const AAAvailableDates = useSelector(AAAvailableDatesSelector);

// Create a temporary layer for each AA window
const AALayers = AAAvailableDates
? [
{
id: 'anticipatory_action_window_1',
title: 'Window 1',
dateItems: AAAvailableDates['Window 1'],
},
{
id: 'anticipatory_action_window_2',
title: 'Window 2',
dateItems: AAAvailableDates['Window 2'],
},
]
: [];

// Replace anticipatory action unique layer by window1 and window2 layers
// Keep anticipatory actions at the top of the timeline
// eslint-disable-next-line fp/no-mutating-methods
const orderedLayers = selectedLayers
.sort((a, b) => {
const aIsAnticipatory = a.id.includes('anticipatory_action');
const bIsAnticipatory = b.id.includes('anticipatory_action');
if (aIsAnticipatory && !bIsAnticipatory) {
return -1;
}
if (!aIsAnticipatory && bIsAnticipatory) {
return 1;
}
return 0;
})
.map(l => {
if (l.type === 'anticipatory_action') {
return AALayers;
}
return l;
})
.flat();

// Hard coded styling for date items (first, second, and third layers)
const DATE_ITEM_STYLING: DateItemStyle[] = React.useMemo(
const DATE_ITEM_STYLING: DateItemStyle[] = useMemo(
() => [
{
class: classes.layerOneDate,
Expand Down Expand Up @@ -151,43 +108,6 @@ const TimelineItems = memo(
[DATE_ITEM_STYLING, orderedLayers, t],
);

const timelineStartDate: string = new Date(
dateRange[0].value,
).toDateString();

const dateSelector = useSelector(dateRangeSelector);
// We truncate layer by removing date that will not be drawn to the Timeline
const truncatedLayers: DateItem[][] = useMemo(() => {
// returns the index of the first date in layer that matches the first Timeline date
const findLayerFirstDateIndex = (items: DateItem[]): number =>
items
.map(d => new Date(d.displayDate).toDateString())
.indexOf(timelineStartDate);

return [
...orderedLayers.map(layer => {
const firstIndex = findLayerFirstDateIndex(layer.dateItems);
const layerQueryDate = getRequestDate(
layer.dateItems,
dateSelector.startDate,
);
// Filter date items based on queryDate and layerQueryDate
const filterDateItems = (items: DateItem[]) =>
items.filter(
item =>
item.queryDate === layerQueryDate ||
item.queryDate === item.displayDate,
);
if (firstIndex === -1) {
return filterDateItems(layer.dateItems);
}
// truncate the date item array at index matching timeline first date
// eslint-disable-next-line fp/no-mutating-methods
return filterDateItems(layer.dateItems.slice(firstIndex));
}),
];
}, [orderedLayers, timelineStartDate, dateSelector.startDate]);

const availableDatesToDisplay = availableDates.filter(
date => date >= dateRange[0].value,
);
Expand Down Expand Up @@ -330,8 +250,9 @@ export interface TimelineItemsProps {
dateRange: DateRangeType[];
clickDate: (arg: number) => void;
locale: string;
selectedLayers: DateCompatibleLayerWithDateItems[];
availableDates: number[];
orderedLayers: DateCompatibleLayerWithDateItems[];
truncatedLayers: DateItem[][];
}

export default TimelineItems;
Loading

0 comments on commit 7e7cd86

Please sign in to comment.