Persistence editorial workflow through own actions & reducer
This commit is contained in:
parent
dd71b59e9e
commit
295cdd2f6d
@ -1,8 +1,12 @@
|
|||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
|
import { actions as notifActions } from 'redux-notifications';
|
||||||
import { BEGIN, COMMIT, REVERT } from 'redux-optimist';
|
import { BEGIN, COMMIT, REVERT } from 'redux-optimist';
|
||||||
import { currentBackend } from '../backends/backend';
|
import { currentBackend } from '../backends/backend';
|
||||||
import { getMedia } from '../reducers';
|
import { getMedia } from '../reducers';
|
||||||
import { EDITORIAL_WORKFLOW } from '../constants/publishModes';
|
import { status, EDITORIAL_WORKFLOW } from '../constants/publishModes';
|
||||||
|
|
||||||
|
const { notifSend } = notifActions;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Contant Declarations
|
* Contant Declarations
|
||||||
*/
|
*/
|
||||||
@ -15,12 +19,12 @@ export const UNPUBLISHED_ENTRIES_FAILURE = 'UNPUBLISHED_ENTRIES_FAILURE';
|
|||||||
|
|
||||||
export const UNPUBLISHED_ENTRY_PERSIST_REQUEST = 'UNPUBLISHED_ENTRY_PERSIST_REQUEST';
|
export const UNPUBLISHED_ENTRY_PERSIST_REQUEST = 'UNPUBLISHED_ENTRY_PERSIST_REQUEST';
|
||||||
export const UNPUBLISHED_ENTRY_PERSIST_SUCCESS = 'UNPUBLISHED_ENTRY_PERSIST_SUCCESS';
|
export const UNPUBLISHED_ENTRY_PERSIST_SUCCESS = 'UNPUBLISHED_ENTRY_PERSIST_SUCCESS';
|
||||||
|
export const UNPUBLISHED_ENTRY_PERSIST_FAILURE = 'UNPUBLISHED_ENTRY_PERSIST_FAILURE';
|
||||||
|
|
||||||
export const UNPUBLISHED_ENTRY_STATUS_CHANGE_REQUEST = 'UNPUBLISHED_ENTRY_STATUS_CHANGE_REQUEST';
|
export const UNPUBLISHED_ENTRY_STATUS_CHANGE_REQUEST = 'UNPUBLISHED_ENTRY_STATUS_CHANGE_REQUEST';
|
||||||
export const UNPUBLISHED_ENTRY_STATUS_CHANGE_SUCCESS = 'UNPUBLISHED_ENTRY_STATUS_CHANGE_SUCCESS';
|
export const UNPUBLISHED_ENTRY_STATUS_CHANGE_SUCCESS = 'UNPUBLISHED_ENTRY_STATUS_CHANGE_SUCCESS';
|
||||||
export const UNPUBLISHED_ENTRY_STATUS_CHANGE_FAILURE = 'UNPUBLISHED_ENTRY_STATUS_CHANGE_FAILURE';
|
export const UNPUBLISHED_ENTRY_STATUS_CHANGE_FAILURE = 'UNPUBLISHED_ENTRY_STATUS_CHANGE_FAILURE';
|
||||||
|
|
||||||
|
|
||||||
export const UNPUBLISHED_ENTRY_PUBLISH_REQUEST = 'UNPUBLISHED_ENTRY_PUBLISH_REQUEST';
|
export const UNPUBLISHED_ENTRY_PUBLISH_REQUEST = 'UNPUBLISHED_ENTRY_PUBLISH_REQUEST';
|
||||||
export const UNPUBLISHED_ENTRY_PUBLISH_SUCCESS = 'UNPUBLISHED_ENTRY_PUBLISH_SUCCESS';
|
export const UNPUBLISHED_ENTRY_PUBLISH_SUCCESS = 'UNPUBLISHED_ENTRY_PUBLISH_SUCCESS';
|
||||||
export const UNPUBLISHED_ENTRY_PUBLISH_FAILURE = 'UNPUBLISHED_ENTRY_PUBLISH_FAILURE';
|
export const UNPUBLISHED_ENTRY_PUBLISH_FAILURE = 'UNPUBLISHED_ENTRY_PUBLISH_FAILURE';
|
||||||
@ -68,24 +72,27 @@ function unpublishedEntriesFailed(error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function unpublishedEntryPersisting(entry) {
|
function unpublishedEntryPersisting(collection, entry, transactionID) {
|
||||||
return {
|
return {
|
||||||
type: UNPUBLISHED_ENTRY_PERSIST_REQUEST,
|
type: UNPUBLISHED_ENTRY_PERSIST_REQUEST,
|
||||||
payload: { entry },
|
payload: { collection, entry },
|
||||||
|
optimist: { type: BEGIN, id: transactionID },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function unpublishedEntryPersisted(entry) {
|
function unpublishedEntryPersisted(collection, entry, transactionID) {
|
||||||
return {
|
return {
|
||||||
type: UNPUBLISHED_ENTRY_PERSIST_SUCCESS,
|
type: UNPUBLISHED_ENTRY_PERSIST_SUCCESS,
|
||||||
payload: { entry },
|
payload: { collection, entry },
|
||||||
|
optimist: { type: COMMIT, id: transactionID },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function unpublishedEntryPersistedFail(error) {
|
function unpublishedEntryPersistedFail(error, transactionID) {
|
||||||
return {
|
return {
|
||||||
type: UNPUBLISHED_ENTRY_PERSIST_SUCCESS,
|
type: UNPUBLISHED_ENTRY_PERSIST_FAILURE,
|
||||||
payload: { error },
|
payload: { error },
|
||||||
|
optimist: { type: REVERT, id: transactionID },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,18 +171,33 @@ export function loadUnpublishedEntries() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function persistUnpublishedEntry(collection, entry) {
|
export function persistUnpublishedEntry(collection, entryDraft, existingUnpublishedEntry) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const backend = currentBackend(state.config);
|
const backend = currentBackend(state.config);
|
||||||
const MediaProxies = entry && entry.get('mediaFiles').map(path => getMedia(state, path));
|
const mediaProxies = entryDraft.get('mediaFiles').map(path => getMedia(state, path));
|
||||||
dispatch(unpublishedEntryPersisting(entry));
|
const entry = entryDraft.get('entry');
|
||||||
backend.persistUnpublishedEntry(state.config, collection, entry, MediaProxies.toJS()).then(
|
const transactionID = uuid.v4();
|
||||||
() => {
|
|
||||||
dispatch(unpublishedEntryPersisted(entry));
|
dispatch(unpublishedEntryPersisting(collection, entry, transactionID));
|
||||||
},
|
const persistAction = existingUnpublishedEntry ? backend.persistUnpublishedEntry : backend.persistEntry;
|
||||||
error => dispatch(unpublishedEntryPersistedFail(error))
|
persistAction.call(backend, state.config, collection, entryDraft, mediaProxies.toJS())
|
||||||
);
|
.then(() => {
|
||||||
|
dispatch(notifSend({
|
||||||
|
message: 'Entry saved',
|
||||||
|
kind: 'success',
|
||||||
|
dismissAfter: 4000,
|
||||||
|
}));
|
||||||
|
dispatch(unpublishedEntryPersisted(collection, entry, transactionID));
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
dispatch(notifSend({
|
||||||
|
message: 'Failed to persist entry',
|
||||||
|
kind: 'danger',
|
||||||
|
dismissAfter: 4000,
|
||||||
|
}));
|
||||||
|
dispatch(unpublishedEntryPersistedFail(error, transactionID));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
import { EDITORIAL_WORKFLOW } from '../../constants/publishModes';
|
import { EDITORIAL_WORKFLOW } from '../../constants/publishModes';
|
||||||
import { selectUnpublishedEntry } from '../../reducers';
|
import { selectUnpublishedEntry } from '../../reducers';
|
||||||
import { loadUnpublishedEntry, persistUnpublishedEntry } from '../../actions/editorialWorkflow';
|
import { loadUnpublishedEntry, persistUnpublishedEntry } from '../../actions/editorialWorkflow';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
export default function EntryPageHOC(EntryPage) {
|
export default function EntryPageHOC(EntryPage) {
|
||||||
class EntryPageHOC extends React.Component {
|
class EntryPageHOC extends React.Component {
|
||||||
@ -12,11 +13,10 @@ export default function EntryPageHOC(EntryPage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps(state, ownProps) {
|
function mapStateToProps(state, ownProps) {
|
||||||
const publish_mode = state.config.get('publish_mode');
|
const isEditorialWorkflow = (state.config.get('publish_mode') === EDITORIAL_WORKFLOW);
|
||||||
const isEditorialWorkflow = (publish_mode === EDITORIAL_WORKFLOW);
|
|
||||||
const unpublishedEntry = ownProps.route && ownProps.route.unpublishedEntry === true;
|
const unpublishedEntry = ownProps.route && ownProps.route.unpublishedEntry === true;
|
||||||
|
|
||||||
const returnObj = {};
|
const returnObj = { isEditorialWorkflow };
|
||||||
if (isEditorialWorkflow && unpublishedEntry) {
|
if (isEditorialWorkflow && unpublishedEntry) {
|
||||||
const status = ownProps.params.status;
|
const status = ownProps.params.status;
|
||||||
const slug = ownProps.params.slug;
|
const slug = ownProps.params.slug;
|
||||||
@ -26,22 +26,34 @@ export default function EntryPageHOC(EntryPage) {
|
|||||||
return returnObj;
|
return returnObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch, ownProps) {
|
function mergeProps(stateProps, dispatchProps, ownProps) {
|
||||||
|
const { isEditorialWorkflow } = stateProps;
|
||||||
|
const { dispatch } = dispatchProps;
|
||||||
|
|
||||||
const unpublishedEntry = ownProps.route && ownProps.route.unpublishedEntry === true;
|
const unpublishedEntry = ownProps.route && ownProps.route.unpublishedEntry === true;
|
||||||
|
const status = ownProps.params.status;
|
||||||
|
|
||||||
const returnObj = {};
|
const returnObj = {};
|
||||||
|
|
||||||
if (unpublishedEntry) {
|
if (unpublishedEntry) {
|
||||||
// Overwrite loadEntry to loadUnpublishedEntry
|
// Overwrite loadEntry to loadUnpublishedEntry
|
||||||
const status = ownProps.params.status;
|
|
||||||
returnObj.loadEntry = (entry, collection, slug) => {
|
returnObj.loadEntry = (entry, collection, slug) => {
|
||||||
dispatch(loadUnpublishedEntry(collection, status, slug));
|
dispatch(loadUnpublishedEntry(collection, status, slug));
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEditorialWorkflow) {
|
||||||
|
// Overwrite persistEntry to persistUnpublishedEntry
|
||||||
returnObj.persistEntry = (collection, entryDraft) => {
|
returnObj.persistEntry = (collection, entryDraft) => {
|
||||||
dispatch(persistUnpublishedEntry(collection, entryDraft));
|
dispatch(persistUnpublishedEntry(collection, entryDraft, unpublishedEntry));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return returnObj;
|
|
||||||
|
return {
|
||||||
|
...ownProps,
|
||||||
|
...returnObj,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return connect(mapStateToProps, mapDispatchToProps)(EntryPageHOC);
|
return connect(mapStateToProps, null, mergeProps)(EntryPageHOC);
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
import { Map, List, fromJS } from 'immutable';
|
import { Map, List, fromJS } from 'immutable';
|
||||||
import { EDITORIAL_WORKFLOW } from '../constants/publishModes';
|
import { status, EDITORIAL_WORKFLOW } from '../constants/publishModes';
|
||||||
import {
|
import {
|
||||||
UNPUBLISHED_ENTRY_REQUEST,
|
UNPUBLISHED_ENTRY_REQUEST,
|
||||||
UNPUBLISHED_ENTRY_SUCCESS,
|
UNPUBLISHED_ENTRY_SUCCESS,
|
||||||
UNPUBLISHED_ENTRIES_REQUEST,
|
UNPUBLISHED_ENTRIES_REQUEST,
|
||||||
UNPUBLISHED_ENTRIES_SUCCESS,
|
UNPUBLISHED_ENTRIES_SUCCESS,
|
||||||
|
UNPUBLISHED_ENTRY_PERSIST_REQUEST,
|
||||||
UNPUBLISHED_ENTRY_STATUS_CHANGE_REQUEST,
|
UNPUBLISHED_ENTRY_STATUS_CHANGE_REQUEST,
|
||||||
UNPUBLISHED_ENTRY_PUBLISH_REQUEST,
|
UNPUBLISHED_ENTRY_PUBLISH_REQUEST,
|
||||||
} from '../actions/editorialWorkflow';
|
} from '../actions/editorialWorkflow';
|
||||||
import { CONFIG_SUCCESS } from '../actions/config';
|
import { CONFIG_SUCCESS } from '../actions/config';
|
||||||
|
|
||||||
const unpublishedEntries = (state = null, action) => {
|
const unpublishedEntries = (state = null, action) => {
|
||||||
|
const publishMode = action.payload && action.payload.publish_mode;
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case CONFIG_SUCCESS:
|
case CONFIG_SUCCESS:
|
||||||
const publish_mode = action.payload && action.payload.publish_mode;
|
if (publishMode === EDITORIAL_WORKFLOW) {
|
||||||
if (publish_mode === EDITORIAL_WORKFLOW) {
|
|
||||||
// Editorial workflow state is explicetelly initiated after the config.
|
// Editorial workflow state is explicetelly initiated after the config.
|
||||||
return Map({ entities: Map(), pages: Map() });
|
return Map({ entities: Map(), pages: Map() });
|
||||||
} else {
|
|
||||||
return state;
|
|
||||||
}
|
}
|
||||||
|
return state;
|
||||||
case UNPUBLISHED_ENTRY_REQUEST:
|
case UNPUBLISHED_ENTRY_REQUEST:
|
||||||
return state.setIn(['entities', `${ action.payload.status }.${ action.payload.slug }`, 'isFetching'], true);
|
return state.setIn(['entities', `${ action.payload.status }.${ action.payload.slug }`, 'isFetching'], true);
|
||||||
|
|
||||||
@ -45,6 +45,15 @@ const unpublishedEntries = (state = null, action) => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
case UNPUBLISHED_ENTRY_PERSIST_REQUEST:
|
||||||
|
// Update Optimistically
|
||||||
|
const { collection, entry } = action.payload;
|
||||||
|
const ownStatus = entry.getIn(['metaData', 'status'], status.first());
|
||||||
|
return state.withMutations((map) => {
|
||||||
|
map.setIn(['entities', `${ ownStatus }.${ entry.get('slug') }`], fromJS(entry));
|
||||||
|
map.updateIn(['pages', 'ids'], List(), list => list.push(entry.get('slug')));
|
||||||
|
});
|
||||||
|
|
||||||
case UNPUBLISHED_ENTRY_STATUS_CHANGE_REQUEST:
|
case UNPUBLISHED_ENTRY_STATUS_CHANGE_REQUEST:
|
||||||
// Update Optimistically
|
// Update Optimistically
|
||||||
return state.withMutations((map) => {
|
return state.withMutations((map) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user