FormMap.tsx 3.92 KB
Newer Older
1
import * as React from 'react';
2
import {withStyles} from 'material-ui/styles';
3

4
import {error} from 'utilities/debug';
5
import {isNumeric} from 'utilities';
6

7
8
9
let Map;
let Marker;
let TileLayer;
10
11
12
13

interface IFormMapProps extends React.ClassAttributes<any> {
    classes: any;
    locations: [{
14
15
        decimalLatitude: any,
        decimalLongitude: any,
16
        mapCountry: any,
17
18
19
        userCountry: any,
        stateProvince: any,
        verbatimLocality: any,
20
    }];
21
    onMouseOut: () => any;
22
    checkGeonames: (lat, lng) => Promise<{userCountry: string, stateProvince: string, verbatimLocality?: string}>;
23
24
}

25
const styleSheet = {
26
    leafletContainer: {
27
        width: '100%',
28
        height: '300px',
29
    },
30
};
31
32
33
34
35
36
37
38
39
40
41
42
43

class FormMap extends React.Component<IFormMapProps, any> {

    public constructor(props: any) {
        super(props);

        this.state = {
            lat: 0,
            lng: 0,
        };
    }

    public componentDidMount() {
44
45
46
47
48
        // leaflet map doesn't work on server (ssr)
        Map = require('react-leaflet').Map;
        Marker = require('react-leaflet').Marker;
        TileLayer = require('react-leaflet').TileLayer;

49
50
51
52
53
54
55
56
57
58
59
        const {decimalLatitude, decimalLongitude} = this.props.locations.find((e) => !!e);

        if (decimalLatitude.input.value && decimalLongitude.input.value) {
            this.setState({lat: decimalLatitude.input.value, lng: decimalLongitude.input.value});
        } else {
            navigator.geolocation.getCurrentPosition((obj) => {
                this.setState({lat: obj.coords.latitude, lng: obj.coords.longitude});
            });
        }
    }

60
61
62
63
    protected getCurrentLocation = () => {
        return this.props.locations.find((e) => !!e);
    }

64
    protected onMapClick = (e) => {
65
66
67
68
        const {checkGeonames} = this.props;
        const {decimalLatitude, decimalLongitude, userCountry, stateProvince, verbatimLocality} = this.getCurrentLocation();

        const {lat, lng} = e.latlng;
69

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
        decimalLatitude.input.onChange(lat);
        decimalLongitude.input.onChange(lng);

        checkGeonames(lat, lng)
            .then((value) => {
                userCountry.input.onChange(value.userCountry);
                stateProvince.input.onChange(value.stateProvince);

                if (!verbatimLocality.input.value) {
                    verbatimLocality.input.onChange(value.verbatimLocality);
                }
            })
            .catch((e) => {
                error(e);
            });
85
86
87
    }

    protected onMarkerRightClick = () => {
88
        const {decimalLatitude, decimalLongitude} = this.getCurrentLocation();
89
90
91
92
93
94

        decimalLatitude.input.onChange(null);
        decimalLongitude.input.onChange(null);
    }

    public render() {
95
96
97
98
        if (!Map) {
            return null;
        }

99
        const {classes} = this.props;
100

101
        const {decimalLatitude, decimalLongitude} = this.getCurrentLocation();
102
103

        let position = null;
104
        if (isNumeric(decimalLatitude.input.value) && isNumeric(decimalLongitude.input.value)) {
105
            position = {
106
107
                lat: parseFloat(decimalLatitude.input.value),
                lng: parseFloat(decimalLongitude.input.value),
108
109
110
111
            };
        }

        return (
112
113
            <div className={ classes.leafletContainer }>
                <Map
114
                    center={ position || this.state }
115
116
117
118
119
                    onClick={ this.onMapClick }
                    onMouseout={ this.props.onMouseOut }
                    zoom={ 6 }
                >
                    <TileLayer
Maxym Borodenko's avatar
Maxym Borodenko committed
120
121
                        attribution={ '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }
                        url={ 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' }
122
123
124
125
                    />
                    { position && <Marker onContextmenu={ this.onMarkerRightClick } position={ position }/> }
                </Map>
            </div>
126
        );
Matija Obreza's avatar
Matija Obreza committed
127
    }
128
129
130
}

export default withStyles(styleSheet)(FormMap);