-
Notifications
You must be signed in to change notification settings - Fork 7
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
Waitp 1224 overlay selector desktop #4685
Changes from 5 commits
43d565a
b0fcb1f
b410783
a0b2de5
fd672eb
7962aff
8ff9041
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
* Tupaia | ||
* Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd | ||
*/ | ||
|
||
import { useQuery } from 'react-query'; | ||
import { get } from '../api'; | ||
import { EntityCode, ProjectCode } from '../../types'; | ||
|
||
export const useFetchMapOverlays = (projectCode?: ProjectCode, entityCode?: EntityCode) => { | ||
return useQuery( | ||
['mapOverlays', projectCode, entityCode], | ||
async () => { | ||
return get(`mapOverlays/${projectCode}/${entityCode}`); | ||
}, | ||
{ | ||
enabled: !!projectCode && !!entityCode, | ||
}, | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
* Tupaia | ||
* Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd | ||
*/ | ||
|
||
import { useQuery } from 'react-query'; | ||
import { get } from '../api'; | ||
import { EntityCode, ProjectCode, SingleMapOverlayItem } from '../../types'; | ||
|
||
export const useMapOverlayData = ( | ||
projectCode?: ProjectCode, | ||
entityCode?: EntityCode, | ||
mapOverlayCode?: SingleMapOverlayItem['code'], | ||
) => { | ||
return useQuery( | ||
['mapOverlayData', projectCode, entityCode, mapOverlayCode], | ||
async () => { | ||
return get( | ||
`measureData?mapOverlayCode=${mapOverlayCode}&organisationUnitCode=${entityCode}&projectCode=${projectCode}&shouldShowAllParentCountryResults=${ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it would be great to use the axios params field here for readability and ease of maintenance. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is that endpoint for fetching the measure data, or for something else? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes that's right for measureData There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm currently getting an error using this, and it seems to be different to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh yeah it looks like there is a bug in the endpoint so yes that's leave this as is for now |
||
projectCode !== entityCode | ||
}`, // TODO: figure out the logic here for shouldShowAllParentCountryResults | ||
); | ||
}, | ||
{ | ||
enabled: !!projectCode && !!entityCode && !!mapOverlayCode, | ||
}, | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,19 +13,24 @@ const Wrapper = styled.div` | |
flex-direction: row; | ||
align-items: flex-end; | ||
justify-content: center; | ||
position: absolute; | ||
background-color: grey; | ||
width: 300px; | ||
height: 50px; | ||
bottom: 1em; | ||
left: 50%; | ||
transform: translateX(-50%); | ||
border-radius: 5px; | ||
width: 100%; | ||
padding: 1rem; | ||
@media screen and (max-width: ${MOBILE_BREAKPOINT}) { | ||
display: none; | ||
} | ||
`; | ||
|
||
const Legend = styled.div` | ||
height: 50px; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably should be rems, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should, but this is just a placeholder so I don't think it's important at this stage There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh true. I just see px and I jump 😆 |
||
width: 300px; | ||
background-color: grey; | ||
border-radius: 5px; | ||
`; | ||
|
||
export const DesktopMapLegend = () => { | ||
return <Wrapper />; | ||
return ( | ||
<Wrapper> | ||
<Legend /> | ||
</Wrapper> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,23 +5,212 @@ | |
|
||
import React from 'react'; | ||
import styled from 'styled-components'; | ||
import { Accordion, Typography, AccordionSummary, AccordionDetails } from '@material-ui/core'; | ||
import { ExpandMore, Layers } from '@material-ui/icons'; | ||
import { Skeleton as MuiSkeleton } from '@material-ui/lab'; | ||
import { MOBILE_BREAKPOINT } from '../../../constants'; | ||
import { Entity } from '../../../types'; | ||
import { useMapOverlayData } from '../../../api/queries'; | ||
import { useParams } from 'react-router'; | ||
import { periodToMoment } from '@tupaia/utils'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just check order of imports here |
||
import { useMapOverlays } from '../../../utils'; | ||
import { MapOverlayList } from './MapOverlayList'; | ||
|
||
// Placeholder for MapOverlaySelector component | ||
const Wrapper = styled.div` | ||
width: 18.75rem; | ||
margin: 1em; | ||
height: 2.5rem; | ||
border-radius: 5px; | ||
background-color: ${({ theme }) => theme.palette.secondary.main}; | ||
opacity: 0.6; | ||
position: absolute; | ||
top: 0; | ||
const MaxHeightContainer = styled.div` | ||
flex: 1; | ||
max-height: 100%; | ||
overflow: hidden; | ||
display: flex; | ||
flex-direction: column; | ||
`; | ||
|
||
const Wrapper = styled(MaxHeightContainer)` | ||
max-width: 21.25rem; | ||
margin: 0.625rem; | ||
@media screen and (max-width: ${MOBILE_BREAKPOINT}) { | ||
display: none; | ||
} | ||
`; | ||
|
||
export const DesktopMapOverlaySelector = () => { | ||
return <Wrapper />; | ||
const Header = styled.div` | ||
padding: 0.9rem 1rem; | ||
background-color: ${({ theme }) => theme.palette.secondary.main}; | ||
border-radius: 5px 5px 0 0; | ||
`; | ||
|
||
const Heading = styled(Typography).attrs({ | ||
variant: 'h2', | ||
})` | ||
font-size: 0.75rem; | ||
text-transform: uppercase; | ||
font-weight: ${({ theme }) => theme.typography.fontWeightMedium}; | ||
`; | ||
|
||
const Container = styled(MaxHeightContainer)` | ||
border-radius: 0 0 5px 5px; | ||
`; | ||
|
||
const MapOverlayNameContainer = styled.div<{ | ||
$hasMapOverlays: boolean; | ||
}>` | ||
padding: 1.3rem 1rem 1rem 1.125rem; | ||
background-color: ${({ theme }) => theme.overlaySelector.overlayNameBackground}; | ||
border-radius: ${({ $hasMapOverlays }) => ($hasMapOverlays ? '0' : '0 0 5px 5px')}; | ||
`; | ||
|
||
const MapOverlayName = styled.span` | ||
font-weight: ${({ theme }) => theme.typography.fontWeightMedium}; | ||
`; | ||
|
||
const Skeleton = styled(MuiSkeleton)` | ||
transform: scale(1, 1); | ||
::after { | ||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); | ||
} | ||
`; | ||
|
||
const OverlayLibraryAccordion = styled(Accordion)` | ||
display: flex; | ||
flex-direction: column; | ||
margin: 0 !important; | ||
background-color: ${({ theme }) => theme.overlaySelector.menuBackground}; | ||
border-radius: 0 0 5px 5px; | ||
&:before { | ||
display: none; | ||
} | ||
&.MuiPaper-root.Mui-expanded { | ||
height: 100%; | ||
overflow: hidden; // make the accordion conform to the max-height of the parent container, regardless of how much content is present | ||
> .MuiCollapse-container.MuiCollapse-entered { | ||
max-height: 100%; | ||
overflow-y: auto; // scrollable content when accordion is expanded; | ||
} | ||
} | ||
`; | ||
|
||
const OverlayLibraryIcon = styled(Layers)` | ||
margin-right: 0.5rem; | ||
.Mui-expanded & { | ||
fill: ${({ theme }) => theme.palette.secondary.main}; | ||
} | ||
`; | ||
|
||
const OverlayLibraryTitle = styled(Typography)` | ||
font-size: 0.75rem; | ||
text-transform: uppercase; | ||
font-weight: ${({ theme }) => theme.typography.fontWeightMedium}; | ||
`; | ||
|
||
const OverlayLibraryHeader = styled(AccordionSummary)` | ||
margin: 0 !important; | ||
min-height: unset !important; | ||
color: rgba(255, 255, 255, 0.6); | ||
.MuiAccordionSummary-content { | ||
margin: 0 !important; | ||
align-items: center; | ||
} | ||
|
||
&:hover, | ||
&.Mui-expanded, | ||
&:focus-visible { | ||
color: ${({ theme }) => theme.palette.text.primary}; | ||
} | ||
`; | ||
|
||
const OverlayLibraryContentWrapper = styled(AccordionDetails)` | ||
padding: 0 1rem 1rem; | ||
`; | ||
|
||
const OverlayLibraryContentContainer = styled.div` | ||
border-top: 1px solid rgba(255, 255, 255, 0.12); | ||
width: 100%; | ||
padding-top: 1rem; | ||
`; | ||
|
||
const LatestDataContainer = styled.div` | ||
background-color: rgba(0, 0, 0, 0.3); | ||
border-radius: 5px; | ||
padding: 0.3rem 0.5rem 0.2rem; | ||
margin-top: 0.5rem; | ||
`; | ||
|
||
const LatestDataText = styled(Typography)` | ||
font-size: 0.875rem; | ||
line-height: 1.3; | ||
`; | ||
|
||
interface DesktopMapOverlaySelectorProps { | ||
entityName?: Entity['name']; | ||
overlayLibraryOpen: boolean; | ||
toggleOverlayLibrary: () => void; | ||
} | ||
|
||
export const DesktopMapOverlaySelector = ({ | ||
entityName, | ||
overlayLibraryOpen, | ||
toggleOverlayLibrary, | ||
}: DesktopMapOverlaySelectorProps) => { | ||
const { | ||
hasMapOverlays, | ||
isLoadingMapOverlays, | ||
selectedOverlayCode, | ||
selectedOverlay, | ||
} = useMapOverlays(); | ||
|
||
const { projectCode, entityCode } = useParams(); | ||
const { data: mapOverlayData } = useMapOverlayData(projectCode, entityCode, selectedOverlayCode); | ||
|
||
return ( | ||
<Wrapper> | ||
<Header> | ||
<Heading>Map Overlays</Heading> | ||
</Header> | ||
<Container> | ||
<MapOverlayNameContainer $hasMapOverlays={hasMapOverlays}> | ||
{isLoadingMapOverlays ? ( | ||
<Skeleton animation="wave" width={200} height={20} /> | ||
) : ( | ||
<Typography> | ||
{hasMapOverlays ? ( | ||
<MapOverlayName>{selectedOverlay?.name}</MapOverlayName> | ||
) : ( | ||
`Select an area with valid data. ${ | ||
entityName && `${entityName} has no map overlays available.` | ||
}` | ||
)} | ||
</Typography> | ||
)} | ||
</MapOverlayNameContainer> | ||
{hasMapOverlays && ( | ||
<OverlayLibraryAccordion | ||
expanded={overlayLibraryOpen} | ||
onChange={toggleOverlayLibrary} | ||
square | ||
> | ||
<OverlayLibraryHeader | ||
expandIcon={<ExpandMore />} | ||
aria-controls="overlay-library-content" | ||
id="overlay-library-header" | ||
> | ||
<OverlayLibraryIcon /> | ||
<OverlayLibraryTitle>Overlay library</OverlayLibraryTitle> | ||
</OverlayLibraryHeader> | ||
<OverlayLibraryContentWrapper> | ||
<OverlayLibraryContentContainer> | ||
<MapOverlayList /> | ||
</OverlayLibraryContentContainer> | ||
</OverlayLibraryContentWrapper> | ||
</OverlayLibraryAccordion> | ||
)} | ||
{mapOverlayData?.period?.latestAvailable && ( | ||
<LatestDataContainer> | ||
<LatestDataText> | ||
Latest overlay data:{' '} | ||
{periodToMoment(mapOverlayData?.period?.latestAvailable).format('DD/MM/YYYY')} | ||
</LatestDataText> | ||
</LatestDataContainer> | ||
)} | ||
</Container> | ||
</Wrapper> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure what to call this query hook, but I have another hook in
utils
calleduseMapOverlays
which means I can't call this the same thingThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be good to just move all the code from packages/tupaia-web/src/utils/useMapOverlays.ts into this file and name this one useMapOverlays since it is just derived api data with the exception of
updateSelectedMapOverlay
. You could then put updateSelectedMapOverlay inline in MapOverlayList, make it a stand alone util or keep it with useMapOverlays if you really want.