Skip to content
102 changes: 102 additions & 0 deletions src/components/effectful/request-map-style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {default as Console} from 'global/console';
import {useEffect} from 'react';
import {json as requestJson} from 'd3-request';
import {generateHashId} from 'utils/utils';

// Utils
import {isValidStyleUrl, getStyleDownloadUrl} from 'utils/map-style-utils/mapbox-gl-style-editor';

// This is exported to aid testing.
export const TASKS = {
loadMapStyleTask,
requestMapStyles
};

export default function RequestMapStyle({
defaultMapStyles,
mapStyles,
loadMapStyles,
mapboxApiAccessToken,
mapboxApiUrl
}) {
useEffect(
() => {
const defaultStyles = Object.values(defaultMapStyles);
// add id to custom map styles if not given
const customStyles = (mapStyles || []).map(ms => ({
...ms,
id: ms.id || generateHashId()
}));

const allStyles = [...customStyles, ...defaultStyles].reduce(
(accu, style) => {
const hasStyleObject = style.style && typeof style.style === 'object';
accu[hasStyleObject ? 'toLoad' : 'toRequest'][style.id] = style;

return accu;
},
{toLoad: {}, toRequest: {}}
);
loadMapStyles(allStyles.toLoad);
// TODO: Make the side effect here and then call loadMapStyles
TASKS.requestMapStyles(allStyles.toRequest, {
mapboxApiAccessToken,
mapboxApiUrl,
loadMapStyles
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[
// This is intentional. This effect is only called once, on mount.
]
);
return null;
}

function requestMapStyles(mapStyles, {mapboxApiAccessToken, mapboxApiUrl, loadMapStyles}) {
return Promise.all(
Object.values(mapStyles)
.map(({id, url, accessToken}) => ({
id,
url: isValidStyleUrl(url)
? getStyleDownloadUrl(url, accessToken || mapboxApiAccessToken, mapboxApiUrl)
: url
}))
.map(TASKS.loadMapStyleTask)
).then(
// success
results =>
loadMapStyles(
results.reduce(
(accu, {id, style}) => ({
...accu,
[id]: {
...mapStyles[id],
style
}
}),
{}
)
),
// error
// loadMapStyleErr
e => {
Console.warn('loadMapStyleErr', e);
}
);
}

function loadMapStyleTask({url, id}) {
return new Promise((success, error) =>
requestJson(url, (err, result) => {
if (err) {
error(err);
} else {
if (!result) {
error(new Error('Map style response is empty'));
}
success({id, style: result});
}
})
);
}
32 changes: 8 additions & 24 deletions src/components/kepler-gl.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ import ModalContainerFactory from './modal-container';
import PlotContainerFactory from './plot-container';
import NotificationPanelFactory from './notification-panel';
import GeoCoderPanelFactory from './geocoder-panel';
import RequestMapStyle from './effectful/request-map-style';

import {generateHashId} from 'utils/utils';
import {validateToken} from 'utils/mapbox-utils';
import {mergeMessages} from 'utils/locale-utils';

Expand Down Expand Up @@ -259,7 +259,6 @@ function KeplerGlFactory(

componentDidMount() {
this._validateMapboxToken();
this._loadMapStyle();
this._handleResize(this.props);
if (typeof this.props.onKeplerGlInitialized === 'function') {
this.props.onKeplerGlInitialized();
Expand Down Expand Up @@ -332,28 +331,6 @@ function KeplerGlFactory(
});
}

_loadMapStyle = () => {
const defaultStyles = Object.values(this.props.mapStyle.mapStyles);
// add id to custom map styles if not given
const customStyles = (this.props.mapStyles || []).map(ms => ({
...ms,
id: ms.id || generateHashId()
}));

const allStyles = [...customStyles, ...defaultStyles].reduce(
(accu, style) => {
const hasStyleObject = style.style && typeof style.style === 'object';
accu[hasStyleObject ? 'toLoad' : 'toRequest'][style.id] = style;

return accu;
},
{toLoad: {}, toRequest: {}}
);

this.props.mapStyleActions.loadMapStyles(allStyles.toLoad);
this.props.mapStyleActions.requestMapStyles(allStyles.toRequest);
};

render() {
const {
id,
Expand Down Expand Up @@ -409,6 +386,13 @@ function KeplerGlFactory(
}}
ref={this.root}
>
<RequestMapStyle
defaultMapStyles={this.props.mapStyle.mapStyles}
mapStyles={this.props.mapStyles}
loadMapStyles={this.props.mapStyleActions.loadMapStyles}
mapboxApiAccessToken={this.props.mapboxApiAccessToken}
mapboxApiUrl={this.props.mapboxApiUrl}
/>
<NotificationPanel {...notificationPanelFields} />
{!uiState.readOnly && !readOnly && <SidePanel {...sideFields} />}
<div className="maps" style={{display: 'flex'}}>
Expand Down
1 change: 1 addition & 0 deletions test/browser/components/effectful/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './request-map-style-test';
Loading