MapPage.tsx 20.5 KB
Newer Older
1
import * as React from 'react';
2
import { connect } from 'react-redux';
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
3
import { Link } from 'react-router-dom';
4
5
6
import { translate } from 'react-i18next';
import { withStyles } from '@material-ui/core/styles';
import { bindActionCreators } from 'redux';
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
7
import {showSnackbar} from 'actions/snackbar';
8
import navigateTo from 'actions/navigation';
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
9
import {currentClimateRequest, geoJsonRequest, loadAccessionsMapInfo} from 'accessions/actions/public';
10
import AccessionFilter from 'model/accession/AccessionFilter';
11
import Loading from 'ui/common/Loading';
12
import AccessionMapInfo from 'model/accession/AccessionMapInfo';
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
13
import MapLayer from 'model/genesys/MapTileLayer';
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
14
import ContentHeader from 'ui/common/heading/ContentHeader';
15
import Button from '@material-ui/core/Button';
16
import Tabs, { Tab } from 'ui/common/Tabs';
17
import PrettyFilters from 'ui/common/filter/PrettyFilters';
Oleksii Savran's avatar
Oleksii Savran committed
18
import ButtonBar from 'ui/common/buttons/ButtonBar';
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
19
20
import ContentLayout from 'ui/layout/ContentLayout';
import MapConfigSection from './c/MapConfigSection';
21

22
import AccessionsFilters from 'accessions/ui/c/Filters';
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
23
24
import BioClimateDisplay from 'accessions/ui/c/BioClimateDisplay';
import {Dialog, Drawer} from '@material-ui/core';
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
25
import PageTitle from 'ui/common/PageTitle';
Oleksii Savran's avatar
Oleksii Savran committed
26
27
28
29
30
31
32
33
import Popover from '@material-ui/core/Popover';
import Paper from '@material-ui/core/Paper';
import Tooltip from '@material-ui/core/Tooltip';
import LayersIcon from '@material-ui/icons/Layers';
import ClimateIcon from '@material-ui/icons/WbSunny';
import FilterIcon from '@material-ui/icons/PermDataSetting';
import CancelIcon from '@material-ui/icons/Cancel';

34

35
let MapComponent;
36
let TileLayer;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
37
let Popup;
Oleksii Savran's avatar
Oleksii Savran committed
38
let Rectangle;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
39
let Control;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
40
41

const popupContentLimit = 11;
42

43
44
45
46
interface IMapPageProps {
    classes?: any;
    t?: any;

47
    apiUrl: string;
48
    mapInfo: AccessionMapInfo;
49
    suggestions: any;
50
51
    currentTab: string;
    filterCode: string;
52
    loadAccessionsMapInfo: any;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
53
    mapLayers: MapLayer[];
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
54
    showSnackbar: (message: string) => void;
55
56
57
    navigateTo: (location: string) => void;
    initialPosition: number[];
    initialZoom: number;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
58
59
60
    loading: boolean;
    geoJsonRequest: (filter, limit: number) => Promise<any>;
    currentClimateRequest: (lat, lng) => Promise<any>;
61
62
63
}

