Skip to content
This repository has been archived by the owner on May 31, 2024. It is now read-only.

Commit

Permalink
refactoring example-forum package
Browse files Browse the repository at this point in the history
  • Loading branch information
SachaG committed Sep 4, 2017
1 parent d0eef54 commit 0a48d0c
Show file tree
Hide file tree
Showing 128 changed files with 6,284 additions and 15 deletions.
1 change: 1 addition & 0 deletions packages/example-forum/lib/client/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../modules/index.js';
12 changes: 12 additions & 0 deletions packages/example-forum/lib/components/admin/AdminUsersPosts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import Posts from '../../modules/posts/index.js';
import { Link } from 'react-router';

const AdminUsersPosts = ({ document: user }) =>
<ul>
{user.posts && user.posts.map(post =>
<li key={post._id}><Link to={Posts.getLink(post)}>{post.title}</Link></li>
)}
</ul>

export default AdminUsersPosts;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import PropTypes from 'prop-types';
import { intlShape } from 'meteor/vulcan:i18n';
import { Components, registerComponent, getFragment, withMessages } from 'meteor/vulcan:core';
import Categories from '../../modules/categories/index.js';

const CategoriesEditForm = (props, context) => {

return (
<div className="categories-edit-form">
<div className="categories-edit-form-admin">
<div className="categories-edit-form-id">ID: {props.category._id}</div>
</div>
<Components.SmartForm
collection={Categories}
documentId={props.category._id}
mutationFragment={getFragment('CategoriesList')}
successCallback={category => {
props.closeModal();
props.flash(context.intl.formatMessage({ id: 'categories.edit_success' }, { name: category.name }), 'success');
}}
removeSuccessCallback={({ documentId, documentTitle }) => {
props.closeModal();
props.flash(context.intl.formatMessage({ id: 'categories.delete_success' }, { name: documentTitle }), 'success');
// context.events.track("category deleted", {_id: documentId});
}}
showRemove={true}
/>
</div>
);
};

CategoriesEditForm.propTypes = {
category: PropTypes.object.isRequired,
closeModal: PropTypes.func,
flash: PropTypes.func,
};

CategoriesEditForm.contextTypes = {
intl: intlShape,
};

registerComponent('CategoriesEditForm', CategoriesEditForm, withMessages);
123 changes: 123 additions & 0 deletions packages/example-forum/lib/components/categories/CategoriesList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { ModalTrigger, Components, registerComponent, withList, Utils } from "meteor/vulcan:core";
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'meteor/vulcan:i18n';
import Button from 'react-bootstrap/lib/Button';
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
import MenuItem from 'react-bootstrap/lib/MenuItem';
import { withRouter } from 'react-router'
import { LinkContainer } from 'react-router-bootstrap';
import Categories from '../../modules/categories/index.js';
import { withApollo } from 'react-apollo';

class CategoriesList extends PureComponent {

constructor() {
super();
this.getCurrentCategoriesArray = this.getCurrentCategoriesArray.bind(this);
this.getCategoryLink = this.getCategoryLink.bind(this);
}

getCurrentCategoriesArray() {
const currentCategories = _.clone(this.props.location.query.cat);
if (currentCategories) {
return Array.isArray(currentCategories) ? currentCategories : [currentCategories]
} else {
return [];
}
}

getCategoryLink(slug) {
const categories = this.getCurrentCategoriesArray();
return {
pathname: '/',
query: {
...this.props.location.query,
cat: categories.includes(slug) ? _.without(categories, slug) : categories.concat([slug])
}
}
}

getNestedCategories() {
const categories = this.props.results;

// check if a category is currently active in the route
const currentCategorySlug = this.props.router.location.query && this.props.router.location.query.cat;
const currentCategory = Categories.findOneInStore(this.props.client.store, {slug: currentCategorySlug});
const parentCategories = Categories.getParents(currentCategory, this.props.client.store);

// decorate categories with active and expanded properties
const categoriesClone = _.map(categories, category => {
return {
...category, // we don't want to modify the objects we got from props
active: currentCategory && category.slug === currentCategory.slug,
expanded: parentCategories && _.contains(_.pluck(parentCategories, 'slug'), category.slug)
};
});

const nestedCategories = Utils.unflatten(categoriesClone, {idProperty: '_id', parentIdProperty: 'parentId'});

return nestedCategories;
}

render() {

const allCategoriesQuery = _.clone(this.props.router.location.query);
delete allCategoriesQuery.cat;
const nestedCategories = this.getNestedCategories();

return (
<div>
<DropdownButton
bsStyle="default"
className="categories-list btn-secondary"
title={<FormattedMessage id="categories"/>}
id="categories-dropdown"
>
<div className="category-menu-item category-menu-item-all dropdown-item">
<LinkContainer className="category-menu-item-title" to={{pathname:"/", query: allCategoriesQuery}}>
<MenuItem eventKey={0}>
<FormattedMessage id="categories.all"/>
</MenuItem>
</LinkContainer>
</div>
{
// categories data are loaded
!this.props.loading ?
// there are currently categories
nestedCategories && nestedCategories.length > 0 ?
nestedCategories.map((category, index) => <Components.CategoriesNode key={index} category={category} index={index} openModal={this.openCategoryEditModal}/>)
// not any category found
: null
// categories are loading
: <div className="dropdown-item"><MenuItem><Components.Loading /></MenuItem></div>
}
<Components.ShowIf check={Categories.options.mutations.new.check}>
<div className="categories-new-button category-menu-item dropdown-item">
<ModalTrigger title={<FormattedMessage id="categories.new"/>} component={<Button bsStyle="primary"><FormattedMessage id="categories.new"/></Button>}>
<Components.CategoriesNewForm/>
</ModalTrigger>
</div>
</Components.ShowIf>
</DropdownButton>

</div>
)

}
}

