Handle delete content type attribute

This commit is contained in:
cyril lopez 2017-08-30 13:38:47 +02:00
parent 9b1dad7ffe
commit 19f62defe6
7 changed files with 103 additions and 11 deletions

View File

@ -7,6 +7,7 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { capitalize } from 'lodash';
import PopUpWarning from 'components/PopUpWarning';
import IcoBoolean from '../../assets/images/icon_boolean.svg';
import IcoDate from '../../assets/images/icon_date.svg';
import IcoImage from '../../assets/images/icon_image.svg';
@ -29,14 +30,24 @@ class AttributeRow extends React.Component { // eslint-disable-line react/prefer
'string': IcoString,
'text': IcoText,
};
this.state = {
showWarning: false,
};
}
edit = () => {
console.log('edit');
this.props.handleEdit(this.props.row.name);
}
delete = () => {
console.log('delete');
this.props.handleDelete(this.props.row.name);
this.setState({ showWarning: false });
}
toggleModalWarning = (e) => {
e.preventDefault();
e.stopPropagation()
this.setState({ showWarning: !this.state.showWarning });
}
renderAttributesBox = () => {
@ -63,16 +74,25 @@ class AttributeRow extends React.Component { // eslint-disable-line react/prefer
<i className="fa fa-pencil ico" onClick={this.edit} role="button" />
</div>
<div className="ico">
<i className="fa fa-trash ico" onClick={this.delete} role="button" />
<i className="fa fa-trash ico" onClick={this.toggleModalWarning} role="button" />
</div>
</div>
</div>
<PopUpWarning
isOpen={this.state.showWarning}
toggleModal={this.toggleModalWarning}
bodyMessage={'popUpWarning.bodyMessage.contentType.delete'}
popUpWarningType={'danger'}
handleConfirm={this.delete}
/>
</li>
);
}
}
AttributeRow.propTypes = {
handleDelete: React.PropTypes.func,
handleEdit: React.PropTypes.func,
row: React.PropTypes.object,
}

View File

