Moved persisting logic to entryDraft reducer + added tests.
This commit is contained in:
parent
ffe27acc10
commit
e53262d92c
@ -211,13 +211,14 @@ export function createEmptyDraft(collection) {
|
||||
};
|
||||
}
|
||||
|
||||
export function persistEntry(collection, entry) {
|
||||
export function persistEntry(collection, entryDraft) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const backend = currentBackend(state.config);
|
||||
const mediaProxies = entry.get('mediaFiles').map(path => getMedia(state, path));
|
||||
const mediaProxies = entryDraft.get('mediaFiles').map(path => getMedia(state, path));
|
||||
const entry = entryDraft.get('entry');
|
||||
dispatch(entryPersisting(collection, entry));
|
||||
backend.persistEntry(state.config, collection, entry, mediaProxies.toJS()).then(
|
||||
backend.persistEntry(state.config, collection, entryDraft, mediaProxies.toJS()).then(
|
||||
() => dispatch(entryPersisted(collection, entry)),
|
||||
error => dispatch(entryPersistFail(collection, entry, error))
|
||||
);
|
||||
|
@ -35,12 +35,12 @@ class EntryPage extends React.Component {
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { entry, collection, slug } = this.props;
|
||||
const { entry, newEntry, collection, slug, createEmptyDraft, loadEntry } = this.props;
|
||||
|
||||
if (this.props.newEntry) {
|
||||
this.props.createEmptyDraft(this.props.collection);
|
||||
if (newEntry) {
|
||||
createEmptyDraft(collection);
|
||||
} else {
|
||||
this.props.loadEntry(entry, collection, slug);
|
||||
loadEntry(entry, collection, slug);
|
||||
this.createDraft(entry);
|
||||
}
|
||||
}
|
||||
@ -63,7 +63,8 @@ class EntryPage extends React.Component {
|
||||
};
|
||||
|
||||
handlePersistEntry = () => {
|
||||
this.props.persistEntry(this.props.collection, this.props.entryDraft);
|
||||
const { persistEntry, collection, entryDraft } = this.props;
|
||||
persistEntry(collection, entryDraft);
|
||||
};
|
||||
|
||||
render() {
|
||||
@ -105,7 +106,15 @@ function mapStateToProps(state, ownProps) {
|
||||
const slug = ownProps.params.slug;
|
||||
const entry = newEntry ? null : selectEntry(state, collection.get('name'), slug);
|
||||
const boundGetMedia = getMedia.bind(null, state);
|
||||
return { collection, collections, newEntry, entryDraft, boundGetMedia, slug, entry };
|
||||
return {
|
||||
collection,
|
||||
collections,
|
||||
newEntry,
|
||||
entryDraft,
|
||||
boundGetMedia,
|
||||
slug,
|
||||
entry,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
|
@ -1,16 +1,15 @@
|
||||
import Immutable, { Map, OrderedMap, fromJS } from 'immutable';
|
||||
import { Map, OrderedMap, fromJS } from 'immutable';
|
||||
import * as actions from '../../actions/entries';
|
||||
import reducer from '../entries';
|
||||
|
||||
let initialState;
|
||||
const initialState = OrderedMap({
|
||||
posts: Map({ name: 'posts' }),
|
||||
});
|
||||
|
||||
describe('entries', () => {
|
||||
it('should mark entries as fetching', () => {
|
||||
const state = OrderedMap({
|
||||
posts: Map({ name: 'posts' }),
|
||||
});
|
||||
expect(
|
||||
reducer(state, actions.entriesLoading(Map({ name: 'posts' })))
|
||||
reducer(initialState, actions.entriesLoading(Map({ name: 'posts' })))
|
||||
).toEqual(
|
||||
OrderedMap(fromJS({
|
||||
posts: { name: 'posts' },
|
||||
@ -22,12 +21,9 @@ describe('entries', () => {
|
||||
});
|
||||
|
||||
it('should handle loaded entries', () => {
|
||||
const state = OrderedMap({
|
||||
posts: Map({ name: 'posts' }),
|
||||
});
|
||||
const entries = [{ slug: 'a', path: '' }, { slug: 'b', title: 'B' }];
|
||||
expect(
|
||||
reducer(state, actions.entriesLoaded(Map({ name: 'posts' }), entries, 0))
|
||||
reducer(initialState, actions.entriesLoaded(Map({ name: 'posts' }), entries, 0))
|
||||
).toEqual(
|
||||
OrderedMap(fromJS(
|
||||
{
|
||||
@ -46,51 +42,4 @@ describe('entries', () => {
|
||||
))
|
||||
);
|
||||
});
|
||||
|
||||
describe('entry persisting', () => {
|
||||
beforeEach(() => {
|
||||
initialState = Immutable.fromJS({
|
||||
entities: {
|
||||
'posts.slug': {
|
||||
collection: 'posts',
|
||||
slug: 'slug',
|
||||
path: 'content/blog/art-and-wine-festival.md',
|
||||
partial: false,
|
||||
raw: '',
|
||||
data: {},
|
||||
metaData: null,
|
||||
},
|
||||
},
|
||||
pages: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle persisting request', () => {
|
||||
const newState = reducer(
|
||||
initialState,
|
||||
actions.entryPersisting(Map({ name: 'posts' }), Map({ slug: 'slug' }))
|
||||
);
|
||||
expect(newState.getIn(['entities', 'posts.slug', 'isPersisting'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle persisting success', () => {
|
||||
let newState = reducer(initialState,
|
||||
actions.entryPersisting(Map({ name: 'posts' }), Map({ slug: 'slug' }))
|
||||
);
|
||||
newState = reducer(newState,
|
||||
actions.entryPersisted(Map({ name: 'posts' }), Map({ slug: 'slug' }))
|
||||
);
|
||||
expect(newState.getIn(['entities', 'posts.slug', 'isPersisting'])).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle persisting error', () => {
|
||||
let newState = reducer(initialState,
|
||||
actions.entryPersisting(Map({ name: 'posts' }), Map({ slug: 'slug' }))
|
||||
);
|
||||
newState = reducer(newState,
|
||||
actions.entryPersistFail(Map({ name: 'posts' }), Map({ slug: 'slug' }), 'Error message')
|
||||
);
|
||||
expect(newState.getIn(['entities', 'posts.slug', 'isPersisting'])).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
126
src/reducers/__tests__/entryDraft.spec.js
Normal file
126
src/reducers/__tests__/entryDraft.spec.js
Normal file
@ -0,0 +1,126 @@
|
||||
import { Map, List, fromJS } from 'immutable';
|
||||
import * as actions from '../../actions/entries';
|
||||
import reducer from '../entryDraft';
|
||||
|
||||
let initialState = Map({ entry: Map(), mediaFiles: List() });
|
||||
|
||||
const entry = {
|
||||
collection: 'posts',
|
||||
slug: 'slug',
|
||||
path: 'content/blog/art-and-wine-festival.md',
|
||||
partial: false,
|
||||
raw: '',
|
||||
data: {},
|
||||
metaData: null,
|
||||
};
|
||||
|
||||
describe('entryDraft reducer', () => {
|
||||
describe('DRAFT_CREATE_FROM_ENTRY', () => {
|
||||
it('should create draft from the entry', () => {
|
||||
expect(
|
||||
reducer(
|
||||
initialState,
|
||||
actions.createDraftFromEntry(fromJS(entry))
|
||||
)
|
||||
).toEqual(
|
||||
fromJS({
|
||||
entry: {
|
||||
...entry,
|
||||
newRecord: false,
|
||||
},
|
||||
mediaFiles: [],
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DRAFT_CREATE_EMPTY', () => {
|
||||
it('should create a new draft ', () => {
|
||||
expect(
|
||||
reducer(
|
||||
initialState,
|
||||
actions.emmptyDraftCreated(fromJS(entry))
|
||||
)
|
||||
).toEqual(
|
||||
fromJS({
|
||||
entry: {
|
||||
...entry,
|
||||
newRecord: true,
|
||||
},
|
||||
mediaFiles: [],
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DRAFT_DISCARD', () => {
|
||||
it('should discard the draft and return initial state', () => {
|
||||
expect(reducer(initialState, actions.discardDraft()))
|
||||
.toEqual(initialState);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DRAFT_CHANGE', () => {
|
||||
it.skip('should update the draft', () => {
|
||||
const newEntry = {
|
||||
...entry,
|
||||
raw: 'updated',
|
||||
};
|
||||
expect(reducer(initialState, actions.changeDraft(newEntry)))
|
||||
.toEqual(fromJS({
|
||||
entry: {
|
||||
...entry,
|
||||
raw: 'updated',
|
||||
},
|
||||
mediaFiles: [],
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('persisting', () => {
|
||||
beforeEach(() => {
|
||||
initialState = fromJS({
|
||||
entities: {
|
||||
'posts.slug': {
|
||||
collection: 'posts',
|
||||
slug: 'slug',
|
||||
path: 'content/blog/art-and-wine-festival.md',
|
||||
partial: false,
|
||||
raw: '',
|
||||
data: {},
|
||||
metaData: null,
|
||||
},
|
||||
},
|
||||
pages: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle persisting request', () => {
|
||||
const newState = reducer(
|
||||
initialState,
|
||||
actions.entryPersisting(Map({ name: 'posts' }), Map({ slug: 'slug' }))
|
||||
);
|
||||
expect(newState.getIn(['entry', 'isPersisting'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle persisting success', () => {
|
||||
let newState = reducer(initialState,
|
||||
actions.entryPersisting(Map({ name: 'posts' }), Map({ slug: 'slug' }))
|
||||
);
|
||||
newState = reducer(newState,
|
||||
actions.entryPersisted(Map({ name: 'posts' }), Map({ slug: 'slug' }))
|
||||
);
|
||||
expect(newState.getIn(['entry', 'isPersisting'])).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle persisting error', () => {
|
||||
let newState = reducer(initialState,
|
||||
actions.entryPersisting(Map({ name: 'posts' }), Map({ slug: 'slug' }))
|
||||
);
|
||||
newState = reducer(newState,
|
||||
actions.entryPersistFail(Map({ name: 'posts' }), Map({ slug: 'slug' }), 'Error message')
|
||||
);
|
||||
expect(newState.getIn(['entry', 'isPersisting'])).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
@ -2,9 +2,6 @@ import { Map, List, fromJS } from 'immutable';
|
||||
import {
|
||||
ENTRY_REQUEST,
|
||||
ENTRY_SUCCESS,
|
||||
ENTRY_PERSIST_REQUEST,
|
||||
ENTRY_PERSIST_SUCCESS,
|
||||
ENTRY_PERSIST_FAILURE,
|
||||
ENTRIES_REQUEST,
|
||||
ENTRIES_SUCCESS,
|
||||
SEARCH_ENTRIES_REQUEST,
|
||||
@ -16,10 +13,6 @@ let loadedEntries;
|
||||
let page;
|
||||
let searchTerm;
|
||||
|
||||
function getEntryPath(collectionName, entrySlug) {
|
||||
return `${ collectionName }.${ entrySlug }`;
|
||||
}
|
||||
|
||||
const entries = (state = Map({ entities: Map(), pages: Map() }), action) => {
|
||||
switch (action.type) {
|
||||
case ENTRY_REQUEST:
|
||||
@ -31,17 +24,6 @@ const entries = (state = Map({ entities: Map(), pages: Map() }), action) => {
|
||||
fromJS(action.payload.entry)
|
||||
);
|
||||
|
||||
case ENTRY_PERSIST_REQUEST: {
|
||||
const { collectionName, entrySlug } = action.payload;
|
||||
return state.setIn(['entities', getEntryPath(collectionName, entrySlug), 'isPersisting'], true);
|
||||
}
|
||||
|
||||
case ENTRY_PERSIST_SUCCESS:
|
||||
case ENTRY_PERSIST_FAILURE: {
|
||||
const { collectionName, entrySlug } = action.payload;
|
||||
return state.deleteIn(['entities', getEntryPath(collectionName, entrySlug), 'isPersisting']);
|
||||
}
|
||||
|
||||
case ENTRIES_REQUEST:
|
||||
return state.setIn(['pages', action.payload.collection, 'isFetching'], true);
|
||||
|
||||
|
@ -1,10 +1,21 @@
|
||||
import { Map, List, fromJS } from 'immutable';
|
||||
import { DRAFT_CREATE_FROM_ENTRY, DRAFT_CREATE_EMPTY, DRAFT_DISCARD, DRAFT_CHANGE } from '../actions/entries';
|
||||
import { ADD_MEDIA, REMOVE_MEDIA } from '../actions/media';
|
||||
import {
|
||||
DRAFT_CREATE_FROM_ENTRY,
|
||||
DRAFT_CREATE_EMPTY,
|
||||
DRAFT_DISCARD,
|
||||
DRAFT_CHANGE,
|
||||
ENTRY_PERSIST_REQUEST,
|
||||
ENTRY_PERSIST_SUCCESS,
|
||||
ENTRY_PERSIST_FAILURE,
|
||||
} from '../actions/entries';
|
||||
import {
|
||||
ADD_MEDIA,
|
||||
REMOVE_MEDIA,
|
||||
} from '../actions/media';
|
||||
|
||||
const initialState = Map({ entry: Map(), mediaFiles: List() });
|
||||
|
||||
const entryDraft = (state = Map(), action) => {
|
||||
const entryDraftReducer = (state = Map(), action) => {
|
||||
switch (action.type) {
|
||||
case DRAFT_CREATE_FROM_ENTRY:
|
||||
// Existing Entry
|
||||
@ -25,14 +36,23 @@ const entryDraft = (state = Map(), action) => {
|
||||
case DRAFT_CHANGE:
|
||||
return state.set('entry', action.payload);
|
||||
|
||||
case ENTRY_PERSIST_REQUEST: {
|
||||
return state.setIn(['entry', 'isPersisting'], true);
|
||||
}
|
||||
|
||||
case ENTRY_PERSIST_SUCCESS:
|
||||
case ENTRY_PERSIST_FAILURE: {
|
||||
return state.deleteIn(['entry', 'isPersisting']);
|
||||
}
|
||||
|
||||
case ADD_MEDIA:
|
||||
return state.update('mediaFiles', (list) => list.push(action.payload.public_path));
|
||||
return state.update('mediaFiles', list => list.push(action.payload.public_path));
|
||||
case REMOVE_MEDIA:
|
||||
return state.update('mediaFiles', (list) => list.filterNot((path) => path === action.payload));
|
||||
return state.update('mediaFiles', list => list.filterNot(path => path === action.payload));
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default entryDraft;
|
||||
export default entryDraftReducer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user