-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Advisory bulletins by fire center - Fixes zoom to province extent
- Loading branch information
Showing
17 changed files
with
633 additions
and
221 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
66 changes: 66 additions & 0 deletions
66
web/src/features/fba/components/infoPanel/AdvisoryReport.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { Box, Tabs, Tab, Grid } from '@mui/material' | ||
import { FireCenter } from 'api/fbaAPI' | ||
import { INFO_PANEL_CONTENT_BACKGROUND } from 'app/theme' | ||
import AdvisoryText from 'features/fba/components/infoPanel/AdvisoryText' | ||
import InfoAccordion from 'features/fba/components/infoPanel/InfoAccordion' | ||
import { DateTime } from 'luxon' | ||
import React, { useState } from 'react' | ||
|
||
interface AdvisoryReportProps { | ||
issueDate: DateTime | null | ||
forDate: DateTime | ||
advisoryThreshold: number | ||
selectedFireCenter?: FireCenter | ||
} | ||
|
||
interface TabPanelProps { | ||
children?: React.ReactNode | ||
index: number | ||
value: number | ||
} | ||
|
||
const TabPanel = ({ children, index, value }: TabPanelProps) => { | ||
return ( | ||
<div hidden={value !== index} id={`tabpanel-${index}`} data-testid={`tabpanel-${index}`}> | ||
{value === index && <Box paddingBottom={3}>{children}</Box>} | ||
</div> | ||
) | ||
} | ||
|
||
const AdvisoryReport = ({ issueDate, forDate, advisoryThreshold, selectedFireCenter }: AdvisoryReportProps) => { | ||
const [tabNumber, setTabNumber] = useState(0) | ||
|
||
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => { | ||
setTabNumber(newValue) | ||
} | ||
|
||
return ( | ||
<div data-testid="advisory-report"> | ||
<InfoAccordion | ||
defaultExpanded={true} | ||
title={'Advisory Report'} | ||
accordionDetailBackgroundColour={INFO_PANEL_CONTENT_BACKGROUND} | ||
> | ||
<Grid container justifyContent="center"> | ||
<Grid item sx={{ width: '90%' }}> | ||
<Box> | ||
<Tabs value={tabNumber} onChange={handleTabChange}> | ||
<Tab label="BULLETIN" /> | ||
</Tabs> | ||
</Box> | ||
<TabPanel value={tabNumber} index={0}> | ||
<AdvisoryText | ||
issueDate={issueDate} | ||
forDate={forDate} | ||
advisoryThreshold={advisoryThreshold} | ||
selectedFireCenter={selectedFireCenter} | ||
></AdvisoryText> | ||
</TabPanel> | ||
</Grid> | ||
</Grid> | ||
</InfoAccordion> | ||
</div> | ||
) | ||
} | ||
|
||
export default AdvisoryReport |
132 changes: 132 additions & 0 deletions
132
web/src/features/fba/components/infoPanel/AdvisoryText.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { Box, Typography } from '@mui/material' | ||
import { FireCenter, FireShapeAreaDetail } from 'api/fbaAPI' | ||
import { DateTime } from 'luxon' | ||
import React from 'react' | ||
import { useSelector } from 'react-redux' | ||
import { selectProvincialSummary } from 'features/fba/slices/provincialSummarySlice' | ||
import { AdvisoryStatus } from 'utils/constants' | ||
import { groupBy } from 'lodash' | ||
|
||
interface AdvisoryTextProps { | ||
issueDate: DateTime | null | ||
forDate: DateTime | ||
selectedFireCenter?: FireCenter | ||
advisoryThreshold: number | ||
} | ||
|
||
const AdvisoryText = ({ issueDate, forDate, advisoryThreshold, selectedFireCenter }: AdvisoryTextProps) => { | ||
const provincialSummary = useSelector(selectProvincialSummary) | ||
|
||
const calculateStatus = (details: FireShapeAreaDetail[]): AdvisoryStatus | undefined => { | ||
const advisoryThresholdDetail = details.find(detail => detail.threshold == 1) | ||
const warningThresholdDetail = details.find(detail => detail.threshold == 2) | ||
const advisoryPercentage = advisoryThresholdDetail?.elevated_hfi_percentage ?? 0 | ||
const warningPercentage = warningThresholdDetail?.elevated_hfi_percentage ?? 0 | ||
|
||
if (warningPercentage > advisoryThreshold) { | ||
return AdvisoryStatus.WARNING | ||
} | ||
|
||
if (advisoryPercentage + warningPercentage > advisoryThreshold) { | ||
return AdvisoryStatus.ADVISORY | ||
} | ||
} | ||
|
||
const getZoneStatusMap = (fireZoneUnitDetails: Record<string, FireShapeAreaDetail[]>) => { | ||
const zoneStatusMap: Record<AdvisoryStatus, string[]> = { | ||
[AdvisoryStatus.ADVISORY]: [], | ||
[AdvisoryStatus.WARNING]: [] | ||
} | ||
|
||
for (const zoneUnit in fireZoneUnitDetails) { | ||
const fireShapeAreaDetails: FireShapeAreaDetail[] = fireZoneUnitDetails[zoneUnit] | ||
const status = calculateStatus(fireShapeAreaDetails) | ||
|
||
if (status) { | ||
zoneStatusMap[status].push(zoneUnit) | ||
} | ||
} | ||
|
||
return zoneStatusMap | ||
} | ||
|
||
const renderDefaultMessage = () => { | ||
return ( | ||
<> | ||
{issueDate?.isValid ? ( | ||
<Typography data-testid="default-message">Please select a fire center.</Typography> | ||
) : ( | ||
<Typography data-testid="no-data-message">No advisory data available for today.</Typography> | ||
)}{' '} | ||
</> | ||
) | ||
} | ||
|
||
const renderAdvisoryText = () => { | ||
const forToday = issueDate?.toISODate() === forDate.toISODate() | ||
const displayForDate = forToday ? 'today' : forDate.toLocaleString({ month: 'short', day: 'numeric' }) | ||
|
||
const fireCenterSummary = provincialSummary[selectedFireCenter!.name] | ||
const groupedFireZoneUnitInfos = groupBy(fireCenterSummary, 'fire_shape_name') | ||
const zoneStatusMap = getZoneStatusMap(groupedFireZoneUnitInfos) | ||
|
||
return ( | ||
<> | ||
{issueDate?.isValid && ( | ||
<Typography | ||
sx={{ whiteSpace: 'pre-wrap' }} | ||
>{`Issued on ${issueDate?.toLocaleString(DateTime.DATE_MED)} for ${displayForDate}.\n\n`}</Typography> | ||
)} | ||
{zoneStatusMap[AdvisoryStatus.WARNING].length > 0 && ( | ||
<> | ||
<Typography data-testid="advisory-message-warning">{`There is a fire behaviour ${AdvisoryStatus.WARNING} in effect in the following areas:`}</Typography> | ||
<ul> | ||
{zoneStatusMap[AdvisoryStatus.WARNING].map(zone => ( | ||
<li key={zone}> | ||
<Typography>{zone}</Typography> | ||
</li> | ||
))} | ||
</ul> | ||
</> | ||
)} | ||
{zoneStatusMap[AdvisoryStatus.ADVISORY].length > 0 && ( | ||
<> | ||
<Typography data-testid="advisory-message-advisory">{`There is a fire behaviour ${AdvisoryStatus.ADVISORY} in effect in the following areas:`}</Typography> | ||
<ul> | ||
{zoneStatusMap[AdvisoryStatus.ADVISORY].map(zone => ( | ||
<li key={zone}> | ||
<Typography>{zone}</Typography> | ||
</li> | ||
))} | ||
</ul> | ||
</> | ||
)} | ||
{zoneStatusMap[AdvisoryStatus.WARNING].length === 0 && zoneStatusMap[AdvisoryStatus.ADVISORY].length === 0 && ( | ||
<Typography data-testid="no-advisory-message"> | ||
No advisories or warnings issued for the selected fire center. | ||
</Typography> | ||
)} | ||
</> | ||
) | ||
} | ||
|
||
return ( | ||
<div data-testid="advisory-text"> | ||
<Box | ||
sx={{ | ||
height: 350, | ||
maxWidth: '100%', | ||
overflow: 'auto', | ||
border: '1px solid #ccc', | ||
padding: 2, | ||
borderRadius: 1, | ||
backgroundColor: 'white' | ||
}} | ||
> | ||
{!selectedFireCenter || !issueDate?.isValid ? renderDefaultMessage() : renderAdvisoryText()} | ||
</Box> | ||
</div> | ||
) | ||
} | ||
|
||
export default AdvisoryText |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.