From 38e07737c3980a2d038f0a6da9990ee23c55ec2f Mon Sep 17 00:00:00 2001 From: Sacha Greif Date: Fri, 26 Feb 2016 10:42:57 +0900 Subject: [PATCH] rework post new and post edit forms to be collection-agnostic --- .../base-components/lib/common/Header.jsx | 8 +- packages/base-components/lib/components.js | 4 +- packages/base-components/lib/posts/Post.jsx | 3 +- .../base-components/lib/posts/PostEdit.jsx | 80 ++++++++-------- .../base-components/lib/posts/PostNew.jsx | 96 +++++++++---------- .../lib/posts/list/PostItem.jsx | 7 +- packages/base-components/lib/routes.jsx | 15 ++- packages/nova-core/lib/components.js | 4 +- .../lib/components/EditDocumentForm.jsx | 54 +++++++++++ .../nova-core/lib/components/ModalButton.jsx | 18 +++- .../lib/components/NewDocumentForm.jsx | 92 +++++++++--------- .../lib/containers/EditContainer.jsx | 0 .../lib/containers/EditDocContainer.jsx | 63 ++++++++++++ .../lib/containers/ItemContainer.jsx | 9 +- .../lib/containers/ListContainer.jsx | 6 +- .../nova-core/lib/containers/NewContainer.jsx | 0 .../lib/containers/NewDocContainer.jsx | 59 ++++++++++++ 17 files changed, 352 insertions(+), 166 deletions(-) create mode 100644 packages/nova-core/lib/components/EditDocumentForm.jsx delete mode 100644 packages/nova-core/lib/containers/EditContainer.jsx create mode 100644 packages/nova-core/lib/containers/EditDocContainer.jsx delete mode 100644 packages/nova-core/lib/containers/NewContainer.jsx create mode 100644 packages/nova-core/lib/containers/NewDocContainer.jsx diff --git a/packages/base-components/lib/common/Header.jsx b/packages/base-components/lib/common/Header.jsx index bf4c3b0ec..8c646ec8d 100644 --- a/packages/base-components/lib/common/Header.jsx +++ b/packages/base-components/lib/common/Header.jsx @@ -3,7 +3,7 @@ import NoSSR from 'react-no-ssr'; const Header = props => { - ({Logo, ListContainer, CategoriesList, FlashContainer, NewPostButton, ModalButton, PostNewContainer, CurrentUserContainer, PostNew} = Telescope.components); + ({Logo, ListContainer, CategoriesList, FlashContainer, NewPostButton, ModalButton, PostNewContainer, CurrentUserContainer, PostNew, NewDocContainer} = Telescope.components); const logoUrl = Telescope.settings.get("logoUrl"); const siteTitle = Telescope.settings.get("title", "Telescope"); @@ -16,7 +16,7 @@ const Header = props => { {tagline ?

{tagline}

: "" }
- {} +
Loading…

}> @@ -25,7 +25,9 @@ const Header = props => { {props.currentUser ?

My Account

: ""} - + + {FlowRouter.go('posts.single', post);}}/> + diff --git a/packages/base-components/lib/components.js b/packages/base-components/lib/components.js index 5cd5a5227..45a9fb674 100644 --- a/packages/base-components/lib/components.js +++ b/packages/base-components/lib/components.js @@ -18,8 +18,8 @@ Telescope.registerComponent("PostList", require('./posts/list/PostList.jsx')); Telescope.registerComponent("PostCategories", require('./posts/list/PostCategories.jsx')); Telescope.registerComponent("PostCommenters", require('./posts/list/PostCommenters.jsx')); Telescope.registerComponent("Post", require('./posts/Post.jsx')); -Telescope.registerComponent("PostEdit", require('./posts/PostEdit.jsx')); -Telescope.registerComponent("PostNew", require('./posts/PostNew.jsx')); +// Telescope.registerComponent("PostEdit", require('./posts/PostEdit.jsx')); +// Telescope.registerComponent("PostNew", require('./posts/PostNew.jsx')); Telescope.registerComponent("NewPostButton", require('./posts/NewPostButton.jsx')); // comments diff --git a/packages/base-components/lib/posts/Post.jsx b/packages/base-components/lib/posts/Post.jsx index 937bce78b..4c6729ba4 100644 --- a/packages/base-components/lib/posts/Post.jsx +++ b/packages/base-components/lib/posts/Post.jsx @@ -21,10 +21,9 @@ const Post = (props) => { publication="comments.list" selector={{postId: post._id}} terms={{postId: post._id, view: "postComments"}} - component={CommentList} limit={0} parentProperty="parentCommentId" - /> + >

New Comment:

diff --git a/packages/base-components/lib/posts/PostEdit.jsx b/packages/base-components/lib/posts/PostEdit.jsx index ae60636a9..caaefcbcc 100644 --- a/packages/base-components/lib/posts/PostEdit.jsx +++ b/packages/base-components/lib/posts/PostEdit.jsx @@ -1,52 +1,52 @@ -import Core from "meteor/nova:core"; -({Messages, NovaForms} = Core); +// import Core from "meteor/nova:core"; +// ({Messages, NovaForms} = Core); -import Formsy from 'formsy-react'; +// import Formsy from 'formsy-react'; -const PostEdit = React.createClass({ +// const PostEdit = React.createClass({ - propTypes: { - document: React.PropTypes.object.isRequired, - currentUser: React.PropTypes.object.isRequired - }, +// propTypes: { +// document: React.PropTypes.object.isRequired, +// currentUser: React.PropTypes.object.isRequired +// }, - submitForm(data) { - const post = this.props.document; - const modifier = {$set: _.compactObject(data)}; +// submitForm(data) { +// const post = this.props.document; +// const modifier = {$set: _.compactObject(data)}; - event.preventDefault(); +// event.preventDefault(); - Meteor.call('posts.edit', post._id, modifier, (error, post) => { - if (error) { - console.log(error) - Messages.flash(error.message, "error") - } else { - Messages.flash("Post edited.", "success") - FlowRouter.go('posts.single', post); - } - }); - }, +// Meteor.call('posts.edit', post._id, modifier, (error, post) => { +// if (error) { +// console.log(error) +// Messages.flash(error.message, "error") +// } else { +// Messages.flash("Post edited.", "success") +// FlowRouter.go('posts.single', post); +// } +// }); +// }, - render() { +// render() { - ({CanEditPost} = Telescope.components); +// ({CanEditPost} = Telescope.components); - const post = this.props.document; +// const post = this.props.document; - const fields = Posts.simpleSchema().getEditableFields(this.props.currentUser); +// const fields = Posts.simpleSchema().getEditableFields(this.props.currentUser); - return ( - -
-

Edit Post “{post.title}”

- - {fields.map(fieldName => NovaForms.getComponent(fieldName, Posts.simpleSchema()._schema[fieldName], post))} - - -
-
- ) - } -}); +// return ( +// +//
+//