@ -3,13 +3,34 @@
* ModelPage actions
*
*/
import { get } from 'lodash';
import { storeData } from '../../utils/storeData';
import {
DEFAULT_ACTION,
DELETE_ATTRIBUTE,
MODEL_FETCH,
MODEL_FETCH_SUCCEEDED,
} from './constants';
export function deleteAttribute(position, modelName) {
const temporaryContentType = storeData.getContentType();
let sendRequest = true;
if (get(temporaryContentType, 'name') === modelName) {
sendRequest = false;
temporaryContentType.attributes.splice(position, 1);
const updatedContentType = temporaryContentType;
storeData.setContentType(updatedContentType);
}
return {
type: DELETE_ATTRIBUTE,
position,
sendRequest,
modelName,
};
}
export function defaultAction() {
return {
type: DEFAULT_ACTION,

View File

@ -5,5 +5,6 @@
*/
export const DEFAULT_ACTION = 'ContentTypeBuilder/ModelPage/DEFAULT_ACTION';
export const DELETE_ATTRIBUTE = 'ContentTypeBuilder/ModelPage/DELETE_ATTRIBUTE';
export const MODEL_FETCH = 'ContentTypeBuilder/ModelPage/MODEL_FETCH';
export const MODEL_FETCH_SUCCEEDED = 'ContentTypeBuilder/ModelPage/MODEL_FETCH_SUCCEEDED';

View File

@ -8,7 +8,7 @@ import React from 'react';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { bindActionCreators } from 'redux';
import { get, has, size, replace, startCase } from 'lodash';
import { get, has, size, replace, startCase, findIndex } from 'lodash';
import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router';
import { router } from 'app';
@ -26,7 +26,11 @@ import PluginLeftMenu from 'components/PluginLeftMenu';
import { storeData } from '../../utils/storeData';
import { modelFetch, modelFetchSucceeded } from './actions';
import {
deleteAttribute,
modelFetch,
modelFetchSucceeded,
} from './actions';
import selectModelPage from './selectors';
import styles from './styles.scss';
@ -84,6 +88,11 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
</div>
)
handleEditAttribute = (attributeName) => {
const index = findIndex(this.props.modelPage.model.attributes, ['name', attributeName]);
console.log(index);
}
fetchModel = () => {
if (storeData.getIsModelTemporary() && get(storeData.getContentType(), 'name') === this.props.params.modelName) {
this.props.modelFetchSucceeded({ model: storeData.getContentType() });
@ -104,6 +113,11 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
router.push(`plugins/content-type-builder/models/${this.props.params.modelName}#choose::attributes`);
}
handleDelete = (attributeName) => {
const index = findIndex(this.props.modelPage.model.attributes, ['name', attributeName]);
this.props.deleteAttribute(index, this.props.params.modelName);
}
toggleModal = () => {
const locationHash = this.props.location.hash ? '' : '#create::contentType::baseSettings';
router.push(`plugins/content-type-builder/models/${this.props.params.modelName}${locationHash}`);
@ -120,7 +134,7 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
</li>
)
renderCustomLi = (row, key) => <AttributeRow key={key} row={row} />
renderCustomLi = (row, key) => <AttributeRow key={key} row={row} handleEdit={this.handleEditAttribute} handleDelete={this.handleDelete} />
renderCustomLink = (props, linkStyles) => {
if (props.link.name === 'button.contentType.add') return this.renderAddLink(props, linkStyles);
@ -227,6 +241,7 @@ const mapStateToProps = createStructuredSelector({
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
deleteAttribute,
modelFetch,
modelFetchSucceeded,
},
@ -235,6 +250,7 @@ function mapDispatchToProps(dispatch) {
}
ModelPage.propTypes = {
deleteAttribute: React.PropTypes.func,
didFetchModel: React.PropTypes.bool,
location: React.PropTypes.object,
menu: React.PropTypes.array,

View File

@ -4,21 +4,30 @@
*
*/
import { fromJS, Map } from 'immutable';
import { fromJS, Map, List } from 'immutable';
/* eslint-disable new-cap */
import {
DELETE_ATTRIBUTE,
MODEL_FETCH_SUCCEEDED,
} from './constants';
const initialState = fromJS({
model: Map(),
model: Map({
attributes: List(),
}),
});
function modelPageReducer(state = initialState, action) {
switch (action.type) {
case DELETE_ATTRIBUTE:
// console.log(action.position);
// console.log(state.getIn(['model', 'attributes']))
return state
.updateIn(['model', 'attributes'], (list) => list.splice(action.position, 1));
case MODEL_FETCH_SUCCEEDED:
return state
.set('model', Map(action.model.model));
.set('model', Map(action.model.model))
.setIn(['model', 'attributes'], List(action.model.model.attributes));
default:
return state;
}

View File

@ -1,11 +1,29 @@
import { LOCATION_CHANGE } from 'react-router-redux';
import { takeLatest } from 'redux-saga';
import { call, take, put, fork, cancel } from 'redux-saga/effects';
import { call, take, put, fork, cancel, select } from 'redux-saga/effects';
import request from 'utils/request';
import { MODEL_FETCH } from './constants';
import { DELETE_ATTRIBUTE, MODEL_FETCH } from './constants';
import { modelFetchSucceeded } from './actions';
import { makeSelectModel } from './selectors';
// Individual exports for testing
export function* attributeDelete(action) {
try {
if (action.sendRequest) {
const body = yield select(makeSelectModel());
const requestUrl = `/content-type-builder/models/${action.modelName}`;
const opts = {
method: 'PUT',
body,
};
yield call(request, requestUrl, opts);
}
} catch(error) {
window.Strapi.notification.error('An error occured');
}
}
export function* fetchModel(action) {
try {
const requestUrl = `/content-type-builder/models/${action.modelName}`;
@ -21,6 +39,7 @@ export function* fetchModel(action) {
export function* defaultSaga() {
const loadModelWatcher = yield fork(takeLatest, MODEL_FETCH, fetchModel);
yield fork(takeLatest, DELETE_ATTRIBUTE, attributeDelete);
yield take(LOCATION_CHANGE);

View File

@ -19,7 +19,13 @@ const selectModelPage = () => createSelector(
(substate) => substate.toJS()
);
const makeSelectModel = () => createSelector(
selectModelPageDomain(),
(substate) => substate.get('model').toJS(),
);
export default selectModelPage;
export {
selectModelPageDomain,
makeSelectModel,
};