Skip to content

Commit

Permalink
Revert "Editor: Make the AddTerm Component more reusable (#8588)"
Browse files Browse the repository at this point in the history
A user noticed "Can not read hierarchical of null" error when loading the editor

This reverts commit 7d6f7a0.
  • Loading branch information
youknowriad committed Oct 11, 2016
1 parent 7d6f7a0 commit 9f169a5
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 170 deletions.
99 changes: 32 additions & 67 deletions client/my-sites/term-tree-selector/add-term.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import ReactDom from 'react-dom';
import classNames from 'classnames';
import { connect } from 'react-redux';
import { localize } from 'i18n-calypso';
import { get, find, noop } from 'lodash';
import { get, find } from 'lodash';

/**
* Internal dependencies
Expand All @@ -16,7 +16,6 @@ import TermTreeSelectorTerms from './terms';
import Button from 'components/button';
import Gridicon from 'components/gridicon';
import FormInputValidation from 'components/forms/form-input-validation';
import FormTextarea from 'components/forms/form-textarea';
import FormTextInput from 'components/forms/form-text-input';
import FormSectionHeading from 'components/forms/form-section-heading';
import FormCheckbox from 'components/forms/form-checkbox';
Expand All @@ -27,7 +26,7 @@ import viewport from 'lib/viewport';
import { getSelectedSiteId } from 'state/ui/selectors';
import { getPostTypeTaxonomy } from 'state/post-types/taxonomies/selectors';
import { getTerms } from 'state/terms/selectors';
import { addTerm } from 'state/terms/actions';
import { addTermForPost } from 'state/posts/actions';

class TermSelectorAddTerm extends Component {
static initialState = {
Expand All @@ -40,21 +39,14 @@ class TermSelectorAddTerm extends Component {

static propTypes = {
labels: PropTypes.object,
onSuccess: PropTypes.func,
postType: PropTypes.string,
postId: PropTypes.number,
showDescriptionInput: PropTypes.bool,
siteId: PropTypes.number,
terms: PropTypes.array,
taxonomy: PropTypes.string,
translate: PropTypes.func
};

static defaultProps = {
onSuccess: noop,
showDescriptionInput: false
};

constructor( props ) {
super( props );
this.state = this.constructor.initialState;
Expand Down Expand Up @@ -100,15 +92,9 @@ class TermSelectorAddTerm extends Component {

getFormValues() {
const name = ReactDom.findDOMNode( this.refs.termName ).value.trim();
const formValues = { name };
if ( this.props.isHierarchical ) {
formValues.parent = this.state.selectedParent.length ? this.state.selectedParent[ 0 ] : 0;
}
if ( this.props.showDescriptionInput ) {
formValues.description = ReactDom.findDOMNode( this.refs.termDescription ).value.trim();
}
const parent = this.state.selectedParent.length ? this.state.selectedParent[ 0 ] : 0;

return formValues;
return { name, parent };
}

isValid() {
Expand All @@ -123,7 +109,7 @@ class TermSelectorAddTerm extends Component {
const lowerCasedTermName = values.name.toLowerCase();
const matchingTerm = find( this.props.terms, ( term ) => {
return ( term.name.toLowerCase() === lowerCasedTermName ) &&
( ! this.props.isHierarchical || ( term.parent === values.parent ) );
( term.parent === values.parent );
} );

if ( matchingTerm ) {
Expand Down Expand Up @@ -159,43 +145,12 @@ class TermSelectorAddTerm extends Component {

const { postId, siteId, taxonomy } = this.props;

this.props
.addTerm( siteId, taxonomy, term, postId )
.then( this.props.onSuccess );
this.props.addTermForPost( siteId, taxonomy, term, postId );
this.closeDialog();
}

renderParentSelector() {
const { labels, siteId, taxonomy, translate } = this.props;
const { searchTerm, selectedParent } = this.state;
const query = {};
if ( searchTerm && searchTerm.length ) {
query.search = searchTerm;
}

return (
<FormFieldset>
<FormLegend>
{ labels.parent_item }
</FormLegend>
<FormLabel>
<FormCheckbox ref="topLevel" checked={ this.state.isTopLevel } onChange={ this.boundOnTopLevelChange } />
<span>{ translate( 'Top level', { context: 'Terms: New term being created is top level' } ) }</span>
</FormLabel>
<TermTreeSelectorTerms
siteId={ siteId }
taxonomy={ taxonomy }
onSearch={ this.boundOnSearch }
onChange={ this.boundOnParentChange }
query={ query }
selected={ selectedParent }
/>
</FormFieldset>
);
}

render() {
const { isHierarchical, labels, translate, terms, showDescriptionInput } = this.props;
const { labels, siteId, taxonomy, translate, terms } = this.props;
const buttons = [ {
action: 'cancel',
label: translate( 'Cancel' )
Expand All @@ -207,6 +162,12 @@ class TermSelectorAddTerm extends Component {
onClick: this.boundSaveTerm
} ];

const { searchTerm, selectedParent } = this.state;
const query = {};
if ( searchTerm && searchTerm.length ) {
query.search = searchTerm;
}

const isError = this.state.error && this.state.error.length;
const totalTerms = terms ? terms.length : 0;
const classes = classNames( 'term-tree-selector__add-term', { 'is-compact': totalTerms < 8 } );
Expand All @@ -232,16 +193,23 @@ class TermSelectorAddTerm extends Component {
onKeyUp={ this.boundValidateInput } />
{ isError && <FormInputValidation isError text={ this.state.error } /> }
</FormFieldset>
{ showDescriptionInput && <FormFieldset>
<FormLegend>
{ translate( 'Description', { context: 'Terms: Term description label' } ) }
</FormLegend>
<FormTextarea
ref="termDescription"
onKeyUp={ this.boundValidateInput } />
</FormFieldset>
}
{ isHierarchical && this.renderParentSelector() }
<FormFieldset>
<FormLegend>
{ labels.parent_item }
</FormLegend>
<FormLabel>
<FormCheckbox ref="topLevel" checked={ this.state.isTopLevel } onChange={ this.boundOnTopLevelChange } />
<span>{ translate( 'Top level', { context: 'Terms: New term being created is top level' } ) }</span>
</FormLabel>
<TermTreeSelectorTerms
siteId={ siteId }
taxonomy={ taxonomy }
onSearch={ this.boundOnSearch }
onChange={ this.boundOnParentChange }
query={ query }
selected={ selectedParent }
/>
</FormFieldset>
</Dialog>
</div>
);
Expand All @@ -252,16 +220,13 @@ export default connect(
( state, ownProps ) => {
const { taxonomy, postType } = ownProps;
const siteId = getSelectedSiteId( state );
const taxonomyDetails = getPostTypeTaxonomy( state, siteId, postType, taxonomy );
const labels = get( taxonomyDetails, 'labels', {} );
const isHierarchical = taxonomyDetails.hierarchical;
const labels = get( getPostTypeTaxonomy( state, siteId, postType, taxonomy ), 'labels', {} );

return {
terms: getTerms( state, siteId, taxonomy ),
isHierarchical,
labels,
siteId
};
},
{ addTerm }
{ addTermForPost }
)( localize( TermSelectorAddTerm ) );
18 changes: 4 additions & 14 deletions client/post-editor/editor-term-selector/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { cloneDeep, findIndex, map, toArray } from 'lodash';
*/
import TermTreeSelector from 'my-sites/term-tree-selector';
import AddTerm from 'my-sites/term-tree-selector/add-term';
import { editPost, addTermForPost } from 'state/posts/actions';
import { editPost } from 'state/posts/actions';
import { getSelectedSiteId } from 'state/ui/selectors';
import { getEditorPostId } from 'state/ui/editor/selectors';
import { getEditedPostValue } from 'state/posts/selectors';
Expand All @@ -31,11 +31,6 @@ class EditorTermSelector extends Component {
this.boundOnTermsChange = this.onTermsChange.bind( this );
}