Edit Post “{post.title}”

+// +// {fields.map(fieldName => NovaForms.getComponent(fieldName, Posts.simpleSchema()._schema[fieldName], post))} +// +// +//
+//
+// ) +// } +// }); -module.exports = PostEdit; \ No newline at end of file +// module.exports = PostEdit; \ No newline at end of file diff --git a/packages/base-components/lib/posts/PostNew.jsx b/packages/base-components/lib/posts/PostNew.jsx index 6440d0fe0..662851a7d 100644 --- a/packages/base-components/lib/posts/PostNew.jsx +++ b/packages/base-components/lib/posts/PostNew.jsx @@ -1,60 +1,60 @@ -import Core from "meteor/nova:core"; -({Messages, NovaForms} = Core); +// import Core from "meteor/nova:core"; +// ({Messages, NovaForms} = Core); -import Formsy from 'formsy-react'; +// import Formsy from 'formsy-react'; -const PostNew = React.createClass({ +// const PostNew = React.createClass({ - propTypes: { - currentUser: React.PropTypes.object, - postNewCallback: React.PropTypes.func, - closeModal: React.PropTypes.func - }, +// propTypes: { +// currentUser: React.PropTypes.object, +// postNewCallback: React.PropTypes.func, +// closeModal: React.PropTypes.func +// }, - getInitialState() { - return { - canSubmit: false - } - }, +// getInitialState() { +// return { +// canSubmit: false +// } +// }, - submitForm(data) { - // remove any empty properties - post = _.compactObject(data); +// submitForm(data) { +// // remove any empty properties +// post = _.compactObject(data); - post = Telescope.callbacks.run("posts.new.client", post); +// post = Telescope.callbacks.run("posts.new.client", post); - Meteor.call('posts.new', post, (error, post) => { - if (error) { - console.log(error) - Messages.flash(error.message, "error") - } else { - Messages.flash("Post created.", "success"); - FlowRouter.go('posts.single', post); - if (this.props.closeModal) { - this.props.closeModal(); - } - } - }); - }, +// Meteor.call('posts.new', post, (error, post) => { +// if (error) { +// console.log(error) +// Messages.flash(error.message, "error") +// } else { +// Messages.flash("Post created.", "success"); +// FlowRouter.go('posts.single', post); +// if (this.props.closeModal) { +// this.props.closeModal(); +// } +// } +// }); +// }, - render() { +// render() { - ({CanCreatePost} = Telescope.components); +// ({CanCreatePost} = Telescope.components); - const fields = Posts.simpleSchema().getEditableFields(this.props.currentUser); +// const fields = Posts.simpleSchema().getEditableFields(this.props.currentUser); - return ( - -
-

