Merge pull request #29 from Tiqa/feat/api/add_statement
Feat/api/add statement
This commit is contained in:
commit
73599eb131
16 changed files with 61 additions and 107 deletions
2
.babelrc
2
.babelrc
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"presets": ["es2015", "react", "stage-0"],
|
||||
"plugins": ["transform-decorators-legacy", "react-hot-loader/babel"]
|
||||
"plugins": ["transform-decorators-legacy", "react-hot-loader/babel", "ramda"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@
|
|||
"babel-core": "<6.3.0",
|
||||
"babel-eslint": "^7.1.0",
|
||||
"babel-loader": "~6.2.1",
|
||||
"babel-plugin-ramda": "^1.1.6",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"babel-plugin-transform-es2015-modules-umd": "^6.8.0",
|
||||
"babel-preset-es2015": "<6.3.0",
|
||||
|
|
|
|||
|
|
@ -15,3 +15,4 @@ export const getStatements = () => get('statements');
|
|||
export const getPublicFiguresAutocomplete = typed => get(`autocomplete/public_figure/${typed}`);
|
||||
export const getSubjectsAutocomplete = typed => get(`autocomplete/subject/${typed}`);
|
||||
export const getPositions = subjectId => get(`subjects/${subjectId}/positions`);
|
||||
export const postStatement = statement => post('statements', statement);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import moment from 'moment';
|
|||
import 'bootstrap-loader';
|
||||
|
||||
const locale = 'fr';
|
||||
|
||||
moment.locale(locale);
|
||||
moment.locale(locale, {
|
||||
calendar : {
|
||||
lastDay : '[Hier]',
|
||||
|
|
|
|||
10
src/components/AddStatementButton/connector.js
Normal file
10
src/components/AddStatementButton/connector.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { onAddStatementValidate } from 'store/actions';
|
||||
|
||||
const mapStateToProps = () => ({});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onValidate: statement => dispatch(onAddStatementValidate(statement)),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps);
|
||||
|
|
@ -1,11 +1,16 @@
|
|||
import React, { Component } from 'react';
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { Button } from 'react-bootstrap';
|
||||
import AddStatementModal from 'components/AddStatementModal';
|
||||
import connect from './connector';
|
||||
|
||||
class AddStatementButton extends Component {
|
||||
static propTypes = {
|
||||
onValidate: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
showModal: false,
|
||||
}
|
||||
};
|
||||
|
||||
close = () => this.setState({ showModal: false });
|
||||
open = () => this.setState({ showModal: true });
|
||||
|
|
@ -20,10 +25,10 @@ class AddStatementButton extends Component {
|
|||
>
|
||||
Nouvelle prise de position
|
||||
</Button>
|
||||
<AddStatementModal show={this.state.showModal} onHide={this.close} />
|
||||
<AddStatementModal show={this.state.showModal} onHide={this.close} onValidate={this.props.onValidate} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AddStatementButton;
|
||||
export default connect(AddStatementButton);
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ class AddStatementModal extends Component {
|
|||
}
|
||||
{step === steps.SUMMARY &&
|
||||
<Button
|
||||
onClick={onValidate}
|
||||
onClick={() => onValidate(this.state)}
|
||||
disabled={!this.isComplete()}
|
||||
bsStyle="success"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ import LastStatements from 'components/LastStatements';
|
|||
import HomeSubjects from './HomeSubjects';
|
||||
import bgSrc from './images/intro-bg.jpg';
|
||||
import styles from './Home.css';
|
||||
import AddStatementButton from 'components/AddStatementButton';
|
||||
|
||||
const Home = () => (
|
||||
<div className="container-fluid" styleName="container">
|
||||
<AddStatementButton />
|
||||
<div className="row" styleName="background-title" style={{ backgroundImage: `url(${bgSrc})` }}>
|
||||
<div styleName="title-mask">
|
||||
<h5 >Bienvenue sur Débats.co</h5>
|
||||
|
|
@ -16,7 +18,7 @@ const Home = () => (
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-1" />
|
||||
<div className="col-md-1"></div>
|
||||
<div className="subjects-index col-md-7 subjects-home">
|
||||
<h1>Sujets d'actualité</h1>
|
||||
<table className="table">
|
||||
|
|
@ -27,7 +29,8 @@ const Home = () => (
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col-md-3 col-centered" style={{ textAlign: 'right' }} >
|
||||
<div className="col-md-1" />
|
||||
<div className="col-md-3 col-centered" style={{ textAlign: 'right' }}>
|
||||
<LastStatements />
|
||||
</div>
|
||||
<div className="col-md-1" />
|
||||
|
|
|
|||
|
|
@ -1,27 +1,6 @@
|
|||
import types from '../actions_types';
|
||||
|
||||
export const onAddStatementPublicFigureSelection = id => ({
|
||||
type: types.ADD_STATEMENT_PUBLIC_FIGURE_SELECTION,
|
||||
id,
|
||||
});
|
||||
export const onAddStatementSubjectSelection = id => ({
|
||||
type: types.ADD_STATEMENT_SUBJECT_SELECTION,
|
||||
id,
|
||||
});
|
||||
export const onAddStatementPositionSelection = id => ({
|
||||
type: types.ADD_STATEMENT_POSITION_SELECTION,
|
||||
id,
|
||||
});
|
||||
|
||||
export const onAddStatementUpdateEvidenceUrl = url => ({
|
||||
type: types.ADD_STATEMENT_UPDATE_EVIDENCE_URL,
|
||||
url,
|
||||
});
|
||||
export const onAddStatementUpdateEvidenceFile = file => ({
|
||||
type: types.ADD_STATEMENT_UPDATE_EVIDENCE_FILE,
|
||||
file,
|
||||
});
|
||||
|
||||
export const onAddStatementValidate = () => ({
|
||||
export const onAddStatementValidate = newStatement => ({
|
||||
type: types.ADD_STATEMENT_VALIDATE,
|
||||
payload: { ...newStatement },
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,11 +1,6 @@
|
|||
export default {
|
||||
ENTITY_ACCESS: 'ENTITY_ACCESS',
|
||||
ENTITY_READ: 'ENTITY_READ',
|
||||
ADD_STATEMENT_NEXT_STEP: 'ADD_STATEMENT_NEXT_STEP',
|
||||
ADD_STATEMENT_PUBLIC_FIGURE_SELECTION: 'ADD_STATEMENT_PUBLIC_FIGURE_SELECTION',
|
||||
ADD_STATEMENT_SUBJECT_SELECTION: 'ADD_STATEMENT_SUBJECT_SELECTION',
|
||||
ADD_STATEMENT_POSITION_SELECTION: 'ADD_STATEMENT_POSITION_SELECTION',
|
||||
ADD_STATEMENT_UPDATE_EVIDENCE_URL: 'ADD_STATEMENT_UPDATE_EVIDENCE_URL',
|
||||
ADD_STATEMENT_UPDATE_EVIDENCE_FILE: 'ADD_STATEMENT_UPDATE_EVIDENCE_FILE',
|
||||
ADD_STATEMENT_VALIDATE: 'ADD_STATEMENT_VALIDATE',
|
||||
STATEMENT_POST_BEGIN: 'STATEMENT_POST_BEGIN',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import createHashHistory from 'history/lib/createHashHistory';
|
|||
import createMemoryHistory from 'history/lib/createMemoryHistory';
|
||||
|
||||
import rootSaga from './sagas';
|
||||
import { entitiesReducer, addStatementReducer } from './reducers';
|
||||
import { entitiesReducer } from './reducers';
|
||||
|
||||
// Build history
|
||||
const createHistory = isClientSide() ? createHashHistory : createMemoryHistory;
|
||||
|
|
@ -22,7 +22,6 @@ const initialState = isClientSide() ? window.__INITIAL_STATE__ : {};
|
|||
const reducer = combineReducers({
|
||||
routing: routerReducer,
|
||||
entities: entitiesReducer,
|
||||
addStatement: addStatementReducer,
|
||||
});
|
||||
|
||||
// MIDDLEWARE
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
import {
|
||||
assoc, compose, not, allPass, prop, isNil, either, complement,
|
||||
} from 'ramda';
|
||||
import actionsTypes from '../actions_types';
|
||||
|
||||
const initialState = {
|
||||
publicFigureId: null,
|
||||
subjectId: null,
|
||||
positionId: null,
|
||||
statementDate: null,
|
||||
evidenceUrl: null,
|
||||
evidenceFile: null,
|
||||
quote: null,
|
||||
note: null,
|
||||
tags: [],
|
||||
};
|
||||
|
||||
const isPublicFigureChosen = compose(not, isNil, prop('publicFigureId'));
|
||||
const isSubjectChosen = compose(not, isNil, prop('publicFigureId'));
|
||||
const isPositionChosen = compose(not, isNil, prop('publicFigureId'));
|
||||
const isStatementComplete = allPass([
|
||||
compose(not, isNil, prop('statementDate')),
|
||||
compose(not, isNil, prop('quote')),
|
||||
compose(not, isNil, prop('statementDate')),
|
||||
either(
|
||||
compose(not, isNil, prop('evidenceUrl')),
|
||||
compose(not, isNil, prop('evidenceFile')),
|
||||
),
|
||||
]);
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
const isPublicFigureMissing = complement(isPublicFigureChosen);
|
||||
const isSubjectMissing = complement(isSubjectChosen);
|
||||
const isPositionMissing = complement(isPositionChosen);
|
||||
const isStatementIncomplete = complement(isStatementComplete);
|
||||
|
||||
export const addStatementReducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case actionsTypes.ADD_STATEMENT_PUBLIC_FIGURE_SELECTION: return assoc('publicFigureId', action.id, state);
|
||||
case actionsTypes.ADD_STATEMENT_SUBJECT_SELECTION: return assoc('subjectId', action.id, state);
|
||||
case actionsTypes.ADD_STATEMENT_POSITION_SELECTION: return assoc('positionId', action.id, state);
|
||||
case actionsTypes.ADD_STATEMENT_UPDATE_EVIDENCE_URL: return assoc('evidenceUrl', action.url, state);
|
||||
case actionsTypes.ADD_STATEMENT_UPDATE_EVIDENCE_FILE: return assoc('evidenceFile', action.file, state);
|
||||
default: return state;
|
||||
}
|
||||
};
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
export * from './entities';
|
||||
export * from './addStatement';
|
||||
|
||||
|
|
|
|||
|
|
@ -42,18 +42,4 @@ function* fetchEntityIfNeeded(action) {
|
|||
export function* watchEntityAccess() {
|
||||
yield* takeEvery(actionsTypes.ENTITY_ACCESS, fetchEntityIfNeeded);
|
||||
}
|
||||
function* fetchPositionsOfSubject(action) {
|
||||
if (action.id) {
|
||||
// Call API
|
||||
const response = yield call(getPositions, action.id);
|
||||
|
||||
// Error actions
|
||||
|
||||
// Success actions
|
||||
yield put({ type: actionsTypes.ENTITY_READ, data: response.data });
|
||||
}
|
||||
}
|
||||
|
||||
export function* watchSubjectSelection() {
|
||||
yield* takeEvery(actionsTypes.ADD_STATEMENT_SUBJECT_SELECTION, fetchPositionsOfSubject);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { watchEntityAccess, watchSubjectSelection } from './apiSaga';
|
||||
|
||||
import { watchEntityAccess } from './apiSaga';
|
||||
import { watchStatementValidation } from './postStatement';
|
||||
|
||||
export default function* rootSaga() {
|
||||
yield [
|
||||
watchEntityAccess(),
|
||||
watchSubjectSelection(),
|
||||
watchStatementValidation(),
|
||||
];
|
||||
}
|
||||
|
|
|
|||
21
src/store/sagas/postStatement.js
Normal file
21
src/store/sagas/postStatement.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { takeEvery } from 'redux-saga';
|
||||
import { call, put } from 'redux-saga/effects';
|
||||
import actionsTypes from '../actions_types';
|
||||
import { postStatement } from 'api/debats';
|
||||
|
||||
function* postNewStatement(action) {
|
||||
yield put({ type: actionsTypes.STATEMENT_POST_BEGIN, payload: action.payload });
|
||||
|
||||
// Gérer d'abord les transferts de fichier sur un ID de transation
|
||||
|
||||
const response = yield call(postStatement);
|
||||
|
||||
// Error actions
|
||||
|
||||
// Success actions
|
||||
yield put({ type: actionsTypes.STATEMENT_POST_SUCCESS, payload: action.payload });
|
||||
}
|
||||
|
||||
export function* watchStatementValidation() {
|
||||
yield* takeEvery(actionsTypes.ADD_STATEMENT_VALIDATE, postNewStatement);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue