Commit e2ce0ca3 authored by jasko.camic's avatar jasko.camic

feat: searchbox connected with map

parent 1654a4a4
Pipeline #128599345 passed with stages
in 5 minutes and 46 seconds
......@@ -2,14 +2,17 @@ import React from 'react'
import './App.scss'
import { AppLayout } from './layout/AppLayout'
import { MapViewProvider } from './context'
import { Map } from './components/Map'
function App() {
return (
<AppLayout>
<Map />
</AppLayout>
<MapViewProvider>
<AppLayout>
<Map />
</AppLayout>
</MapViewProvider>
)
}
......
import React, { FC } from 'react'
import React, { FC, useState } from 'react'
import cn from 'classnames'
import PlacesAutocomplete, { geocodeByAddress, getLatLng } from 'react-places-autocomplete'
import { MdSearch, MdClose } from 'react-icons/md'
import { Coordinates } from './interfaces'
import { RegionSelectEvent } from './interfaces'
import './AutoSearchBox.scss'
interface SearchBoxProps {
onChange: (region: string, latLng?: Coordinates) => void
resetInput: () => void
value: string
onChange: RegionSelectEvent
className?: string
}
......@@ -17,23 +15,30 @@ const iconProps = {
color: 'rgb(144, 144, 144)',
}
const removeCountry: (text: string) => string = text => text.replace(', Deutschland', '').trim()
const removeCountry: (text: string) => string = (text) => text.replace(', Deutschland', '').trim()
export const AutoSearchBox: FC<SearchBoxProps> = ({ onChange, resetInput, value, className }) => {
const handleChange: (value: string) => void = value => {
onChange(value)
export const AutoSearchBox: FC<SearchBoxProps> = ({ onChange, className }) => {
const [inputVal, setInputVal] = useState<string>('')
const handleChange: (value: string) => void = (value) => {
setInputVal(value)
}
const handleSelect: (selectedValue: string, _placeId: string) => void = selectedValue => {
const handleSelect: (selectedValue: string, _placeId: string) => void = (selectedValue) => {
geocodeByAddress(selectedValue)
.then(results => getLatLng(results[0]))
.then(latLng => onChange(removeCountry(selectedValue), latLng))
.catch(error => console.error('Error', error))
.then((results) => getLatLng(results[0]))
.then((latLng) => onChange(removeCountry(selectedValue), latLng))
.catch((error) => console.error('Error', error))
}
const handleReset: () => void = () => {
setInputVal('')
onChange('', undefined)
}
return (
<PlacesAutocomplete
value={value}
value={inputVal}
onChange={handleChange}
onSelect={handleSelect}
searchOptions={{
......@@ -47,7 +52,7 @@ export const AutoSearchBox: FC<SearchBoxProps> = ({ onChange, resetInput, value,
<span className="location-search__icon-wrapper">
<MdSearch {...iconProps} />
</span>
<span onClick={resetInput} className="location-search__reset-wrapper">
<span onClick={handleReset} className="location-search__reset-wrapper">
<MdClose {...iconProps} />
</span>
<input
......
......@@ -2,3 +2,5 @@ export interface Coordinates {
lat: number
lng: number
}
export type RegionSelectEvent = (region: string, latLng?: Coordinates) => void
......@@ -7,6 +7,7 @@ import 'rc-slider/assets/index.css'
import Slider from 'rc-slider'
import { AutoSearchBox } from '../../../components'
import { useMapView } from '../../../context'
import './ControlPanel.scss'
......@@ -43,13 +44,13 @@ const capacityTypes: Array<CapacityOptionType> = [
]
export const ControlPanel: FC<ControlPanelProps> = ({ controlProps, onChange }) => {
const [selectedRegion, setSelectedRegion] = useState<string>('')
const [showCapacity, setShowCapacity] = useState(controlProps.showCapacity)
const [showInfections, setShowInfections] = useState(controlProps.showInfections)
const [predictionPeriode, setPredictionPeriode] = useState(controlProps.predictionDay)
const [capacityType, setCapacityType] = useState<CapacityOptionType>(
capacityTypes.find((c) => c.value === controlProps.capacityType) || capacityTypes[0]
)
const { changeRegion } = useMapView()
const onChangeShowCapacity = (checked: boolean) => {
setShowCapacity(checked)
......@@ -67,12 +68,8 @@ export const ControlPanel: FC<ControlPanelProps> = ({ controlProps, onChange })
})
}
const handlePredictionSlider = (newPredictionDay: number): void => {
setPredictionPeriode(newPredictionDay)
onChange({
...controlProps,
predictionDay: newPredictionDay,
})
const handlePredictionSlider = (predictionPeriode: number): void => {
setPredictionPeriode(predictionPeriode)
}
const handleAccuracy = (predictionPeriode: number): JSX.Element => {
......@@ -103,12 +100,7 @@ export const ControlPanel: FC<ControlPanelProps> = ({ controlProps, onChange })
return (
<div className="control-panel">
<AutoSearchBox
value={selectedRegion}
onChange={(region) => setSelectedRegion(region)}
resetInput={() => setSelectedRegion('')}
className="search-box"
/>
<AutoSearchBox onChange={changeRegion} className="search-box" />
{/* <button className="collapser">
<IoIosArrowBack />
</button> */}
......
......@@ -2,6 +2,7 @@ import React, { FC, useEffect, useCallback, useRef, useState } from 'react'
import ReactMapGL, { Source, Layer, InteractiveMapProps, PointerEvent } from 'react-map-gl'
import { Map as MapType } from 'mapbox-gl'
import { FeatureCollection } from 'geojson'
import { useMapView } from '../../context'
import { debounce } from '../../utils/debounce'
import {
......@@ -36,6 +37,7 @@ export const Map: FC = () => {
const capacityRef = useRef<MapType>(null)
const infectionsRef = useRef<MapType>(null)
const containerRef = useRef(null)
const { latLng } = useMapView()
const [viewport, setViewport] = useState<InteractiveMapProps>({
width: '100%',
height: '100%',
......@@ -43,6 +45,10 @@ export const Map: FC = () => {
...GERMANY_LAT_LONG,
})
useEffect(() => {
latLng && setViewport((viewp) => ({ ...viewp, zoom: 10, latitude: latLng?.lat, longitude: latLng?.lng }))
}, [latLng])
useEffect(() => {
const resizeListener = debounce(() => {
setViewport({
......
export { MapViewProvider, useMapView } from './mapViewContext'
import React, { FC, useState, createContext, useContext } from 'react'
import { Coordinates, RegionSelectEvent } from '../components/AutoSearchBox/interfaces'
interface MapViewProps {
latLng?: Coordinates
region: string
changeRegion: RegionSelectEvent
}
const INITIAL_MAP_VIEW: MapViewProps = {
region: '',
changeRegion: (_region) => {},
}
const MapViewContext = createContext<MapViewProps>(INITIAL_MAP_VIEW)
export const MapViewProvider: FC = ({ children }) => {
const [region, setRegion] = useState<MapViewProps['region']>(INITIAL_MAP_VIEW.region)
const [latLng, setLatLng] = useState<MapViewProps['latLng']>(INITIAL_MAP_VIEW.latLng)
const changeRegion: RegionSelectEvent = (region, latLng) => {
setRegion(region)
latLng && setLatLng(latLng)
}
return <MapViewContext.Provider value={{ region, latLng, changeRegion }}>{children}</MapViewContext.Provider>
}
export const useMapView: () => MapViewProps = () => {
const mapViewData = useContext(MapViewContext)
if (!mapViewData) console.error('useMapView hat to be inner MapViewProvider!')
return mapViewData
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment