@woosmap/ui 2.36.0 → 2.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@woosmap/ui",
3
- "version": "2.36.0",
3
+ "version": "2.37.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/WebGeoServices/ui.git"
7
7
  },
8
8
  "main": "src/index.js",
9
9
  "dependencies": {
10
+ "@mapbox/polyline": "^1.1.1",
10
11
  "axios": "^0.21.1",
11
12
  "classnames": "^2.3.1",
12
13
  "framer-motion": "^4.1.17",
package/src/Constants.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export default {
2
2
  woosmapKey: 'woos-5ec4eecd-d907-3da0-90f0-f2f3b7e4e672',
3
+ geolocationWoosmapSearchKey: 'woos-81a699ca-5082-3ffd-9f54-a684a4b82853',
3
4
  gmapKey: 'AIzaSyAogtvSQJ8e1LO6WH6GzSI-QtwaRPCV5C8',
4
5
  };
@@ -41,7 +41,7 @@ export const Default = Template.bind({});
41
41
  Default.args = {};
42
42
 
43
43
  const SimpleCardTemplate = () => (
44
- <SimpleCard isDisabled isActive title="My hotels in France" subtitle="18 assets - 12K queries">
44
+ <SimpleCard isDisabled isActive isFavorite title="My hotels in France" subtitle="18 assets - 12K queries">
45
45
  <Tooltip text="Localities" direction="n" product="LOCALITIES">
46
46
  <Label round size="nano" label="L" product="LOCALITIES" />
47
47
  </Tooltip>
@@ -2,10 +2,13 @@
2
2
  import React, { Component } from 'react';
3
3
  import cl from 'classnames';
4
4
  import PropTypes from 'prop-types';
5
+ import Icon from '../Icon/Icon';
6
+ import { tr } from '../utils/locale';
5
7
 
6
8
  class SimpleCard extends Component {
7
9
  render() {
8
- const { title, subtitle, className, children, isSelected, isActive, isDisabled, ...rest } = this.props;
10
+ const { title, subtitle, className, children, isSelected, isActive, isDisabled, isFavorite, ...rest } =
11
+ this.props;
9
12
  return (
10
13
  <div
11
14
  className={cl(
@@ -18,6 +21,9 @@ class SimpleCard extends Component {
18
21
  {...rest}
19
22
  >
20
23
  {title && <div className="simplecard__title">{title}</div>}
24
+ {isFavorite && (
25
+ <Icon className="simplecard__favorite" title={tr('Favorite project')} icon="star-filled" />
26
+ )}
21
27
  {subtitle && <div className="simplecard__subtitle">{subtitle}</div>}
22
28
  {children && <div className="simplecard__content">{children}</div>}
23
29
  </div>
@@ -33,6 +39,7 @@ SimpleCard.defaultProps = {
33
39
  isSelected: false,
34
40
  isActive: false,
35
41
  isDisabled: false,
42
+ isFavorite: false,
36
43
  };
37
44
 
38
45
  SimpleCard.propTypes = {
@@ -43,6 +50,7 @@ SimpleCard.propTypes = {
43
50
  title: PropTypes.string,
44
51
  subtitle: PropTypes.string,
45
52
  className: PropTypes.string,
53
+ isFavorite: PropTypes.bool,
46
54
  };
47
55
 
48
56
  export default SimpleCard;
@@ -2,6 +2,7 @@
2
2
  flexCol()
3
3
  br()
4
4
  trans()
5
+ position relative
5
6
  background-color $light
6
7
  padding 1.6rem
7
8
  border .1rem solid $secondary20
@@ -36,6 +37,11 @@
36
37
  margin-top auto
37
38
  padding-top 1rem
38
39
  flexMiddle()
40
+ &__favorite
41
+ position absolute
42
+ right 1rem
43
+ top 1.3rem
44
+ fill $favorite
39
45
  .tooltip
40
46
  position relative
41
47
  $mr = -.2rem
@@ -1,13 +1,11 @@
1
1
  /* eslint-disable jsx-a11y/click-events-have-key-events */
2
2
  import axios from 'axios';
3
3
  import React, { Component } from 'react';
4
- import GoogleMapReact from 'google-map-react';
5
4
  import PropTypes from 'prop-types';
6
5
  import cl from 'classnames';
6
+ import polyline from '@mapbox/polyline';
7
7
  import Demo from './SkeletonDemo';
8
- import Marker from '../Map/Marker';
9
8
  import Input from '../Input/Input';
10
- import { polyline, decodePath, extendedBounds } from '../Map/drawOnMap';
11
9
  import Constants from '../../Constants';
12
10
  import LocalitiesAutocomplete from '../Woosmap/LocalitiesAutocomplete';
13
11
  import Button from '../Button/Button';
@@ -16,6 +14,8 @@ import DrivingImg from '../../images/car.png';
16
14
  import CyclingImg from '../../images/cycle.png';
17
15
  import WalkingImg from '../../images/walk.png';
18
16
  import { tr } from '../utils/locale';
17
+ import markerIcon from '../../images/marker.png';
18
+ import Script from '../utils/Script';
19
19
 
20
20
  const languages = [
21
21
  { value: 'fr', label: 'French' },
@@ -66,13 +66,15 @@ export default class DistanceDemo extends Component {
66
66
 
67
67
  this.mounted = true;
68
68
  this.map = null;
69
- this.marker = null;
69
+ this.markers = [];
70
70
  this.requestUrl = 'https://api.woosmap.com/distance/route/json';
71
71
  this.polylines = [];
72
+ this.directionsRenderer = null;
73
+ this.mapDivRef = React.createRef();
72
74
  }
73
75
 
74
76
  componentDidMount() {
75
- this.requestDistance();
77
+ this.displayMap();
76
78
  }
77
79
 
78
80
  componentWillUnmount() {
@@ -83,21 +85,56 @@ export default class DistanceDemo extends Component {
83
85
  }
84
86
 
85
87
  displayOnMap = () => {
86
- const { routes } = this.state;
87
- for (let i = 0; i < this.polylines.length; i++) {
88
- this.polylines[i].setMap(null);
89
- }
90
-
91
- if (routes && routes.length > 0 && this.map) {
92
- this.map.fitBounds(extendedBounds(routes.map((route) => route.bounds)));
93
- this.map.setZoom(this.map.getZoom() - 1);
94
-
95
- this.polylines = routes.map((route) => {
96
- const routePolyline = polyline(decodePath(route.overview_polyline.points));
97
- routePolyline.setMap(this.map);
98
-
99
- return routePolyline;
100
- });
88
+ if (this.map) {
89
+ const { originLocation, destinationLocation, routes } = this.state;
90
+
91
+ if (!this.directionsRenderer) {
92
+ this.directionsRenderer = new window.woosmap.map.DirectionsRenderer({ preserveViewport: true });
93
+ this.directionsRenderer.setMap(this.map);
94
+ }
95
+
96
+ if (this.markers.length > 0) {
97
+ this.markers.forEach((marker) => marker.setMap(null));
98
+ this.markers = [];
99
+ }
100
+
101
+ const bounds = new window.woosmap.map.LatLngBounds();
102
+
103
+ this.markers.push(
104
+ new window.woosmap.map.Marker({
105
+ icon: { url: markerIcon, scaledSize: { height: 46, width: 30 } },
106
+ position: originLocation,
107
+ map: this.map,
108
+ })
109
+ );
110
+ bounds.extend(new window.woosmap.map.LatLng(originLocation.lat, originLocation.lng));
111
+
112
+ this.markers.push(
113
+ new window.woosmap.map.Marker({
114
+ icon: { url: markerIcon, scaledSize: { height: 46, width: 30 } },
115
+ position: destinationLocation,
116
+ map: this.map,
117
+ })
118
+ );
119
+ bounds.extend(new window.woosmap.map.LatLng(destinationLocation.lat, destinationLocation.lng));
120
+
121
+ routes.forEach((route) =>
122
+ Object.values(route.bounds).forEach((bound) =>
123
+ bounds.extend(new window.woosmap.map.LatLng(bound.lat, bound.lng))
124
+ )
125
+ );
126
+
127
+ const decodedRoutes = routes.map((route) => ({
128
+ ...route,
129
+ overview_path: route.overview_polyline
130
+ ? polyline
131
+ .decode(route.overview_polyline.points)
132
+ .map((e) => new window.woosmap.map.LatLng(e[0], e[1]))
133
+ : undefined,
134
+ }));
135
+
136
+ this.directionsRenderer.setDirections({ routes: decodedRoutes });
137
+ this.map.fitBounds(bounds, { top: 70, bottom: 70, left: 70, right: 70 });
101
138
  }
102
139
  };
103
140
 
@@ -166,36 +203,21 @@ export default class DistanceDemo extends Component {
166
203
  return <ul>{result}</ul>;
167
204
  };
168
205
 
169
- renderMap = () => {
170
- const { originLocation, destinationLocation } = this.state;
171
-
172
- const markerOrigin = <Marker lat={originLocation.lat} lng={originLocation.lng} />;
173
- const markerDestination = <Marker lat={destinationLocation.lat} lng={destinationLocation.lng} />;
206
+ displayMap = () => {
207
+ if (this.timeoutMap) {
208
+ clearTimeout(this.timeoutMap);
209
+ }
174
210
 
175
- return (
176
- <GoogleMapReact
177
- defaultZoom={8}
178
- center={[originLocation.lat, originLocation.lng]}
179
- bootstrapURLKeys={{
180
- key: Constants.gmapKey,
181
- libraries: ['geometry', 'places'],
182
- }}
183
- yesIWantToUseGoogleMapApiInternals
184
- onGoogleApiLoaded={({ map }) => {
185
- google.maps.event.addListenerOnce(map, 'idle', () => {
186
- this.timeout = setTimeout(() => {
187
- this.map = map;
188
- this.displayOnMap();
189
- }, 1000);
190
- });
191
- }}
192
- >
193
- {markerOrigin}
194
- {markerDestination}
195
- </GoogleMapReact>
196
- );
211
+ if (window.woosmap && window.woosmap.map && this.mapDivRef.current) {
212
+ this.map = new window.woosmap.map.Map(this.mapDivRef.current);
213
+ this.requestDistance();
214
+ } else {
215
+ this.timeoutMap = setTimeout(this.displayMap, 300);
216
+ }
197
217
  };
198
218
 
219
+ renderMap = () => <div className="map" ref={this.mapDivRef} />;
220
+
199
221
  localitiesOnChangeCallBack = (type) => (item) => {
200
222
  const newState = {};
201
223
  newState[`${type}Location`] = item ? item.location : {};
@@ -323,21 +345,24 @@ export default class DistanceDemo extends Component {
323
345
  ),
324
346
  };
325
347
  return (
326
- <Demo
327
- id="distance-demo"
328
- className="demo--distance"
329
- docLink="https://developers.woosmap.com/products/distance-api/get-started/"
330
- header={headerLabels}
331
- footerFilters={this.renderFooterFilters()}
332
- headerFilters={this.renderHeaderFilters()}
333
- request={this.requestUrl}
334
- noheader={noheader}
335
- params={this.getRequestparams()}
336
- referer="http://localhost/"
337
- response={error || routes}
338
- result={this.renderRoutesSummary()}
339
- map={this.renderMap()}
340
- />
348
+ <>
349
+ <Script url={`https://sdk.woosmap.com/map/map.js?key=${Constants.woosmapKey}`} />
350
+ <Demo
351
+ id="distance-demo"
352
+ className="demo--distance"
353
+ docLink="https://developers.woosmap.com/products/distance-api/get-started/"
354
+ header={headerLabels}
355
+ footerFilters={this.renderFooterFilters()}
356
+ headerFilters={this.renderHeaderFilters()}
357
+ request={this.requestUrl}
358
+ noheader={noheader}
359
+ params={this.getRequestparams()}
360
+ referer="http://localhost/"
361
+ response={error || routes}
362
+ result={this.renderRoutesSummary()}
363
+ map={this.renderMap()}
364
+ />
365
+ </>
341
366
  );
342
367
  }
343
368
  }
@@ -1,13 +1,17 @@
1
1
  /* eslint-disable jsx-a11y/click-events-have-key-events */
2
2
  import axios from 'axios';
3
3
  import React, { Component } from 'react';
4
- import GoogleMapReact from 'google-map-react';
5
4
  import PropTypes from 'prop-types';
6
5
  import Demo from './SkeletonDemo';
7
- import Marker from '../Map/Marker';
8
- import { viewport, boundsFromViewport } from '../Map/drawOnMap';
6
+
9
7
  import Constants from '../../Constants';
10
8
  import { tr } from '../utils/locale';
9
+ import markerIcon from '../../images/marker.png';
10
+ import markerIconAlt from '../../images/marker-alt.png';
11
+ import Script from '../utils/Script';
12
+ import Input from '../Input/Input';
13
+
14
+ import { WoosmapMapBoundingBox, woosmapBoundsFromViewport } from '../Map/drawOnMap';
11
15
 
12
16
  export default class GeolocationDemo extends Component {
13
17
  constructor(props) {
@@ -15,15 +19,20 @@ export default class GeolocationDemo extends Component {
15
19
  this.state = {
16
20
  geolocation: null,
17
21
  error: null,
22
+ showStores: false,
23
+ hasStores: false,
18
24
  };
19
25
  this.map = null;
20
26
  this.marker = null;
21
27
  this.viewport = null;
22
- this.requestUrl = 'https://api.woosmap.com/geolocation/position/';
28
+ this.requestUrl = 'https://api.woosmap.com/geolocation/stores';
29
+ this.mapDivRef = React.createRef();
30
+ this.overlay = null;
31
+ this.storeMarkers = [];
23
32
  }
24
33
 
25
34
  componentDidMount() {
26
- this.requestGeolocation();
35
+ this.displayMap();
27
36
  }
28
37
 
29
38
  requestGeolocation = () => {
@@ -32,10 +41,11 @@ export default class GeolocationDemo extends Component {
32
41
  params: this.getRequestparams(),
33
42
  })
34
43
  .then((response) => {
35
- this.setState({
36
- geolocation: response.data,
37
- error: null,
38
- });
44
+ const { data: geolocation } = response;
45
+ const { stores } = geolocation;
46
+ const hasStores = stores && stores.length > 1;
47
+
48
+ this.setState({ geolocation, hasStores, error: null }, this.displayOnMap);
39
49
  })
40
50
  .catch((error) => {
41
51
  const errorResult = (error && error.response && error.response.data) || 'Unhandled error';
@@ -44,20 +54,87 @@ export default class GeolocationDemo extends Component {
44
54
  };
45
55
 
46
56
  getRequestparams = () => ({
47
- key: Constants.woosmapKey,
57
+ key: Constants.geolocationWoosmapSearchKey,
58
+ radius: 200000,
48
59
  });
49
60
 
61
+ processMarker = (latLng, icon, forceMap = null) => {
62
+ const { showStores } = this.state;
63
+
64
+ let map;
65
+ if (!forceMap) map = showStores ? this.map : null;
66
+ else map = forceMap;
67
+
68
+ return new window.woosmap.map.Marker({
69
+ icon: { url: icon, scaledSize: { height: 46, width: 30 } },
70
+ position: latLng,
71
+ map,
72
+ });
73
+ };
74
+
50
75
  displayOnMap = () => {
51
76
  const { geolocation } = this.state;
52
- if (this.viewport) {
53
- this.viewport.setMap(null);
54
- }
77
+
55
78
  if (this.map && geolocation) {
56
- this.map.fitBounds(boundsFromViewport(geolocation.viewport), 20);
57
- this.viewport = viewport(this.map, geolocation.viewport);
79
+ const location = new window.woosmap.map.LatLng(geolocation.latitude, geolocation.longitude);
80
+
81
+ if (this.marker) {
82
+ this.marker.setMap(null);
83
+ this.marker = null;
84
+ }
85
+
86
+ if (this.storeMarkers) {
87
+ this.storeMarkers.forEach((store) => store.setMap(null));
88
+ this.storeMarkers = [];
89
+ }
90
+
91
+ if (this.overlay) {
92
+ this.overlay.setMap(null);
93
+ this.overlay = null;
94
+ }
95
+
96
+ this.marker = this.processMarker(location, markerIconAlt, this.map);
97
+
98
+ if (geolocation?.stores?.features) {
99
+ geolocation.stores.features.forEach((feature) => {
100
+ const [lng, lat] = feature.geometry.coordinates;
101
+ this.storeMarkers.push(this.processMarker(new window.woosmap.map.LatLng({ lat, lng }), markerIcon));
102
+ });
103
+ }
104
+
105
+ const bounds = woosmapBoundsFromViewport(geolocation.viewport);
106
+
107
+ this.overlay = new WoosmapMapBoundingBox(bounds, { top: 55, left: 30, bottom: 10, right: 30 });
108
+ this.overlay.setMap(this.map);
109
+
110
+ this.map.fitBounds(bounds, { top: 70, left: 70, bottom: 70, right: 70 });
58
111
  }
59
112
  };
60
113
 
114
+ renderFooterFilters = () => {
115
+ const { hasStores, showStores } = this.state;
116
+
117
+ if (!hasStores) {
118
+ return [];
119
+ }
120
+
121
+ const filterStores = {
122
+ label: tr('Display Geolocation POIs'),
123
+ component: (
124
+ <Input
125
+ type="checkbox"
126
+ key="stores"
127
+ checked={showStores}
128
+ onChange={(e) => {
129
+ this.setState({ showStores: e.target.checked }, this.displayMap);
130
+ }}
131
+ />
132
+ ),
133
+ };
134
+
135
+ return [filterStores];
136
+ };
137
+
61
138
  renderGeolocationInfo = () => {
62
139
  const { geolocation } = this.state;
63
140
  if (!geolocation) {
@@ -73,7 +150,7 @@ export default class GeolocationDemo extends Component {
73
150
  ].forEach((item) => {
74
151
  if (geolocation[item.id]) {
75
152
  result.push(
76
- <li key={item}>
153
+ <li key={item.id}>
77
154
  {item.label}:&nbsp;
78
155
  <strong>{geolocation[item.id]}</strong>
79
156
  </li>
@@ -99,26 +176,21 @@ export default class GeolocationDemo extends Component {
99
176
  return <ul>{result}</ul>;
100
177
  };
101
178
 
102
- renderMap = () => {
103
- const { geolocation } = this.state;
104
- const location = geolocation || {};
105
- const marker = geolocation ? <Marker lat={geolocation.latitude} lng={geolocation.longitude} /> : null;
106
- return (
107
- <GoogleMapReact
108
- defaultZoom={10}
109
- center={[location.latitude, location.longitude]}
110
- bootstrapURLKeys={{ key: Constants.gmapKey, libraries: ['geometry', 'places'] }}
111
- yesIWantToUseGoogleMapApiInternals
112
- onGoogleApiLoaded={({ map }) => {
113
- this.map = map;
114
- this.displayOnMap();
115
- }}
116
- >
117
- {marker}
118
- </GoogleMapReact>
119
- );
179
+ displayMap = () => {
180
+ if (this.timeoutMap) {
181
+ clearTimeout(this.timeoutMap);
182
+ }
183
+
184
+ if (window.woosmap && window.woosmap.map && this.mapDivRef.current) {
185
+ this.map = new window.woosmap.map.Map(this.mapDivRef.current);
186
+ this.requestGeolocation();
187
+ } else {
188
+ this.timeoutMap = setTimeout(this.displayMap, 300);
189
+ }
120
190
  };
121
191
 
192
+ renderMap = () => <div className="map" ref={this.mapDivRef} />;
193
+
122
194
  render() {
123
195
  const { geolocation, error } = this.state;
124
196
  const { noheader } = this.props;
@@ -142,20 +214,24 @@ export default class GeolocationDemo extends Component {
142
214
  }
143
215
  }
144
216
  return (
145
- <Demo
146
- className="demo--geolocation"
147
- docLink="https://developers.woosmap.com/products/geolocation-api/location/"
148
- id="geolocation-demo"
149
- header={headerLabels}
150
- headerTagline={precisionInfo}
151
- request={this.requestUrl}
152
- params={this.getRequestparams()}
153
- referer="http://localhost/"
154
- noheader={noheader}
155
- response={error || geolocation}
156
- result={this.renderGeolocationInfo()}
157
- map={this.renderMap()}
158
- />
217
+ <>
218
+ <Script url={`https://sdk.woosmap.com/map/map.js?key=${Constants.geolocationWoosmapSearchKey}`} />
219
+ <Demo
220
+ className="demo--geolocation"
221
+ docLink="https://developers.woosmap.com/products/geolocation-api/location/"
222
+ id="geolocation-demo"
223
+ header={headerLabels}
224
+ headerTagline={precisionInfo}
225
+ request={this.requestUrl}
226
+ params={this.getRequestparams()}
227
+ referer="http://localhost/"
228
+ noheader={noheader}
229
+ response={error || geolocation}
230
+ result={this.renderGeolocationInfo()}
231
+ map={this.renderMap()}
232
+ footerFilters={this.renderFooterFilters()}
233
+ />
234
+ </>
159
235
  );
160
236
  }
161
237
  }
@@ -2,15 +2,14 @@
2
2
  import React, { Component } from 'react';
3
3
  import axios from 'axios';
4
4
  import PropTypes from 'prop-types';
5
- import GoogleMapReact from 'google-map-react';
6
5
  import Demo from './SkeletonDemo';
7
6
  import AddressAutocomplete from '../Woosmap/AddressAutocomplete';
8
- import Marker from '../Map/Marker';
9
7
  import Constants from '../../Constants';
10
- import { viewpoint } from '../Map/drawOnMap';
11
8
  import CountrySelect from '../Select/CountrySelect';
12
9
  import { tr } from '../utils/locale';
13
10
  import Input from '../Input/Input';
11
+ import markerIcon from '../../images/marker.png';
12
+ import Script from '../utils/Script';
14
13
 
15
14
  export default class LocalitiesAddressDemo extends Component {
16
15
  constructor(props) {
@@ -31,6 +30,11 @@ export default class LocalitiesAddressDemo extends Component {
31
30
  this.requestDetailsUrl = 'https://api.woosmap.com/localities/details';
32
31
  this.inputRef = React.createRef();
33
32
  this.addressAutocompleteRef = React.createRef();
33
+ this.mapDivRef = React.createRef();
34
+ }
35
+
36
+ componentDidMount() {
37
+ this.displayMap();
34
38
  }
35
39
 
36
40
  componentWillUnmount() {
@@ -83,12 +87,15 @@ export default class LocalitiesAddressDemo extends Component {
83
87
  })
84
88
  .then((response) => {
85
89
  if (this.mounted) {
86
- this.setState({
87
- error: null,
88
- showDetails: true,
89
- response: response.data.result,
90
- selectedLocality: response.data.result,
91
- });
90
+ this.setState(
91
+ {
92
+ error: null,
93
+ showDetails: true,
94
+ response: response.data.result,
95
+ selectedLocality: response.data.result,
96
+ },
97
+ this.displayOnMap
98
+ );
92
99
  }
93
100
  })
94
101
  .catch((error) => {
@@ -124,14 +131,23 @@ export default class LocalitiesAddressDemo extends Component {
124
131
  };
125
132
 
126
133
  displayOnMap = () => {
127
- const { selectedAddress } = this.state;
128
- if (this.viewport) {
129
- this.viewport.setMap(null);
130
- }
131
- if (this.map && selectedAddress) {
132
- if (selectedAddress.viewpoint) {
133
- this.viewport = viewpoint(this.map, selectedAddress.viewpoint);
134
- this.map.fitBounds(selectedAddress.viewpoint.bounds, 10);
134
+ if (this.map) {
135
+ const { selectedLocality } = this.state;
136
+
137
+ if (selectedLocality?.geometry?.location) {
138
+ this.map.setCenter(selectedLocality.geometry.location);
139
+ this.map.setZoom(17);
140
+
141
+ if (this.marker) {
142
+ this.marker.setMap(null);
143
+ this.marker = null;
144
+ }
145
+
146
+ this.marker = new window.woosmap.map.Marker({
147
+ icon: { url: markerIcon, scaledSize: { height: 46, width: 30 } },
148
+ position: selectedLocality.geometry.location,
149
+ map: this.map,
150
+ });
135
151
  } else {
136
152
  this.map.setZoom(10);
137
153
  }
@@ -304,31 +320,21 @@ export default class LocalitiesAddressDemo extends Component {
304
320
  );
305
321
  };
306
322
 
307
- renderMap = () => {
308
- const { selectedLocality } = this.state;
323
+ displayMap = () => {
324
+ if (this.timeoutMap) {
325
+ clearTimeout(this.timeoutMap);
326
+ }
309
327
 
310
- const location =
311
- selectedLocality && selectedLocality.geometry
312
- ? selectedLocality.geometry.location
313
- : { lat: 48.863350992156306, lng: 2.3484066674237796 };
314
- const marker =
315
- selectedLocality && selectedLocality.geometry ? <Marker lat={location.lat} lng={location.lng} /> : null;
316
- return (
317
- <GoogleMapReact
318
- defaultZoom={10}
319
- center={[location.lat, location.lng]}
320
- bootstrapURLKeys={{ key: Constants.gmapKey, libraries: ['geometry', 'places'] }}
321
- yesIWantToUseGoogleMapApiInternals
322
- onGoogleApiLoaded={({ map }) => {
323
- this.map = map;
324
- this.displayOnMap();
325
- }}
326
- >
327
- {marker}
328
- </GoogleMapReact>
329
- );
328
+ if (window.woosmap && window.woosmap.map && this.mapDivRef.current) {
329
+ this.map = new window.woosmap.map.Map(this.mapDivRef.current);
330
+ this.requestAddress();
331
+ } else {
332
+ this.timeoutMap = setTimeout(this.displayMap, 300);
333
+ }
330
334
  };
331
335
 
336
+ renderMap = () => <div className="map" ref={this.mapDivRef} />;
337
+
332
338
  render() {
333
339
  const { response, error, showDetails } = this.state;
334
340
  const { noheader, headerLabels, subHeader } = this.props;
@@ -337,21 +343,24 @@ export default class LocalitiesAddressDemo extends Component {
337
343
  request = this.requestDetailsUrl;
338
344
  }
339
345
  return (
340
- <Demo
341
- noheader={noheader}
342
- header={headerLabels}
343
- subHeader={subHeader}
344
- id="localities-demo"
345
- className="demo--localitiesaddress"
346
- footerFilters={this.renderFooterFilters()}
347
- headerFilters={this.renderHeaderFilters()}
348
- request={request}
349
- params={this.getRequestparams()}
350
- referer="http://localhost/"
351
- response={error || response}
352
- result={this.renderAddress()}
353
- map={this.renderMap()}
354
- />
346
+ <>
347
+ <Script url={`https://sdk.woosmap.com/map/map.js?key=${Constants.woosmapKey}`} />
348
+ <Demo
349
+ noheader={noheader}
350
+ header={headerLabels}
351
+ subHeader={subHeader}
352
+ id="localities-demo"
353
+ className="demo--localitiesaddress"
354
+ footerFilters={this.renderFooterFilters()}
355
+ headerFilters={this.renderHeaderFilters()}
356
+ request={request}
357
+ params={this.getRequestparams()}
358
+ referer="http://localhost/"
359
+ response={error || response}
360
+ result={this.renderAddress()}
361
+ map={this.renderMap()}
362
+ />
363
+ </>
355
364
  );
356
365
  }
357
366
  }
@@ -3,17 +3,17 @@ import axios from 'axios';
3
3
  import cl from 'classnames';
4
4
  import React, { Component } from 'react';
5
5
  import PropTypes from 'prop-types';
6
- import GoogleMapReact from 'google-map-react';
7
6
  import Demo from './SkeletonDemo';
8
- import Marker from '../Map/Marker';
9
7
  import Input from '../Input/Input';
10
8
  import Select from '../Select/Select';
11
9
  import Button from '../Button/Button';
12
10
  import ButtonGroup from '../Button/ButtonGroup';
13
11
  import CountrySelect from '../Select/CountrySelect';
14
- import { viewpoint } from '../Map/drawOnMap';
15
12
  import Constants from '../../Constants';
16
13
  import { tr } from '../utils/locale';
14
+ import markerIcon from '../../images/marker.png';
15
+ import Script from '../utils/Script';
16
+ import { WoosmapMapBoundingBox } from '../Map/drawOnMap';
17
17
 
18
18
  const languages = [
19
19
  { value: 'fr', label: 'French' },
@@ -64,10 +64,12 @@ export default class LocalitiesDemo extends Component {
64
64
  this.marker = null;
65
65
  this.viewport = null;
66
66
  this.requestUrl = 'https://api.woosmap.com/localities/autocomplete/';
67
+ this.mapDivRef = React.createRef();
68
+ this.overlay = null;
67
69
  }
68
70
 
69
71
  componentDidMount() {
70
- this.requestLocalities();
72
+ this.displayMap();
71
73
  }
72
74
 
73
75
  componentWillUnmount() {
@@ -114,14 +116,31 @@ export default class LocalitiesDemo extends Component {
114
116
 
115
117
  displayOnMap = () => {
116
118
  const { selectedLocality } = this.state;
117
- if (this.viewport) {
118
- this.viewport.setMap(null);
119
- }
120
- if (this.map && selectedLocality) {
119
+
120
+ if (this.map && selectedLocality?.location) {
121
+ if (this.marker) {
122
+ this.marker.setMap(null);
123
+ this.marker = null;
124
+ }
125
+
126
+ if (this.overlay) {
127
+ this.overlay.setMap(null);
128
+ this.overlay = null;
129
+ }
130
+
131
+ this.marker = new window.woosmap.map.Marker({
132
+ icon: { url: markerIcon, scaledSize: { height: 46, width: 30 } },
133
+ position: selectedLocality.location,
134
+ map: this.map,
135
+ });
136
+
121
137
  if (selectedLocality.viewpoint) {
122
- this.viewport = viewpoint(this.map, selectedLocality.viewpoint);
123
- this.map.fitBounds(selectedLocality.viewpoint.bounds, 10);
138
+ this.overlay = new WoosmapMapBoundingBox(selectedLocality.viewpoint.bounds);
139
+ this.overlay.setMap(this.map);
140
+
141
+ this.map.fitBounds(selectedLocality.viewpoint.bounds, { top: 70, bottom: 70, left: 70, right: 70 });
124
142
  } else {
143
+ this.map.setCenter(selectedLocality.location);
125
144
  this.map.setZoom(10);
126
145
  }
127
146
  }
@@ -170,28 +189,21 @@ export default class LocalitiesDemo extends Component {
170
189
  return <ul>{result}</ul>;
171
190
  };
172
191
 
173
- renderMap = () => {
174
- const { selectedLocality } = this.state;
175
- const location = selectedLocality ? selectedLocality.location : {};
176
- const marker = selectedLocality ? (
177
- <Marker lat={selectedLocality.location.lat} lng={selectedLocality.location.lng} />
178
- ) : null;
179
- return (
180
- <GoogleMapReact
181
- defaultZoom={10}
182
- center={[location.lat, location.lng]}
183
- bootstrapURLKeys={{ key: Constants.gmapKey, libraries: ['geometry', 'places'] }}
184
- yesIWantToUseGoogleMapApiInternals
185
- onGoogleApiLoaded={({ map }) => {
186
- this.map = map;
187
- this.displayOnMap();
188
- }}
189
- >
190
- {marker}
191
- </GoogleMapReact>
192
- );
192
+ displayMap = () => {
193
+ if (this.timeoutMap) {
194
+ clearTimeout(this.timeoutMap);
195
+ }
196
+
197
+ if (window.woosmap && window.woosmap.map && this.mapDivRef.current) {
198
+ this.map = new window.woosmap.map.Map(this.mapDivRef.current);
199
+ this.requestLocalities();
200
+ } else {
201
+ this.timeoutMap = setTimeout(this.displayMap, 300);
202
+ }
193
203
  };
194
204
 
205
+ renderMap = () => <div className="map" ref={this.mapDivRef} />;
206
+
195
207
  renderHeaderFilters = () => {
196
208
  const { input } = this.state;
197
209
  const { usecaseFilter } = this.props;
@@ -259,22 +271,25 @@ export default class LocalitiesDemo extends Component {
259
271
  const { localities, error } = this.state;
260
272
  const { noheader, headerLabels, subHeader } = this.props;
261
273
  return (
262
- <Demo
263
- id="localities-demo"
264
- header={headerLabels}
265
- subHeader={subHeader}
266
- docLink="https://developers.woosmap.com/products/localities/get-started/"
267
- className="demo--localities"
268
- footerFilters={this.renderFooterFilters()}
269
- headerFilters={this.renderHeaderFilters()}
270
- request={this.requestUrl}
271
- noheader={noheader}
272
- params={this.getRequestparams()}
273
- referer="http://localhost/"
274
- response={error || localities}
275
- result={this.renderAutocompleteList()}
276
- map={this.renderMap()}
277
- />
274
+ <>
275
+ <Script url={`https://sdk.woosmap.com/map/map.js?key=${Constants.woosmapKey}`} />
276
+ <Demo
277
+ id="localities-demo"
278
+ header={headerLabels}
279
+ subHeader={subHeader}
280
+ docLink="https://developers.woosmap.com/products/localities/get-started/"
281
+ className="demo--localities"
282
+ footerFilters={this.renderFooterFilters()}
283
+ headerFilters={this.renderHeaderFilters()}
284
+ request={this.requestUrl}
285
+ noheader={noheader}
286
+ params={this.getRequestparams()}
287
+ referer="http://localhost/"
288
+ response={error || localities}
289
+ result={this.renderAutocompleteList()}
290
+ map={this.renderMap()}
291
+ />
292
+ </>
278
293
  );
279
294
  }
280
295
  }
@@ -2,14 +2,15 @@ import axios from 'axios';
2
2
  import cl from 'classnames';
3
3
  import React, { Component } from 'react';
4
4
  import PropTypes from 'prop-types';
5
- import GoogleMapReact, { fitBounds } from 'google-map-react';
6
5
  import Demo from './SkeletonDemo';
7
- import Marker from '../Map/Marker';
8
6
  import Input from '../Input/Input';
9
7
  import Constants from '../../Constants';
10
8
  import FilterSelect from '../Select/FilterSelect';
11
9
  import LocalitiesAutocomplete from '../Woosmap/LocalitiesAutocomplete';
12
10
  import { tr } from '../utils/locale';
11
+ import markerIcon from '../../images/marker.png';
12
+ import markerIconAlt from '../../images/marker-alt.png';
13
+ import Script from '../utils/Script';
13
14
 
14
15
  export default class SearchDemo extends Component {
15
16
  constructor(props) {
@@ -31,8 +32,13 @@ export default class SearchDemo extends Component {
31
32
  };
32
33
  this.mounted = true;
33
34
  this.map = null;
34
- this.marker = null;
35
+ this.markers = [];
35
36
  this.requestUrl = 'https://api.woosmap.com/stores/search/';
37
+ this.mapDivRef = React.createRef();
38
+ }
39
+
40
+ componentDidMount() {
41
+ this.displayMap();
36
42
  }
37
43
 
38
44
  componentWillUnmount() {
@@ -70,38 +76,6 @@ export default class SearchDemo extends Component {
70
76
  };
71
77
  };
72
78
 
73
- getZoomAndCenter = (stores) => {
74
- if (!this.map) {
75
- return { center: null, zoom: null };
76
- }
77
- const bounds = new google.maps.LatLngBounds();
78
-
79
- const { selectedLocality } = this.state;
80
- const locality = selectedLocality && selectedLocality.localion ? selectedLocality : this.defaultLocality;
81
- if (locality && locality.location) {
82
- bounds.extend(new google.maps.LatLng(locality.location.lat, locality.location.lng));
83
- }
84
- if (stores && stores.length > 0) {
85
- stores.forEach((store) => {
86
- bounds.extend(new google.maps.LatLng(store.geometry.coordinates[1], store.geometry.coordinates[0]));
87
- });
88
- }
89
-
90
- return fitBounds(
91
- {
92
- ne: {
93
- lat: bounds.getNorthEast().lat(),
94
- lng: bounds.getNorthEast().lng(),
95
- },
96
- sw: {
97
- lat: bounds.getSouthWest().lat(),
98
- lng: bounds.getSouthWest().lng(),
99
- },
100
- },
101
- { height: 360, width: 400 }
102
- );
103
- };
104
-
105
79
  requestSearch = () => {
106
80
  axios
107
81
  .get(this.requestUrl, {
@@ -110,10 +84,13 @@ export default class SearchDemo extends Component {
110
84
  .then((response) => {
111
85
  if (this.mounted) {
112
86
  const { data } = response;
113
- this.setState({
114
- data: data || [],
115
- error: null,
116
- });
87
+ this.setState(
88
+ {
89
+ data: data || [],
90
+ error: null,
91
+ },
92
+ this.displayOnMap
93
+ );
117
94
  }
118
95
  })
119
96
  .catch((error) => {
@@ -164,50 +141,62 @@ export default class SearchDemo extends Component {
164
141
  return <ul>{result}</ul>;
165
142
  };
166
143
 
167
- renderMarkers = () => {
168
- const { data, selectedLocality } = this.state;
169
- const stores = data.features || [];
170
- const markers = stores.map((store) => (
171
- <Marker
172
- key={store.properties.store_id}
173
- lat={store.geometry.coordinates[1]}
174
- lng={store.geometry.coordinates[0]}
175
- />
176
- ));
177
- if (selectedLocality && selectedLocality.location) {
178
- markers.push(
179
- <Marker
180
- isSecondaryColor
181
- key="current_location"
182
- lat={selectedLocality.location.lat}
183
- lng={selectedLocality.location.lng}
184
- />
185
- );
144
+ displayOnMap = () => {
145
+ if (this.map) {
146
+ const { data, selectedLocality } = this.state;
147
+ const { features } = data;
148
+
149
+ const bounds = new window.woosmap.map.LatLngBounds();
150
+
151
+ if (this.markers.length > 0) {
152
+ this.markers.forEach((marker) => marker.setMap(null));
153
+ this.markers = [];
154
+ }
155
+
156
+ if (features && features.length > 0) {
157
+ features.forEach((store) => {
158
+ const [lng, lat] = store.geometry.coordinates;
159
+ bounds.extend(new window.woosmap.map.LatLng(lat, lng));
160
+ this.markers.push(
161
+ new window.woosmap.map.Marker({
162
+ icon: { url: markerIcon, scaledSize: { height: 46, width: 30 } },
163
+ position: { lat, lng },
164
+ map: this.map,
165
+ })
166
+ );
167
+ });
168
+
169
+ const location = selectedLocality?.location || this.defaultLocality.location;
170
+ if (location) bounds.extend(new window.woosmap.map.LatLng(location.lat, location.lng));
171
+ }
172
+
173
+ if (selectedLocality && selectedLocality.location) {
174
+ this.markers.push(
175
+ new window.woosmap.map.Marker({
176
+ icon: { url: markerIconAlt, scaledSize: { height: 46, width: 30 } },
177
+ position: selectedLocality.location,
178
+ map: this.map,
179
+ })
180
+ );
181
+ }
182
+
183
+ this.map.fitBounds(bounds, { top: 70, bottom: 70, left: 70, right: 70 });
186
184
  }
187
- return markers;
188
185
  };
189
186
 
190
- renderMap = () => {
191
- const { selectedLocality, data } = this.state;
192
- const { center, zoom } = this.getZoomAndCenter(data.features);
193
- const location = selectedLocality ? selectedLocality.location : {};
194
- return (
195
- <GoogleMapReact
196
- defaultZoom={10}
197
- zoom={zoom}
198
- center={center || [location.lat, location.lng]}
199
- bootstrapURLKeys={{ key: Constants.gmapKey, libraries: ['geometry', 'places'] }}
200
- yesIWantToUseGoogleMapApiInternals
201
- onGoogleApiLoaded={({ map }) => {
202
- this.map = map;
203
- this.requestSearch();
204
- }}
205
- >
206
- {this.renderMarkers()}
207
- </GoogleMapReact>
208
- );
187
+ displayMap = () => {
188
+ if (this.timeoutMap) clearTimeout(this.timeoutMap);
189
+
190
+ if (window.woosmap && window.woosmap.map && this.mapDivRef.current) {
191
+ this.map = new window.woosmap.map.Map(this.mapDivRef.current);
192
+ this.requestSearch();
193
+ } else {
194
+ this.timeoutMap = setTimeout(this.displayMap, 300);
195
+ }
209
196
  };
210
197
 
198
+ renderMap = () => <div className="map" ref={this.mapDivRef} />;
199
+
211
200
  renderHeaderFilters = () => {
212
201
  const { selectedLocality } = this.state;
213
202
  const originInputs = {
@@ -320,21 +309,24 @@ export default class SearchDemo extends Component {
320
309
  ),
321
310
  };
322
311
  return (
323
- <Demo
324
- id="search-demo"
325
- className="demo--search"
326
- docLink="https://developers.woosmap.com/products/search-api/get-started/"
327
- header={headerLabels}
328
- footerFilters={this.renderFooterFilters()}
329
- headerFilters={this.renderHeaderFilters()}
330
- request={this.requestUrl}
331
- params={this.getRequestparams(true)}
332
- referer="http://localhost/"
333
- response={error || data}
334
- noheader={noheader}
335
- result={this.renderStoreList()}
336
- map={this.renderMap()}
337
- />
312
+ <>
313
+ <Script url={`https://sdk.woosmap.com/map/map.js?key=${Constants.woosmapKey}`} />
314
+ <Demo
315
+ id="search-demo"
316
+ className="demo--search"
317
+ docLink="https://developers.woosmap.com/products/search-api/get-started/"
318
+ header={headerLabels}
319
+ footerFilters={this.renderFooterFilters()}
320
+ headerFilters={this.renderHeaderFilters()}
321
+ request={this.requestUrl}
322
+ params={this.getRequestparams(true)}
323
+ referer="http://localhost/"
324
+ response={error || data}
325
+ noheader={noheader}
326
+ result={this.renderStoreList()}
327
+ map={this.renderMap()}
328
+ />
329
+ </>
338
330
  );
339
331
  }
340
332
  }
@@ -55,21 +55,29 @@
55
55
  sq($buttonHeightNano)
56
56
  padding 0
57
57
  min-height unset
58
- &--localities
58
+ &--LOCALITIES
59
+ &-localities
59
60
  background-color $localities
61
+ &--GEOLOCATION
60
62
  &--geolocation
61
63
  background-color $geolocation
64
+ &--DISTANCE
62
65
  &--distance
63
66
  background-color $distance
64
- &--stores
67
+ &--STORES
68
+ &-stores
65
69
  background-color $stores
70
+ &--ADDRESS
66
71
  &--address
67
72
  background-color $address
73
+ &--MAP
68
74
  &--map
69
75
  background-color $map
70
- &--merchants
76
+ &--MERCHANT
77
+ &--merchant
71
78
  background-color $merchant
72
- &--traffic
79
+ &--TRAFFIC
80
+ &--merchant
73
81
  background-color $traffic
74
82
  &--free
75
83
  background-color $free
@@ -8,8 +8,8 @@ export default class Marker extends Component {
8
8
  return (
9
9
  <div
10
10
  className={cl({
11
- marker: true,
12
- 'marker--alt': isSecondaryColor,
11
+ 'ui-marker': true,
12
+ 'ui-marker--alt': isSecondaryColor,
13
13
  })}
14
14
  />
15
15
  );
@@ -6,9 +6,9 @@ import Marker from './Marker';
6
6
 
7
7
  it('renders a marker', () => {
8
8
  const { container } = render(<Marker />);
9
- expect(container.firstChild).toHaveClass('marker');
9
+ expect(container.firstChild).toHaveClass('ui-marker');
10
10
  });
11
11
  it('renders a marker with seondary color', () => {
12
12
  const { container } = render(<Marker isSecondaryColor />);
13
- expect(container.firstChild).toHaveClass('marker--alt');
13
+ expect(container.firstChild).toHaveClass('ui-marker--alt');
14
14
  });
@@ -76,3 +76,70 @@ export const extendedBounds = function extendedBounds(boundsArray) {
76
76
 
77
77
  return bounds;
78
78
  };
79
+
80
+ export const woosmapBoundsFromViewport = function woosmapBoundsFromViewport(viewportObj) {
81
+ return new window.woosmap.map.LatLngBounds(
82
+ new window.woosmap.map.LatLng(viewportObj.southwest),
83
+ new window.woosmap.map.LatLng(viewportObj.northeast)
84
+ );
85
+ };
86
+
87
+ export class WoosmapMapBoundingBox {
88
+ constructor(bounds, padding) {
89
+ this.overlayView = new window.woosmap.map.OverlayView();
90
+
91
+ this.bounds = !(bounds instanceof window.woosmap.map.LatLngBounds)
92
+ ? new window.woosmap.map.LatLngBounds(
93
+ { lng: bounds.east, lat: bounds.north },
94
+ { lng: bounds.west, lat: bounds.south }
95
+ )
96
+ : bounds;
97
+
98
+ this.padding = {
99
+ right: padding?.right || 0,
100
+ left: padding?.left || 0,
101
+ top: padding?.top || 0,
102
+ bottom: padding?.bottom || 0,
103
+ };
104
+
105
+ const self = this;
106
+
107
+ this.overlayView.onAdd = () => {
108
+ const panes = this.overlayView.getPanes();
109
+
110
+ this.div = document.createElement('div');
111
+ this.div.style.borderStyle = 'solid';
112
+ this.div.style.borderWidth = '1px';
113
+ this.div.style.borderColor = 'rgba(0, 0, 255, 0.8)';
114
+ this.div.style.position = 'absolute';
115
+ this.div.style.backgroundColor = 'rgba(0, 0, 255, 0.2)';
116
+
117
+ panes.overlayLayer.appendChild(this.div);
118
+ };
119
+
120
+ this.overlayView.draw = () => {
121
+ const overlayProjection = this.overlayView.getProjection();
122
+
123
+ const sw = overlayProjection.fromLatLngToDivPixel(self.bounds.getSouthWest());
124
+ const ne = overlayProjection.fromLatLngToDivPixel(self.bounds.getNorthEast());
125
+
126
+ if (this.div) {
127
+ this.div.style.left = `${sw.x - self.padding.left}px`;
128
+ this.div.style.top = `${ne.y - self.padding.top}px`;
129
+ this.div.style.width = `${ne.x - sw.x + (self.padding.left + self.padding.right)}px`;
130
+ this.div.style.height = `${sw.y - ne.y + (self.padding.top + self.padding.bottom)}px`;
131
+ }
132
+ };
133
+
134
+ this.overlayView.onRemove = () => {
135
+ if (this.div) {
136
+ this.div.parentNode.removeChild(this.div);
137
+ delete this.div;
138
+ }
139
+ };
140
+ }
141
+
142
+ setMap(map) {
143
+ this.overlayView.setMap(map);
144
+ }
145
+ }
@@ -1,4 +1,4 @@
1
- .marker
1
+ .ui-marker
2
2
  position absolute
3
3
  width 3rem
4
4
  height 4.6rem
@@ -29,6 +29,7 @@
29
29
  "Default": "Default",
30
30
  "Destination": "Destination",
31
31
  "Display Map POIs": "Display Map POIs",
32
+ "Display Geolocation POIs": "Display points of interest",
32
33
  "Display Woosmap Stores overlay": "Display Woosmap Stores overlay",
33
34
  "Display your regional promotions and catchment area.": "Display your regional promotions and catchment area.",
34
35
  "Distance API": "Distance API",
@@ -44,7 +45,7 @@
44
45
  "Grey": "Grey",
45
46
  "Identify the country to redirect users to the suitable website, or adapt your services according to the timezone.": "Identify the country to redirect users to the suitable website, or adapt your services according to the timezone.",
46
47
  "In Store Wifi": "In Store Wifi",
47
- "Initialise your map display around the end user and retrieve your own Points of Interest.": "Initialise your map display around the end user and retrieve your own Points of Interest.",
48
+ "Initialise your map display around the end user and retrieve your own Points of Interest.": "Initialise your map display around the end user and retrieve your own points of interest.",
48
49
  "Language": "Language",
49
50
  "Light Grey": "Light Grey",
50
51
  "Loading...": "Loading...",
@@ -29,8 +29,9 @@
29
29
  "Default": "Défaut",
30
30
  "Destination": "Destination",
31
31
  "Display Map POIs": "Afficher les POIs de la carte",
32
+ "Display Geolocation POIs": "Afficher les points de vente",
32
33
  "Display Woosmap Stores overlay": "Afficher la couche de magasins Woosmap",
33
- "Display your regional promotions and catchment area.": "Affichez les offres promotionnelles de la région, et la zone de chalandise.",
34
+ "Display your regional promotions and catchment area.": "Affichez les offres promotionnelles de la région et la zone de chalandise.",
34
35
  "Distance API": "Distance API",
35
36
  "Features": "Caractéristiques",
36
37
  "Filter by": "Filtrer par",
@@ -44,7 +45,7 @@
44
45
  "Grey": "Gris",
45
46
  "Identify the country to redirect users to the suitable website, or adapt your services according to the timezone.": "Identifiez le pays pour rediriger vers le bon site et adaptez vos offres de services en fonction du fuseau horaire de vos visiteurs.",
46
47
  "In Store Wifi": "Wifi",
47
- "Initialise your map display around the end user and retrieve your own Points of Interest.": "Listez vos propres points de vente et centrez votre affichage cartographique autour de sa position.",
48
+ "Initialise your map display around the end user and retrieve your own Points of Interest.": "Centrez la carte autour de la position de votre visiteur et affichez vos propres points de vente.",
48
49
  "Language": "Language",
49
50
  "Light Grey": "Gris clair",
50
51
  "Loading...": "Chargement...",
@@ -70,6 +70,8 @@ $special2 = #ff3260
70
70
  $special3 = #46cebc
71
71
  $focus = #3633ff
72
72
 
73
+ $favorite = #ffc200
74
+
73
75
  $modalBg = rgba(0, 11, 31, .85)
74
76
 
75
77
  // Labels