New Post

- - {fields.map(fieldName => NovaForms.getComponent(fieldName, Posts.simpleSchema()._schema[fieldName]))} - - -
-
- ) - } -}); +// return ( +// +//
+//

New Post

+// +// {fields.map(fieldName => NovaForms.getComponent(fieldName, Posts.simpleSchema()._schema[fieldName]))} +// +// +//
+//
+// ) +// } +// }); -module.exports = PostNew; \ No newline at end of file +// module.exports = PostNew; \ No newline at end of file diff --git a/packages/base-components/lib/posts/list/PostItem.jsx b/packages/base-components/lib/posts/list/PostItem.jsx index de9226c35..b51d0075d 100644 --- a/packages/base-components/lib/posts/list/PostItem.jsx +++ b/packages/base-components/lib/posts/list/PostItem.jsx @@ -21,7 +21,7 @@ const PostItem = React.createClass({ renderActions() { - ({ModalButton, ItemContainer, PostEdit} = Telescope.components); + ({ModalButton, ItemContainer, EditDocContainer} = Telescope.components); const component = ( @@ -29,8 +29,9 @@ const PostItem = React.createClass({ collection={Posts} publication="posts.single" terms={{_id: this.props.post._id}} - component={PostEdit} - /> + > + + ); diff --git a/packages/base-components/lib/routes.jsx b/packages/base-components/lib/routes.jsx index 5f5c3174f..6c90e51fb 100644 --- a/packages/base-components/lib/routes.jsx +++ b/packages/base-components/lib/routes.jsx @@ -18,9 +18,8 @@ FlowRouter.route('/', { selector={selector} options={options} terms={queryParams} - component={PostList} joins={Posts.simpleSchema().getJoins()} - />}) + >}) } }); @@ -41,9 +40,8 @@ FlowRouter.route('/posts/:_id', { collection={Posts} publication="posts.single" terms={params} - component={Post} joins={Posts.simpleSchema().getJoins()} - />}); + >}); } }); @@ -56,7 +54,7 @@ FlowRouter.route('/posts/:_id/edit', { publication="posts.single" terms={{_id: params._id}} component={PostEdit} - />}); + >}); } }); @@ -69,8 +67,7 @@ FlowRouter.route('/users/:slug', { collection={Users} publication="users.single" terms={{'telescope.slug': params.slug}} - component={UsersSingle} - />}); + >}); } }); @@ -84,7 +81,7 @@ FlowRouter.route('/account', { publication="users.single" terms={{_id: Meteor.userId()}} component={UsersEdit} - />}); + >}); } }); @@ -98,7 +95,7 @@ FlowRouter.route('/users/:slug/edit', { publication="users.single" terms={params} component={UsersEdit} - />}); + >}); } }); diff --git a/packages/nova-core/lib/components.js b/packages/nova-core/lib/components.js index 39b130d96..5627b7a32 100644 --- a/packages/nova-core/lib/components.js +++ b/packages/nova-core/lib/components.js @@ -3,5 +3,7 @@ Telescope.registerComponent("ItemContainer", require('./containers/ItemContainer Telescope.registerComponent("ListContainer", require('./containers/ListContainer.jsx')); Telescope.registerComponent("FlashContainer", require('./containers/FlashContainer.jsx')); Telescope.registerComponent("CurrentUserContainer", require('./containers/CurrentUserContainer.jsx')); +Telescope.registerComponent("NewDocContainer", require('./containers/NewDocContainer.jsx')); +Telescope.registerComponent("EditDocContainer", require('./containers/EditDocContainer.jsx')); -Telescope.registerComponent("ModalButton", require('./components/ModalButton.jsx')); \ No newline at end of file +Telescope.registerComponent("ModalButton", require('./components/ModalButton.jsx')); diff --git a/packages/nova-core/lib/components/EditDocumentForm.jsx b/packages/nova-core/lib/components/EditDocumentForm.jsx new file mode 100644 index 000000000..941c0b502 --- /dev/null +++ b/packages/nova-core/lib/components/EditDocumentForm.jsx @@ -0,0 +1,54 @@ +// import Messages from "../messages.js"; +// import NovaForms from "../forms.jsx"; + +// import Formsy from 'formsy-react'; + +// const EditDocumentForm = React.createClass({ + +// propTypes: { +// document: React.PropTypes.object.isRequired, +// currentUser: React.PropTypes.object.isRequired, +// collection: React.PropTypes.object.isRequired, +// label: React.PropTypes.string, +// callback: React.PropTypes.func, +// methodName: React.PropTypes.string +// }, + +// submitForm(data) { +// const document = this.props.document; +// const modifier = {$set: _.compactObject(data)}; +// const collection = this.props.collection; +// const methodName = this.props.methodName ? this.props.methodName : collection._name+'.edit'; + +// Meteor.call(methodName, document._id, modifier, (error, document) => { +// if (error) { +// console.log(error) +// Messages.flash(error.message, "error") +// } else { +// Messages.flash("Document edited.", "success"); +// if (this.props.callback) { +// this.props.callback(document); +// } +// } +// }); +// }, + +// render() { + +// const document = this.props.document; +// const collection = this.props.collection; +// const fields = collection.simpleSchema().getEditableFields(this.props.currentUser); + +// return ( +//
+//

