Editorial workflow Drag'nDrop
This commit is contained in:
@ -1,16 +1,25 @@
|
||||
.container {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.column {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
width: 28%;
|
||||
width: 33%;
|
||||
height: 100%;
|
||||
transition: background-color .5s ease;
|
||||
& h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.highlighted {
|
||||
background-color: #e1eeea;
|
||||
}
|
||||
|
||||
.column:not(:last-child) {
|
||||
margin-right: 8%;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.card {
|
||||
@ -30,3 +39,10 @@
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.clear::after {
|
||||
content:"";
|
||||
display:block;
|
||||
clear:both;
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
import React from 'react';
|
||||
import React, { PropTypes } from 'react';
|
||||
import { DragDropContext, DragSource, DropTarget } from 'react-dnd';
|
||||
import HTML5Backend from 'react-dnd-html5-backend';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import moment from 'moment';
|
||||
import { Card } from './UI';
|
||||
@ -6,16 +8,93 @@ import { Link } from 'react-router';
|
||||
import { statusDescriptions } from '../constants/publishModes';
|
||||
import styles from './UnpublishedListing.css';
|
||||
|
||||
export default class UnpublishedListing extends React.Component {
|
||||
const CARD = 'card';
|
||||
|
||||
/*
|
||||
* Column DropTarget Component
|
||||
*/
|
||||
function Column({ connectDropTarget, status, isOver, children }) {
|
||||
const className = isOver ? `${styles.column} ${styles.highlighted}` : styles.column;
|
||||
return connectDropTarget(
|
||||
<div className={className}>
|
||||
<h2>{statusDescriptions.get(status)}</h2>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const columnTargetSpec = {
|
||||
drop(props, monitor) {
|
||||
const slug = monitor.getItem().slug;
|
||||
const collection = monitor.getItem().collection;
|
||||
const oldStatus = monitor.getItem().currentStatus;
|
||||
props.onChangeStatus(collection, slug, oldStatus, props.status);
|
||||
}
|
||||
};
|
||||
|
||||
function columnCollect(connect, monitor) {
|
||||
return {
|
||||
connectDropTarget: connect.dropTarget(),
|
||||
isOver: monitor.isOver()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Column = DropTarget(CARD, columnTargetSpec, columnCollect)(Column);
|
||||
|
||||
|
||||
/*
|
||||
* Card DropTarget Component
|
||||
*/
|
||||
function EntryCard({ connectDragSource, children }) {
|
||||
return connectDragSource(
|
||||
<div>
|
||||
<Card className={styles.card}>
|
||||
{children}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const cardDragSpec = {
|
||||
beginDrag(props) {
|
||||
return {
|
||||
slug: props.slug,
|
||||
collection: props.collection,
|
||||
currentStatus: props.status
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function cardCollect(connect, monitor) {
|
||||
return {
|
||||
connectDragSource: connect.dragSource()
|
||||
};
|
||||
}
|
||||
|
||||
EntryCard = DragSource(CARD, cardDragSpec, cardCollect)(EntryCard);
|
||||
|
||||
/*
|
||||
* The actual exported component implementation
|
||||
*/
|
||||
class UnpublishedListing extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.renderColumns = this.renderColumns.bind(this);
|
||||
}
|
||||
|
||||
renderColumns(entries, column) {
|
||||
if (!entries) return;
|
||||
|
||||
if (!column) {
|
||||
return entries.entrySeq().map(([currColumn, currEntries]) => (
|
||||
<div key={currColumn} className={styles.column}>
|
||||
<h2>{statusDescriptions.get(currColumn)}</h2>
|
||||
<Column
|
||||
key={currColumn}
|
||||
status={currColumn}
|
||||
onChangeStatus={this.props.handleChangeStatus}
|
||||
>
|
||||
{this.renderColumns(currEntries, currColumn)}
|
||||
</div>
|
||||
</Column>
|
||||
));
|
||||
} else {
|
||||
return <div>
|
||||
@ -25,10 +104,15 @@ export default class UnpublishedListing extends React.Component {
|
||||
const timeStamp = moment(entry.getIn(['metaData', 'timeStamp'])).format('llll');
|
||||
const link = `/editorialworkflow/${entry.getIn(['metaData', 'collection'])}/${entry.getIn(['metaData', 'status'])}/${entry.get('slug')}`;
|
||||
return (
|
||||
<Card key={entry.get('slug')} className={styles.card}>
|
||||
<EntryCard
|
||||
key={entry.get('slug')}
|
||||
slug={entry.get('slug')}
|
||||
status={entry.getIn(['metaData', 'status'])}
|
||||
collection={entry.getIn(['metaData', 'collection'])}
|
||||
>
|
||||
<h1><Link to={link}>{entry.getIn(['data', 'title'])}</Link> <small>by {author}</small></h1>
|
||||
<p>Last updated: {timeStamp} by {entry.getIn(['metaData', 'user'])}</p>
|
||||
</Card>
|
||||
</EntryCard>
|
||||
);
|
||||
}
|
||||
)}
|
||||
@ -40,9 +124,11 @@ export default class UnpublishedListing extends React.Component {
|
||||
const columns = this.renderColumns(this.props.entries);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.clear}>
|
||||
<h1>Editorial Workflow</h1>
|
||||
<div className={styles.container}>
|
||||
{columns}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -50,4 +136,7 @@ export default class UnpublishedListing extends React.Component {
|
||||
|
||||
UnpublishedListing.propTypes = {
|
||||
entries: ImmutablePropTypes.orderedMap,
|
||||
handleChangeStatus: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default DragDropContext(HTML5Backend)(UnpublishedListing);
|
||||
|
Reference in New Issue
Block a user