@woosmap/ui 2.34.0 → 2.38.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.34.0",
3
+ "version": "2.38.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
  };
@@ -35,6 +35,7 @@ export default class Button extends Component {
35
35
  { active },
36
36
  { 'btn--loading': isLoading },
37
37
  { 'btn--no-label': !label },
38
+ { 'btn--custom-icon-size': iconSize && iconSize !== 24 },
38
39
  className
39
40
  );
40
41
  let iconComponent = icon ? <Icon size={iconSize} icon={icon} /> : null;
@@ -215,7 +215,7 @@ export const WithDropdown = TemplateBtnWithDropdown.bind({});
215
215
 
216
216
  const TemplateBtnSwitch = (args) => {
217
217
  const { active } = args;
218
- return <ButtonSwitch icon="flag" activeIcon="member" active={active} />;
218
+ return <ButtonSwitch iconSize={32} size="small" icon="star" activeIcon="star-filled" active={active} />;
219
219
  };
220
220
 
221
221
  TemplateBtnSwitch.args = {
@@ -11,7 +11,7 @@ export default class ButtonSwitch extends Component {
11
11
  }
12
12
 
13
13
  ButtonSwitch.defaultProps = {
14
- isBtnIcon: true,
14
+ isBtnIcon: false,
15
15
  disabled: false,
16
16
  children: null,
17
17
  size: undefined,
@@ -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
@@ -22,10 +23,9 @@
22
23
  &.disabled
23
24
  background #fff url('../../images/texture.png')
24
25
  color $secondary60
25
- .simplecard__content
26
- opacity .5
27
26
  &.active
28
27
  background $primary6 url('../../images/texture.png')
28
+
29
29
  &__title
30
30
  font-weight 600
31
31
  margin-bottom .2rem
@@ -36,6 +36,13 @@
36
36
  margin-top auto
37
37
  padding-top 1rem
38
38
  flexMiddle()
39
+ .disabled &
40
+ opacity .5
41
+ &__favorite
42
+ position absolute
43
+ right 1rem
44
+ top 1.3rem
45
+ fill $favorite
39
46
  .tooltip
40
47
  position relative
41
48
  $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
  }