const styles = (theme) => ({
Oleksii Savran's avatar
Oleksii Savran committed
64
    /*tslint:disable*/
65
66
67
    leafletContainer: {
        width: '100%',
        minHeight: '500px',
Oleksii Savran's avatar
Oleksii Savran committed
68
69
70
71
72
73
74
75
76
77
78
79
80
        height: 'calc(100vh - 245px)',
        [theme.breakpoints.down('md')]: {
            height: 'calc(100vh - 211px)',
        },
        [theme.breakpoints.down('sm')]: {
          height: 'calc(100vh - 199px)',
        },
        '& a[aria-label="Zoom in"], & a[aria-label="Zoom out"],': {
            color: '#000',
            '&:hover': {
                color: '#88ba42',
            },
        },
81
    },
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
82
83
84
85
86
87
88
89
90
    crosshair: {
        '& > div': {
            cursor: 'crosshair !important' as 'crosshair !important',
        },
    },
    climateDialog: {
        marginBottom: 0,
        overflow: 'auto' as 'auto',
    },
Oleksii Savran's avatar
Oleksii Savran committed
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    mapButton: {
        height: '34px',
        width: '34px',
        minWidth: 'auto',
        minHeight: 'initial',
        padding: '5px 8px',
        backgroundColor: '#fff',
        borderRadius: '4px',
        border: 'solid 2px #b7b7b7',
        transition: 'none',
        '& > span > svg': {
            color: '#000',
        },
        '&:hover': {
            backgroundColor: '#f4f4f4',
            '& > span > svg': {
                color: '#88ba42',
            },
        },
Oleksii Savran's avatar
Oleksii Savran committed
110
111
112
        'html[dir="rtl"] &' : {
            left: 0,
        },
Oleksii Savran's avatar
Oleksii Savran committed
113
114
115
116
117
118
119
    },
    mapIcon: {
        fontSize: '20px',
    },
    tooltip: {
        fontSize: '1rem',
    },
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
120
121
    filterAccessionsButton: {
        position: 'absolute' as 'absolute',
Oleksii Savran's avatar
Oleksii Savran committed
122
        top: '4px',
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
123
124
125
    },
    pickPositionButton: {
        position: 'absolute' as 'absolute',
Oleksii Savran's avatar
Oleksii Savran committed
126
        top: '42px',
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
127
    },
Oleksii Savran's avatar
Oleksii Savran committed
128
129
130
131
132
133
134
135
136
137
138
139
    layersButton: {
        width: '50px',
        height: '50px',
        '&:hover > span > svg': {
            color: '#000',
        },
    },
    layersControl: {
        maxHeight: '55vh',
        overflow: 'auto',
    },
    /*tslint:enable*/
140
141
142
});

class BrowsePage extends React.Component<IMapPageProps, any> {
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
143
144

    private clickTimeout;
145
    private mapRef = null;
Oleksii Savran's avatar
Oleksii Savran committed
146
    private anchorRef = null;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
147

148
    protected static needs = [
149
150
      ({ params: { filterCode, initialPosition, initialZoom } }) => {
        return loadAccessionsMapInfo(filterCode || '', {center: initialPosition, zoom: initialZoom});
151
152
153
      },
    ];

Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
154
    public state = {
Oleksii Savran's avatar
Oleksii Savran committed
155
156
      clickLocation: [],
      searchBox: null,
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
157
158
      geoData: [],
      otherCount: 0,
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
159
160
161
162
      sidebarOpened: false,
      trackClickPos: false,
      dialogOpened: false,
      climateData: null,
Oleksii Savran's avatar
Oleksii Savran committed
163
      layersControlsIsOpen: false,
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
164
165
    };

166
167
168
    constructor(props, context) {
        super(props, context);
        if (typeof window !== 'undefined') {
169
            MapComponent = require('react-leaflet').Map;
170
            TileLayer = require('react-leaflet').TileLayer;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
171
            Popup = require('react-leaflet').Popup;
Oleksii Savran's avatar
Oleksii Savran committed
172
            Rectangle = require('react-leaflet').Rectangle;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
173
            Control = require('react-leaflet-control').default;
174
175
176
177
178
        }
    }


    public componentWillMount() {
179
      const { mapInfo, filterCode, loadAccessionsMapInfo, initialPosition, initialZoom } = this.props;
180
181
182
      // console.log(`Filter code for map ${filterCode} ?== ${mapInfo && mapInfo.filterCode}`, filterCode, mapInfo ? mapInfo.filterCode : 'No mapInfo');
      if (mapInfo && mapInfo.filterCode !== filterCode) {
        // console.log(`mapInfo.filterCode !== filterCode. updatingRoute`);
183
        loadAccessionsMapInfo(filterCode || '', {center: initialPosition, zoom: initialZoom});
184
      } else if (!mapInfo) {
185
        loadAccessionsMapInfo(filterCode || '', {center: initialPosition, zoom: initialZoom});
186
187
188
      }
    }

Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
189
190
191
192
193
194
195
196
    private openSidebar = () => {
      return this.setState({sidebarOpened: true});
    }