{this.props.label}

+// +// {fields.map(fieldName => NovaForms.getComponent(fieldName, collection.simpleSchema()._schema[fieldName], document))} +// +// +//
+// ) +// } +// }); + +// module.exports = EditDocumentForm; \ No newline at end of file diff --git a/packages/nova-core/lib/components/ModalButton.jsx b/packages/nova-core/lib/components/ModalButton.jsx index 64014c510..dc0cd140b 100644 --- a/packages/nova-core/lib/components/ModalButton.jsx +++ b/packages/nova-core/lib/components/ModalButton.jsx @@ -14,7 +14,6 @@ const customStyles = { const ModalButton = React.createClass({ propTypes: { - propsToPass: React.PropTypes.object, label: React.PropTypes.string.isRequired, className: React.PropTypes.string }, @@ -39,7 +38,21 @@ const ModalButton = React.createClass({ // see http://stackoverflow.com/a/32371612/649299 const childrenWithProps = React.Children.map(this.props.children, (child) => { - return React.cloneElement(child, { ...this.props.propsToPass, closeModal: this.closeModal }); + + // if child component already has a callback, create new callback + // that both calls original callback and also closes modal + let callback; + if (child.props.callback) { + callback = (document) => { + child.props.callback(document); + this.closeModal(); + } + } else { + callback = this.closeModal; + } + + return React.cloneElement(child, { callback: callback }); + }); return ( @@ -50,7 +63,6 @@ const ModalButton = React.createClass({ onRequestClose={this.closeModal} style={customStyles} > - {childrenWithProps} diff --git a/packages/nova-core/lib/components/NewDocumentForm.jsx b/packages/nova-core/lib/components/NewDocumentForm.jsx index 7ef3f50eb..a29234951 100644 --- a/packages/nova-core/lib/components/NewDocumentForm.jsx +++ b/packages/nova-core/lib/components/NewDocumentForm.jsx @@ -1,54 +1,58 @@ -import Core from "meteor/nova:core"; -({Messages, NovaForms} = Core); +// import Messages from "../messages.js"; +// import NovaForms from "../forms.jsx"; -import Formsy from 'formsy-react'; +// import Formsy from 'formsy-react'; -const NewDocumentForm = React.createClass({ +// const NewDocumentForm = React.createClass({ - propTypes: { - currentUser: React.PropTypes.object, - categories: React.PropTypes.array, - collection: React.PropTypes.object, - postNewCallback: React.PropTypes.func - }, +// propTypes: { +// currentUser: React.PropTypes.object.isRequired, +// collection: React.PropTypes.object.isRequired, +// label: React.PropTypes.string, +// callback: React.PropTypes.func, +// methodName: React.PropTypes.string +// }, - getInitialState() { - return { - canSubmit: false - } - }, +// getInitialState() { +// return { +// canSubmit: false +// } +// }, - submitForm(data) { - // remove any empty properties - document = _.compactObject(data); +// submitForm(data) { +// // remove any empty properties +// const document = _.compactObject(data); +// const collection = this.props.collection; +// const methodName = this.props.methodName ? this.props.methodName : collection._name+'.create'; - Meteor.call(this.props.collection._name+'.create', document, (error, result) => { - if (error) { - console.log(error) - Messages.flash(error.message, "error") - } else { - Messages.flash("Document created.", "success"); - if (this.props.postNewCallback) { - this.props.postNewCallback(result); - } - } - }); - }, +// Meteor.call(methodName, document, (error, document) => { +// if (error) { +// console.log(error) +// Messages.flash(error.message, "error") +// } else { +// Messages.flash("Document created.", "success"); +// if (this.props.callback) { +// this.props.callback(document); +// } +// } +// }); +// }, - render() { +// render() { - const fields = this.props.collection.simpleSchema().getEditableFields(this.props.currentUser); +// const collection = this.props.collection; +// const fields = collection.simpleSchema().getEditableFields(this.props.currentUser); - return ( -
-

