Skip to content

Commit f859a38

Browse files
authored
Merge pull request #3642 from Vizzuality/feature/map-tour
Feature/map tour
2 parents 37e7de3 + ed070f6 commit f859a38

29 files changed

+760
-42
lines changed

.env.prod.sample

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Application
2+
3+
LAYER_SPEC=layerspec
4+
5+
# GFW Links
6+
GFW_API=https://production-api.globalforestwatch.org
7+
GFW_API_OLD=https://api.globalforestwatch.org
8+
GFW_ASSETS_URL=https://gfw-assets.s3.amazonaws.com/static/gfw-assets.nightly.js
9+
GFW_BLOG_HOST=http://blog.globalforestwatch.org
10+
GFW_HOWTO_URL=http://vizzuality.github.io/gfw-howto
11+
GFW_DEVELOPERS_URL=http://vizzuality.github.io/gfw-atlas
12+
13+
# External APIs
14+
CARTO_API=https://wri-01.carto.com/api/v2
15+
RESOURCE_WATCH_API=https://api.resourcewatch.org/v1
16+
CLIMATE_WATCH_API=https://climate-watch.vizzuality.com/api/v1
17+
18+
# AWS
19+
AWS_HOST=/uploads
20+
AWS_ACCESS_KEY_ID=
21+
AWS_SECRET_ACCESS_KEY=
22+
AWS_REGION=my-excellent-region
23+
S3_BUCKET_NAME=
24+
S3_DATA_BUCKET_NAME=
25+
26+
# Google
27+
ANALYTICS_PROPERTY_ID=
28+
LANDSTAD_KEY=
29+
SENTINEL_KEY=
30+
GOOGLE_MAPS_API_KEY=
31+
GOOGLE_CUSTOM_SEARCH_CX=
32+
GOOGLE_SEARCH_API_KEY=
33+
34+
# Bitly
35+
BITLY_API_URL=https://api-ssl.bitly.com/v3
36+
BITLY_USER=
37+
BITLY_API_KEY=
38+
39+
# Datasets
40+
COUNTRIES_PAGE_DATASET=a20e9c0e-8d7d-422f-90f5-3b9bca355aaf
41+
GLAD_ISO_DATASET=391ca96d-303f-4aef-be4b-9cdb4856832c
42+
GLAD_ADM1_DATASET=c7a1d922-e320-4e92-8e4c-11ea33dd6e35
43+
GLAD_ADM2_DATASET=428db321-5ebb-4e86-a3df-32c63b6d3c83
44+
FIRES_ISO_DATASET=ff289906-aa83-4a89-bba0-562edd8c16c6
45+
FIRES_ADM1_DATASET=9b9e56fc-270e-486d-8db5-e0a839c9a1a9
46+
FIRES_ADM2_DATASET=0f24299d-2aaa-4afc-945c-b614028c12d1
47+
48+
# Transifex
49+
TRANSIFEX_URL=https://www.transifex.com/api/2/project
50+
TRANSIFEX_PROJECT=
51+
TRANSIFEX_SLUG=
52+
TRANSIFEX_API_TOKEN=
53+
TRANSIFEX_RESOURCE_API_TOKEN=
54+
LOCALES_PATH=app/javascript/locales
55+
56+
# SMTP
57+
SMTP_USERNAME=
58+
SMTP_PASSWORD=
59+
60+
# CYPRESS
61+
CYPRESS_RECORD_KEY=