    private closeSidebar = () => {
      return this.setState({sidebarOpened: false});
    }

Oleksii Savran's avatar
Oleksii Savran committed
197
198
199
200
201
202
203
204
    private openLayersControls = () => {
      return this.setState({layersControlsIsOpen: true});
    }

    private closeLayersControls = () => {
      return this.setState({layersControlsIsOpen: false});
    }

Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
205
206
207
208
209
210
211
212
    private setPositionPick = (e) => {
      e.preventDefault();
      e.stopPropagation();
      this.setState({trackClickPos: !this.state.trackClickPos});
      return false;
    }

    private handleTrackPosition = (e) => {
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
213
      const {showSnackbar, t, currentClimateRequest } = this.props;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
214
215
216
217
      const { lat, lng } = e.latlng;

      this.setState({climateData: null});

Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
218
      currentClimateRequest(lat, lng)
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
        .then((res) => {
          // @ts-ignore
          if (!res || res === '') {
            return showSnackbar(t('accessions.public.p.map.noClimateData'));
          }
          return this.setState({climateData: res, dialogOpened: true});
        })
        .catch((error) =>  {
          if (error.code === 404) {
            return showSnackbar(t('accessions.public.p.map.noClimateData'));
          }
        });
    }

    private hideDialog = () => {
      this.setState({dialogOpened: false});
    }
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
236

237
238
239
240
241
242
243
244
245
246
247
    private handleMoveEnd = (e) => {
      const {navigateTo, filterCode} = this.props;
      if (this.mapRef) {
        const {viewport: {center, zoom}} = this.mapRef;
        // console.log('Updating URL center: ', center, ' Zoom: ', zoom);
        if (center && center[0] !== 0 || center[1] !== 0) {
          navigateTo(`/a/map${filterCode && `/${filterCode}`}/@${center[0]},${center[1]},${zoom}z`);
        }
      }
    }

Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
248
    private onMapClick = (e) => {
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
249
250
251
252
253
254
255
256
257

        if (e.originalEvent.target.className.indexOf('leaflet-touch') === -1) {
          return;
        }

        if (this.state.trackClickPos) {
          return this.handleTrackPosition(e);
        }

Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
258
259
260
261
262
263
264
265
266
267
268
269
270
271
        if (this.clickTimeout) {
            console.log('prevented');
            clearTimeout(this.clickTimeout);
            this.clickTimeout = null;
            return;
        }
        this.clickTimeout = setTimeout(() => {
            console.log('started');
            this.clickTimeout = null;
            const currentZoom = e.target._zoom;
            if (currentZoom < 4) {
                return;
            }

Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
272
            const {mapInfo: {filter}, geoJsonRequest} = this.props;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
273
274
275
276
277

            const correctLng = Math.abs(e.latlng.lng) > 180 ? (360 + e.latlng.lng) % 180 : e.latlng.lng;

            console.log(e);

Oleksii Savran's avatar
Oleksii Savran committed
278
            const width = Math.pow(2, currentZoom - 2);
279
            // console.log(`zoom=${currentZoom} width=${width} diff=${ 3 / width}`);
Oleksii Savran's avatar
Oleksii Savran committed
280
281
282
283
            const searchBounds: number[][] = [
                [ e.latlng.lat - (3 / width), correctLng - (3 / width) ],
                [ e.latlng.lat + (3 / width), correctLng + (3 / width) ],
            ];
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
284
285
286
287
            const filterWithGeo = {
                ...filter,
                geo: {
                    longitude: {
Oleksii Savran's avatar
Oleksii Savran committed
288
289
                        ge: searchBounds[0][1],
                        le: searchBounds[1][1],
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
290
291
                    },
                    latitude: {
Oleksii Savran's avatar
Oleksii Savran committed
292
293
                        ge: searchBounds[0][0],
                        le: searchBounds[1][0],
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
294
                    },
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
295
                    climate: filter && filter.geo && filter.geo.climate,
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
296
297
                },
            };
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
298
            geoJsonRequest(filterWithGeo, popupContentLimit)
Oleksii Savran's avatar
Oleksii Savran committed
299
                .then((res) => this.setState({clickLocation: [ e.latlng.lat,  e.latlng.lng], searchBox: searchBounds, geoData: res.geoJson, otherCount: res.otherCount}));
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
300
301
302
        }, 200);
    }

303
304
305
306
307
    /// Wrap loadAccessionsMapInfo dispatch and fills the current sort selection
    protected myApplyFilters = (filters: AccessionFilter) => {
      const { loadAccessionsMapInfo } = this.props;

      loadAccessionsMapInfo(filters);
308
309
310
    }

