252 lines
6.9 KiB
JavaScript
Raw Normal View History

2016-04-12 10:24:16 +12:00
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
Correct naming for JS and CSS files in client/ Removed some dist/js/*.js files since they're no longer built as individual files. This was a side effect of them living in the toplevel folder of admin/client/src/, which used to have all the legacy/*.js files in there (they do need to be built). Following AirBnB convention: https://github.com/airbnb/javascript#naming--filename-matches-export While it technically allows index.js files, we found them to be bad for dev and debugging in practice: Depending on the used IDE, editor tabs all look the same. Other views like Chrome Dev Tools with sourcemaps rely on path context, and are harder to auto-complete. There's no direct rules for CSS files, but same principles apply here. Also renamed the sections/ folder to containers/, which more clearly communicates the distinction between components/ (shouldn't contain state-dependant, smart components). Renamed state/ files to follow AirBnB naming conventions https://github.com/airbnb/javascript#naming--filename-matches-export https://github.com/airbnb/javascript#naming--camelCase-default-export https://github.com/airbnb/javascript#naming--PascalCase-singleton Leaving the folder name in state/<state-key> lowercase since that's also the key to reducers in the actual state object. References: http://engineering.kapost.com/2016/01/organizing-large-react-applications/ https://github.com/erikras/react-redux-universal-hot-example/tree/master/src https://github.com/RickWong/react-isomorphic-starterkit/tree/master/src https://github.com/react-toolbox/react-toolbox/issues/98 https://github.com/react-bootstrap/react-bootstrap/tree/master/src
2016-04-21 21:59:44 +12:00
import * as recordActions from 'state/records/RecordsActions';
import * as campaignActions from 'state/campaign/CampaignActions';
import SilverStripeComponent from 'lib/SilverStripeComponent';
import Accordion from 'components/Accordion/Accordion';
import AccordionGroup from 'components/Accordion/AccordionGroup';
import AccordionItem from 'components/Accordion/AccordionItem';
import NorthHeader from 'components/NorthHeader/NorthHeader';
import FormAction from 'components/FormAction/FormAction';
import CampaignAdminItem from './CampaignAdminItem';
import BreadcrumbComponent from 'components/Breadcrumb/Breadcrumb';
import Preview from 'components/Preview/Preview';
2016-04-12 09:15:04 +12:00
import i18n from 'i18n';
2016-04-12 10:24:16 +12:00
2016-04-12 10:24:16 +12:00
/**
* Represents a campaign list view
*/
Correct naming for JS and CSS files in client/ Removed some dist/js/*.js files since they're no longer built as individual files. This was a side effect of them living in the toplevel folder of admin/client/src/, which used to have all the legacy/*.js files in there (they do need to be built). Following AirBnB convention: https://github.com/airbnb/javascript#naming--filename-matches-export While it technically allows index.js files, we found them to be bad for dev and debugging in practice: Depending on the used IDE, editor tabs all look the same. Other views like Chrome Dev Tools with sourcemaps rely on path context, and are harder to auto-complete. There's no direct rules for CSS files, but same principles apply here. Also renamed the sections/ folder to containers/, which more clearly communicates the distinction between components/ (shouldn't contain state-dependant, smart components). Renamed state/ files to follow AirBnB naming conventions https://github.com/airbnb/javascript#naming--filename-matches-export https://github.com/airbnb/javascript#naming--camelCase-default-export https://github.com/airbnb/javascript#naming--PascalCase-singleton Leaving the folder name in state/<state-key> lowercase since that's also the key to reducers in the actual state object. References: http://engineering.kapost.com/2016/01/organizing-large-react-applications/ https://github.com/erikras/react-redux-universal-hot-example/tree/master/src https://github.com/RickWong/react-isomorphic-starterkit/tree/master/src https://github.com/react-toolbox/react-toolbox/issues/98 https://github.com/react-bootstrap/react-bootstrap/tree/master/src
2016-04-21 21:59:44 +12:00
class CampaignAdminList extends SilverStripeComponent {
2016-04-12 10:24:16 +12:00
2016-04-12 09:15:04 +12:00
constructor(props) {
super(props);
this.handlePublish = this.handlePublish.bind(this);
}
2016-04-12 10:24:16 +12:00
componentDidMount() {
const fetchURL = this.props.itemListViewEndpoint.replace(/:id/, this.props.campaignId);
super.componentDidMount();
2016-04-12 09:15:04 +12:00
this.props.recordActions.fetchRecord('ChangeSet', 'get', fetchURL);
2016-04-12 10:24:16 +12:00
}
/**
* Renders a list of items in a Campaign.
*
* @return object
*/
render() {
const itemID = 1; // todo - hook up to "click" handler for changesetitems
const campaignId = this.props.campaignId;
const campaign = this.props.record;
2016-04-12 10:24:16 +12:00
// Trigger different layout when preview is enabled
const previewUrl = this.previewURLForItem(itemID);
const itemGroups = this.groupItemsForSet();
const classNames = previewUrl ? 'cms-content__split cms-content__split--left-sm' : 'cms-content__split cms-content__split--none';
2016-04-12 10:24:16 +12:00
// Get items in this set
let accordionGroups = [];
Object.keys(itemGroups).forEach(className => {
const group = itemGroups[className];
const groupCount = group.items.length;
let accordionItems = [];
let title = `${groupCount} ${groupCount === 1 ? group.singular : group.plural}`;
let groupid = `Set_${campaignId}_Group_${className}`;
// Create items for this group
group.items.forEach(item => {
// Add extra css class for published items
let itemClassName = '';
if (item.ChangeType === 'none' || campaign.State === 'published') {
2016-04-12 10:24:16 +12:00
itemClassName = 'list-group-item--published';
}
accordionItems.push(
<AccordionItem key={item.ID} className={itemClassName}>
Correct naming for JS and CSS files in client/ Removed some dist/js/*.js files since they're no longer built as individual files. This was a side effect of them living in the toplevel folder of admin/client/src/, which used to have all the legacy/*.js files in there (they do need to be built). Following AirBnB convention: https://github.com/airbnb/javascript#naming--filename-matches-export While it technically allows index.js files, we found them to be bad for dev and debugging in practice: Depending on the used IDE, editor tabs all look the same. Other views like Chrome Dev Tools with sourcemaps rely on path context, and are harder to auto-complete. There's no direct rules for CSS files, but same principles apply here. Also renamed the sections/ folder to containers/, which more clearly communicates the distinction between components/ (shouldn't contain state-dependant, smart components). Renamed state/ files to follow AirBnB naming conventions https://github.com/airbnb/javascript#naming--filename-matches-export https://github.com/airbnb/javascript#naming--camelCase-default-export https://github.com/airbnb/javascript#naming--PascalCase-singleton Leaving the folder name in state/<state-key> lowercase since that's also the key to reducers in the actual state object. References: http://engineering.kapost.com/2016/01/organizing-large-react-applications/ https://github.com/erikras/react-redux-universal-hot-example/tree/master/src https://github.com/RickWong/react-isomorphic-starterkit/tree/master/src https://github.com/react-toolbox/react-toolbox/issues/98 https://github.com/react-bootstrap/react-bootstrap/tree/master/src
2016-04-21 21:59:44 +12:00
<CampaignAdminItem item={item} campaign={this.props.record} />
2016-04-12 10:24:16 +12:00
</AccordionItem>
);
});
// Merge into group
accordionGroups.push(
<AccordionGroup key={groupid} groupid={groupid} title={title}>
{accordionItems}
</AccordionGroup>
);
});
return (
<div className={classNames}>
<div className="cms-content__left collapse in" aria-expanded="true">
<NorthHeader>
<BreadcrumbComponent crumbs={this.props.breadcrumbs} multiline />
</NorthHeader>
<div className="container-fluid campaign-items panel-scrollable--double-toolbar">
2016-04-12 10:24:16 +12:00
<Accordion>
{accordionGroups}
</Accordion>
</div>
<div className="toolbar--south">
2016-04-12 09:15:04 +12:00
{this.renderButtonToolbar()}
</div>
2016-04-12 10:24:16 +12:00
</div>
Correct naming for JS and CSS files in client/ Removed some dist/js/*.js files since they're no longer built as individual files. This was a side effect of them living in the toplevel folder of admin/client/src/, which used to have all the legacy/*.js files in there (they do need to be built). Following AirBnB convention: https://github.com/airbnb/javascript#naming--filename-matches-export While it technically allows index.js files, we found them to be bad for dev and debugging in practice: Depending on the used IDE, editor tabs all look the same. Other views like Chrome Dev Tools with sourcemaps rely on path context, and are harder to auto-complete. There's no direct rules for CSS files, but same principles apply here. Also renamed the sections/ folder to containers/, which more clearly communicates the distinction between components/ (shouldn't contain state-dependant, smart components). Renamed state/ files to follow AirBnB naming conventions https://github.com/airbnb/javascript#naming--filename-matches-export https://github.com/airbnb/javascript#naming--camelCase-default-export https://github.com/airbnb/javascript#naming--PascalCase-singleton Leaving the folder name in state/<state-key> lowercase since that's also the key to reducers in the actual state object. References: http://engineering.kapost.com/2016/01/organizing-large-react-applications/ https://github.com/erikras/react-redux-universal-hot-example/tree/master/src https://github.com/RickWong/react-isomorphic-starterkit/tree/master/src https://github.com/react-toolbox/react-toolbox/issues/98 https://github.com/react-bootstrap/react-bootstrap/tree/master/src
2016-04-21 21:59:44 +12:00
{ previewUrl && <Preview previewUrl={previewUrl} /> }
2016-04-12 10:24:16 +12:00
</div>
);
}
2016-04-12 09:15:04 +12:00
renderButtonToolbar() {
const items = this.getItems();
2016-04-12 09:15:04 +12:00
// let itemSummaryLabel;
if (!items) {
return <div className="btn-toolbar"></div>;
2016-04-12 09:15:04 +12:00
}
// let itemSummaryLabel = i18n.sprintf(
// items.length === 1
// ? i18n._t('Campaigns.ITEM_SUMMARY_SINGULAR')
// : i18n._t('Campaigns.ITEM_SUMMARY_PLURAL'),
// items.length
// );
let actionProps = {};
if (this.props.record.State === 'open') {
actionProps = Object.assign(actionProps, {
label: i18n._t('Campaigns.PUBLISHCAMPAIGN'),
bootstrapButtonStyle: 'success',
loading: this.props.campaign.isPublishing,
handleClick: this.handlePublish,
icon: 'rocket',
});
} else if (this.props.record.State === 'published') {
// TODO Implement "revert" feature
actionProps = Object.assign(actionProps, {
label: i18n._t('Campaigns.REVERTCAMPAIGN'),
bootstrapButtonStyle: 'default',
icon: 'back-in-time',
disabled: true,
});
}
// TODO Fix indicator positioning
// const itemCountIndicator = (
// <span className="text-muted">
// <span className="label label-warning label--empty">&nbsp;</span>
// &nbsp;{itemSummaryLabel}
// </span>
// );
return (
<div className="btn-toolbar">
<FormAction {...actionProps} />
</div>
);
2016-04-12 09:15:04 +12:00
}
2016-04-12 10:24:16 +12:00
/**
* Gets preview URL for itemid
* @param int id
* @returns string
*/
previewURLForItem(id) {
if (!id) {
return '';
}
// hard code in baseurl for any itemid preview url
return document.getElementsByTagName('base')[0].href;
}
2016-04-12 09:15:04 +12:00
/**
* @return {Array}
*/
getItems() {
if (this.props.record && this.props.record._embedded) {
return this.props.record._embedded.ChangeSetItems;
}
return null;
}
2016-04-12 10:24:16 +12:00
/**
* Group items for changeset display
*
* @return array
*/
groupItemsForSet() {
const groups = {};
2016-04-12 09:15:04 +12:00
const items = this.getItems();
if (!items) {
2016-04-12 10:24:16 +12:00
return groups;
}
// group by whatever
items.forEach(item => {
// Create new group if needed
const classname = item.BaseClass;
if (!groups[classname]) {
groups[classname] = {
singular: item.Singular,
plural: item.Plural,
items: [],
};
}
// Push items
groups[classname].items.push(item);
});
return groups;
}
2016-04-12 09:15:04 +12:00
handlePublish(e) {
e.preventDefault();
this.props.campaignActions.publishCampaign(
this.props.publishApi,
this.props.campaignId
);
}
2016-04-12 10:24:16 +12:00
}
Correct naming for JS and CSS files in client/ Removed some dist/js/*.js files since they're no longer built as individual files. This was a side effect of them living in the toplevel folder of admin/client/src/, which used to have all the legacy/*.js files in there (they do need to be built). Following AirBnB convention: https://github.com/airbnb/javascript#naming--filename-matches-export While it technically allows index.js files, we found them to be bad for dev and debugging in practice: Depending on the used IDE, editor tabs all look the same. Other views like Chrome Dev Tools with sourcemaps rely on path context, and are harder to auto-complete. There's no direct rules for CSS files, but same principles apply here. Also renamed the sections/ folder to containers/, which more clearly communicates the distinction between components/ (shouldn't contain state-dependant, smart components). Renamed state/ files to follow AirBnB naming conventions https://github.com/airbnb/javascript#naming--filename-matches-export https://github.com/airbnb/javascript#naming--camelCase-default-export https://github.com/airbnb/javascript#naming--PascalCase-singleton Leaving the folder name in state/<state-key> lowercase since that's also the key to reducers in the actual state object. References: http://engineering.kapost.com/2016/01/organizing-large-react-applications/ https://github.com/erikras/react-redux-universal-hot-example/tree/master/src https://github.com/RickWong/react-isomorphic-starterkit/tree/master/src https://github.com/react-toolbox/react-toolbox/issues/98 https://github.com/react-bootstrap/react-bootstrap/tree/master/src
2016-04-21 21:59:44 +12:00
CampaignAdminList.propTypes = {
campaign: React.PropTypes.shape({
isPublishing: React.PropTypes.bool.isRequired,
}),
campaignActions: React.PropTypes.object.isRequired,
2016-04-12 09:15:04 +12:00
publishApi: React.PropTypes.func.isRequired,
record: React.PropTypes.object.isRequired,
recordActions: React.PropTypes.object.isRequired,
2016-04-12 09:15:04 +12:00
};
2016-04-12 10:24:16 +12:00
function mapStateToProps(state, ownProps) {
// Find record specific to this item
let record = null;
if (state.records && state.records.ChangeSet && ownProps.campaignId) {
record = state.records.ChangeSet[parseInt(ownProps.campaignId, 10)];
2016-04-12 10:24:16 +12:00
}
return {
record: record || {},
2016-04-13 10:12:42 +12:00
campaign: state.campaign,
2016-04-12 10:24:16 +12:00
};
}
function mapDispatchToProps(dispatch) {
return {
2016-04-12 09:15:04 +12:00
recordActions: bindActionCreators(recordActions, dispatch),
campaignActions: bindActionCreators(campaignActions, dispatch),
2016-04-12 10:24:16 +12:00
};
}
Correct naming for JS and CSS files in client/ Removed some dist/js/*.js files since they're no longer built as individual files. This was a side effect of them living in the toplevel folder of admin/client/src/, which used to have all the legacy/*.js files in there (they do need to be built). Following AirBnB convention: https://github.com/airbnb/javascript#naming--filename-matches-export While it technically allows index.js files, we found them to be bad for dev and debugging in practice: Depending on the used IDE, editor tabs all look the same. Other views like Chrome Dev Tools with sourcemaps rely on path context, and are harder to auto-complete. There's no direct rules for CSS files, but same principles apply here. Also renamed the sections/ folder to containers/, which more clearly communicates the distinction between components/ (shouldn't contain state-dependant, smart components). Renamed state/ files to follow AirBnB naming conventions https://github.com/airbnb/javascript#naming--filename-matches-export https://github.com/airbnb/javascript#naming--camelCase-default-export https://github.com/airbnb/javascript#naming--PascalCase-singleton Leaving the folder name in state/<state-key> lowercase since that's also the key to reducers in the actual state object. References: http://engineering.kapost.com/2016/01/organizing-large-react-applications/ https://github.com/erikras/react-redux-universal-hot-example/tree/master/src https://github.com/RickWong/react-isomorphic-starterkit/tree/master/src https://github.com/react-toolbox/react-toolbox/issues/98 https://github.com/react-bootstrap/react-bootstrap/tree/master/src
2016-04-21 21:59:44 +12:00
export default connect(mapStateToProps, mapDispatchToProps)(CampaignAdminList);