Skip to content

Commit

Permalink
feat: Data layers (#189)
Browse files Browse the repository at this point in the history
  • Loading branch information
ccallendar authored Jul 25, 2024
1 parent 92420c8 commit 26d938e
Show file tree
Hide file tree
Showing 40 changed files with 1,262 additions and 195 deletions.
2 changes: 2 additions & 0 deletions frontend/e2e/pages/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,6 @@ export const map_page = async (page: Page) => {
const showResultsBtn = page.getByRole('button', { name: 'Show Results' })
await expect(showResultsBtn).toBeVisible()
await showResultsBtn.click()

await page.getByTitle('Close').click({ force: true })
}
3 changes: 1 addition & 2 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useEffect } from 'react'
import { BrowserRouter } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { useSelector } from 'react-redux'
import { Box, CircularProgress, Stack } from '@mui/material'

import Header from '@/components/Header'
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/assets/svgs/fa-chevron-up.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions frontend/src/components/DataLayersCheckboxGroup.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
.data-layers-checkbox-group {
gap: 24px;
}

.data-layers-checkbox-group.data-layers-checkbox-group--small {
gap: 32px;
scrollbar-width: none;
}

.data-layers-top-section {
gap: 8px;
padding: 0 8px;
}

.data-layers-checkbox-group--small .data-layers-top-section {
padding: 0;
}

.data-layers-top-text,
.data-layers-top-link {
color: var(--typography-color-disabled);
font-size: 14px;
font-style: italic;
}

.data-layers-top-link,
.data-layers-top-link:hover {
text-decoration: underline;
}

.data-layers-type-text {
color: var(--typography-color-primary);
font-weight: 700;
}

.available-layers-row {
display: flex;
justify-content: space-between;
align-items: center;
height: 28px;
flex: 0 0 28px;
}

.available-layers-text {
color: var(--typography-color-primary);
}
114 changes: 114 additions & 0 deletions frontend/src/components/DataLayersCheckboxGroup.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { screen } from '@testing-library/react'

import { DataLayersCheckboxGroup } from './DataLayersCheckboxGroup'
import { render } from '@/test-utils'
import { useDataLayers, useHasDataLayersOn } from '@/features/map/map-slice'
import { DataLayer } from '@/interfaces/data-layers'
import { DATA_LAYER_GROUPS } from '@/constants/data-layers'

interface State {
dataLayers?: DataLayer[]
hasDataLayersOn?: boolean
}

describe('Test suite for DataLayersCheckboxGroup', () => {
function renderComponent(
isSmall = false,
className: string | undefined = undefined,
) {
const state: State = {}
const TestComponent = () => {
Object.assign(state, {
dataLayers: useDataLayers(),
hasDataLayersOn: useHasDataLayersOn(),
})
return <DataLayersCheckboxGroup isSmall={isSmall} className={className} />
}
const { user } = render(<TestComponent />, {
withStateProvider: true,
})
return { user, state }
}

it('should render large DataLayersCheckboxGroup', async () => {
const { user, state } = renderComponent(false, 'test-class')
screen.getByText(/^All data layers sourced from GeoBC/)
expect(state.dataLayers).toHaveLength(0)
expect(state.hasDataLayersOn).toBe(false)

const div = screen.getByTestId('data-layers-checkbox-group')
expect(div).not.toHaveClass('data-layers-checkbox-group--small')
expect(div).toHaveClass('test-class')

DATA_LAYER_GROUPS.forEach(({ name, layers }) => {
screen.getByRole('button', { name, pressed: true })
layers.forEach((layer) => {
const cb = screen.getByLabelText(layer.name)
expect(cb).not.toBeChecked()
if (layer.url) {
expect(cb).toBeEnabled()
} else {
expect(cb).toBeDisabled()
}
})
})

expect(screen.queryByText('Available Layers')).not.toBeInTheDocument()
expect(screen.queryByText('Reset')).not.toBeInTheDocument()
expect(screen.queryByText('Reset Layers')).not.toBeInTheDocument()

const toggle = screen.getByRole('button', {
name: 'Aquifers and Water Wells',
pressed: true,
})
// should be expanded by default
screen.getByText('Aquifers - All')

await user.click(toggle)

// Should be collapsed now
screen.getByRole('button', {
name: 'Aquifers and Water Wells',
pressed: false,
})
expect(screen.queryByText('Aquifers - All')).not.toBeInTheDocument()

const cb = screen.getByLabelText('FWA Wetlands')
expect(cb).not.toBeChecked()

await user.click(cb)
expect(cb).toBeChecked()
expect(state.dataLayers).toHaveLength(1)
expect(state.hasDataLayersOn).toBe(true)

const resetBtn = screen.getByRole('button', { name: 'Reset Layers' })
await user.click(resetBtn)

expect(state.dataLayers).toHaveLength(0)
expect(state.hasDataLayersOn).toBe(false)
expect(screen.queryByText('Reset Layers')).not.toBeInTheDocument()
})

it('should render small DataLayersCheckboxGroup', async () => {
const { user, state } = renderComponent(true)
screen.getByText(/^All data layers sourced from GeoBC/)
expect(state.dataLayers).toHaveLength(0)

const div = screen.getByTestId('data-layers-checkbox-group')
expect(div).toHaveClass('data-layers-checkbox-group--small')

const cb = screen.getByLabelText('Water Rights - Licences')
expect(cb).not.toBeChecked()

await user.click(cb)
expect(cb).toBeChecked()
expect(state.dataLayers).toHaveLength(1)
expect(state.hasDataLayersOn).toBe(true)

const resetLink = screen.getByRole('button', { name: 'Reset' })
await user.click(resetLink)

expect(state.dataLayers).toHaveLength(0)
expect(screen.queryByText('Reset Layers')).not.toBeInTheDocument()
})
})
101 changes: 101 additions & 0 deletions frontend/src/components/DataLayersCheckboxGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from 'react'
import { useDispatch } from 'react-redux'
import { Button, Stack, Typography } from '@mui/material'
import clsx from 'clsx'