onAddTerm = ( term ) => {
const { postId, taxonomyName, siteId } = this.props;
this.props.addTermForPost( siteId, taxonomyName, term, postId );
}

onTermsChange( selectedTerm ) {
const { postTerms, taxonomyName, siteId, postId } = this.props;
const terms = cloneDeep( postTerms ) || {};
Expand Down Expand Up @@ -63,7 +58,7 @@ class EditorTermSelector extends Component {
}

render() {
const { postType, siteId, taxonomyName, canEditTerms } = this.props;
const { postType, postId, siteId, taxonomyName, canEditTerms } = this.props;

return (
<div>
Expand All @@ -75,12 +70,7 @@ class EditorTermSelector extends Component {
siteId={ siteId }
multiple={ true }
/>
{ canEditTerms &&
<AddTerm
taxonomy={ taxonomyName }
postType={ postType }
onSuccess={ this.onAddTerm } />
}
{ canEditTerms && <AddTerm taxonomy={ taxonomyName } postType={ postType } postId={ postId } /> }
</div>
);
}
Expand All @@ -99,5 +89,5 @@ export default connect(
postId
};
},
{ editPost, addTermForPost }
{ editPost }
)( EditorTermSelector );
3 changes: 2 additions & 1 deletion client/state/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
* Internal dependencies
*/
import noticesMiddleware from './notices/middleware';
import postsEditMiddleware from './posts/middleware';
import application from './application/reducer';
import comments from './comments/reducer';
import componentsUsageStats from './components-usage-stats/reducer';
Expand Down Expand Up @@ -93,7 +94,7 @@ export const reducer = combineReducers( {
wordads
} );

