2016-04-12 10:24:16 +12:00
|
|
|
import React from 'react';
|
|
|
|
import { bindActionCreators } from 'redux';
|
|
|
|
import { connect } from 'react-redux';
|
2016-05-09 14:16:17 +12:00
|
|
|
import * as breadcrumbsActions from 'state/breadcrumbs/BreadcrumbsActions';
|
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';
|
2016-04-26 17:45:51 +12:00
|
|
|
import AccordionBlock from 'components/Accordion/AccordionBlock';
|
|
|
|
import ListGroupItem from 'components/ListGroup/ListGroupItem';
|
2016-04-26 10:47:07 +12:00
|
|
|
import Toolbar from 'components/Toolbar/Toolbar';
|
2016-04-21 21:59:44 +12:00
|
|
|
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-18 16:48:07 +12:00
|
|
|
|
2016-04-12 10:24:16 +12:00
|
|
|
/**
|
|
|
|
* Represents a campaign list view
|
|
|
|
*/
|
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-27 14:26:39 +12:00
|
|
|
this.handleItemSelected = this.handleItemSelected.bind(this);
|
2016-05-09 14:16:17 +12:00
|
|
|
this.setBreadcrumbs = this.setBreadcrumbs.bind(this);
|
2016-04-12 09:15:04 +12:00
|
|
|
}
|
|
|
|
|
2016-04-12 10:24:16 +12:00
|
|
|
componentDidMount() {
|
|
|
|
const fetchURL = this.props.itemListViewEndpoint.replace(/:id/, this.props.campaignId);
|
|
|
|
super.componentDidMount();
|
2016-05-09 14:16:17 +12:00
|
|
|
this.setBreadcrumbs();
|
|
|
|
this.props.recordActions.fetchRecord('ChangeSet', 'get', fetchURL).then(this.setBreadcrumbs);
|
|
|
|
}
|
2016-05-09 14:16:17 +12:00
|
|
|
|
2016-05-09 14:16:17 +12:00
|
|
|
/**
|
|
|
|
* Update breadcrumbs for this view
|
|
|
|
*/
|
|
|
|
setBreadcrumbs() {
|
|
|
|
// Setup breadcrumbs if record is loaded
|
|
|
|
if (!this.props.record) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-09 14:16:17 +12:00
|
|
|
|
2016-05-09 14:16:17 +12:00
|
|
|
// Check that we haven't navigated away from this page once the callback has returned
|
|
|
|
const thisLink = this.props.sectionConfig.campaignViewRoute
|
|
|
|
.replace(/:type\?/, 'set')
|
|
|
|
.replace(/:id\?/, this.props.campaignId)
|
|
|
|
.replace(/:view\?/, 'show');
|
|
|
|
const applies = window.ss.router.routeAppliesToCurrentLocation(
|
|
|
|
window.ss.router.resolveURLToBase(thisLink)
|
|
|
|
);
|
|
|
|
if (!applies) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-09 14:16:17 +12:00
|
|
|
|
2016-05-09 14:16:17 +12:00
|
|
|
// Push breadcrumb
|
|
|
|
const breadcrumbs = this.props.baseBreadcrumbs.slice(0);
|
|
|
|
breadcrumbs.push({
|
|
|
|
text: this.props.record.Name,
|
|
|
|
href: thisLink,
|
|
|
|
});
|
2016-05-09 14:16:17 +12:00
|
|
|
|
2016-05-09 14:16:17 +12:00
|
|
|
this.props.breadcrumbsActions.setBreadcrumbs(breadcrumbs);
|
2016-04-12 10:24:16 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Renders a list of items in a Campaign.
|
|
|
|
*
|
|
|
|
* @return object
|
|
|
|
*/
|
|
|
|
render() {
|
2016-04-27 14:26:39 +12:00
|
|
|
let itemID = this.props.campaign.changeSetItemId;
|
2016-05-03 11:08:09 +12:00
|
|
|
let itemLinks = null;
|
2016-04-12 10:24:16 +12:00
|
|
|
const campaignId = this.props.campaignId;
|
2016-04-13 13:17:32 +12:00
|
|
|
const campaign = this.props.record;
|
2016-04-12 10:24:16 +12:00
|
|
|
|
|
|
|
// Trigger different layout when preview is enabled
|
|
|
|
const itemGroups = this.groupItemsForSet();
|
|
|
|
|
|
|
|
// Get items in this set
|
2016-04-26 17:45:51 +12:00
|
|
|
let accordionBlocks = [];
|
|
|
|
|
2016-04-12 10:24:16 +12:00
|
|
|
Object.keys(itemGroups).forEach(className => {
|
|
|
|
const group = itemGroups[className];
|
|
|
|
const groupCount = group.items.length;
|
|
|
|
|
2016-04-26 17:45:51 +12:00
|
|
|
let listGroupItems = [];
|
2016-04-12 10:24:16 +12:00
|
|
|
let title = `${groupCount} ${groupCount === 1 ? group.singular : group.plural}`;
|
|
|
|
let groupid = `Set_${campaignId}_Group_${className}`;
|
|
|
|
|
|
|
|
// Create items for this group
|
|
|
|
group.items.forEach(item => {
|
2016-04-27 14:26:39 +12:00
|
|
|
// Auto-select first item
|
|
|
|
if (!itemID) {
|
|
|
|
itemID = item.ID;
|
|
|
|
}
|
|
|
|
const selected = (itemID === item.ID);
|
2016-05-03 11:08:09 +12:00
|
|
|
|
|
|
|
// Check links
|
2016-04-27 14:26:39 +12:00
|
|
|
if (selected && item._links.preview) {
|
2016-05-03 11:08:09 +12:00
|
|
|
itemLinks = item._links;
|
2016-04-27 14:26:39 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add extra css class for published items
|
|
|
|
const itemClassNames = [];
|
2016-04-13 13:17:32 +12:00
|
|
|
if (item.ChangeType === 'none' || campaign.State === 'published') {
|
2016-05-03 13:03:12 +12:00
|
|
|
itemClassNames.push('list-group-item--inactive');
|
2016-04-27 14:26:39 +12:00
|
|
|
}
|
|
|
|
if (selected) {
|
|
|
|
itemClassNames.push('active');
|
2016-04-12 10:24:16 +12:00
|
|
|
}
|
|
|
|
|
2016-04-26 17:45:51 +12:00
|
|
|
listGroupItems.push(
|
|
|
|
<ListGroupItem
|
|
|
|
key={item.ID}
|
|
|
|
className={itemClassNames.join(' ')}
|
|
|
|
handleClick={this.handleItemSelected}
|
|
|
|
handleClickArg={item.ID}
|
|
|
|
>
|
2016-04-21 21:59:44 +12:00
|
|
|
<CampaignAdminItem item={item} campaign={this.props.record} />
|
2016-04-26 17:45:51 +12:00
|
|
|
</ListGroupItem>
|
2016-04-12 10:24:16 +12:00
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Merge into group
|
2016-04-26 17:45:51 +12:00
|
|
|
accordionBlocks.push(
|
|
|
|
<AccordionBlock key={groupid} groupid={groupid} title={title}>
|
|
|
|
{listGroupItems}
|
|
|
|
</AccordionBlock>
|
2016-04-12 10:24:16 +12:00
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-04-27 14:26:39 +12:00
|
|
|
// Get preview details
|
2016-05-03 11:08:09 +12:00
|
|
|
const classNames = itemLinks
|
2016-04-27 14:26:39 +12:00
|
|
|
? 'cms-content__split cms-content__split--left-sm'
|
|
|
|
: 'cms-content__split cms-content__split--none';
|
|
|
|
|
2016-04-12 10:24:16 +12:00
|
|
|
return (
|
|
|
|
<div className={classNames}>
|
2016-05-09 14:16:17 +12:00
|
|
|
<div className="cms-content__left cms-campaigns collapse in" aria-expanded="true">
|
|
|
|
<Toolbar showBackButton handleBackButtonClick={this.props.handleBackButtonClick}>
|
2016-05-09 14:16:17 +12:00
|
|
|
<BreadcrumbComponent multiline crumbs={this.props.breadcrumbs} />
|
2016-04-26 10:47:07 +12:00
|
|
|
</Toolbar>
|
2016-04-21 10:17:20 +12:00
|
|
|
<div className="container-fluid campaign-items panel-scrollable--double-toolbar">
|
2016-04-12 10:24:16 +12:00
|
|
|
<Accordion>
|
2016-04-26 17:45:51 +12:00
|
|
|
{accordionBlocks}
|
2016-04-12 10:24:16 +12:00
|
|
|
</Accordion>
|
|
|
|
</div>
|
2016-04-19 16:37:25 +12:00
|
|
|
<div className="toolbar--south">
|
2016-04-12 09:15:04 +12:00
|
|
|
{this.renderButtonToolbar()}
|
|
|
|
</div>
|
2016-04-12 10:24:16 +12:00
|
|
|
</div>
|
2016-05-03 11:08:09 +12:00
|
|
|
{ itemLinks && <Preview itemLinks={itemLinks} /> }
|
2016-04-12 10:24:16 +12:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-04-27 14:26:39 +12:00
|
|
|
/**
|
|
|
|
* Callback for items being clicked on
|
|
|
|
*
|
|
|
|
* @param {object} event
|
|
|
|
* @param {number} itemId
|
|
|
|
*/
|
|
|
|
handleItemSelected(event, itemId) {
|
|
|
|
this.props.campaignActions.selectChangeSetItem(itemId);
|
|
|
|
}
|
|
|
|
|
2016-04-12 09:15:04 +12:00
|
|
|
renderButtonToolbar() {
|
2016-04-14 14:01:50 +12:00
|
|
|
const items = this.getItems();
|
2016-04-12 09:15:04 +12:00
|
|
|
|
2016-04-14 14:01:50 +12:00
|
|
|
// let itemSummaryLabel;
|
|
|
|
if (!items) {
|
|
|
|
return <div className="btn-toolbar"></div>;
|
2016-04-12 09:15:04 +12:00
|
|
|
}
|
|
|
|
|
2016-04-14 14:01:50 +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'),
|
2016-05-03 18:29:28 +12:00
|
|
|
bootstrapButtonStyle: 'primary',
|
2016-04-14 14:01:50 +12:00
|
|
|
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"> </span>
|
|
|
|
// {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
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-04-21 21:59:44 +12:00
|
|
|
CampaignAdminList.propTypes = {
|
2016-04-14 14:01:50 +12:00
|
|
|
campaign: React.PropTypes.shape({
|
|
|
|
isPublishing: React.PropTypes.bool.isRequired,
|
2016-04-27 14:26:39 +12:00
|
|
|
changeSetItemId: React.PropTypes.number,
|
2016-04-14 14:01:50 +12:00
|
|
|
}),
|
2016-05-09 14:16:17 +12:00
|
|
|
breadcrumbsActions: React.PropTypes.object.isRequired,
|
2016-04-14 14:01:50 +12:00
|
|
|
campaignActions: React.PropTypes.object.isRequired,
|
2016-04-12 09:15:04 +12:00
|
|
|
publishApi: React.PropTypes.func.isRequired,
|
2016-04-14 14:01:50 +12:00
|
|
|
record: React.PropTypes.object.isRequired,
|
|
|
|
recordActions: React.PropTypes.object.isRequired,
|
2016-05-09 14:16:17 +12:00
|
|
|
baseBreadcrumbs: React.PropTypes.array.isRequired,
|
|
|
|
sectionConfig: React.PropTypes.object.isRequired,
|
|
|
|
handleBackButtonClick: React.PropTypes.func,
|
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) {
|
2016-04-13 10:12:14 +12:00
|
|
|
record = state.records.ChangeSet[parseInt(ownProps.campaignId, 10)];
|
2016-04-12 10:24:16 +12:00
|
|
|
}
|
|
|
|
return {
|
2016-04-14 14:01:50 +12:00
|
|
|
record: record || {},
|
2016-04-13 10:12:42 +12:00
|
|
|
campaign: state.campaign,
|
2016-05-09 14:16:17 +12:00
|
|
|
breadcrumbs: state.breadcrumbs,
|
2016-04-12 10:24:16 +12:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function mapDispatchToProps(dispatch) {
|
|
|
|
return {
|
2016-05-09 14:16:17 +12:00
|
|
|
breadcrumbsActions: bindActionCreators(breadcrumbsActions, dispatch),
|
2016-04-12 09:15:04 +12:00
|
|
|
recordActions: bindActionCreators(recordActions, dispatch),
|
|
|
|
campaignActions: bindActionCreators(campaignActions, dispatch),
|
2016-04-12 10:24:16 +12:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-04-21 21:59:44 +12:00
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(CampaignAdminList);
|