Confirm navigation when it would discard unsaved changes
- New state field: `state.entryDraft.hasChanged`, initialized to `false`. - `state.entryDraft.hasChanged` set to `true` in `entryDraft` reducer for `DRAFT_CHANGE_FIELD`. - `EntryPage` adds a `listenBefore` listener to `history` on `componentDidMount` that checks `this.props.entryDraft.hasChanged` and, if that is true, asks the user to confirm the navigation. - `EntryPage` removes its listener on `componentWillUnmount`.
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import history from '../routing/history';
|
||||||
import {
|
import {
|
||||||
loadEntry,
|
loadEntry,
|
||||||
createDraftFromEntry,
|
createDraftFromEntry,
|
||||||
@ -49,6 +50,13 @@ class EntryPage extends React.Component {
|
|||||||
} else {
|
} else {
|
||||||
loadEntry(collection, slug);
|
loadEntry(collection, slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.unlisten = history.listenBefore((location) => {
|
||||||
|
if (this.props.entryDraft.get('hasChanged')) {
|
||||||
|
return "Are you sure you want to leave this page?";
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
@ -63,6 +71,7 @@ class EntryPage extends React.Component {
|
|||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.props.discardDraft();
|
this.props.discardDraft();
|
||||||
|
this.unlisten();
|
||||||
}
|
}
|
||||||
|
|
||||||
createDraft = (entry) => {
|
createDraft = (entry) => {
|
||||||
|
@ -2,7 +2,13 @@ import { Map, List, fromJS } from 'immutable';
|
|||||||
import * as actions from '../../actions/entries';
|
import * as actions from '../../actions/entries';
|
||||||
import reducer from '../entryDraft';
|
import reducer from '../entryDraft';
|
||||||
|
|
||||||
let initialState = Map({ entry: Map(), mediaFiles: List(), fieldsMetaData: Map(), fieldsErrors: Map() });
|
let initialState = Map({
|
||||||
|
entry: Map(),
|
||||||
|
mediaFiles: List(),
|
||||||
|
fieldsMetaData: Map(),
|
||||||
|
fieldsErrors: Map(),
|
||||||
|
hasChanged: false,
|
||||||
|
});
|
||||||
|
|
||||||
const entry = {
|
const entry = {
|
||||||
collection: 'posts',
|
collection: 'posts',
|
||||||
@ -31,6 +37,7 @@ describe('entryDraft reducer', () => {
|
|||||||
mediaFiles: [],
|
mediaFiles: [],
|
||||||
fieldsMetaData: Map(),
|
fieldsMetaData: Map(),
|
||||||
fieldsErrors: Map(),
|
fieldsErrors: Map(),
|
||||||
|
hasChanged: false,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -52,6 +59,7 @@ describe('entryDraft reducer', () => {
|
|||||||
mediaFiles: [],
|
mediaFiles: [],
|
||||||
fieldsMetaData: Map(),
|
fieldsMetaData: Map(),
|
||||||
fieldsErrors: Map(),
|
fieldsErrors: Map(),
|
||||||
|
hasChanged: false,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -77,6 +85,7 @@ describe('entryDraft reducer', () => {
|
|||||||
raw: 'updated',
|
raw: 'updated',
|
||||||
},
|
},
|
||||||
mediaFiles: [],
|
mediaFiles: [],
|
||||||
|
hasChanged: true,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -19,7 +19,13 @@ import {
|
|||||||
REMOVE_ASSET,
|
REMOVE_ASSET,
|
||||||
} from '../actions/media';
|
} from '../actions/media';
|
||||||
|
|
||||||
const initialState = Map({ entry: Map(), mediaFiles: List(), fieldsMetaData: Map(), fieldsErrors: Map() });
|
const initialState = Map({
|
||||||
|
entry: Map(),
|
||||||
|
mediaFiles: List(),
|
||||||
|
fieldsMetaData: Map(),
|
||||||
|
fieldsErrors: Map(),
|
||||||
|
hasChanged: false,
|
||||||
|
});
|
||||||
|
|
||||||
const entryDraftReducer = (state = Map(), action) => {
|
const entryDraftReducer = (state = Map(), action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
@ -47,6 +53,7 @@ const entryDraftReducer = (state = Map(), action) => {
|
|||||||
return state.withMutations((state) => {
|
return state.withMutations((state) => {
|
||||||
state.setIn(['entry', 'data', action.payload.field], action.payload.value);
|
state.setIn(['entry', 'data', action.payload.field], action.payload.value);
|
||||||
state.mergeIn(['fieldsMetaData'], fromJS(action.payload.metadata));
|
state.mergeIn(['fieldsMetaData'], fromJS(action.payload.metadata));
|
||||||
|
state.set('hasChanged', true);
|
||||||
});
|
});
|
||||||
|
|
||||||
case DRAFT_VALIDATION_ERRORS:
|
case DRAFT_VALIDATION_ERRORS:
|
||||||
|
Reference in New Issue
Block a user