app/javascript/app/layouts/root/component.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class App extends PureComponent {
4141
{!embed &&
4242
route.headerOptions && (
4343
<Header
44+
className={cx('map-tour-main-menu')}
4445
isMobile={!isDesktop}
4546
loggedIn={loggedIn}
4647
{...route.headerOptions}
@@ -63,6 +64,7 @@ class App extends PureComponent {
6364
embed={embed}
6465
path={route.component}
6566
sections={route.sections}
67+
isDesktop={isDesktop}
6668
/>
6769
</div>
6870
{!embed && <MyGFWProvider />}

app/javascript/app/reducers.js

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { reduxModule as Popup } from 'components/map-v2/components/popup';
1616
import { reduxModule as Draw } from 'components/map-v2/components/draw';
1717
import { reduxModule as Header } from 'pages/dashboards/header';
1818
import { reduxModule as MapNew } from 'components/map-v2';
19+
import { reduxModule as MapTour } from 'components/map-v2/components/map-tour';
1920
import { reduxModule as MapOld } from 'components/map';
2021
import { reduxModule as MapMenu } from 'pages/map/components/menu';
2122

@@ -59,6 +60,7 @@ const componentsReducers = {
5960
map: handleModule(MapNew),
6061
mapOld: handleModule(MapOld),
6162
mapMenu: handleModule(MapMenu),
63+
mapTour: handleModule(MapTour),
6264
// modals
6365
modalVideo: handleModule(ModalVideo),
6466
modalMeta: handleModule(ModalMeta),

app/javascript/components/map-v2/components/basemaps/basemaps-component.jsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ class Basemaps extends React.PureComponent {
104104
? { label: activeBoundaries.name }
105105
: boundaries && boundaries[0];
106106
return (
107-
<div className="c-basemaps" {...getTooltipContentProps()}>
107+
<div
108+
className={cx('c-basemaps', 'map-tour-basemaps')}
109+
{...getTooltipContentProps()}
110+
>
108111
<div className="basemaps-top-section">
109112
{isDesktop && (
110113
<div className="basemaps-header">

app/javascript/components/map-v2/components/data-analysis-menu/component.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ class DataAnalysisMenu extends PureComponent {
2525
<div
2626
className={cx(
2727
'c-data-analysis-menu',
28+
'map-tour-legend',
2829
{ '-relocate': !!menuSection },
2930
{ '-big': menuSection && menuSection.large },
3031
{ '-embed': embed },
3132
className
3233
)}
34+
data-map-tour="step-two"
3335
>
3436
<SubNavMenu
3537
className="nav"

app/javascript/components/map-v2/components/map-controls/map-controls-component.jsx

+38-9
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,27 @@ import minusIcon from 'assets/icons/minus.svg';
1818
import shareIcon from 'assets/icons/share.svg';
1919
import fullscreenIcon from 'assets/icons/fit-zoom.svg';
2020
import printIcon from 'assets/icons/print.svg';
21+
import helpIocn from 'assets/icons/help.svg';
2122
import globeIcon from 'assets/icons/globe.svg';
2223
import satelliteIcon from 'assets/icons/satellite.svg';
2324

2425
import './map-controls-styles.scss';
2526

2627
class MapControlsButtons extends PureComponent {
2728
state = {
28-
showBasemaps: false
29+
pulseTourBtn: false
2930
};
3031

32+
componentDidUpdate(prevProps) {
33+
const { mapTourOpen } = this.props;
34+
if (!mapTourOpen && mapTourOpen !== prevProps.mapTourOpen) {
35+
this.setPulseTourBtn(true);
36+
setTimeout(() => this.setPulseTourBtn(false), 3000);
37+
}
38+
}
39+
40+
setPulseTourBtn = pulseTourBtn => this.setState({ pulseTourBtn });
41+
3142
handleHidePanels = () => {
3243
const {
3344
setMapSettings,
@@ -49,7 +60,7 @@ class MapControlsButtons extends PureComponent {
4960
onBasemapsRequestClose = () => {
5061
const isTargetOnTooltip = isParent(this.basemapsRef, this.basemapsRef.evt);
5162
this.basemapsRef.clearEvt();
52-
if (!isTargetOnTooltip && this.state.showBasemaps) {
63+
if (!isTargetOnTooltip && this.props.settings.showBasemaps) {
5364
this.toggleBasemaps();
5465
}
5566
};
@@ -67,8 +78,8 @@ class MapControlsButtons extends PureComponent {
6778
};
6879

6980
toggleBasemaps = () => {
70-
const { setRecentImagerySettings } = this.props;
71-
this.setState(state => ({ showBasemaps: !state.showBasemaps }));
81+
const { setRecentImagerySettings, setMapSettings, settings } = this.props;
82+
setMapSettings({ showBasemaps: !settings.showBasemaps });
7283
setRecentImagerySettings({ visible: false });
7384
};
7485

@@ -120,7 +131,7 @@ class MapControlsButtons extends PureComponent {
120131

121132
return (
122133
<Button
123-
className="recent-imagery-btn"
134+
className={cx('recent-imagery-btn', 'map-tour-recent-imagery')}
124135
theme="theme-button-map-control"
125136
onClick={this.handleToggleRecentImagery}
126137
disabled={datasetsLoading}
@@ -148,11 +159,11 @@ class MapControlsButtons extends PureComponent {
148159
};
149160

150161
renderBasemapsBtn = () => {
151-
const { showBasemaps } = this.state;
162+
const { showBasemaps } = this.props.settings;
152163

153164
return (
154165
<Button
155-
className="basemaps-btn"
166+
className={cx('basemaps-btn')}
156167
theme="theme-button-map-control"
157168
onClick={this.toggleBasemaps}
158169
tooltip={
@@ -189,7 +200,7 @@ class MapControlsButtons extends PureComponent {
189200
};
190201

191202
renderBasemapsTooltip = () => {
192-
const { showBasemaps } = this.state;
203+
const { showBasemaps } = this.props.settings;
193204

194205
return (
195206
<Tooltip
@@ -302,6 +313,21 @@ class MapControlsButtons extends PureComponent {
302313
</Button>
303314
);
304315

316+
renderMapTourBtn = () => (
317+
<Button
318+
theme="theme-button-map-control"
319+
tooltip={{ text: 'Take a tour of the map' }}
320+
onClick={() => this.props.setMapTourOpen(true)}
321+
>
322+
<Icon
323+
icon={helpIocn}
324+
className={cx('map-tour-icon', {
325+
'pulse-tour-btn': this.state.pulseTourBtn
326+
})}
327+
/>
328+
</Button>
329+
);
330+
305331
renderMapPosition = () => {
306332
const { settings } = this.props;
307333
const { zoom, center } = settings || {};
@@ -331,11 +357,12 @@ class MapControlsButtons extends PureComponent {
331357
{this.renderBasemapsTooltip()}
332358
</div>
333359
)}
334-
<div className="controls-wrapper">
360+
<div className={cx('controls-wrapper', 'map-tour-map-controls')}>
335361
{this.renderZoomButtons()}
336362
{this.renderShowPanelsButton()}
337363
{this.renderShareButton()}
338364
{this.renderPrintButton()}
365+
{this.renderMapTourBtn()}
339366
</div>
340367
{this.renderMapPosition()}
341368
</Fragment>
@@ -357,6 +384,8 @@ MapControlsButtons.propTypes = {
357384
settings: PropTypes.object,
358385
active: PropTypes.bool,
359386
setMenuSettings: PropTypes.func,
387+
setMapTourOpen: PropTypes.func,
388+
mapTourOpen: PropTypes.bool,
360389
recentSettings: PropTypes.object,
361390
recentLoading: PropTypes.bool,
362391
setRecentImagerySettings: PropTypes.func,

app/javascript/components/map-v2/components/map-controls/map-controls-selectors.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import {
99
} from 'components/map-v2/components/recent-imagery/recent-imagery-selectors';
1010

1111
const getDatasetsLoading = state => state.datasets.loading;
12+
const getMapTourOpen = state => state.mapTour.open;
1213

1314
export const getMapControlsProps = createStructuredSelector({
1415
recentLoading: getRecentImageryLoading,
1516
datasetsLoading: getDatasetsLoading,
1617
settings: getMapSettings,
1718
recentSettings: getRecentImagerySettings,
1819
recentActive: getActive,
19-
recentImageryDataset: getRecentImageryDataset
20+
recentImageryDataset: getRecentImageryDataset,
21+
mapTourOpen: getMapTourOpen
2022
});

app/javascript/components/map-v2/components/map-controls/map-controls-styles.scss

+12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@import '~styles/settings.scss';
2+
@import '~styles/utils.scss';
23

34
.c-map-controls {
45
.c-icon {
@@ -73,6 +74,17 @@
7374
.minus-icon {
7475
width: rem(13px);
7576
}
77+
78+
.map-tour-icon {
79+
fill: $white;
80+
background: $slate;
81+
border-radius: 15px;
82+
padding: 2px;
83+
}
84+
85+
.pulse-tour-btn {
86+
animation: pulse 1.5s infinite;
87+
}
7688
}
7789

7890
.mobile-controls-wrapper {

app/javascript/components/map-v2/components/map-controls/map-controls.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { connect } from 'react-redux';
22

3+
import { setMapTourOpen } from 'components/map-v2/components/map-tour/actions';
34
import * as shareActions from 'components/modals/share/share-actions';
45
import * as mapActions from 'components/map-v2/actions';
56
import * as recentImageryActions from 'components/map-v2/components/recent-imagery/recent-imagery-actions';
@@ -12,6 +13,7 @@ const actions = {
1213
...mapActions,
1314
...shareActions,
1415
setMenuSettings,
16+
setMapTourOpen,
1517
...recentImageryActions
1618
};
1719

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { createAction, createThunkAction } from 'redux-tools';
2+
3+
export const setMapTourOpen = createAction('setMapTourOpen');
4+
5+
export const setExploreView = createThunkAction(
6+
'setExploreView',
7+
() => (dispatch, getState) => {
8+
const { query, type, payload } = getState().location;
9+
dispatch({
10+
type,
11+
payload,
12+
query: {
13+
...query,
14+
menu: {
15+
menuSection: 'explore'
16+
}
17+
}
18+
});
19+
}
20+
);
21+
22+
export const setAnalysisView = createThunkAction(
23+
'setAnalysisView',
24+
() => (dispatch, getState) => {
25+
const { query, type, payload } = getState().location;
26+
dispatch({
27+
type,
28+
payload,
29+
query: {
30+
...query,
31+
analysis: {
32+
showAnalysis: true
33+
}
34+
}
35+
});
36+
}
37+
);

0 commit comments

Comments
 (0)