Skip to content

Commit

Permalink
feat: New Clear Search Button (#355)
Browse files Browse the repository at this point in the history
Co-authored-by: Om Mishra <[email protected]>
  • Loading branch information
popkinj and mishraomp authored Jan 28, 2025
1 parent 97d5fef commit 904c309
Show file tree
Hide file tree
Showing 22 changed files with 214 additions and 77 deletions.
2 changes: 1 addition & 1 deletion frontend/e2e/pages/auth.list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const authorization_list_page = async (page: Page) => {
await expect(page.getByLabel('Notification')).toBeVisible()
await page.getByLabel('Notification').check()
await expect(page.getByLabel('Compost Production Facility')).toBeVisible()
await expect(page.getByLabel('Land Application Biosolids')).toBeVisible()
await expect(page.getByLabel('Land Application')).toBeVisible()
await expect(
page.getByRole('button', { name: 'Reset Filters' }),
).toBeVisible()
Expand Down
6 changes: 3 additions & 3 deletions frontend/e2e/pages/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const map_page = async (page: Page) => {
).toBeVisible()
await expect(page.getByRole('button', { name: 'Point Search' })).toBeVisible()

const searchBy = page.getByText('Search By:')
const searchBy = page.getByText('Status')
await expect(searchBy).toBeVisible()
await searchBy.click()

Expand All @@ -35,7 +35,7 @@ export const map_page = async (page: Page) => {

await expect(page.getByLabel('Inactive')).toBeHidden()

const filterBy = page.getByText('Filter by Facility Type')
const filterBy = page.getByText('Filter')
await expect(filterBy).toBeVisible()
await filterBy.click()

Expand All @@ -46,7 +46,7 @@ export const map_page = async (page: Page) => {
page.getByRole('checkbox', { name: 'Compost Production Facility' }),
).toBeVisible()
await expect(
page.getByRole('checkbox', { name: 'Land Application Biosolids' }),
page.getByRole('checkbox', { name: 'Land Application' }),
).toBeVisible()
await expect(page.getByRole('checkbox', { name: 'Permit' })).toBeVisible()
await expect(page.getByRole('checkbox', { name: 'Approval' })).toBeVisible()
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/app/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'

export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
18 changes: 17 additions & 1 deletion frontend/src/features/map/map-slice.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { useSelector } from 'react-redux'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit'
import { LatLngBoundsLiteral, LatLngTuple } from 'leaflet'

import { RootState } from '@/app/store'
import OmrrData from '@/interfaces/omrr'
import { DataLayer } from '@/interfaces/data-layers'
import { useCallback } from 'react'
import { ActiveToolEnum } from '@/constants/constants'
import { setSearchTextFilter } from '@/features/omrr/omrr-slice'

export interface ZoomPosition {
position: LatLngTuple
Expand All @@ -30,6 +31,7 @@ export interface MapSliceState {
// Keeps track of the active tool - point/polygon search (all screen sizes), and
// data layers, search by and filter by (small screens only - shown in bottom drawer)
activeTool?: ActiveToolEnum
searchResults: OmrrData[]
}

export const initialState: MapSliceState = {
Expand All @@ -41,6 +43,7 @@ export const initialState: MapSliceState = {
selectedItem: undefined,
dataLayers: [],
activeTool: undefined,
searchResults: [],
}

export const mapSlice = createSlice({
Expand Down Expand Up @@ -93,6 +96,9 @@ export const mapSlice = createSlice({
clearActiveTool: (state) => {
state.activeTool = undefined
},
clearSearchResults: (state) => {
state.searchResults = []
},
},
})

Expand All @@ -107,8 +113,18 @@ export const {
resetDataLayers,
toggleActiveTool,
clearActiveTool,
clearSearchResults,
} = mapSlice.actions

// Create a thunk to clear both search results and search text
export const clearSearchAndResults = createAsyncThunk(
'map/clearSearchAndResults',
async (_, { dispatch }) => {
dispatch(clearSearchResults())
dispatch(setSearchTextFilter(''))
},
)

// Selectors
const selectMyLocationVisible = (state: RootState) =>
state.map.isMyLocationVisible
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/interfaces/omrr-filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const facilityTypeFilters: OmrrFilter[] = [
},
{
value: OPERATION_TYPE_LAND_APPLICATION,
label: 'Land Application Biosolids',
label: 'Land Application',
field: 'Operation Type',
on: false,
// Compare to start of value instead of exact match
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe('Test suite for DetailsSection', () => {
it('should render DetailsSection for Notification Land Application', () => {
const materialLandApplied = 'Class B Biosolids'
const notification: OmrrData = createMockOmrrData('Notification', {
'Operation Type': 'Land Application Biosolids',
'Operation Type': 'Land Application',
'Material Land Applied': materialLandApplied,
'Intended Dates of Land Application': 'September 1, 2008',
})
Expand All @@ -99,7 +99,7 @@ describe('Test suite for DetailsSection', () => {
screen.getByText('Authorization Type')
screen.getByText('Notification')
screen.getByText('Operation Type')
screen.getByText('Land Application Biosolids')
screen.getByText('Land Application')
screen.getByText('Regulation')
screen.getByRole('link', { name: 'Organic Matter Recycling Regulation' })
screen.getByText('Material Land Applied')
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/map/MapView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ describe('Test suite for MapView', () => {
expect(inactiveCb).not.toBeChecked()

const filterBy = screen.getByRole('button', {
name: 'Filter by Facility Type',
name: 'Filter',
})
expect(filterBy).not.toHaveClass('map-button--active')
await user.click(filterBy)
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/pages/map/drawer/MapBottomDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ function getTitle(
case ActiveToolEnum.pointSearch:
return 'Point Search'
case ActiveToolEnum.searchBy:
return 'Search By'
return 'Status'
case ActiveToolEnum.filterBy:
return 'Filter by Facility Type'
return 'Filter'
default:
return hasSelectedItem ? '' : 'Search Results'
}
Expand Down
19 changes: 18 additions & 1 deletion frontend/src/pages/map/drawer/MapSidebar.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,21 @@ button.map-sidebar-close-button {

.zoom-to-button .MuiButton-startIcon {
margin: 0 6px 0 -8px;
}
}

.clear-results-button {
font-size: 0.75rem;
background: none;
border: none;
color: #666;
padding: 0 0 0 8px;
cursor: pointer;
display: inline-flex;
align-items: center;
margin-top: 2px;
margin-right: 28px;
}

.clear-results-button:hover {
color: #333;
}
24 changes: 23 additions & 1 deletion frontend/src/pages/map/drawer/MapSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IconButton } from '@mui/material'
import clsx from 'clsx'
import { useAppDispatch } from '@/app/hooks'

import { useSidebarState } from '../hooks/useSidebarState'
import { SearchResultsList } from './SearchResultsList'
Expand All @@ -8,18 +9,28 @@ import { ZoomToButton } from './ZoomToButton'
import { ClearSelectedItemButton } from './ClearSelectedItemButton'

import CloseIcon from '@/assets/svgs/close.svg?react'
import { clearSearchAndResults } from '@/features/map/map-slice'
import { useSearchTextFilter } from '@/features/omrr/omrr-slice'

import './MapSidebar.css'

export function MapSidebar() {
const dispatch = useAppDispatch()
// This hook keeps track of the expanded state and calculates the sidebar width
const { isExpanded, setExpanded, selectedItem, width, expandedWidth } =
useSidebarState()

const searchText = useSearchTextFilter()
const hasResults = searchText.length > 0

const onClose = () => {
setExpanded(false)
}

const onClearResults = () => {
dispatch(clearSearchAndResults())
}

const style = { width: `${width}px` }
return (
<div
Expand All @@ -39,7 +50,18 @@ export function MapSidebar() {
<ZoomToButton items={[selectedItem]} />
</>
) : (
'Search Results'
<>
Search Results
{hasResults && (
<button
onClick={onClearResults}
className="clear-results-button"
title="Clear all search results"
>
Clear Results
</button>
)}
</>
)}
</div>
<IconButton
Expand Down
7 changes: 4 additions & 3 deletions frontend/src/pages/map/layers/DataLayersControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,19 @@ export function DataLayersControl() {
display: 'flex',
'& .MuiBadge-badge': {
right: -3,
bottom: 3,
bottom: -15,
top: 'auto',
padding: '0 4px',
minWidth: '16px',
height: '16px',
fontSize: '0.75rem',
backgroundColor: 'var(--surface-color-primary-active-border)',
backgroundColor:
'var(--surface-color-primary-dangerButton-default, #ce3e39)',
color: 'var(--surface-color-background-white)',
},
}}
>
<LayersIcon />
<LayersIcon className="layers-icon" />
</Badge>
</div>
</IconButton>
Expand Down
9 changes: 4 additions & 5 deletions frontend/src/pages/map/layers/MapControls.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
align-items: center;
border-radius: 8px;
background: var(--surface-color-background-white);
color: var(--surface-color-primary-active-border);
border: 2px solid var(--surface-color-primary-active-border);
color: var(--surface-color-primary-default);
border: 1px solid var(--surface-color-primary-default);
box-shadow: var(--box-shadow-small);
transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
Expand All @@ -34,14 +34,13 @@

.map-controls button.map-control-button:focus,
.map-controls .map-control-button:focus {
outline: 2px solid rgba(46, 93, 215, 0.5);
outline: 2px solid var(--surface-color-primary-active-border);
}

.map-controls button.map-control-button--active,
.map-controls .map-control-button--active {
background-color: var(--surface-color-primary-active-border);
color: var(--surface-color-background-white);
border-color: var(--surface-color-background-white);
}

.map-controls button.map-control-button--active:hover,
Expand All @@ -52,7 +51,7 @@
/* Make all SVG icons in the buttons blue */
.map-controls button.map-control-button svg,
.map-controls .map-control-button svg {
color: var(--surface-color-primary-active-border);
color: var(--surface-color-primary-default);
}

.map-controls button.map-control-button--active svg,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/map/search/AutocompleteItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function getLabel(matchType: MatchType, item: OmrrData | undefined): ReactNode {
const { 'Authorization Number': number = 0 } = item
return (
<span>
Authorization #: <u>{number}</u>
Authorization #: <b>{number}</b>
</span>
)
}
Expand Down
10 changes: 6 additions & 4 deletions frontend/src/pages/map/search/DataLayersButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useSidebarWidth, useDataLayers } from '@/features/map/map-slice'
import { DataLayersCheckboxGroup } from '@/components/DataLayersCheckboxGroup'
import { Badge } from '@mui/material'

import layersIcon from '@/assets/svgs/fa-layers.svg'
import LayersIcon from '@/assets/svgs/fa-layers.svg?react'

export function DataLayersButton() {
const sidebarWidth = useSidebarWidth()
Expand All @@ -30,17 +30,19 @@ export function DataLayersButton() {
display: 'flex',
'& .MuiBadge-badge': {
right: -3,
top: 3,
bottom: -15,
top: 'auto',
padding: '0 4px',
minWidth: '16px',
height: '16px',
fontSize: '0.75rem',
backgroundColor: 'var(--surface-color-primary-active-border)',
backgroundColor:
'var(--surface-color-primary-dangerButton-default, #ce3e39)',
color: 'var(--surface-color-background-white)',
},
}}
>
<img src={layersIcon} alt="Data layers icon" />
<LayersIcon className="layers-icon" />
</Badge>
</div>
}
Expand Down
Loading

0 comments on commit 904c309

Please sign in to comment.