const middleware = [ thunkMiddleware, noticesMiddleware ];
const middleware = [ thunkMiddleware, noticesMiddleware, postsEditMiddleware ];

if ( typeof window === 'object' ) {
// Browser-specific middlewares
Expand Down
34 changes: 6 additions & 28 deletions client/state/posts/actions.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
/**
* External dependencies
*/
import { isNumber, toArray } from 'lodash';

/**
* Internal dependencies
*/
import wpcom from 'lib/wp';
import { extendAction } from 'state/utils';
import { normalizePostForApi } from './utils';
import { getEditedPost } from 'state/posts/selectors';
import { addTerm } from 'state/terms/actions';
import {
POST_DELETE,
POST_DELETE_SUCCESS,
Expand Down Expand Up @@ -301,7 +297,9 @@ export function restorePost( siteId, postId ) {
}

/**
* Returns an action thunk which, when dispatched, adds a term to the current edited post
* Returns an action thunk which, when dispatched, triggers a network request
* to create a new term. All actions dispatched by the thunk will include meta
* to associate it with the specified post ID.
*
* @param {Number} siteId Site ID
* @param {String} taxonomy Taxonomy Slug
Expand All @@ -310,25 +308,5 @@ export function restorePost( siteId, postId ) {
* @return {Function} Action thunk
*/
export function addTermForPost( siteId, taxonomy, term, postId ) {
return ( dispatch, getState ) => {
const state = getState();
const post = getEditedPost( state, siteId, postId );

// if there is no post, no term, or term is temporary, bail
if ( ! post || ! term || ! isNumber( term.ID ) ) {
return;
}

const postTerms = post.terms || {};

// ensure we have an array since API returns an object
const taxonomyTerms = toArray( postTerms[ taxonomy ] );
taxonomyTerms.push( term );

dispatch( editPost( siteId, postId, {
terms: {
[ taxonomy ]: taxonomyTerms
}
} ) );
};
return extendAction( addTerm( siteId, taxonomy, term ), { postId } );
}
49 changes: 49 additions & 0 deletions client/state/posts/middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* External dependencies
*/
import { isNumber, toArray } from 'lodash';

/**
* Internal dependencies
*/
import { TERMS_RECEIVE } from 'state/action-types';
import { getEditedPost } from 'state/posts/selectors';
import { editPost } from 'state/posts/actions';

/**
* Dispatches editPost when a new term has been added
* that also has a postId on the action
*
* @param {Function} dispatch Dispatch method
* @param {Object} state Global state tree
* @param {Object} action Action object
*/
export function onTermsReceive( dispatch, state, action ) {
const { postId, taxonomy, terms, siteId } = action;
const post = getEditedPost( state, siteId, postId );
const newTerm = terms[ 0 ];

// if there is no post, no term, or term is temporary, bail
if ( ! post || ! newTerm || ! isNumber( newTerm.ID ) ) {
return;
}

const postTerms = post.terms || {};

// ensure we have an array since API returns an object
const taxonomyTerms = toArray( postTerms[ taxonomy ] );
taxonomyTerms.push( newTerm );

dispatch( editPost( siteId, postId, {
terms: {
[ taxonomy ]: taxonomyTerms
}
} ) );
}

export default ( { dispatch, getState } ) => ( next ) => ( action ) => {
if ( TERMS_RECEIVE === action.type && action.hasOwnProperty( 'postId' ) ) {
onTermsReceive( dispatch, getState(), action );
}
return next( action );
};
Loading

0 comments on commit 9f169a5

Please sign in to comment.