-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: search bar stops and vehicles (#85)
* feature: search bar stops and vehicles * removed unused styles for search bar * sashachabin review * removed search bar for map without controls * fixed visibility of vehicles of selected direction, typo in search through units * removed useless media query * moved form within into form * fixes for mobile safari * always show closer for input when there is text
- Loading branch information
Showing
33 changed files
with
872 additions
and
278 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
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,18 @@ | ||
import { uniqBy } from 'lodash'; | ||
import { Unit } from 'transport-common/types/masstrans'; | ||
|
||
const uniqUnitsIteratee = (unit: Unit) => `${unit.num}${unit.routeDirection}`; | ||
|
||
export function searchThroughUnits(units: Unit[], searchText: string) { | ||
return uniqBy( | ||
units | ||
.filter( | ||
(unit) => | ||
unit.lastStation.toLowerCase().includes(searchText) || | ||
unit.firstStation.toLowerCase().includes(searchText) || | ||
unit.num.toLowerCase().includes(searchText), | ||
) | ||
.sort((a, b) => a.firstStation.localeCompare(b.firstStation, 'ru', { numeric: true })), | ||
uniqUnitsIteratee, | ||
); | ||
} |
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,79 @@ | ||
.MapSearchBar { | ||
display: flex; | ||
flex-direction: column; | ||
gap: 2px; | ||
|
||
height: max-content; | ||
max-height: calc(45vh - 100px); | ||
|
||
border-radius: 8px; | ||
border: 4px solid rgba(230, 228, 224, 0.64); | ||
|
||
background-color: rgba(230, 228, 224, 0.64); | ||
} | ||
|
||
.MapSearchBar__form { | ||
display: flex; | ||
|
||
height: 48px; | ||
width: 100%; | ||
|
||
padding: 12px 16px; | ||
border-radius: 4px; | ||
|
||
background-color: #fff; | ||
gap: 8px; | ||
|
||
&:focus-within { | ||
outline: 2px solid #282828; | ||
} | ||
} | ||
|
||
.MapSearchBar__form_withResult { | ||
border-radius: 4px 4px 0px 0px; | ||
} | ||
|
||
.MapSearchBar__input { | ||
width: 100%; | ||
padding: 0; | ||
border: none; | ||
outline: none; | ||
|
||
font-family: inherit; | ||
font-weight: 400; | ||
font-size: 18px; | ||
line-height: 24px; | ||
|
||
background-color: transparent; | ||
|
||
&::placeholder { | ||
color: #000; | ||
opacity: 1; | ||
} | ||
|
||
&:focus::placeholder { | ||
opacity: 0; | ||
} | ||
|
||
&::-webkit-search-cancel-button { | ||
appearance: none; | ||
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTYgNkwxOCAxOE02IDE4TDE4IDYiIHN0cm9rZT0iIzlCQUFDMyIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWNhcD0ic3F1YXJlIi8+Cjwvc3ZnPgoK); | ||
background-size: contain; | ||
opacity: 1; | ||
pointer-events: all; | ||
cursor: pointer; | ||
width: 24px; | ||
height: 24px; | ||
margin: 0; | ||
} | ||
} | ||
|
||
.MapSearchBar__results { | ||
display: flex; | ||
flex-direction: column; | ||
gap: 2px; | ||
|
||
overflow: auto; | ||
|
||
border-radius: 0px 0px 4px 4px; | ||
} |
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,98 @@ | ||
import React, { useCallback, useMemo, useRef, useState } from 'react'; | ||
import { useSelector } from 'react-redux'; | ||
import classNames from 'classnames/bind'; | ||
|
||
import { ClientUnit, Unit } from 'transport-common/types/masstrans'; | ||
import { StrapiStop } from 'transport-common/types/strapi'; | ||
|
||
import { useDisablePropagation } from 'hooks/useDisablePropagation'; | ||
import { State } from 'common/types/state'; | ||
|
||
import { MapSearchBarUnitResult } from './UnitResult/UnitResult'; | ||
import { MapSearchBarStopResult } from './StopsResult/StopResult'; | ||
|
||
import styles from './SearchBar.module.css'; | ||
import { searchThroughUnits } from './SearchBar.helpers'; | ||
|
||
const cn = classNames.bind(styles); | ||
|
||
const INPUT_PLACEHOLDER = 'Поиск'; | ||
|
||
export function MapSearchBar() { | ||
const searchBarRef = useRef<HTMLDivElement>(null); | ||
const [searchResult, setSearchResult] = useState<{ stops: StrapiStop[]; units: Unit[] }>({ | ||
stops: [], | ||
units: [], | ||
}); | ||
|
||
const stops = useSelector((state: State) => state.publicTransport.stops); | ||
const units = useSelector((state: State) => state.publicTransport.units); | ||
|
||
useDisablePropagation(searchBarRef); | ||
|
||
const onSearch = useCallback( | ||
(event) => { | ||
const searchText = (event.target as HTMLInputElement).value.toLowerCase(); | ||
|
||
if (!searchText) { | ||
setSearchResult({ stops: [], units: [] }); | ||
|
||
return; | ||
} | ||
|
||
const stopsSearch = stops | ||
.filter((stop) => stop.attributes.title.toLowerCase().includes(searchText)) | ||
.sort((a, b) => | ||
a.attributes.title.localeCompare(b.attributes.title, 'ru', { numeric: true }), | ||
); | ||
|
||
const trollsSearch = searchThroughUnits(units[ClientUnit.Troll], searchText); | ||
const tramsSearch = searchThroughUnits(units[ClientUnit.Tram], searchText); | ||
const busesSearch = searchThroughUnits(units[ClientUnit.Bus], searchText); | ||
|
||
setSearchResult({ | ||
stops: stopsSearch, | ||
units: [...trollsSearch, ...tramsSearch, ...busesSearch], | ||
}); | ||
}, | ||
[stops, units], | ||
) as React.FormEventHandler; | ||
|
||
const hasResults = useMemo( | ||
() => Boolean(searchResult.stops.length || searchResult.units.length), | ||
[searchResult], | ||
); | ||
|
||
const onSubmit = useCallback((event) => { | ||
event.preventDefault(); | ||
}, []) as React.FormEventHandler; | ||
|
||
return ( | ||
<div className={cn(styles.MapSearchBar)} ref={searchBarRef}> | ||
<form | ||
className={cn(styles.MapSearchBar__form, { | ||
[styles.MapSearchBar__form_withResult]: hasResults, | ||
})} | ||
onSubmit={onSubmit} | ||
> | ||
<img src="/icons/search.svg" alt="" /> | ||
<input | ||
type="search" | ||
placeholder={INPUT_PLACEHOLDER} | ||
onInput={onSearch} | ||
className={cn(styles.MapSearchBar__input)} | ||
/> | ||
</form> | ||
{hasResults && ( | ||
<div className={cn(styles.MapSearchBar__results)}> | ||
{searchResult.units.map((unit) => ( | ||
<MapSearchBarUnitResult {...unit} /> | ||
))} | ||
{searchResult.stops.map(({ attributes: stop }) => ( | ||
<MapSearchBarStopResult {...stop} /> | ||
))} | ||
</div> | ||
)} | ||
</div> | ||
); | ||
} |
38 changes: 38 additions & 0 deletions
38
client/components/Map/SearchBar/StopsResult/StopResult.module.css
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,38 @@ | ||
.MapSearchBarStopResult__wrapper { | ||
display: flex; | ||
align-items: center; | ||
cursor: pointer; | ||
border: none; | ||
|
||
background-color: #fff; | ||
|
||
font-family: inherit; | ||
font-size: 20px; | ||
font-style: normal; | ||
font-weight: 400; | ||
line-height: 1.05; | ||
|
||
padding: 8px; | ||
gap: 10px; | ||
|
||
transition: background-color 150ms ease-out; | ||
|
||
& span { | ||
font-size: 28px; | ||
line-height: 1.16; | ||
} | ||
|
||
&:hover { | ||
background-color: #f4f4f4; | ||
} | ||
} | ||
|
||
.MapSearchBarStopResult__wrapper_selected { | ||
background-color: #f4f4f4; | ||
} | ||
|
||
.MapSearchBarStopResult__text { | ||
margin: 0; | ||
text-align: left; | ||
color: #000; | ||
} |
Oops, something went wrong.