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

Load available dates and storm from dates endpoint #1401

Open
wants to merge 28 commits into
base: feat/timeline-tooltip
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5f5b56b
Load available dates and storm from dates endpoint
ericboucher Dec 20, 2024
f16799e
lint
ericboucher Dec 20, 2024
967dd04
Additional fixes
ericboucher Dec 20, 2024
afba00c
Update index.tsx
ericboucher Dec 20, 2024
9d4aa5c
remove unecessary available dates
ericboucher Dec 20, 2024
6b4ff61
Use selectedDateTime
ericboucher Dec 20, 2024
7fbff29
lint
ericboucher Dec 20, 2024
3cfb2f5
lint
ericboucher Dec 20, 2024
2684044
lint
ericboucher Dec 22, 2024
ab39b18
Merge branch 'feat/timeline-tooltip' into load-from-dates
ericboucher Dec 22, 2024
9d3832b
cleanup merge
ericboucher Dec 22, 2024
25cc45c
Use latest windstate for init
ericboucher Dec 22, 2024
21745fc
Track loading state to avoid race conditions
ericboucher Dec 22, 2024
6862c87
Update index.tsx
ericboucher Dec 22, 2024
5e241e8
Fix typing
ericboucher Dec 22, 2024
5c11b90
Update layer ordering
ericboucher Dec 22, 2024
c241169
Show report dates in tooltip
ericboucher Dec 22, 2024
4b55b9e
Use report date in tooltip
ericboucher Dec 22, 2024
2bf262c
Add temp logging
ericboucher Dec 22, 2024
c5fc3c6
tentatively add hash
ericboucher Dec 22, 2024
b2de44a
Update index.ts
ericboucher Dec 22, 2024
f985f7c
Update startDate when necessary
ericboucher Dec 22, 2024
9f01991
Fix closing tooltip
ericboucher Dec 22, 2024
c87d178
Update tooltip style
ericboucher Dec 22, 2024
caf6e56
Use lines instead of polygon fills
ericboucher Jan 7, 2025
9f04dea
Default to January start for timeline AA Storm
ericboucher Jan 7, 2025
1726c44
Replace buffer by uncertainty cone
ericboucher Jan 7, 2025
1b4b5ba
add icons
wadhwamatic Jan 7, 2025
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
1 change: 1 addition & 0 deletions .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ jobs:
runs-on: ubuntu-latest
env:
surge_url: prism-${{ github.event.pull_request.number }}.surge.sh
GIT_HASH: ${{ github.event.pull_request.head.sha }}
steps:
- name: Checkout
uses: actions/checkout@v2
Expand Down
Binary file modified frontend/public/images/anticipatory-action-storm/default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ function AAStormTimelineItem({ currentDate }: AAStormTimelineItemProps) {
const classes = useStyles();

const getStylingClass = () => {
if (windStates.length === 0) {
if (windStates.states.length === 0) {
return classes.emptySpace;
}

if (windStates.find(({ state }) => state === WindState.activated_118)) {
if (
windStates.states.find(({ state }) => state === WindState.activated_118)
) {
return classes.activated2Indicator;
}

if (windStates.find(({ state }) => state === WindState.activated_64)) {
if (
windStates.states.find(({ state }) => state === WindState.activated_64)
) {
return classes.activated1Indicator;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import { MouseEvent } from 'react';
import { formatInUTC } from 'components/MapView/Layers/AnticipatoryActionStormLayer/utils';
import { createStyles, makeStyles, Typography } from '@material-ui/core';
import {
AAFiltersSelector,
AADataSelector,
loadStormReport,
setAAFilters,
} from 'context/anticipatoryAction/AAStormStateSlice';
import { useDispatch, useSelector } from 'react-redux';
import { updateDateRange } from 'context/mapStateSlice';
import { getFormattedDate } from 'utils/date-utils';
import { useUrlHistory } from 'utils/url-utils';
import { useWindStatesByTime } from '../hooks';

function AAStormTooltipContent({ date }: AAStormTooltipContentProps) {
const filters = useSelector(AAFiltersSelector);
const { updateHistory } = useUrlHistory();
const stormData = useSelector(AADataSelector);
const windStates = useWindStatesByTime(date.value);
const classes = useStyles();
const dispatch = useDispatch();
Expand All @@ -21,24 +24,38 @@ function AAStormTooltipContent({ date }: AAStormTooltipContentProps) {
_event: MouseEvent<HTMLElement>,
value: string,
) => {
dispatch(setAAFilters({ selectedDate: value }));
dispatch(loadStormReport({ date: value, stormName: 'chido' }));
const stormDate = new Date(value);
stormDate.setUTCHours(12);
const time = stormDate.getTime();
updateHistory('date', getFormattedDate(time, 'default') as string);
dispatch(updateDateRange({ startDate: time }));
dispatch(
loadStormReport({
date: value,
stormName: windStates.cycloneName || 'chido',
}),
);
};

return (
<div className={classes.container}>
<Typography> {formatInUTC(new Date(date.value), 'MM/dd/yy')}</Typography>
<ToggleButtonGroup
value={filters.selectedDate}
value={stormData.forecastDetails?.reference_time}
exclusive
onChange={hourToggleHandler}
>
{windStates.map(item => {
{windStates.states.map(item => {
const itemDate = new Date(item.ref_time);
const formattedItemTime = formatInUTC(itemDate, 'K aaa');
const formattedItemTime = formatInUTC(itemDate, 'h aaa');

return (
<ToggleButton key={itemDate.valueOf()} value={item.ref_time}>
<ToggleButton
key={itemDate.valueOf()}
value={item.ref_time}
onMouseDown={e => e.preventDefault()}
className={classes.toggleButton}
>
<Typography className={classes.time}>
{formattedItemTime}
</Typography>
Expand All @@ -64,10 +81,15 @@ const useStyles = makeStyles(() =>
lineHeight: '15px',
color: '#101010',
},
toggleButton: {
padding: '6px 6px',
minHeight: 0,
},
}),
);

interface AAStormTooltipContentProps {
date: DateRangeType;
}

export default AAStormTooltipContent;
Original file line number Diff line number Diff line change
@@ -1,43 +1,70 @@
import {
AADataSelector,
AAWindStateReports,
} from 'context/anticipatoryAction/AAStormStateSlice';
import { AAWindStateReports } from 'context/anticipatoryAction/AAStormStateSlice';
import { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { getDateInUTC } from 'components/MapView/Layers/AnticipatoryActionStormLayer/utils';
import { datesAreEqualWithoutTime } from 'utils/date-utils';
import { WindStateReport } from './types';

export const useWindStatesByTime = (currentDate: number) => {
const AAData = useSelector(AADataSelector);
const getWindStatesForDate = (windStateReports: any, date: string | null) => {
if (!date) {
return { states: [], cycloneName: null };
}

// TODO: Handle cases where multiple cyclones overlap in the same time period
const firstAvailableCyclone = Object.keys(windStateReports[date])[0];
if (!firstAvailableCyclone) {
return { states: [], cycloneName: null };
}

return {
states: windStateReports[date][firstAvailableCyclone],
cycloneName: firstAvailableCyclone,
};
};

export const useWindStatesByTime = (currentDate: number): WindStateReport => {
const windStateReports = useSelector(AAWindStateReports);
const cycloneOfInterest = AAData.forecastDetails?.cyclone_name;

return useMemo(() => {
if (!cycloneOfInterest) {
return [];
const dates = Object.keys(windStateReports);
if (dates.length === 0) {
return { states: [], cycloneName: null };
}
// If currentDate is 0 or null, get the latest report
if (!currentDate) {
const latestDate = dates.reduce((latest, current) =>
new Date(current) > new Date(latest) ? current : latest,
);
return getWindStatesForDate(windStateReports, latestDate);
}

const date = Object.keys(windStateReports).find(analysedDate => {
const analysedDateInUTC = getDateInUTC(analysedDate, false);
if (!analysedDateInUTC) {
return false;
}

return datesAreEqualWithoutTime(analysedDateInUTC, currentDate);
const isEqual = datesAreEqualWithoutTime(analysedDateInUTC, currentDate);
return isEqual;
});

if (!date) {
return [];
}
const result = getWindStatesForDate(windStateReports, date || null);
return result;
}, [currentDate, windStateReports]);
};

const foundCycloneName = Object.keys(windStateReports[date])
.map(i => i.toLowerCase())
.find(cycloneName => cycloneName === cycloneOfInterest.toLowerCase());
export const useLatestWindStates = (): WindStateReport => {
const windStateReports = useSelector(AAWindStateReports);

if (!foundCycloneName) {
return [];
return useMemo(() => {
const dates = Object.keys(windStateReports);
if (dates.length === 0) {
return { states: [], cycloneName: null };
}

return windStateReports[date][foundCycloneName];
}, [cycloneOfInterest, currentDate, windStateReports]);
const latestDate = dates.reduce((latest, current) =>
new Date(current) > new Date(latest) ? current : latest,
);

return getWindStatesForDate(windStateReports, latestDate);
}, [windStateReports]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ const useStyles = makeStyles(() =>
},
AAStormTooltip: {
backgroundColor: '#FFFFFF',
border: '1px solid #D3D3D3',
},
layerOneDate: createLayerStyles(LIGHT_BLUE_HEX, 0),
layerTwoDate: createLayerStyles(LIGHT_GREEN_HEX, 10),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ type ShortDate = string;
type CycloneName = string;
export type TimeAndState = { ref_time: string; state: WindState };
export type DateJSON = Record<ShortDate, Record<CycloneName, TimeAndState[]>>;

export type WindStateReport = {
states: TimeAndState[];
cycloneName: string | null;
};
2 changes: 1 addition & 1 deletion frontend/src/components/MapView/DateSelector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const calculateStartAndEndDates = (startDate: Date, selectedTab: string) => {
? 1
: 0);

const startMonth = isAnticipatoryActionLayer(selectedTab) ? 3 : 0; // April for anticipatory_action, January otherwise
const startMonth = Panel.AnticipatoryActionDrought === selectedTab ? 3 : 0; // April for anticipatory_action, January otherwise

const start = new Date(year, startMonth, 1);
const end = new Date(year, startMonth + 11, 31);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ exports[`AAStormLandfallPopup component renders as expected 1`] = `
classname="makeStyles-text-4 makeStyles-title-5"
variant="body1"
>
Forecast date:
Report date:
2024-03-01 6pm
</mock-typography>
<div
Expand Down Expand Up @@ -56,7 +56,7 @@ exports[`AAStormLandfallPopup component renders as expected 1`] = `
classname="makeStyles-text-4 makeStyles-textAlignRight-6"
variant="body1"
>
1 - 6 hrs
247 - 252 hrs
</mock-typography>
</div>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,9 @@ describe('AAStormLandfallPopup component', () => {
district: 'Inhassoro',
severity: [AACategory.Severe, AACategory.Moderate],
};
const timelineDate = '2024-03-12 00:00:00';

const { container } = render(
<PopupContent
reportDate={reportDate}
landfallInfo={landfallInfo}
timelineDate={timelineDate}
/>,
<PopupContent reportDate={reportDate} landfallInfo={landfallInfo} />,
);
expect(container).toMatchSnapshot();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ import {
formatReportDate,
} from '../../utils';

function PopupContent({
landfallInfo,
reportDate,
timelineDate,
}: PopupContentProps) {
function PopupContent({ landfallInfo, reportDate }: PopupContentProps) {
const classes = useStyles();

return (
Expand All @@ -20,7 +16,7 @@ function PopupContent({
variant="body1"
className={`${classes.text} ${classes.title}`}
>
Forecast date: {formatReportDate(reportDate)}
Report date: {formatReportDate(reportDate)}
</Typography>
<div className={classes.itemContainer}>
<Typography variant="body1" className={classes.text}>
Expand All @@ -45,7 +41,7 @@ function PopupContent({
variant="body1"
className={`${classes.text} ${classes.textAlignRight}`}
>
{formatLandfallEstimatedLeadtime(landfallInfo.time, timelineDate)}
{formatLandfallEstimatedLeadtime(landfallInfo.time, reportDate)}
</Typography>
</div>
<div className={classes.itemContainer}>
Expand Down Expand Up @@ -98,7 +94,6 @@ const useStyles = makeStyles(() =>
interface PopupContentProps {
landfallInfo: LandfallInfo;
reportDate: string;
timelineDate: string;
}

export default PopupContent;
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ function AAStormLandfallPopup({
onClose,
landfallInfo,
reportDate,
timelineDate,
}: AAStormLandfallPopupProps) {
const classes = useStyles();

Expand All @@ -28,11 +27,7 @@ function AAStormLandfallPopup({
className={classes.popup}
maxWidth="280px"
>
<PopupContent
landfallInfo={landfallInfo}
reportDate={reportDate}
timelineDate={timelineDate}
/>
<PopupContent landfallInfo={landfallInfo} reportDate={reportDate} />
</Popup>
);
}
Expand All @@ -41,7 +36,6 @@ interface AAStormLandfallPopupProps {
point: Point;
landfallInfo: LandfallInfo;
reportDate: string;
timelineDate: string;
onClose: () => void;
}

Expand Down
Loading
Loading