diff --git a/src/actions/editorialWorkflow.js b/src/actions/editorialWorkflow.js index 5c906f1c..ee44f857 100644 --- a/src/actions/editorialWorkflow.js +++ b/src/actions/editorialWorkflow.js @@ -4,6 +4,10 @@ import { EDITORIAL_WORKFLOW } from '../constants/publishModes'; * Contant Declarations */ export const INIT = 'init'; + +export const UNPUBLISHED_ENTRY_REQUEST = 'UNPUBLISHED_ENTRY_REQUEST'; +export const UNPUBLISHED_ENTRY_SUCCESS = 'UNPUBLISHED_ENTRY_SUCCESS'; + export const UNPUBLISHED_ENTRIES_REQUEST = 'UNPUBLISHED_ENTRIES_REQUEST'; export const UNPUBLISHED_ENTRIES_SUCCESS = 'UNPUBLISHED_ENTRIES_SUCCESS'; export const UNPUBLISHED_ENTRIES_FAILURE = 'UNPUBLISHED_ENTRIES_FAILURE'; @@ -12,6 +16,21 @@ export const UNPUBLISHED_ENTRIES_FAILURE = 'UNPUBLISHED_ENTRIES_FAILURE'; /* * Simple Action Creators (Internal) */ + +function unpublishedEntryLoading(collection, slug) { + return { + type: UNPUBLISHED_ENTRY_REQUEST, + payload: { collection, slug } + }; +} + +function unpublishedEntryLoaded(entry) { + return { + type: UNPUBLISHED_ENTRY_SUCCESS, + payload: { entry } + }; +} + function unpublishedEntriesLoading() { return { type: UNPUBLISHED_ENTRIES_REQUEST @@ -49,6 +68,17 @@ export function init() { /* * Exported Thunk Action Creators */ + +export function loadUnpublishedEntry(collection, slug) { + return (dispatch, getState) => { + const state = getState(); + const backend = currentBackend(state.config); + dispatch(unpublishedEntryLoading(collection, slug)); + backend.unpublishedEntry(collection, slug) + .then((entry) => dispatch(unpublishedEntryLoaded(entry))); + }; +} + export function loadUnpublishedEntries() { return (dispatch, getState) => { const state = getState(); diff --git a/src/backends/backend.js b/src/backends/backend.js index 66fbd33c..c2c4d100 100644 --- a/src/backends/backend.js +++ b/src/backends/backend.js @@ -83,6 +83,10 @@ class Backend { }); } + unpublishedEntry(collection, slug) { + return this.implementation.unpublishedEntry(collection, slug).then(this.entryWithFormat(collection)); + } + slugFormatter(template, entry) { var date = new Date(); return template.replace(/\{\{([^\}]+)\}\}/g, function(_, name) { diff --git a/src/backends/github/implementation.js b/src/backends/github/implementation.js index a4540ce1..6ce1c865 100644 --- a/src/backends/github/implementation.js +++ b/src/backends/github/implementation.js @@ -90,4 +90,12 @@ export default class GitHub { }; }); } + + unpublishedEntry(collection, slug) { + return this.unpublishedEntries().then((response) => ( + response.entries.filter((entry) => ( + entry.metaData && entry.metaData.collection === collection.get('name') && entry.slug === slug + ))[0] + )); + } } diff --git a/src/components/UnpublishedListing.js b/src/components/UnpublishedListing.js index e43c8b07..af179aac 100644 --- a/src/components/UnpublishedListing.js +++ b/src/components/UnpublishedListing.js @@ -2,6 +2,7 @@ import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import dateFormat from 'dateFormat'; import { Card } from './UI'; +import { Link } from 'react-router' import { statusDescriptions } from '../constants/publishModes'; import styles from './UnpublishedListing.css'; @@ -22,9 +23,10 @@ export default class UnpublishedListing extends React.Component { // Look for an "author" field. Fallback to username on backend implementation; const author = entry.getIn(['data', 'author'], entry.getIn(['metaData', 'user'])); const timeStamp = dateFormat(Date.parse(entry.getIn(['metaData', 'timeStamp'])), 'longDate'); + const link = `/editorialworkflow/${entry.getIn(['metaData', 'collection'])}/${entry.getIn(['metaData', 'status'])}/${entry.get('slug')}`; return ( -

{entry.getIn(['data', 'title'])} by {author}

+

{entry.getIn(['data', 'title'])} by {author}

Last updated: {timeStamp} by {entry.getIn(['metaData', 'user'])}

); diff --git a/src/containers/CollectionPage.js b/src/containers/CollectionPage.js index 5790fbf0..96143bad 100644 --- a/src/containers/CollectionPage.js +++ b/src/containers/CollectionPage.js @@ -5,7 +5,7 @@ import { loadEntries } from '../actions/entries'; import { selectEntries } from '../reducers'; import { Loader } from '../components/UI'; import EntryListing from '../components/EntryListing'; -import EditorialWorkflow from './EditorialWorkflowHoC'; +import CollectionPageHOC from './editorialWorkflow/CollectionPageHOC'; class DashboardPage extends React.Component { componentDidMount() { @@ -48,7 +48,7 @@ DashboardPage.propTypes = { * Instead of checking the publish mode everywhere to dispatch & render the additional editorial workflow stuff, * We delegate it to a Higher Order Component */ -DashboardPage = EditorialWorkflow(DashboardPage); +DashboardPage = CollectionPageHOC(DashboardPage); function mapStateToProps(state, ownProps) { diff --git a/src/containers/EntryPage.js b/src/containers/EntryPage.js index 81c9947b..ecb2cda2 100644 --- a/src/containers/EntryPage.js +++ b/src/containers/EntryPage.js @@ -12,6 +12,7 @@ import { import { addMedia, removeMedia } from '../actions/media'; import { selectEntry, getMedia } from '../reducers'; import EntryEditor from '../components/EntryEditor'; +import EntryPageHOC from './editorialWorkflow/EntryPageHOC'; class EntryPage extends React.Component { constructor(props) { @@ -56,6 +57,7 @@ class EntryPage extends React.Component { const { entry, entryDraft, boundGetMedia, collection, changeDraft, addMedia, removeMedia } = this.props; + console.log(entry) if (entryDraft == null || entryDraft.get('entry') == undefined || entry && entry.get('isFetching')) { return
Loading...
; } @@ -100,6 +102,12 @@ function mapStateToProps(state, ownProps) { return { collection, collections, newEntry, entryDraft, boundGetMedia, slug, entry }; } +/* + * Instead of checking the publish mode everywhere to dispatch & render the additional editorial workflow stuff, + * We delegate it to a Higher Order Component + */ +EntryPage = EntryPageHOC(EntryPage); + export default connect( mapStateToProps, { diff --git a/src/containers/EditorialWorkflowHoC.js b/src/containers/editorialWorkflow/CollectionPageHOC.js similarity index 76% rename from src/containers/EditorialWorkflowHoC.js rename to src/containers/editorialWorkflow/CollectionPageHOC.js index 603f7819..590e1fb1 100644 --- a/src/containers/EditorialWorkflowHoC.js +++ b/src/containers/editorialWorkflow/CollectionPageHOC.js @@ -1,14 +1,14 @@ import React, { PropTypes } from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { OrderedMap } from 'immutable'; -import { init, loadUnpublishedEntries } from '../actions/editorialWorkflow'; -import { selectUnpublishedEntries } from '../reducers'; -import { EDITORIAL_WORKFLOW, status } from '../constants/publishModes'; -import UnpublishedListing from '../components/UnpublishedListing'; +import { init, loadUnpublishedEntries } from '../../actions/editorialWorkflow'; +import { selectUnpublishedEntries } from '../../reducers'; +import { EDITORIAL_WORKFLOW, status } from '../../constants/publishModes'; +import UnpublishedListing from '../../components/UnpublishedListing'; import { connect } from 'react-redux'; -export default function EditorialWorkflow(WrappedComponent) { - class EditorialWorkflow extends WrappedComponent { +export default function CollectionPageHOC(CollectionPage) { + class CollectionPageHOC extends CollectionPage { componentDidMount() { const { dispatch, isEditorialWorkflow } = this.props; @@ -32,7 +32,7 @@ export default function EditorialWorkflow(WrappedComponent) { } } - EditorialWorkflow.propTypes = { + CollectionPageHOC.propTypes = { dispatch: PropTypes.func.isRequired, isEditorialWorkflow: PropTypes.bool.isRequired, unpublishedEntries: ImmutablePropTypes.map, @@ -56,5 +56,5 @@ export default function EditorialWorkflow(WrappedComponent) { return returnObj; } - return connect(mapStateToProps)(EditorialWorkflow); + return connect(mapStateToProps)(CollectionPageHOC); } diff --git a/src/containers/editorialWorkflow/EntryPageHOC.js b/src/containers/editorialWorkflow/EntryPageHOC.js new file mode 100644 index 00000000..4d958a14 --- /dev/null +++ b/src/containers/editorialWorkflow/EntryPageHOC.js @@ -0,0 +1,46 @@ +import React from 'react'; +import { EDITORIAL_WORKFLOW } from '../../constants/publishModes'; +import { selectUnpublishedEntry } from '../../reducers'; +import { loadUnpublishedEntry } from '../../actions/editorialWorkflow'; +import { connect } from 'react-redux'; + +export default function EntryPageHOC(EntryPage) { + class EntryPageHOC extends React.Component { + render() { + return ; + } + } + + function mapStateToProps(state, ownProps) { + const publish_mode = state.config.get('publish_mode'); + const isEditorialWorkflow = (publish_mode === EDITORIAL_WORKFLOW); + const unpublishedEntry = ownProps.route && ownProps.route.unpublishedEntry === true; + + const returnObj = {}; + if (isEditorialWorkflow && unpublishedEntry) { + const status = ownProps.params.status; + const slug = ownProps.params.slug; + const entry = selectUnpublishedEntry(state, status, slug); + returnObj.entry = entry; + + returnObj.persistEntry = () => { + // TODO - for now, simply ignore + }; + } + return returnObj; + } + + function mapDispatchToProps(dispatch, ownProps) { + const unpublishedEntry = ownProps.route && ownProps.route.unpublishedEntry === true; + const returnObj = {}; + if (unpublishedEntry) { + // Overwrite loadEntry to loadUnpublishedEntry + returnObj.loadEntry = (collection, slug) => { + dispatch(loadUnpublishedEntry(collection, slug)); + }; + } + return returnObj; + } + + return connect(mapStateToProps, mapDispatchToProps)(EntryPageHOC); +} diff --git a/src/reducers/editorialWorkflow.js b/src/reducers/editorialWorkflow.js index 95cf9e28..fb5a96f5 100644 --- a/src/reducers/editorialWorkflow.js +++ b/src/reducers/editorialWorkflow.js @@ -27,9 +27,9 @@ const unpublishedEntries = (state = null, action) => { } }; -export const selectUnpublishedEntry = (state, status, slug) => ( - state.getIn(['entities', `${status}.${slug}`]) -); +export const selectUnpublishedEntry = (state, status, slug) => { + return state && state.getIn(['entities', `${status}.${slug}`]); +}; export const selectUnpublishedEntries = (state, status) => { if (!state) return; diff --git a/src/routing/routes.js b/src/routing/routes.js index 59f2aa7f..6dc9f55e 100644 --- a/src/routing/routes.js +++ b/src/routing/routes.js @@ -12,6 +12,7 @@ export default ( +