CategoriesList.propTypes = {
results: PropTypes.array,
};


const options = {
collection: Categories,
queryName: 'categoriesListQuery',
fragmentName: 'CategoriesList',
limit: 0,
pollInterval: 0,
};

registerComponent('CategoriesList', CategoriesList, withRouter, withApollo, [withList, options]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import PropTypes from 'prop-types';
import { intlShape } from 'meteor/vulcan:i18n';
import { Components, registerComponent, getFragment, withMessages } from 'meteor/vulcan:core';
import Categories from '../../modules/categories/index.js';

const CategoriesNewForm = (props, context) => {

return (
<div className="categories-new-form">
<Components.SmartForm
collection={Categories}
mutationFragment={getFragment('CategoriesList')}
successCallback={category => {
props.closeModal();
props.flash(context.intl.formatMessage({id: 'categories.new_success'}, {name: category.name}), "success");
}}
/>
</div>
)
}

CategoriesNewForm.displayName = "CategoriesNewForm";

CategoriesNewForm.propTypes = {
closeCallback: PropTypes.func,
flash: PropTypes.func,
};

CategoriesNewForm.contextTypes = {
intl: intlShape,
};

registerComponent('CategoriesNewForm', CategoriesNewForm, withMessages);
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Components, registerComponent } from 'meteor/vulcan:core';
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

class CategoriesNode extends PureComponent {

renderCategory(category) {
return (
<Components.Category category={category} key={category._id} openModal={this.props.openModal} />
)
}

renderChildren(children) {
return (
<div className="categories-children">
{children.map(category => <CategoriesNode category={category} key={category._id} />)}
</div>
)
}

render() {

const category = this.props.category;
const children = this.props.category.childrenResults;

return (
<div className="categories-node">
{this.renderCategory(category)}
{children ? this.renderChildren(children) : null}
</div>
)
}

}

CategoriesNode.propTypes = {
category: PropTypes.object.isRequired, // the current category
};

registerComponent('CategoriesNode', CategoriesNode);
52 changes: 52 additions & 0 deletions packages/example-forum/lib/components/categories/Category.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { ModalTrigger, Components, registerComponent } from 'meteor/vulcan:core';
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { LinkContainer } from 'react-router-bootstrap';
import MenuItem from 'react-bootstrap/lib/MenuItem'
import { withRouter } from 'react-router'
import Categories from '../../modules/categories/index.js';

class Category extends PureComponent {

renderEdit() {
return (
<ModalTrigger title="Edit Category" component={<a className="edit-category-link"><Components.Icon name="edit"/></a>}>
<Components.CategoriesEditForm category={this.props.category}/>
</ModalTrigger>
)
}

render() {

const {category, index, router} = this.props;

// const currentQuery = router.location.query;
const currentCategorySlug = router.location.query.cat;
const newQuery = _.clone(router.location.query);
newQuery.cat = category.slug;

return (
<div className="category-menu-item dropdown-item">
<LinkContainer to={{pathname:"/", query: newQuery}}>
<MenuItem
eventKey={index+1}
key={category._id}
>
{currentCategorySlug === category.slug ? <Components.Icon name="voted"/> : null}
{category.name}
</MenuItem>
</LinkContainer>
<Components.ShowIf check={Categories.options.mutations.edit.check} document={category}>{this.renderEdit()}</Components.ShowIf>
</div>
)
}
}

Category.propTypes = {
category: PropTypes.object,
index: PropTypes.number,
currentCategorySlug: PropTypes.string,
openModal: PropTypes.func
};

registerComponent('Category', Category, withRouter);
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Components, registerComponent, getFragment, withMessages } from 'meteor/vulcan:core';
import React from 'react';
import PropTypes from 'prop-types';
import Comments from '../../modules/comments/index.js';

const CommentsEditForm = (props, context) => {
return (
<div className="comments-edit-form">
<Components.SmartForm
layout="elementOnly"
collection={Comments}
documentId={props.comment._id}
successCallback={props.successCallback}
cancelCallback={props.cancelCallback}
removeSuccessCallback={props.removeSuccessCallback}
showRemove={true}
mutationFragment={getFragment('CommentsList')}
/>
</div>
)
}

CommentsEditForm.propTypes = {
comment: PropTypes.object.isRequired,
successCallback: PropTypes.func,
cancelCallback: PropTypes.func
};

registerComponent('CommentsEditForm', CommentsEditForm, withMessages);

0 comments on commit 0a48d0c

Please sign in to comment.