import { DATA_LAYER_GROUPS } from '@/constants/data-layers'
import {
resetDataLayers,
toggleDataLayer,
useHasDataLayersOn,
} from '@/features/map/map-slice'
import { DataLayer, DataLayerGroup } from '@/interfaces/data-layers'
import { DataLayersToggleGroup } from './DataLayersToggleGroup'

import './DataLayersCheckboxGroup.css'

interface Props {
isSmall?: boolean
className?: string
}

export function DataLayersCheckboxGroup({
isSmall = false,
className,
}: Readonly<Props>) {
const dispatch = useDispatch()
const isLarge = !isSmall
const hasDataLayers = useHasDataLayersOn()

const onLayerToggle = (layer: DataLayer) => {
dispatch(toggleDataLayer(layer))
}

const onReset = () => {
dispatch(resetDataLayers())
}

const isGuidanceReady = false

return (
<Stack
direction="column"
className={clsx(
'data-layers-checkbox-group',
!isSmall && 'thin-scrollbar',
isSmall && 'data-layers-checkbox-group--small',
className,
)}
data-testid="data-layers-checkbox-group"
>
<Stack direction="column" className="data-layers-top-section">
<Typography className="data-layers-top-text">
All data layers sourced from GeoBC.
</Typography>
{isGuidanceReady && (
<Typography className="data-layers-top-link">
Click here to read our guidance page about map layers.
</Typography>
)}
</Stack>
{isSmall && (
<div className="available-layers-row">
<Typography
className="available-layers-text"
fontSize="18px"
fontWeight={700}
>
Available Layers
</Typography>
{hasDataLayers && (
<Button
variant="text"
size="small"
className="data-layers-reset-link"
onClick={onReset}
>
Reset
</Button>
)}
</div>
)}
{DATA_LAYER_GROUPS.map((group: DataLayerGroup) => (
<DataLayersToggleGroup
key={`DataLayersToggleGroup-${group.name}`}
group={group}
onLayerToggle={onLayerToggle}
isSmall={isSmall}
/>
))}
{isLarge && hasDataLayers && (
<Button
variant="outlined"
onClick={onReset}
className="data-layers-reset-button"
>
Reset Layers
</Button>
)}
</Stack>
)
}
82 changes: 82 additions & 0 deletions frontend/src/components/DataLayersToggleGroup.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
button.data-layers-toggle-button {
justify-content: space-between;
color: var(--typography-color-primary);
font-size: 16px;
font-weight: 700;
padding: 0 8px;
}

button.data-layers-toggle-button .MuiButton-endIcon {
margin: 0 4px
}

.data-layers-toggle-group--small button.data-layers-toggle-button {
font-weight: 400;
padding: 0;
}

button.data-layers-reset-button {
align-self: flex-start;
color: var(--typography-color-primary);
border-color: var(--surface-color-border-dark);
}

button.data-layers-reset-link {
color: var(--typography-color-link);
font-size: 18px;
line-height: 28px;
padding: 4px;
}

.data-layers-expand-arrow {
transform: rotate(0deg);
transition: transform 0.2s linear;
}

.data-layers-expand-arrow--invert {
transform: rotate(180deg);
}

.data-layers-checkbox-list {
gap: 2px;
padding-left: 4px;
}

.data-layers-toggle-group--small .data-layers-checkbox-list {
gap: 8px;
padding-left: 0;
}

label.data-layers-checkbox-item {
display: flex;
align-items: center;
gap: 8px;
margin: 0;
padding: 0;
min-height: 40px;
color: var(--typography-color-secondary);
font-size: 14px;
font-weight: 400;
}

label.data-layers-checkbox-item:hover {
color: var(--typography-color-primary);
}

label.data-layers-checkbox-item .MuiCheckbox-root {
padding: 8px;
}

.data-layers-toggle-group--small label.data-layers-checkbox-item {
flex-direction: row-reverse;
padding: 0 16px;
color: var(--typography-color-primary);
background-color: var(--surface-color-brand-gray-20);
border: 1px solid var(--surface-color-border-medium);
border-radius: 4px;
}

label.data-layers-checkbox-item .MuiFormControlLabel-label {
flex: 1;
text-align: left;
}
Loading

0 comments on commit 26d938e

Please sign in to comment.