New

- - {fields.map(fieldName => NovaForms.getComponent(fieldName, this.props.collection.simpleSchema()._schema[fieldName]))} - - -
- ) - } -}); +// return ( +//
+//

{this.props.label}

+// +// {fields.map(fieldName => NovaForms.getComponent(fieldName, collection.simpleSchema()._schema[fieldName]))} +// +// +//
+// ) +// } +// }); -module.exports = NewDocumentForm; \ No newline at end of file +// module.exports = NewDocumentForm; \ No newline at end of file diff --git a/packages/nova-core/lib/containers/EditContainer.jsx b/packages/nova-core/lib/containers/EditContainer.jsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/nova-core/lib/containers/EditDocContainer.jsx b/packages/nova-core/lib/containers/EditDocContainer.jsx new file mode 100644 index 000000000..9e7a5ba63 --- /dev/null +++ b/packages/nova-core/lib/containers/EditDocContainer.jsx @@ -0,0 +1,63 @@ +import Messages from "../messages.js"; +import NovaForms from "../forms.jsx"; + +import Formsy from 'formsy-react'; + +const EditDocContainer = React.createClass({ + + propTypes: { + document: React.PropTypes.object, // required but might be passed later on + collection: React.PropTypes.object, // required but might be passed later on + label: React.PropTypes.string, + callback: React.PropTypes.func, + methodName: React.PropTypes.string + }, + + mixins: [ReactMeteorData], + + getMeteorData() { + console.log(this) + + return { + currentUser: Meteor.user() + }; + }, + + submitForm(data) { + const document = this.props.document; + const modifier = {$set: _.compactObject(data)}; + const collection = this.props.collection; + const methodName = this.props.methodName ? this.props.methodName : collection._name+'.edit'; + + Meteor.call(methodName, document._id, modifier, (error, document) => { + if (error) { + console.log(error) + Messages.flash(error.message, "error") + } else { + Messages.flash("Document edited.", "success"); + if (this.props.callback) { + this.props.callback(document); + } + } + }); + }, + + render() { + + const document = this.props.document; + const collection = this.props.collection; + const fields = collection.simpleSchema().getEditableFields(this.data.currentUser); + + return ( +
+