    public render() {
Oleksii Savran's avatar
Oleksii Savran committed
311
        const { searchBox, geoData, otherCount, sidebarOpened, trackClickPos, dialogOpened, climateData, layersControlsIsOpen} = this.state;
312
        const { mapInfo, mapLayers, currentTab, classes, filterCode, loading, suggestions, t, loadAccessionsMapInfo, initialPosition, initialZoom } = this.props;
313

Oleksii Savran's avatar
Oleksii Savran committed
314
315
316
317
318
        const position = initialPosition[0] && initialPosition[1] ? initialPosition : [5, 5];
        const initialBounds = [
          [-40, 60],
          [50, -50],
        ];
319
320
321
322

        if (! mapInfo) {
          return <Loading />;
        }
323

324
325
326
327
328
329
330
331
332
        if (mapInfo.bounds[0][0] !== null && mapInfo.bounds[1][0] !== null) {
          if (Math.abs(mapInfo.bounds[0][0] - mapInfo.bounds[1][0]) < Math.abs(initialBounds[0][0] - initialBounds[1][0])) {
            initialBounds[0][0] = mapInfo.bounds[0][0];
            initialBounds[1][0] = mapInfo.bounds[1][0];
          }
          if (Math.abs(mapInfo.bounds[0][1] - mapInfo.bounds[1][1]) < Math.abs(initialBounds[0][1] - initialBounds[1][1])) {
            initialBounds[0][1] = mapInfo.bounds[0][1];
            initialBounds[1][1] = mapInfo.bounds[1][1];
          }
Oleksii Savran's avatar
Oleksii Savran committed
333
334
        }

335
336
337
338
339
340
341
342
343
344
345
346
        const suggestionTerms = new Map();
        if (suggestions) {
            Object.keys(suggestions).forEach((key) => {
              const overviewEl = suggestions[key];
              const terms = new Map();
              overviewEl.terms.forEach((term) => terms.set(term.term, term.count));
              suggestionTerms.set(key, terms);
            });
        }

        console.log(suggestionTerms);

347
        // const color = 'f00ba0';
348
        const layerUrl = `{s}/acn/tile/{z}/{x}/{y}?f=${filterCode ? filterCode : ''}`; // `&color=${color}`;
349
350

        return (
Oleksii Savran's avatar
Oleksii Savran committed
351
            <ContentLayout customHeaderHeight>
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
352
353
              <PageTitle title={ t('accessions.public.p.browse.title') } />
              <ContentHeader title={ t('accessions.public.p.browse.title') } subTitle={ t('accessions.public.p.browse.subTitle') } />
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
354
355

              <Drawer variant="temporary" open={ sidebarOpened } onClose={ this.closeSidebar }>
356
                    <AccessionsFilters terms={ suggestionTerms } onSubmit={ loadAccessionsMapInfo } initialValues={ mapInfo && mapInfo.filter }/>
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
357
358
359
360
361
362
363
364
                </Drawer>


              <Dialog open={ dialogOpened } onClose={ this.hideDialog } maxWidth="md" fullWidth>
                <BioClimateDisplay classes={ {section: classes.climateDialog} } climateData={ climateData }/>
              </Dialog>

                <Tabs
365
366
                    tab={ currentTab }
                    actions={
Oleksii Savran's avatar
Oleksii Savran committed
367
                      <ButtonBar>
368
                        <span>
Matija Obreza's avatar
Matija Obreza committed
369
370
                          <form method="post" action="/proxy/api/v1/acn/downloadKml">
                            <input type="hidden" name="f" value={ filterCode } />
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
371
                            <Button type="submit">{ `${t('common:action.download')} ${t('accessions.public.p.map.kml')}` }</Button>
Matija Obreza's avatar
Matija Obreza committed
372
                          </form>
373
                        </span>
Oleksii Savran's avatar
Oleksii Savran committed
374
                      </ButtonBar>
375
376
                    }
                >
Viacheslav Pavlov's avatar
i18n    
Viacheslav Pavlov committed
377
                  <Tab name="overview" to={ `/a/overview/${filterCode || ''}` }>{ t('accessions.tab.overview') }</Tab>
Oleksii Savran's avatar
Oleksii Savran committed
378
                  <Tab name="data" to={ `/a/${filterCode || ''}` }>{ t('accessions.tab.data') }</Tab>
Viacheslav Pavlov's avatar
i18n    
Viacheslav Pavlov committed
379
                  <Tab name="map" to={ `/a/map/${filterCode || '' }` }>{ t('accessions.tab.map') }</Tab>
380
381
382
                </Tabs>
                <PrettyFilters
                    prefix="accessions"
383
                    filterObj={ mapInfo && mapInfo.filter || {} }
384
                    onSubmit={ this.myApplyFilters }
Oleksii Savran's avatar
Oleksii Savran committed
385
386
                    displayName="accessions.common.modelName"
                    amount={ mapInfo && mapInfo.accessionCount }
387
                />
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
388
                <div className={ `${classes.leafletContainer} ${trackClickPos && classes.crosshair}` }>
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
389
390
                  { loading && <Loading /> }
                  { mapInfo && typeof window !== 'undefined' &&
391
                    <MapComponent
392
                        onMoveend={ this.handleMoveEnd }
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
393
                        onClick={ this.onMapClick }
394
                        center={ position }
395
                        zoom={ initialZoom || 3 } minZoom={ 2 } maxZoom={ 14 }
Oleksii Savran's avatar
Oleksii Savran committed
396
397
                        zoomDelta={ 0.5 }
                        bounds={ !initialZoom && initialPosition[0] && !initialPosition[1] ? mapInfo.bounds : initialBounds }
398
                        ref={ (ref) => this.mapRef = ref }
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
399
                    >
Oleksii Savran's avatar
Oleksii Savran committed
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
                        <Control position="topleft">
                            <Tooltip
                              classes={ { tooltip: classes.tooltip } }
                              className={ `${classes.filterAccessionsButton} ${classes.mapButton}` }
                              title={ t(`accessions.public.p.map.filterAccessions`) }
                              placement="right"
                            >
                                <Button variant="outlined" onClick={ this.openSidebar }>
                                    <FilterIcon className={ classes.mapIcon }/>
                                </Button>
                            </Tooltip>
                        </Control>
                        <Control position="topleft">
                            <Tooltip
                              classes={ { tooltip: classes.tooltip } }
                              className={ `${classes.pickPositionButton} ${classes.mapButton}` }
                              title={ t(`accessions.public.p.map.${ trackClickPos ? 'stopPick' : 'pick'}`) }
                              placement="right"
                            >
                                <Button variant="outlined" onClick={ this.setPositionPick }>
                                    { trackClickPos ?
                                        <CancelIcon className={ classes.mapIcon }/> :
                                        <ClimateIcon className={ classes.mapIcon }/>
                                    }
                                </Button>
                            </Tooltip>
                        </Control>
                        <Control position="topright">
                            <div
                              onMouseEnter={ this.openLayersControls }
                              ref={ (ref) => this.anchorRef = ref }
                            >
                                <Button
                                  variant="contained"
Oleksii Savran's avatar
Oleksii Savran committed
434
                                  className={ `${classes.mapButton} ${classes.layersButton}` }
Oleksii Savran's avatar
Oleksii Savran committed
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
                                  onClick={ this.openLayersControls }
                                >
                                    <LayersIcon/>
                                </Button>
                                <Popover open={ layersControlsIsOpen }
                                         anchorEl={ this.anchorRef }
                                         onClose={ this.closeLayersControls }
                                         transformOrigin={ {
                                             vertical: 'top',
                                             horizontal: 'right',
                                         } }
                                         anchorOrigin={ {
                                             vertical: 'top',
                                             horizontal: 'right',
                                         } }
                                >
                                    <Paper className={ classes.layersControl } onMouseLeave={ this.closeLayersControls }>
                                        <MapConfigSection/>
                                    </Paper>
                                </Popover>
                            </div>
                        </Control>
                        <TileLayer
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
458
                            zIndex={ 0 }
459
                            opacity={ 0.50 }
460
461
                            attribution={ '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>' }
                            url={ 'https://maps.tilehosting.com/styles/positron/{z}/{x}/{y}.png?key=frAVvE3XbD6EF3BM2kDW' }
462
                        />
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
463
464
465

                        { mapLayers && mapLayers.filter((layer) => layer.enabled).map((layer, index) => <TileLayer zIndex={ index + 1 } key={ layer.name } { ...layer }/>) }

Matija Obreza's avatar
Matija Obreza committed
466
                        <TileLayer
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
467
                            zIndex={ mapLayers.length + 1 }
468
469
470
471
                            updateInterval={ 1000 }
                            updateWhenZooming={ false }
                            attribution="&amp;copy Accession localities from <a href=&quot;/&quot;>Genesys PGR</a>"
                            url={ layerUrl }
472
                            subdomains={ mapInfo.tileServers }
473
                        />
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
474
                        { geoData && geoData.length > 0 &&
Oleksii Savran's avatar
Oleksii Savran committed
475
476
477
478
                            <Rectangle
                              bounds={ searchBox }
                              ref={ (marker) => marker && marker.leafletElement.openPopup() }
                            >
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
479
480
                                <Popup open>
                                    <div>
481
                                        { geoData.map((feature, idx) => (<div key={ idx }><Link to={ `/a/${feature.properties.uuid}` }>{ `${feature.properties.accessionNumber} ${feature.properties.instCode}` }</Link></div>)) }
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
482
483
484
                                        { otherCount > 0 && <div>{ t('accessions.public.p.map.andMore', {otherMore: otherCount}) }</div> }
                                    </div>
                                </Popup>
Oleksii Savran's avatar
Oleksii Savran committed
485
                            </Rectangle>
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
486
                        }
487
                    </MapComponent>
488
489
                }
                </div>
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
490
            </ContentLayout>
491
492
493
494
495
        );
    }
}

