From 82a15c5adc7b99b358d6d87c9fb42ef874eff779 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 13 Aug 2018 22:53:23 +0800 Subject: [PATCH 1/5] initial separation of container and template --- src/modules/blocks/event-venue/container.js | 32 +++++++++++++++ src/modules/blocks/event-venue/index.js | 6 +-- .../event-venue/{block.js => template.js} | 39 +++---------------- 3 files changed, 39 insertions(+), 38 deletions(-) create mode 100644 src/modules/blocks/event-venue/container.js rename src/modules/blocks/event-venue/{block.js => template.js} (88%) diff --git a/src/modules/blocks/event-venue/container.js b/src/modules/blocks/event-venue/container.js new file mode 100644 index 000000000..fc907755c --- /dev/null +++ b/src/modules/blocks/event-venue/container.js @@ -0,0 +1,32 @@ +/** + * External dependencies + */ +import { connect } from 'react-redux'; +import { compose, bindActionCreators } from 'redux'; + +/** + * Internal dependencies + */ +import EventVenue from './template'; +import { withStore, withSaveData, withDetails, withForm } from 'editor/hoc'; +import { actions, selectors } from 'data/blocks/venue'; +import { VENUE } from 'editor/post-types'; + +const mapStateToProps = ( state ) => ( { + venue: selectors.getVenue( state ), + showMapLink: selectors.getshowMapLink( state ), + showMap: selectors.getshowMap( state ), +} ); + +const mapDispatchToProps = ( dispatch ) => bindActionCreators( actions, dispatch ); + +export default compose( + withStore( { postType: VENUE } ), + connect( + mapStateToProps, + mapDispatchToProps, + ), + withSaveData(), + withDetails( 'venue' ), + withForm( ( props ) => props.name ), +)( EventVenue ); diff --git a/src/modules/blocks/event-venue/index.js b/src/modules/blocks/event-venue/index.js index bda1d95d9..8c15e02ed 100644 --- a/src/modules/blocks/event-venue/index.js +++ b/src/modules/blocks/event-venue/index.js @@ -6,10 +6,8 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import EventVenue from './block'; -import { withStore } from 'editor/hoc'; +import EventVenue from './container'; import { Icons } from 'elements'; -import { VENUE } from 'editor/post-types'; /** * Module Code @@ -50,7 +48,7 @@ export default { }, }, - edit: withStore( { postType: VENUE } )( EventVenue ), + edit: EventVenue, save( props ) { return null; diff --git a/src/modules/blocks/event-venue/block.js b/src/modules/blocks/event-venue/template.js similarity index 88% rename from src/modules/blocks/event-venue/block.js rename to src/modules/blocks/event-venue/template.js index 7987ce3ef..01a29ba97 100644 --- a/src/modules/blocks/event-venue/block.js +++ b/src/modules/blocks/event-venue/template.js @@ -1,21 +1,16 @@ /** * External dependencies */ -import React from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { isEmpty } from 'lodash'; import { addressToMapString } from 'utils/geo-data'; import classNames from 'classnames'; -import { connect } from 'react-redux'; -import { compose, bindActionCreators } from 'redux'; /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { Component } from '@wordpress/element'; -import './style.pcss'; - import { Spinner, Placeholder, @@ -23,10 +18,7 @@ import { PanelBody, Dashicon, } from '@wordpress/components'; - -import { - InspectorControls, -} from '@wordpress/editor'; +import { InspectorControls } from '@wordpress/editor'; /** * Internal dependencies @@ -39,13 +31,12 @@ import { GoogleMap, EditLink, } from 'elements'; - import { VENUE } from 'editor/post-types'; -import { withSaveData, withDetails, withForm } from 'editor/hoc'; import VenueDetails from './venue'; import VenueIcon from 'icons/venue.svg'; import CloseIcon from 'icons/close.svg'; -import { actions, selectors, utils } from 'data/blocks/venue'; +import { utils } from 'data/blocks/venue'; +import './style.pcss'; /** * Module Code @@ -74,10 +65,6 @@ class EventVenue extends Component { toggleVenueMapLink: PropTypes.func, }; - constructor() { - super( ...arguments ); - } - componentDidUpdate( prevProps = {} ) { const { isSelected, edit, create, setSubmit } = this.props; const unSelected = prevProps.isSelected && ! isSelected; @@ -306,20 +293,4 @@ class EventVenue extends Component { } } -const mapStateToProps = ( state ) => ( { - venue: selectors.getVenue( state ), - showMapLink: selectors.getshowMapLink( state ), - showMap: selectors.getshowMap( state ), -} ); - -const mapDispatchToProps = ( dispatch ) => bindActionCreators( actions, dispatch ); - -export default compose( - connect( - mapStateToProps, - mapDispatchToProps, - ), - withSaveData(), - withDetails( 'venue' ), - withForm( ( props ) => props.name ), -)( EventVenue ); +export default EventVenue; From 73cf1693657eace5ab940d08b46b04201c6f3589 Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 14 Aug 2018 00:23:46 +0800 Subject: [PATCH 2/5] move onFormSubmit and onItemSelect functions to container --- src/modules/blocks/event-venue/container.js | 35 +++- src/modules/blocks/event-venue/template.js | 197 +++++++++----------- 2 files changed, 117 insertions(+), 115 deletions(-) diff --git a/src/modules/blocks/event-venue/container.js b/src/modules/blocks/event-venue/container.js index fc907755c..1370f1477 100644 --- a/src/modules/blocks/event-venue/container.js +++ b/src/modules/blocks/event-venue/container.js @@ -8,25 +8,48 @@ import { compose, bindActionCreators } from 'redux'; * Internal dependencies */ import EventVenue from './template'; +import { toVenue } from 'elements'; import { withStore, withSaveData, withDetails, withForm } from 'editor/hoc'; import { actions, selectors } from 'data/blocks/venue'; import { VENUE } from 'editor/post-types'; +const setVenue = ( dispatch ) => ( id ) => { + const { setVenue, setShowMap, setShowMapLink } = actions; + dispatch( setVenue( id ) ); + dispatch( setShowMap( true ) ); + dispatch( setShowMapLink( true ) ); +}; + +const onFormComplete = ( dispatch, ownProps ) => ( body ) => { + const { setDetails } = ownProps; + const { id } = body; + setDetails( id, body ); + setVenue( dispatch )( id ); +}; + +const onFormSubmit = ( dispatch, ownProps ) => ( fields ) => ( + ownProps.sendForm( toVenue( fields ), onFormComplete( dispatch, ownProps ) ) +); + +const onItemSelect = ( dispatch ) => setVenue( dispatch ); + const mapStateToProps = ( state ) => ( { venue: selectors.getVenue( state ), showMapLink: selectors.getshowMapLink( state ), showMap: selectors.getshowMap( state ), } ); -const mapDispatchToProps = ( dispatch ) => bindActionCreators( actions, dispatch ); +const mapDispatchToProps = ( dispatch, ownProps ) => ( { + ...bindActionCreators( actions, dispatch ), + onFormSubmit: onFormSubmit( dispatch, ownProps ), + onItemSelect: onItemSelect( dispatch ), +} ); export default compose( withStore( { postType: VENUE } ), - connect( - mapStateToProps, - mapDispatchToProps, - ), - withSaveData(), + connect( mapStateToProps ), withDetails( 'venue' ), withForm( ( props ) => props.name ), + connect( null, mapDispatchToProps ), + withSaveData(), )( EventVenue ); diff --git a/src/modules/blocks/event-venue/template.js b/src/modules/blocks/event-venue/template.js index 01a29ba97..452f7cf73 100644 --- a/src/modules/blocks/event-venue/template.js +++ b/src/modules/blocks/event-venue/template.js @@ -27,7 +27,6 @@ import { SearchOrCreate, VenueForm, toFields, - toVenue, GoogleMap, EditLink, } from 'elements'; @@ -57,15 +56,16 @@ class EventVenue extends Component { createDraft: PropTypes.func, editDraft: PropTypes.func, removeDraft: PropTypes.func, - setVenue: PropTypes.func, setDraftDetails: PropTypes.func, clear: PropTypes.func, sendForm: PropTypes.func, toggleVenueMap: PropTypes.func, toggleVenueMapLink: PropTypes.func, + onFormSubmit: PropTypes.func, + onItemSelect: PropTypes.func, }; - componentDidUpdate( prevProps = {} ) { + componentDidUpdate( prevProps ) { const { isSelected, edit, create, setSubmit } = this.props; const unSelected = prevProps.isSelected && ! isSelected; if ( unSelected && ( edit || create ) ) { @@ -77,48 +77,31 @@ class EventVenue extends Component { this.removeVenue(); } - render() { - return [ this.renderBlock(), this.renderControls() ]; - } - - renderBlock() { - const { showMap } = this.props; - - const containerClass = classNames( - { - 'tribe-editor__venue': this.hasVenue(), - 'tribe-editor__venue--has-map': this.hasVenue() && showMap, - }, - ); - + renderForm = () => { + const { fields, onFormSubmit } = this.props; return ( -
- { this.getContainer() } - { this.renderMap() } - { this.editActions() } -
+ ); } - getContainer() { - const { isLoading, edit, create, submit } = this.props; - - if ( isLoading || submit ) { - return ( - - - - ); - } - - if ( edit || create ) { - return this.renderForm(); + renderEditAction() { + const { isSelected, edit, create, isLoading, submit, volatile } = this.props; + const idle = edit || create || isLoading || submit; + if ( ! this.hasVenue() || ! isSelected || ! volatile || idle ) { + return null; } - return this.hasVenue() ? this.renderDetails() : this.renderSearchOrCreate(); + return ( + + ); } - renderDetails() { + renderDetails = () => { const { showMapLink, details } = this.props; const { getAddress } = utils; @@ -134,7 +117,9 @@ class EventVenue extends Component { } renderSearchOrCreate() { - const { isSelected, store, name } = this.props; + // TODO: The store should not be passed through like this as a prop. + // Instead, we should hook up the element with a HOC. + const { isSelected, store, name, onItemSelect } = this.props; return ( ); } - renderForm = () => { - const { fields } = this.props; - return ( - - ); - }; - - onSubmit = ( fields ) => { - const { sendForm } = this.props; - sendForm( toVenue( fields ), this.formCompleted ); - }; - - formCompleted = ( body = {} ) => { - const { setDetails } = this.props; - const { id } = body; - setDetails( id, body ); - this.setVenue( id ); - }; + getContainer() { + const { isLoading, edit, create, submit } = this.props; - setVenue = ( id ) => { - const { setVenue, setShowMap, setShowMapLink } = this.props; - setVenue( id ); - setShowMap( true ); - setShowMapLink( true ); - }; + if ( isLoading || submit ) { + return ( + + + + ); + } - setDraftTitle = ( title ) => { - const { createDraft } = this.props; - createDraft( { - title: { - rendered: title, - }, - } ); - }; + if ( edit || create ) { + return this.renderForm(); + } - hasVenue() { - const { details } = this.props; - return ! isEmpty( details ); + return this.hasVenue() ? this.renderDetails() : this.renderSearchOrCreate(); } renderMap() { @@ -211,27 +171,6 @@ class EventVenue extends Component { ); } - maybeEdit = () => { - const { volatile } = this.props; - if ( this.hasVenue() && volatile ) { - return this.edit(); - } - } - - renderEditAction() { - const { isSelected, edit, create, isLoading, submit, volatile } = this.props; - const idle = edit || create || isLoading || submit; - if ( ! this.hasVenue() || ! isSelected || ! volatile || idle ) { - return null; - } - - return ( - - ); - } - editActions() { const { isSelected, edit, create, isLoading, submit } = this.props; if ( ! this.hasVenue() || ! isSelected || edit || create || isLoading || submit ) { @@ -250,18 +189,20 @@ class EventVenue extends Component { ); } - removeVenue = () => { - const { volatile, maybeRemoveEntry, removeVenue, details } = this.props; - removeVenue(); - if ( volatile ) { - maybeRemoveEntry( details ); - } - }; + renderBlock() { + const containerClass = classNames( { + 'tribe-editor__venue': this.hasVenue(), + 'tribe-editor__venue--has-map': this.hasVenue() && this.props.showMap, + } ); - edit = () => { - const { details, editEntry } = this.props; - editEntry( details ); - }; + return ( +
+ { this.getContainer() } + { this.renderMap() } + { this.editActions() } +
+ ); + } renderControls() { const { venue, showMapLink, showMap, toggleVenueMap, toggleVenueMapLink } = this.props; @@ -291,6 +232,44 @@ class EventVenue extends Component { ); } + + render() { + return [ this.renderBlock(), this.renderControls() ]; + } + + setDraftTitle = ( title ) => { + const { createDraft } = this.props; + createDraft( { + title: { + rendered: title, + }, + } ); + }; + + hasVenue() { + const { details } = this.props; + return ! isEmpty( details ); + } + + maybeEdit = () => { + const { volatile } = this.props; + if ( this.hasVenue() && volatile ) { + return this.edit(); + } + } + + removeVenue = () => { + const { volatile, maybeRemoveEntry, removeVenue, details } = this.props; + removeVenue(); + if ( volatile ) { + maybeRemoveEntry( details ); + } + }; + + edit = () => { + const { details, editEntry } = this.props; + editEntry( details ); + }; } export default EventVenue; From efb9b7964f5f64000cbf26062d5f62fde5ee8a8b Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 14 Aug 2018 01:38:31 +0800 Subject: [PATCH 3/5] move onCreateNew and removeVenue to container --- src/modules/blocks/event-venue/container.js | 19 +++++++++ src/modules/blocks/event-venue/template.js | 46 +++++++++++---------- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/modules/blocks/event-venue/container.js b/src/modules/blocks/event-venue/container.js index 1370f1477..73ec6da01 100644 --- a/src/modules/blocks/event-venue/container.js +++ b/src/modules/blocks/event-venue/container.js @@ -33,6 +33,23 @@ const onFormSubmit = ( dispatch, ownProps ) => ( fields ) => ( const onItemSelect = ( dispatch ) => setVenue( dispatch ); +const onCreateNew = ( ownProps ) => ( title ) => ownProps.createDraft( { + title: { + rendered: title, + }, +} ); + +// TODO: need to remove the use of "maybe" functions as they hold logic they +// ultimately should not. +const removeVenue = ( dispatch, ownProps ) => () => { + const { volatile, maybeRemoveEntry, details } = ownProps; + + dispatch( actions.removeVenue() ); + if ( volatile ) { + maybeRemoveEntry( details ); + } +} + const mapStateToProps = ( state ) => ( { venue: selectors.getVenue( state ), showMapLink: selectors.getshowMapLink( state ), @@ -43,6 +60,8 @@ const mapDispatchToProps = ( dispatch, ownProps ) => ( { ...bindActionCreators( actions, dispatch ), onFormSubmit: onFormSubmit( dispatch, ownProps ), onItemSelect: onItemSelect( dispatch ), + onCreateNew: onCreateNew( ownProps ), + removeVenue: removeVenue( dispatch, ownProps ), } ); export default compose( diff --git a/src/modules/blocks/event-venue/template.js b/src/modules/blocks/event-venue/template.js index 452f7cf73..92185b447 100644 --- a/src/modules/blocks/event-venue/template.js +++ b/src/modules/blocks/event-venue/template.js @@ -63,6 +63,8 @@ class EventVenue extends Component { toggleVenueMapLink: PropTypes.func, onFormSubmit: PropTypes.func, onItemSelect: PropTypes.func, + onCreateNew: PropTypes.func, + removeVenue: PropTypes.func, }; componentDidUpdate( prevProps ) { @@ -74,7 +76,11 @@ class EventVenue extends Component { } componentWillUnmount() { - this.removeVenue(); + // TODO: this does not work as intended. If one deletes a block, then adds + // another block, the venue id persists because of the setInitialState() + // function. This will perform as intended once setInitialState() is + // removed. + this.props.removeVenue(); } renderForm = () => { @@ -119,7 +125,7 @@ class EventVenue extends Component { renderSearchOrCreate() { // TODO: The store should not be passed through like this as a prop. // Instead, we should hook up the element with a HOC. - const { isSelected, store, name, onItemSelect } = this.props; + const { isSelected, store, name, onItemSelect, onCreateNew } = this.props; return ( ); @@ -172,7 +178,15 @@ class EventVenue extends Component { } editActions() { - const { isSelected, edit, create, isLoading, submit } = this.props; + const { + isSelected, + edit, + create, + isLoading, + submit, + removeVenue + } = this.props; + if ( ! this.hasVenue() || ! isSelected || edit || create || isLoading || submit ) { return null; } @@ -181,7 +195,7 @@ class EventVenue extends Component {
@@ -237,20 +251,16 @@ class EventVenue extends Component { return [ this.renderBlock(), this.renderControls() ]; } - setDraftTitle = ( title ) => { - const { createDraft } = this.props; - createDraft( { - title: { - rendered: title, - }, - } ); - }; - + // TODO: this hasVenue is coupled to the existence of details, not the venue ID. + // Given how withDetails is currently tightly coupled with the state, this cannot + // be moved to the container. withDetails should be decoupled from state. hasVenue() { const { details } = this.props; return ! isEmpty( details ); } + // TODO: this function cannot be moved to container as it depends on hasVenue(). + // Once withDetails is decoupled from state, this should move to container. maybeEdit = () => { const { volatile } = this.props; if ( this.hasVenue() && volatile ) { @@ -258,14 +268,6 @@ class EventVenue extends Component { } } - removeVenue = () => { - const { volatile, maybeRemoveEntry, removeVenue, details } = this.props; - removeVenue(); - if ( volatile ) { - maybeRemoveEntry( details ); - } - }; - edit = () => { const { details, editEntry } = this.props; editEntry( details ); From c9b0763dbd72b6786f206872f763d8c2c042e22e Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 14 Aug 2018 01:44:44 +0800 Subject: [PATCH 4/5] move editVenue to container --- src/modules/blocks/event-venue/container.js | 8 +++++- src/modules/blocks/event-venue/template.js | 31 ++++++++++++--------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/modules/blocks/event-venue/container.js b/src/modules/blocks/event-venue/container.js index 73ec6da01..634cba7f7 100644 --- a/src/modules/blocks/event-venue/container.js +++ b/src/modules/blocks/event-venue/container.js @@ -48,7 +48,12 @@ const removeVenue = ( dispatch, ownProps ) => () => { if ( volatile ) { maybeRemoveEntry( details ); } -} +}; + +const editVenue = ( ownProps ) => () => { + const { details, editEntry } = ownProps; + editEntry( details ); +}; const mapStateToProps = ( state ) => ( { venue: selectors.getVenue( state ), @@ -62,6 +67,7 @@ const mapDispatchToProps = ( dispatch, ownProps ) => ( { onItemSelect: onItemSelect( dispatch ), onCreateNew: onCreateNew( ownProps ), removeVenue: removeVenue( dispatch, ownProps ), + editVenue: editVenue( ownProps ), } ); export default compose( diff --git a/src/modules/blocks/event-venue/template.js b/src/modules/blocks/event-venue/template.js index 92185b447..1bd40f90c 100644 --- a/src/modules/blocks/event-venue/template.js +++ b/src/modules/blocks/event-venue/template.js @@ -65,6 +65,7 @@ class EventVenue extends Component { onItemSelect: PropTypes.func, onCreateNew: PropTypes.func, removeVenue: PropTypes.func, + editVenue: PropTypes.func, }; componentDidUpdate( prevProps ) { @@ -94,14 +95,23 @@ class EventVenue extends Component { } renderEditAction() { - const { isSelected, edit, create, isLoading, submit, volatile } = this.props; + const { + isSelected, + edit, + create, + isLoading, + submit, + volatile, + editVenue + } = this.props; + const idle = edit || create || isLoading || submit; if ( ! this.hasVenue() || ! isSelected || ! volatile || idle ) { return null; } return ( - ); @@ -140,7 +150,7 @@ class EventVenue extends Component { ); } - getContainer() { + renderContainer() { const { isLoading, edit, create, submit } = this.props; if ( isLoading || submit ) { @@ -177,7 +187,7 @@ class EventVenue extends Component { ); } - editActions() { + renderRemoveAction() { const { isSelected, edit, @@ -211,9 +221,9 @@ class EventVenue extends Component { return (
- { this.getContainer() } + { this.renderContainer() } { this.renderMap() } - { this.editActions() } + { this.renderRemoveAction() }
); } @@ -262,16 +272,11 @@ class EventVenue extends Component { // TODO: this function cannot be moved to container as it depends on hasVenue(). // Once withDetails is decoupled from state, this should move to container. maybeEdit = () => { - const { volatile } = this.props; + const { volatile, editVenue } = this.props; if ( this.hasVenue() && volatile ) { - return this.edit(); + return editVenue; } } - - edit = () => { - const { details, editEntry } = this.props; - editEntry( details ); - }; } export default EventVenue; From 89c00d67d17121c5cd8fdc10211699c917a97790 Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 14 Aug 2018 02:02:53 +0800 Subject: [PATCH 5/5] changelog --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 9db07453d..2d7020f50 100644 --- a/readme.md +++ b/readme.md @@ -27,6 +27,7 @@ This plugin is our first attempt at integrating the Event post type with the Gut #### 0.2.7-alpha - TBD * Tweak - Use event timezone as default value +* Tweak - Separate logic and presentation in event venue block * Fix - Allow removal of organizers from classic block if the organizer block is removed #### 0.2.6-alpha - 2018-08-10