{this.props.label}

+ + {fields.map(fieldName => NovaForms.getComponent(fieldName, collection.simpleSchema()._schema[fieldName], document))} + + +
+ ) + } +}); + +module.exports = EditDocContainer; \ No newline at end of file diff --git a/packages/nova-core/lib/containers/ItemContainer.jsx b/packages/nova-core/lib/containers/ItemContainer.jsx index 23ef8db13..83f7a3ea1 100644 --- a/packages/nova-core/lib/containers/ItemContainer.jsx +++ b/packages/nova-core/lib/containers/ItemContainer.jsx @@ -4,11 +4,10 @@ const ItemContainer = React.createClass({ propTypes: { collection: React.PropTypes.object.isRequired, - component: React.PropTypes.func.isRequired, publication: React.PropTypes.string.isRequired, terms: React.PropTypes.object, - propsToPass: React.PropTypes.object, - joins: React.PropTypes.array + joins: React.PropTypes.array, + callback: React.PropTypes.func // a callback function to pass through, for modals (note: use Redux?) }, mixins: [ReactMeteorData], @@ -55,9 +54,7 @@ const ItemContainer = React.createClass({ const Component = this.props.component; // could be Post or PostEdit if (this.data.document) { - return ( - - ) + return React.cloneElement(this.props.children, { ...this.data, callback: this.props.callback, collection: this.props.collection }); } else { return

Loading…

} diff --git a/packages/nova-core/lib/containers/ListContainer.jsx b/packages/nova-core/lib/containers/ListContainer.jsx index 864f04939..dcef0b458 100644 --- a/packages/nova-core/lib/containers/ListContainer.jsx +++ b/packages/nova-core/lib/containers/ListContainer.jsx @@ -29,7 +29,6 @@ const ListContainer = React.createClass({ propTypes: { collection: React.PropTypes.object.isRequired, // the collection to paginate - component: React.PropTypes.func.isRequired, // the component results will be passed to publication: React.PropTypes.string, // the publication to subscribe to terms: React.PropTypes.object, // an object passed to the publication selector: React.PropTypes.object, // the selector used in collection.find() @@ -134,10 +133,7 @@ const ListContainer = React.createClass({ }, render() { - const Component = this.props.component; - return ( - - ) + return React.cloneElement(this.props.children, { ...this.data, loadMore: this.loadMore}); } }); diff --git a/packages/nova-core/lib/containers/NewContainer.jsx b/packages/nova-core/lib/containers/NewContainer.jsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/nova-core/lib/containers/NewDocContainer.jsx b/packages/nova-core/lib/containers/NewDocContainer.jsx new file mode 100644 index 000000000..f98d4f62f --- /dev/null +++ b/packages/nova-core/lib/containers/NewDocContainer.jsx @@ -0,0 +1,59 @@ +import Messages from "../messages.js"; +import NovaForms from "../forms.jsx"; + +import Formsy from 'formsy-react'; + +const NewDocContainer = React.createClass({ + + propTypes: { + collection: React.PropTypes.object.isRequired, + label: React.PropTypes.string, + callback: React.PropTypes.func, + methodName: React.PropTypes.string + }, + + mixins: [ReactMeteorData], + + getMeteorData() { + return { + currentUser: Meteor.user() + }; + }, + + submitForm(data) { + // remove any empty properties + const document = _.compactObject(data); + const collection = this.props.collection; + const methodName = this.props.methodName ? this.props.methodName : collection._name+'.create'; + + Meteor.call(methodName, document, (error, document) => { + if (error) { + console.log(error) + Messages.flash(error.message, "error") + } else { + Messages.flash("Document created.", "success"); + if (this.props.callback) { + this.props.callback(document); + } + } + }); + }, + + render() { + + const collection = this.props.collection; + const fields = collection.simpleSchema().getEditableFields(this.data.currentUser); + + return ( +
+

{this.props.label}

+ + {fields.map(fieldName => NovaForms.getComponent(fieldName, collection.simpleSchema()._schema[fieldName]))} + + +
+ ) + } +}); + +module.exports = NewDocContainer; \ No newline at end of file