const mapStateToProps = (state, ownProps) => ({
496
    suggestions: state.accessions.public.suggestions,
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
497
498
    mapInfo: state.accessions.public.mapInfo ? state.accessions.public.mapInfo.data : undefined,
    loading: state.accessions.public.mapInfo ? state.accessions.public.mapInfo.loading : false,
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
499
    mapLayers: state.accessions.public.mapLayers,
500
    filterCode: ownProps.match.params.filterCode || (state.accessions.public.mapInfo ? state.accessions.public.mapInfo.data && state.accessions.public.mapInfo.data.filterCode : ''),
501
    currentTab: ownProps.match.params.tab || 'map', // current tab, or ownProps.location.pathname
502
503
    initialPosition: isNaN(Number(ownProps.match.params.lat)) || isNaN(Number(ownProps.match.params.lng)) ? [] : [Number(ownProps.match.params.lat), Number(ownProps.match.params.lng)],
    initialZoom: isNaN(Number(ownProps.match.params.zoom)) ? null : Number(ownProps.match.params.zoom),
504
505
506
});

const mapDispatchToProps = (dispatch) => bindActionCreators({
507
    loadAccessionsMapInfo,
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
508
509
    geoJsonRequest,
    currentClimateRequest,
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
510
    showSnackbar,
511
    navigateTo,
512
513
}, dispatch);

514
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(translate()(BrowsePage)));