summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/extensions/blocks/map/edit.js')
-rw-r--r--plugins/jetpack/extensions/blocks/map/edit.js283
1 files changed, 283 insertions, 0 deletions
diff --git a/plugins/jetpack/extensions/blocks/map/edit.js b/plugins/jetpack/extensions/blocks/map/edit.js
new file mode 100644
index 00000000..87889f63
--- /dev/null
+++ b/plugins/jetpack/extensions/blocks/map/edit.js
@@ -0,0 +1,283 @@
+/**
+ * External dependencies
+ */
+import apiFetch from '@wordpress/api-fetch';
+import { __ } from '@wordpress/i18n';
+import { Component, createRef, Fragment } from '@wordpress/element';
+import {
+ Button,
+ ButtonGroup,
+ ExternalLink,
+ IconButton,
+ PanelBody,
+ Placeholder,
+ Spinner,
+ TextControl,
+ ToggleControl,
+ Toolbar,
+ withNotices,
+} from '@wordpress/components';
+import {
+ BlockAlignmentToolbar,
+ BlockControls,
+ InspectorControls,
+ PanelColorSettings,
+} from '@wordpress/editor';
+
+/**
+ * Internal dependencies
+ */
+import AddPoint from './add-point';
+import Locations from './locations';
+import Map from './component.js';
+import MapThemePicker from './map-theme-picker';
+import { settings } from './settings.js';
+
+const API_STATE_LOADING = 0;
+const API_STATE_FAILURE = 1;
+const API_STATE_SUCCESS = 2;
+
+class MapEdit extends Component {
+ constructor() {
+ super( ...arguments );
+ this.state = {
+ addPointVisibility: false,
+ apiState: API_STATE_LOADING,
+ };
+ this.mapRef = createRef();
+ }
+ addPoint = point => {
+ const { attributes, setAttributes } = this.props;
+ const { points } = attributes;
+ const newPoints = points.slice( 0 );
+ let duplicateFound = false;
+ points.map( existingPoint => {
+ if ( existingPoint.id === point.id ) {
+ duplicateFound = true;
+ }
+ } );
+ if ( duplicateFound ) {
+ return;
+ }
+ newPoints.push( point );
+ setAttributes( { points: newPoints } );
+ this.setState( { addPointVisibility: false } );
+ };
+ updateAlignment = value => {
+ this.props.setAttributes( { align: value } );
+ // Allow one cycle for alignment change to take effect
+ setTimeout( this.mapRef.current.sizeMap, 0 );
+ };
+ updateAPIKeyControl = value => {
+ this.setState( {
+ apiKeyControl: value,
+ } );
+ };
+ updateAPIKey = () => {
+ const { noticeOperations } = this.props;
+ const { apiKeyControl } = this.state;
+ noticeOperations.removeAllNotices();
+ apiKeyControl && this.apiCall( apiKeyControl, 'POST' );
+ };
+ removeAPIKey = () => {
+ this.apiCall( null, 'DELETE' );
+ };
+ apiCall( serviceApiKey = null, method = 'GET' ) {
+ const { noticeOperations } = this.props;
+ const { apiKey } = this.state;
+ const path = '/wpcom/v2/service-api-keys/mapbox';
+ const fetch = serviceApiKey
+ ? { path, method, data: { service_api_key: serviceApiKey } }
+ : { path, method };
+ this.setState( { apiRequestOutstanding: true }, () => {
+ apiFetch( fetch ).then(
+ result => {
+ noticeOperations.removeAllNotices();
+ this.setState( {
+ apiState: result.service_api_key ? API_STATE_SUCCESS : API_STATE_FAILURE,
+ apiKey: result.service_api_key,
+ apiKeyControl: result.service_api_key,
+ apiRequestOutstanding: false,
+ } );
+ },
+ result => {
+ this.onError( null, result.message );
+ this.setState( {
+ apiRequestOutstanding: false,
+ apiKeyControl: apiKey,
+ } );
+ }
+ );
+ } );
+ }
+ componentDidMount() {
+ this.apiCall();
+ }
+ onError = ( code, message ) => {
+ const { noticeOperations } = this.props;
+ noticeOperations.removeAllNotices();
+ noticeOperations.createErrorNotice( message );
+ };
+ render() {
+ const { className, setAttributes, attributes, noticeUI, notices } = this.props;
+ const { mapStyle, mapDetails, points, zoom, mapCenter, markerColor, align } = attributes;
+ const {
+ addPointVisibility,
+ apiKey,
+ apiKeyControl,
+ apiState,
+ apiRequestOutstanding,
+ } = this.state;
+ const inspectorControls = (
+ <Fragment>
+ <BlockControls>
+ <BlockAlignmentToolbar
+ value={ align }
+ onChange={ this.updateAlignment }
+ controls={ [ 'center', 'wide', 'full' ] }
+ />
+ <Toolbar>
+ <IconButton
+ icon={ settings.markerIcon }
+ label="Add a marker"
+ onClick={ () => this.setState( { addPointVisibility: true } ) }
+ />
+ </Toolbar>
+ </BlockControls>
+ <InspectorControls>
+ <PanelBody title={ __( 'Map Theme', 'jetpack' ) }>
+ <MapThemePicker
+ value={ mapStyle }
+ onChange={ value => setAttributes( { mapStyle: value } ) }
+ options={ settings.mapStyleOptions }
+ />
+ <ToggleControl
+ label={ __( 'Show street names', 'jetpack' ) }
+ checked={ mapDetails }
+ onChange={ value => setAttributes( { mapDetails: value } ) }
+ />
+ </PanelBody>
+ <PanelColorSettings
+ title={ __( 'Colors', 'jetpack' ) }
+ initialOpen={ true }
+ colorSettings={ [
+ {
+ value: markerColor,
+ onChange: value => setAttributes( { markerColor: value } ),
+ label: 'Marker Color',
+ },
+ ] }
+ />
+ { points.length ? (
+ <PanelBody title={ __( 'Markers', 'jetpack' ) } initialOpen={ false }>
+ <Locations
+ points={ points }
+ onChange={ value => {
+ setAttributes( { points: value } );
+ } }
+ />
+ </PanelBody>
+ ) : null }
+ <PanelBody title={ __( 'Mapbox Access Token', 'jetpack' ) } initialOpen={ false }>
+ <TextControl
+ label={ __( 'Mapbox Access Token', 'jetpack' ) }
+ value={ apiKeyControl }
+ onChange={ value => this.setState( { apiKeyControl: value } ) }
+ />
+ <ButtonGroup>
+ <Button type="button" onClick={ this.updateAPIKey } isDefault>
+ { __( 'Update Token', 'jetpack' ) }
+ </Button>
+ <Button type="button" onClick={ this.removeAPIKey } isDefault>
+ { __( 'Remove Token', 'jetpack' ) }
+ </Button>
+ </ButtonGroup>
+ </PanelBody>
+ </InspectorControls>
+ </Fragment>
+ );
+ const placholderAPIStateLoading = (
+ <Placeholder icon={ settings.icon }>
+ <Spinner />
+ </Placeholder>
+ );
+ const placeholderAPIStateFailure = (
+ <Placeholder icon={ settings.icon } label={ __( 'Map', 'jetpack' ) } notices={ notices }>
+ <Fragment>
+ <div className="components-placeholder__instructions">
+ { __( 'To use the map block, you need an Access Token.', 'jetpack' ) }
+ <br />
+ <ExternalLink href="https://www.mapbox.com">
+ { __( 'Create an account or log in to Mapbox.', 'jetpack' ) }
+ </ExternalLink>
+ <br />
+ { __(
+ 'Locate and copy the default access token. Then, paste it into the field below.',
+ 'jetpack'
+ ) }
+ </div>
+ <TextControl
+ className="wp-block-jetpack-map-components-text-control-api-key"
+ disabled={ apiRequestOutstanding }
+ placeholder={ __( 'Paste Token Here', 'jetpack' ) }
+ value={ apiKeyControl }
+ onChange={ this.updateAPIKeyControl }
+ />
+ <Button
+ className="wp-block-jetpack-map-components-text-control-api-key-submit"
+ isLarge
+ disabled={ apiRequestOutstanding || ! apiKeyControl || apiKeyControl.length < 1 }
+ onClick={ this.updateAPIKey }
+ >
+ { __( 'Set Token', 'jetpack' ) }
+ </Button>
+ </Fragment>
+ </Placeholder>
+ );
+ const placeholderAPIStateSuccess = (
+ <Fragment>
+ { inspectorControls }
+ <div className={ className }>
+ <Map
+ ref={ this.mapRef }
+ mapStyle={ mapStyle }
+ mapDetails={ mapDetails }
+ points={ points }
+ zoom={ zoom }
+ mapCenter={ mapCenter }
+ markerColor={ markerColor }
+ onSetZoom={ value => {
+ setAttributes( { zoom: value } );
+ } }
+ admin={ true }
+ apiKey={ apiKey }
+ onSetPoints={ value => setAttributes( { points: value } ) }
+ onMapLoaded={ () => this.setState( { addPointVisibility: true } ) }
+ onMarkerClick={ () => this.setState( { addPointVisibility: false } ) }
+ onError={ this.onError }
+ >
+ { addPointVisibility && (
+ <AddPoint
+ onAddPoint={ this.addPoint }
+ onClose={ () => this.setState( { addPointVisibility: false } ) }
+ apiKey={ apiKey }
+ onError={ this.onError }
+ tagName="AddPoint"
+ />
+ ) }
+ </Map>
+ </div>
+ </Fragment>
+ );
+ return (
+ <Fragment>
+ { noticeUI }
+ { apiState === API_STATE_LOADING && placholderAPIStateLoading }
+ { apiState === API_STATE_FAILURE && placeholderAPIStateFailure }
+ { apiState === API_STATE_SUCCESS && placeholderAPIStateSuccess }
+ </Fragment>
+ );
+ }
+}
+
+export default withNotices( MapEdit );