diff options
| author | Thomas Haddad | 2017-01-04 11:10:15 +0100 |
|---|---|---|
| committer | Thomas Haddad | 2017-01-04 11:10:15 +0100 |
| commit | 9c08e8f9f42906f9be17a8fbce7fcd83dbd51179 (patch) | |
| tree | 65e132910ffadab7534f4b5ad2257539f06b309b | |
| parent | 9560056852d1d48767c5ed150bce4e3abffcca00 (diff) | |
| parent | 66dc68487a6e8a826ec4d4ffcee2f34456488dea (diff) | |
| download | chouette-core-9c08e8f9f42906f9be17a8fbce7fcd83dbd51179.tar.bz2 | |
Merge branch 'mission_redux'
46 files changed, 992 insertions, 21 deletions
diff --git a/app/assets/javascripts/es6_browserified/actions/index.js b/app/assets/javascripts/es6_browserified/itineraries/actions/index.js index 7d225f2f6..7d225f2f6 100644 --- a/app/assets/javascripts/es6_browserified/actions/index.js +++ b/app/assets/javascripts/es6_browserified/itineraries/actions/index.js diff --git a/app/assets/javascripts/es6_browserified/components/App.js b/app/assets/javascripts/es6_browserified/itineraries/components/App.js index 7488b0b39..7488b0b39 100644 --- a/app/assets/javascripts/es6_browserified/components/App.js +++ b/app/assets/javascripts/es6_browserified/itineraries/components/App.js diff --git a/app/assets/javascripts/es6_browserified/components/BSelect2.js b/app/assets/javascripts/es6_browserified/itineraries/components/BSelect2.js index 0bf3ebf38..0bf3ebf38 100644 --- a/app/assets/javascripts/es6_browserified/components/BSelect2.js +++ b/app/assets/javascripts/es6_browserified/itineraries/components/BSelect2.js diff --git a/app/assets/javascripts/es6_browserified/components/Todo.js b/app/assets/javascripts/es6_browserified/itineraries/components/Todo.js index f2932ab1d..f2932ab1d 100644 --- a/app/assets/javascripts/es6_browserified/components/Todo.js +++ b/app/assets/javascripts/es6_browserified/itineraries/components/Todo.js diff --git a/app/assets/javascripts/es6_browserified/components/TodoList.js b/app/assets/javascripts/es6_browserified/itineraries/components/TodoList.js index 3ea2c90e1..3ea2c90e1 100644 --- a/app/assets/javascripts/es6_browserified/components/TodoList.js +++ b/app/assets/javascripts/es6_browserified/itineraries/components/TodoList.js diff --git a/app/assets/javascripts/es6_browserified/containers/AddTodo.js b/app/assets/javascripts/es6_browserified/itineraries/containers/AddTodo.js index d0128f16d..d0128f16d 100644 --- a/app/assets/javascripts/es6_browserified/containers/AddTodo.js +++ b/app/assets/javascripts/es6_browserified/itineraries/containers/AddTodo.js diff --git a/app/assets/javascripts/es6_browserified/containers/VisibleTodoList.js b/app/assets/javascripts/es6_browserified/itineraries/containers/VisibleTodoList.js index 464d6e482..464d6e482 100644 --- a/app/assets/javascripts/es6_browserified/containers/VisibleTodoList.js +++ b/app/assets/javascripts/es6_browserified/itineraries/containers/VisibleTodoList.js diff --git a/app/assets/javascripts/es6_browserified/form_helper.js b/app/assets/javascripts/es6_browserified/itineraries/form_helper.js index d48718841..d48718841 100644 --- a/app/assets/javascripts/es6_browserified/form_helper.js +++ b/app/assets/javascripts/es6_browserified/itineraries/form_helper.js diff --git a/app/assets/javascripts/es6_browserified/reducers/index.js b/app/assets/javascripts/es6_browserified/itineraries/reducers/index.js index 381b32d8b..381b32d8b 100644 --- a/app/assets/javascripts/es6_browserified/reducers/index.js +++ b/app/assets/javascripts/es6_browserified/itineraries/reducers/index.js diff --git a/app/assets/javascripts/es6_browserified/reducers/todos.js b/app/assets/javascripts/es6_browserified/itineraries/reducers/todos.js index 215a3e2c2..215a3e2c2 100644 --- a/app/assets/javascripts/es6_browserified/reducers/todos.js +++ b/app/assets/javascripts/es6_browserified/itineraries/reducers/todos.js diff --git a/app/assets/javascripts/es6_browserified/stop_points.js b/app/assets/javascripts/es6_browserified/itineraries/stop_points.js index d5f53fb4f..d5f53fb4f 100644 --- a/app/assets/javascripts/es6_browserified/stop_points.js +++ b/app/assets/javascripts/es6_browserified/itineraries/stop_points.js diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js b/app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js new file mode 100644 index 000000000..0342b5df1 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js @@ -0,0 +1,130 @@ +const actions = { + receiveJourneyPatterns : (json) => ({ + type: "RECEIVE_JOURNEY_PATTERNS", + json + }), + loadFirstPage: (dispatch) => ({ + type: 'LOAD_FIRST_PAGE', + dispatch + }), + goToPreviousPage : (dispatch, currentPage) => ({ + type: 'GO_TO_PREVIOUS_PAGE', + dispatch, + currentPage, + nextPage : false + }), + goToNextPage : (dispatch, currentPage) => ({ + type: 'GO_TO_NEXT_PAGE', + dispatch, + currentPage, + nextPage : true + }), + updateCheckboxValue : (e, index) => ({ + type : 'UPDATE_CHECKBOX_VALUE', + id : e.currentTarget.id, + index + }), + openEditModal : (index, journeyPattern) => ({ + type : 'EDIT_JOURNEYPATTERN_MODAL', + index, + journeyPattern + }), + openCreateModal : () => ({ + type : 'CREATE_JOURNEYPATTERN_MODAL' + }), + deleteJourneyPattern : (index, journeyPattern) => ({ + type : 'DELETE_JOURNEYPATTERN', + index, + journeyPattern + }), + closeModal : () => ({ + type : 'CLOSE_MODAL' + }), + saveModal : (index, data) => ({ + type: 'SAVE_MODAL', + data, + index + }), + addJourneyPattern : (index, data) => ({ + type: 'ADD_JOURNEYPATTERN', + data, + index + }), + savePage : (dispatch, currentPage) => ({ + type: 'SAVE_PAGE', + dispatch + }), + submitJourneyPattern : (dispatch, state) => { + let urlJSON = window.location.pathname + ".json" + let req = new Request(urlJSON, { + credentials: 'same-origin', + method: 'PATCH', + contentType: 'application/json; charset=utf-8', + Accept: 'application/json', + body: JSON.stringify(state), + headers: { + 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') + } + }) + fetch(req) + .then(response => response.json()) + .then((json) => { + console.log('request for submit') + // dispatch(actions.receiveJourneyPatterns(journeyPatterns)) + }) + }, + fetchJourneyPatterns : (dispatch, currentPage, nextPage) => { + if(currentPage == undefined){ + currentPage = 1 + } + let journeyPatterns = [] + let page + switch (nextPage) { + case true: + page = currentPage + 1 + break + case false: + if(currentPage > 1){ + page = currentPage - 1 + } + break + default: + page = currentPage + break + } + let str = ".json" + if(page > 1){ + str = '.json?page=' + page.toString() + } + let urlJSON = window.location.pathname + str + let req = new Request(urlJSON, { + credentials: 'same-origin', + }) + fetch(req) + .then(response => response.json()) + .then((json) => { + let val + for (val of json){ + for (let stop_point of val.route_short_description.stop_points){ + stop_point.checked = false + val.stop_area_short_descriptions.map((element) => { + if(element.stop_area_short_description.id === stop_point.id){ + stop_point.checked = true + } + }) + } + journeyPatterns.push({ + name: val.name, + object_id: val.object_id, + published_name: val.published_name, + registration_number: val.registration_number, + stop_points: val.route_short_description.stop_points, + deletable: false + }) + } + dispatch(actions.receiveJourneyPatterns(journeyPatterns)) + }) + } +} + +module.exports = actions diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/App.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/App.js new file mode 100644 index 000000000..5c2454dac --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/App.js @@ -0,0 +1,20 @@ +var React = require('react') +var AddJourneyPattern = require('../containers/AddJourneyPattern') +var Navigate = require('../containers/Navigate') +var Modal = require('../containers/Modal') +var SaveJourneyPattern = require('../containers/SaveJourneyPattern') +var JourneyPatternList = require('../containers/JourneyPatternList') + +const App = () => ( + <div> + <div className='clearfix' style={{ marginBottom: 10 }}> + <Navigate /> + <AddJourneyPattern /> + </div> + <JourneyPatternList /> + <SaveJourneyPattern /> + <Modal/> + </div> +) + +module.exports = App diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js new file mode 100644 index 000000000..c9142e9ab --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js @@ -0,0 +1,105 @@ +var React = require('react') +var Component = require('react').Component +var PropTypes = require('react').PropTypes + +class CreateModal extends Component { + constructor(props) { + super(props) + } + handleSubmit(e) { + e.preventDefault() + this.props.onAddJourneyPattern((this.props.journeyPatterns.length + 1), this.refs) + } + + render() { + return ( + <div className='pull-right'> + <button + type='button' + className='btn btn-primary btn-sm' + data-toggle='modal' + data-target='#NewJourneyPatternModal' + onClick={this.props.onOpenCreateModal} + > + <span className='fa fa-plus'></span> Ajouter une mission + </button> + + <div className={ 'modal fade ' + (this.props.modal.create ? 'in' : '') } id='NewJourneyPatternModal'> + <div className='modal-dialog'> + <div className='modal-content'> + <div className='modal-header clearfix'> + <h4>Ajouter une mission</h4> + </div> + + <div className='modal-body'> + {this.props.modal.create && ( + <form> + <div className='form-group'> + <label>Nom</label> + <input + type='text' + ref='name' + className='form-control' + /> + </div> + <div className='row'> + <div className='col-lg-6 col-md-6 col-sm-6 col-xs-6'> + <div className='form-group'> + <label>Nom public</label> + <input + type='text' + ref='published_name' + className='form-control' + /> + </div> + </div> + <div className='col-lg-6 col-md-6 col-sm-6 col-xs-6'> + <div className='form-group'> + <label>N° d'enregistrement</label> + <input + type='text' + ref='registration_number' + className='form-control' + /> + </div> + </div> + </div> + </form> + )} + </div> + + <div className='modal-footer'> + <button + className='btn btn-default' + data-dismiss='modal' + type='button' + onClick={this.props.onModalClose} + > + Annuler + </button> + <button + className='btn btn-danger' + data-dismiss='modal' + type='button' + onClick={this.handleSubmit.bind(this)} + > + Valider + </button> + </div> + </div> + </div> + </div> + </div> + ) + } +} + +CreateModal.propTypes = { + index: PropTypes.number, + modal: PropTypes.object, + onOpenCreateModal: PropTypes.func.isRequired, + onModalClose: PropTypes.func.isRequired, + onAddJourneyPattern: PropTypes.func.isRequired +} + +module.exports = CreateModal diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/EditModal.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/EditModal.js new file mode 100644 index 000000000..560e44a26 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/EditModal.js @@ -0,0 +1,130 @@ +var React = require('react') +var Component = require('react').Component +var PropTypes = require('react').PropTypes + +class EditModal extends Component { + constructor(props) { + super(props) + } + handleSubmit(e) { + e.preventDefault() + this.props.saveModal(this.props.modal.modalProps.index, this.refs) + } + + render() { + return ( + <div className={ 'modal fade ' + (this.props.modal.edit ? 'in' : '') } id='JourneyPatternModal'> + <div className='modal-dialog'> + <div className='modal-content'> + <div className='modal-header clearfix'> + <h4 className='pull-left'> + Modifier la mission + {this.props.modal.open && ( + <em> "{this.props.modal.modalProps.journeyPattern.name}"</em> + )} + </h4> + <div className='btn-group btn-group-sm pull-right'> + <button + type='button' + className='btn btn-primary dropdown-toggle' + data-toggle='dropdown' + > + <span className='fa fa-bars'></span> + <span className='caret'></span> + </button> + + <ul className='dropdown-menu'> + <li><a href='#'>Horaires des courses</a></li> + <li> + <a + href='#' + data-dismiss='modal' + onClick={(e) => { + e.preventDefault() + this.props.onDeleteJourneyPattern(this.props.modal.modalProps.index, this.props.modal.modalProps.journeyPattern)} + } + > + Supprimer la mission + </a> + </li> + </ul> + </div> + </div> + <div className='modal-body'> + {this.props.modal.edit && ( + <form> + <div className='form-group'> + <label>Nom</label> + <input + type='text' + ref='name' + className='form-control' + id={this.props.modal.modalProps.index} + defaultValue={this.props.modal.modalProps.journeyPattern.name} + /> + </div> + + <div className='row'> + <div className='col-lg-6 col-md-6 col-sm-6 col-xs-6'> + <div className='form-group'> + <label>Nom public</label> + <input + type='text' + ref='published_name' + className='form-control' + id={this.props.modal.modalProps.index} + defaultValue={this.props.modal.modalProps.journeyPattern.published_name} + /> + </div> + </div> + <div className='col-lg-6 col-md-6 col-sm-6 col-xs-6'> + <div className='form-group'> + <label>N° d'enregistrement</label> + <input + type='text' + ref='registration_number' + className='form-control' + id={this.props.modal.modalProps.index} + defaultValue={this.props.modal.modalProps.journeyPattern.registration_number} + /> + </div> + </div> + </div> + + </form> + )} + </div> + <div className='modal-footer'> + <button + className='btn btn-default' + data-dismiss='modal' + type='button' + onClick={this.props.onModalClose} + > + Annuler + </button> + <button + className='btn btn-danger' + data-dismiss='modal' + type='button' + onClick={this.handleSubmit.bind(this)} + > + Valider + </button> + </div> + </div> + </div> + </div> + ) + } +} + +EditModal.propTypes = { + index: PropTypes.number, + modal: PropTypes.object, + onModalClose: PropTypes.func.isRequired, + saveModal: PropTypes.func.isRequired, + onDeleteJourneyPattern: PropTypes.func.isRequired +} + +module.exports = EditModal diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js new file mode 100644 index 000000000..78e2e6d9c --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js @@ -0,0 +1,55 @@ +var React = require('react') +var PropTypes = require('react').PropTypes + +const JourneyPattern = (props) => { + return ( + <div className={'list-group-item ' + (props.value.deletable ? 'disabled' : '') + (props.value.object_id ? '' : 'to_record')}> + <div style={{display: 'inline-block', verticalAlign: 'top', width: '40%'}}> + <p className='small'><strong>Index: </strong>{props.index}</p> + <p className='small'><strong>Name: </strong>{props.value.name}</p> + </div> + + <div style={{display: 'inline-block', verticalAlign: 'top', width: '40%'}}> + <p className='small'><strong>ObjectID: </strong>{props.value.object_id}</p> + <p className='small'><strong>Published name: </strong>{props.value.published_name}</p> + </div> + + <div className='clearfix' style={{display: 'inline-block', verticalAlign: 'top', width: '20%'}}> + <button className={(props.value.deletable ? 'disabled' : '') + ' btn btn-xs btn-danger pull-right'} onClick={props.onOpenEditModal} data-toggle='modal' data-target='#JourneyPatternModal'> + <span className='fa fa-pencil'></span> + </button> + </div> + + <p className='small'><strong>Stop points: </strong></p> + <ul className='list-group'> + {props.value.stop_points.map((stopPoint, i) => + <li + key={ i } + className='list-group-item clearfix' + > + <span className='label label-default' style={{marginRight: 5}}>{stopPoint.id}</span> + <span>{stopPoint.name}</span> + <span className='pull-right'> + <input + onChange = {(e) => props.onCheckboxChange(e)} + type='checkbox' + id={stopPoint.id} + checked={stopPoint.checked} + disabled={props.value.deletable ? 'disabled' : ''} + ></input> + </span> + </li> + )} + </ul> + </div> + ) +} + +JourneyPattern.propTypes = { + value: PropTypes.object, + index: PropTypes.number, + onCheckboxChange: PropTypes.func.isRequired, + onOpenEditModal: PropTypes.func.isRequired +} + +module.exports = JourneyPattern diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js new file mode 100644 index 000000000..160631697 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js @@ -0,0 +1,38 @@ +var React = require('react') +var Component = require('react').Component +var PropTypes = require('react').PropTypes +var JourneyPattern = require('./JourneyPattern') + +class JourneyPatterns extends Component{ + constructor(props){ + super(props) + } + + componentDidMount() { + this.props.onLoadFirstPage() + } + + render() { + return ( + <div className='list-group'> + {this.props.journeyPatterns.map((journeyPattern, index) => + <JourneyPattern + value={ journeyPattern } + key={ index } + onCheckboxChange= {(e) => this.props.onCheckboxChange(e, index)} + onOpenEditModal= {() => this.props.onOpenEditModal(index, journeyPattern)} + /> + )} + </div> + ) + } +} + +JourneyPatterns.propTypes = { + journeyPatterns: PropTypes.array.isRequired, + onCheckboxChange: PropTypes.func.isRequired, + onLoadFirstPage: PropTypes.func.isRequired, + onOpenEditModal: PropTypes.func.isRequired +} + +module.exports = JourneyPatterns diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/containers/AddJourneyPattern.js b/app/assets/javascripts/es6_browserified/journey_patterns/containers/AddJourneyPattern.js new file mode 100644 index 000000000..a4c5c09c9 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/containers/AddJourneyPattern.js @@ -0,0 +1,28 @@ +var actions = require('../actions') +var connect = require('react-redux').connect +var CreateModal = require('../components/CreateModal') + +const mapStateToProps = (state) => { + return { + modal: state.modal, + journeyPatterns: state.journeyPatterns + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onModalClose: () =>{ + dispatch(actions.closeModal()) + }, + onAddJourneyPattern: (index, data) =>{ + dispatch(actions.addJourneyPattern(index, data)) + }, + onOpenCreateModal: () =>{ + dispatch(actions.openCreateModal()) + } + } +} + +const AddJourneyPattern = connect(mapStateToProps, mapDispatchToProps)(CreateModal) + +module.exports = AddJourneyPattern diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/containers/JourneyPatternList.js b/app/assets/javascripts/es6_browserified/journey_patterns/containers/JourneyPatternList.js new file mode 100644 index 000000000..73dc6a1c7 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/containers/JourneyPatternList.js @@ -0,0 +1,27 @@ +var actions = require('../actions') +var connect = require('react-redux').connect +var JourneyPatterns = require('../components/JourneyPatterns') + +const mapStateToProps = (state) => { + return { + journeyPatterns: state.journeyPatterns + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onLoadFirstPage: () =>{ + dispatch(actions.loadFirstPage(dispatch)) + }, + onCheckboxChange: (e, index) =>{ + dispatch(actions.updateCheckboxValue(e, index)) + }, + onOpenEditModal: (index, journeyPattern) =>{ + dispatch(actions.openEditModal(index, journeyPattern)) + } + } +} + +const JourneyPatternList = connect(mapStateToProps, mapDispatchToProps)(JourneyPatterns) + +module.exports = JourneyPatternList diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/containers/Modal.js b/app/assets/javascripts/es6_browserified/journey_patterns/containers/Modal.js new file mode 100644 index 000000000..553d69119 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/containers/Modal.js @@ -0,0 +1,29 @@ +var connect = require('react-redux').connect +var EditModal = require('../components/EditModal') +var CreateModal = require('../components/CreateModal') +var actions = require('../actions') + +const mapStateToProps = (state) => { + return { + modal: state.modal, + journeyPattern: state.journeyPattern + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onModalClose: () =>{ + dispatch(actions.closeModal()) + }, + saveModal: (index, data) =>{ + dispatch(actions.saveModal(index, data)) + }, + onDeleteJourneyPattern: (index, journeyPattern) =>{ + dispatch(actions.deleteJourneyPattern(index, journeyPattern)) + } + } +} + +const ModalContainer = connect(mapStateToProps, mapDispatchToProps)(EditModal, CreateModal) + +module.exports = ModalContainer diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/containers/Navigate.js b/app/assets/javascripts/es6_browserified/journey_patterns/containers/Navigate.js new file mode 100644 index 000000000..c8e681edb --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/containers/Navigate.js @@ -0,0 +1,45 @@ +var React = require('react') +var connect = require('react-redux').connect +var actions = require('../actions') + +let Navigate = ({ dispatch, journeyPatterns, page, length }) => { + let firstPage = 1 + let lastPage = Math.ceil(length / 12) + + return ( + <form className='btn-group btn-group-sm' onSubmit={e => { + e.preventDefault() + }}> + <button + onClick={e => { + e.preventDefault() + dispatch(actions.goToPreviousPage(dispatch, page)) + }} + type="submit" + className={ (page == firstPage ? "hidden" : "") + " btn btn-default" }> + <span className="fa fa-chevron-left"></span> + </button> + <button + onClick={e => { + e.preventDefault() + dispatch(actions.goToNextPage(dispatch, page)) + }} + type="submit" + className={ (page == lastPage ? "hidden" : "") + " btn btn-default" }> + <span className="fa fa-chevron-right"></span> + </button> + </form> + ) +} + +const mapStateToProps = (state) => { + return { + journeyPatterns: state.journeyPatterns, + page: state.pagination, + length: state.totalCount + } +} + +Navigate = connect(mapStateToProps)(Navigate) + +module.exports = Navigate diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/containers/SaveJourneyPattern.js b/app/assets/javascripts/es6_browserified/journey_patterns/containers/SaveJourneyPattern.js new file mode 100644 index 000000000..1fdc385a5 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/containers/SaveJourneyPattern.js @@ -0,0 +1,31 @@ +var React = require('react') +var connect = require('react-redux').connect +var actions = require('../actions') + +let SaveJourneyPattern = ({ dispatch, journeyPatterns, page }) => { + return ( + <form className='clearfix' onSubmit={e => {e.preventDefault()}}> + <button + className='btn btn-danger pull-right' + type='submit' + onClick={e => { + e.preventDefault() + dispatch(actions.savePage(dispatch, page)) + }} + > + Valider + </button> + </form> + ) +} + +const mapStateToProps = (state) => { + return { + journeyPatterns: state.journeyPatterns, + page: state.pagination + } +} + +SaveJourneyPattern = connect(mapStateToProps)(SaveJourneyPattern) + +module.exports = SaveJourneyPattern diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/index.js b/app/assets/javascripts/es6_browserified/journey_patterns/index.js new file mode 100644 index 000000000..aab21fb0b --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/index.js @@ -0,0 +1,37 @@ +var React = require('react') +var render = require('react-dom').render +var Provider = require('react-redux').Provider +var createStore = require('redux').createStore +var journeyPatternsApp = require('./reducers') +var App = require('./components/App') + +// logger, DO NOT REMOVE +// var applyMiddleware = require('redux').applyMiddleware +// var createLogger = require('redux-logger') +// var thunkMiddleware = require('redux-thunk').default +// var promise = require('redux-promise') + +var initialState = { + journeyPatterns: [], + pagination: 1, + totalCount: window.journeyPatternLength, + modal: { + edit: false, + create: false, + modalProps: {} + } +} +// const loggerMiddleware = createLogger() + +let store = createStore( + journeyPatternsApp, + initialState + // applyMiddleware(thunkMiddleware, promise, loggerMiddleware) +) + +render( + <Provider store={store}> + <App /> + </Provider>, + document.getElementById('journey_patterns') +) diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/reducers/index.js b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/index.js new file mode 100644 index 000000000..71ff8b6f5 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/index.js @@ -0,0 +1,14 @@ +var combineReducers = require('redux').combineReducers +var journeyPatterns = require('./journeyPatterns') +var pagination = require('./pagination') +var totalCount = require('./totalCount') +var modal = require('./modal') + +const journeyPatternsApp = combineReducers({ + journeyPatterns, + pagination, + totalCount, + modal +}) + +module.exports = journeyPatternsApp diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/reducers/journeyPatterns.js b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/journeyPatterns.js new file mode 100644 index 000000000..68346b242 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/journeyPatterns.js @@ -0,0 +1,87 @@ +var actions = require("../actions") + +const journeyPattern = (state = {}, action) => { + switch (action.type) { + case 'ADD_JOURNEYPATTERN': + const stop_points = state[0].stop_points.map((s)=>{ + s.checked = false + return s + }) + return { + name: action.data.name.value, + published_name: action.data.published_name.value, + registration_number: action.data.registration_number.value, + stop_points: stop_points, + deletable: false + } + case 'UPDATE_CHECKBOX_VALUE': + var updatedStopPoints = state.stop_points.map((s) => { + if (s.id.toString() == action.id) { + return Object.assign({}, s, {checked : !s.checked}) + }else { + return s + } + }) + return Object.assign({}, state, {stop_points: updatedStopPoints}) + default: + return state + } +} + +const journeyPatterns = (state = {}, action) => { + switch (action.type) { + case 'RECEIVE_JOURNEY_PATTERNS': + return [...action.json] + case 'LOAD_FIRST_PAGE': + actions.fetchJourneyPatterns(action.dispatch) + case 'GO_TO_PREVIOUS_PAGE': + if(action.currentPage > 1){ + actions.fetchJourneyPatterns(action.dispatch, action.currentPage, action.nextPage) + } + return state + case 'GO_TO_NEXT_PAGE': + if (window.journeyPatternLength - (action.currentPage * 12) > 0){ + actions.fetchJourneyPatterns(action.dispatch, action.currentPage, action.nextPage) + } + return state + case 'UPDATE_CHECKBOX_VALUE': + return state.map((j, i) =>{ + if(i == action.index) { + return journeyPattern(j, action) + } else { + return j + } + }) + case 'DELETE_JOURNEYPATTERN': + return state.map((j, i) =>{ + if(i == action.index) { + return Object.assign({}, j, {deletable: true}) + } else { + return j + } + }) + case 'ADD_JOURNEYPATTERN': + return [ + ...state, + journeyPattern(state, action) + ] + case 'SAVE_MODAL': + return state.map((j, i) =>{ + if(i == action.index) { + return Object.assign({}, j, { + name: action.data.name.value, + published_name: action.data.published_name.value, + registration_number: action.data.registration_number.value + }) + } else { + return j + } + }) + case 'SAVE_PAGE': + actions.submitJourneyPattern(action.dispatch, state) + default: + return state + } +} + +module.exports = journeyPatterns diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/reducers/modal.js b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/modal.js new file mode 100644 index 000000000..16f89be3e --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/modal.js @@ -0,0 +1,33 @@ +const modal = (state = {}, action) => { + switch (action.type) { + case 'EDIT_JOURNEYPATTERN_MODAL': + return { + edit: true, + create: false, + modalProps: { + index: action.index, + journeyPattern: action.journeyPattern + } + } + case 'CREATE_JOURNEYPATTERN_MODAL': + return { + create: true, + edit: false, + modalProps: { index: action.index } + } + case 'DELETE_JOURNEYPATTERN': + return Object.assign({}, state, { edit: false, create: false }) + case 'SAVE_MODAL': + return Object.assign({}, state, { edit: false, create: false }) + case 'CLOSE_MODAL': + return { + edit: false, + create: false, + modalProps: {} + } + default: + return state + } +} + +module.exports = modal diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/reducers/pagination.js b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/pagination.js new file mode 100644 index 000000000..0103fe248 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/pagination.js @@ -0,0 +1,18 @@ +const pagination = (state = 0, action) => { + switch (action.type) { + case 'GO_TO_PREVIOUS_PAGE': + if (action.currentPage > 1){ + return state - 1 + } + return state + case 'GO_TO_NEXT_PAGE': + if (window.journeyPatternLength - (action.currentPage * 12) > 0){ + return state + 1 + } + return state + default: + return state + } +} + +module.exports = pagination diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/reducers/totalCount.js b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/totalCount.js new file mode 100644 index 000000000..830de28aa --- /dev/null +++ b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/totalCount.js @@ -0,0 +1,8 @@ +const totalCount = (state = 0, action) => { + switch (action.type) { + default: + return state + } +} + +module.exports = totalCount diff --git a/app/controllers/journey_patterns_collections_controller.rb b/app/controllers/journey_patterns_collections_controller.rb new file mode 100644 index 000000000..39355932e --- /dev/null +++ b/app/controllers/journey_patterns_collections_controller.rb @@ -0,0 +1,51 @@ +class JourneyPatternsCollectionsController < ChouetteController + respond_to :html + respond_to :json + + belongs_to :referential do + belongs_to :line, :parent_class => Chouette::Line do + belongs_to :route, :parent_class => Chouette::Route + end + end + alias_method :route, :parent + + def show + journey_patterns_state + end + + def update + state = JSON.parse request.raw_post + state.each do |item| + journey_pattern = journey_pattern_by_objectid(item['object_id']) + journey_pattern_update_stop_points(journey_pattern, item['stop_points']) if journey_pattern + end + + journey_patterns_state + end + + protected + + def journey_pattern_update_stop_points journey_pattern, stop_points + stop_points.each do |sp| + stop_id = sp['id'] + exist = journey_pattern.stop_area_ids.include?(stop_id) + next if exist && sp['checked'] + + stop_point = route.stop_points.find_by(stop_area_id: stop_id) + if sp['checked'] && !exist + journey_pattern.stop_points << stop_point + else + journey_pattern.stop_points.delete(stop_point) + end + end + end + + def journey_patterns_state + @q = route.journey_patterns.includes(:stop_points) + @journey_patterns ||= @q.paginate(:page => params[:page]).order(:name) + end + + def journey_pattern_by_objectid objectid + Chouette::JourneyPattern.find_by(objectid: objectid) + end +end diff --git a/app/models/chouette/journey_pattern.rb b/app/models/chouette/journey_pattern.rb index 9b2b2a9da..75e1a4a14 100644 --- a/app/models/chouette/journey_pattern.rb +++ b/app/models/chouette/journey_pattern.rb @@ -7,6 +7,7 @@ class Chouette::JourneyPattern < Chouette::TridentActiveRecord has_many :vehicle_journeys, :dependent => :destroy has_many :vehicle_journey_at_stops, :through => :vehicle_journeys has_and_belongs_to_many :stop_points, -> { order("stop_points.position") }, :before_add => :vjas_add, :before_remove => :vjas_remove, :after_add => :shortcuts_update_for_add, :after_remove => :shortcuts_update_for_remove + has_many :stop_areas, through: :stop_points has_many :journey_pattern_sections has_many :route_sections, through: :journey_pattern_sections, dependent: :destroy diff --git a/app/views/api/v1/routes/short_description.rabl b/app/views/api/v1/routes/short_description.rabl index ae149167d..900096ac5 100644 --- a/app/views/api/v1/routes/short_description.rabl +++ b/app/views/api/v1/routes/short_description.rabl @@ -5,3 +5,10 @@ extends "api/v1/trident_objects/short_description" attributes attr, :unless => lambda { |m| m.send( attr).nil?} end +child :stop_points => :stop_points do |stop_points| + node do |stop_point| + partial("api/v1/stop_areas/short_description", :object => stop_point.stop_area).merge(position: stop_point.position) + end +end + + diff --git a/app/views/api/v1/stop_areas/short_description.rabl b/app/views/api/v1/stop_areas/short_description.rabl index 73627c5a1..fb0213510 100644 --- a/app/views/api/v1/stop_areas/short_description.rabl +++ b/app/views/api/v1/stop_areas/short_description.rabl @@ -1,10 +1,10 @@ object @stop_area -extends "api/v1/trident_objects/short_description" +extends "api/v1/trident_objects/short_description" -[ :name, :area_type, :longitude, :latitude, :long_lat_type].each do |attr| +[ :id, :name, :area_type, :longitude, :latitude, :long_lat_type].each do |attr| attributes attr, :unless => lambda { |m| m.send( attr).nil?} end node(:parent_object_id) do |stop_area| - stop_area.parent.objectid + stop_area.parent.objectid end unless root_object.parent.nil? diff --git a/app/views/journey_patterns_collections/show.html.slim b/app/views/journey_patterns_collections/show.html.slim new file mode 100644 index 000000000..7b6f7ae7a --- /dev/null +++ b/app/views/journey_patterns_collections/show.html.slim @@ -0,0 +1,4 @@ +#journey_patterns += javascript_tag do + | window.journeyPatternLength = #{@journey_patterns.total_entries()} += javascript_include_tag 'es6_browserified/journey_patterns/index.js' diff --git a/app/views/journey_patterns_collections/show.rabl b/app/views/journey_patterns_collections/show.rabl new file mode 100644 index 000000000..c241a9c0e --- /dev/null +++ b/app/views/journey_patterns_collections/show.rabl @@ -0,0 +1,3 @@ +collection @journey_patterns +extends "api/v1/journey_patterns/show" + diff --git a/app/views/journey_patterns_collections/update.rabl b/app/views/journey_patterns_collections/update.rabl new file mode 100644 index 000000000..13ced5655 --- /dev/null +++ b/app/views/journey_patterns_collections/update.rabl @@ -0,0 +1,2 @@ +collection @journey_patterns +extends "api/v1/journey_patterns/show" diff --git a/app/views/routes/_form.html.slim b/app/views/routes/_form.html.slim index 9893e4ed7..ae07d41de 100644 --- a/app/views/routes/_form.html.slim +++ b/app/views/routes/_form.html.slim @@ -29,4 +29,4 @@ | window.itinerary_stop = "#{URI.escape(route_json_for_edit(@route))}" / StopPoints Reactux component -= javascript_include_tag 'es6_browserified/stop_points.js' += javascript_include_tag 'es6_browserified/itineraries/stop_points.js' diff --git a/app/views/routes/show.html.slim b/app/views/routes/show.html.slim index c914030c9..3f0e22006 100644 --- a/app/views/routes/show.html.slim +++ b/app/views/routes/show.html.slim @@ -63,14 +63,32 @@ p.after_map div style='display: inline-block;width: 90%;vertical-align: middle;' = linktxt -/ .panel.panel-default -/ .panel-heading -/ h4.panel-title -/ strong = t('.journey_patterns') -/ -/ .panel-body -/ .journey_patterns.paginated_content -/ = paginated_content( @route.journey_patterns, "journey_patterns/journey_pattern") +.panel.panel-default#journey_patterns + .panel-heading + h4.panel-title + strong = t('.journey_patterns') + + .list-group + - @route.journey_patterns.each do |journey_pattern| + .list-group-item.clearfix title="#{t('journey_patterns.journey_pattern.stop_count', count: journey_pattern.stop_points.count, route_count: @route.stop_points.count)} | #{t('journey_patterns.journey_pattern.vehicle_journeys_count', count: journey_pattern.vehicle_journeys.count)}" + span.label.label-default style='margin-right: 10px;' = journey_pattern.objectid.local_id + strong = "#{journey_name(journey_pattern)} " + + - unless journey_pattern.stop_points.empty? + em.small + = t('journey_patterns.journey_pattern.from_to', departure: journey_pattern.stop_points.first.stop_area.name, arrival: journey_pattern.stop_points.last.stop_area.name) + + .btn-group.btn-group-xs.pull-right + .btn.btn-primary.dropdown-toggle data-toggle='dropdown' + span.fa.fa-bars + span.caret + ul.dropdown-menu + li = link_to 'Voir', [@referential, @line, @route, journey_pattern], title: "#{Chouette::JourneyPattern.model_name.human.capitalize} #{journey_name(journey_pattern)}" + li = link_to 'Supprimer', referential_line_route_journey_pattern_path(@referential, @line, @route, journey_pattern), method: :delete, data: {confirm: t('journey_patterns.actions.destroy_confirm')} + + / .panel-body + / .journey_patterns.paginated_content + / = paginated_content( @route.journey_patterns, "journey_patterns/journey_pattern") - content_for :sidebar do ul.actions @@ -86,6 +104,7 @@ p.after_map / li = link_to t('routes.actions.edit_boarding_alighting'), edit_boarding_alighting_referential_line_route_path(@referential, @line, @route), class: 'edit' - if @route.journey_patterns.size > 0 + li = link_to t('journey_patterns.actions.edit_journey_patterns_collection'), [@referential, @line, @route, :journey_patterns_collection], class: 'edit' li = link_to t('vehicle_journeys.actions.index'), [@referential, @line, @route, :vehicle_journeys], class: 'clock' / ul.actions diff --git a/config/locales/journey_patterns.en.yml b/config/locales/journey_patterns.en.yml index 856dd6d15..b11c59bb1 100644 --- a/config/locales/journey_patterns.en.yml +++ b/config/locales/journey_patterns.en.yml @@ -11,6 +11,7 @@ en: destroy: "Remove this journey pattern" destroy_confirm: A"re you sure you want destroy this journey pattern ?" edit_route_sections: "Update route sections" + edit_journey_patterns_collection: "Edit journey patterns" new: title: "Add a new journey pattern" edit: diff --git a/config/locales/journey_patterns.fr.yml b/config/locales/journey_patterns.fr.yml index 78860514a..83e77e474 100644 --- a/config/locales/journey_patterns.fr.yml +++ b/config/locales/journey_patterns.fr.yml @@ -11,6 +11,7 @@ fr: destroy: "Supprimer cette mission" destroy_confirm: "Etes vous sûr de vouloir détruire cette mission ?" edit_route_sections: "Modifier les sections de parcours" + edit_journey_patterns_collection: "Modifier les missions" new: title: "Ajouter une mission" edit: diff --git a/config/routes.rb b/config/routes.rb index c49b28a07..9d4141198 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -99,10 +99,9 @@ ChouetteIhm::Application.routes.draw do get 'edit_boarding_alighting' put 'save_boarding_alighting' end + resource :journey_patterns_collection, :only => [:show, :update] resources :journey_patterns do - member do - get 'new_vehicle_journey' - end + get 'new_vehicle_journey', on: :member resource :route_sections_selector, path: 'sections' do post 'selection' end diff --git a/package.json b/package.json index 43f8c4c6a..d2e9a56b7 100644 --- a/package.json +++ b/package.json @@ -16,5 +16,8 @@ "license": "MIT", "engines": { "node": ">= 0.10" + }, + "devDependencies": { + "es6-object-assign": "^1.0.3" } } diff --git a/spec/controllers/journey_patterns_collections_controller_spec.rb b/spec/controllers/journey_patterns_collections_controller_spec.rb new file mode 100644 index 000000000..888281036 --- /dev/null +++ b/spec/controllers/journey_patterns_collections_controller_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe JourneyPatternsCollectionsController, :type => :controller do + +end diff --git a/spec/javascripts/actions_spec.js b/spec/javascripts/actions_spec.js index 55de1c31f..f86466375 100644 --- a/spec/javascripts/actions_spec.js +++ b/spec/javascripts/actions_spec.js @@ -1,4 +1,4 @@ -var actions = require('es6_browserified/actions') +var actions = require('es6_browserified/itineraries/actions') describe('actions', () => { it('should create an action to add a stop', () => { diff --git a/spec/javascripts/components_spec.js b/spec/javascripts/components_spec.js new file mode 100644 index 000000000..c7e541783 --- /dev/null +++ b/spec/javascripts/components_spec.js @@ -0,0 +1,40 @@ +var React = require('react'); +var Provider = require('react-redux').Provider; +var actions = require('es6_browserified/itineraries/actions/index'); +var App = require('es6_browserified/itineraries/components/TodoList'); +var ConnectedApp = require('es6_browserified/itineraries/containers/VisibleTodoList'); +var TestUtils = require('react-addons-test-utils'); + +xdescribe('ConnectedApp', function() { + var connectedApp, store, initialItems; + var state; + state = [ + { + text: 'first', + index: 0, + for_boarding: 'normal', + for_alighting: 'normal' + }, + { + text: 'second', + index: 1, + for_boarding: 'normal', + for_alighting: 'normal' + } + ] + + beforeEach(function() { + store = state + }); + + describe('state provided by the store', function() { + beforeEach(function() { + connectedApp = TestUtils.renderIntoDocument(<Provider store={store}><ConnectedApp/></Provider>); + }); + + it('passes down items', function() { + app = TestUtils.findRenderedComponentWithType(connectedApp, App); + expect(app.props.items).toEqual(initialItems); + }); + }); +}); diff --git a/spec/javascripts/reducers_spec.js b/spec/javascripts/reducers_spec.js index a4880e73e..253229dda 100644 --- a/spec/javascripts/reducers_spec.js +++ b/spec/javascripts/reducers_spec.js @@ -1,4 +1,4 @@ -var reducer = require('es6_browserified/reducers/todos') +var reducer = require('es6_browserified/itineraries/reducers/todos') let state = [] describe('stops reducer', () => { beforeEach(()=>{ @@ -120,7 +120,7 @@ describe('stops reducer', () => { }) //TODO unskip when es6 is properly functionnal - xit('should handle UPDATE_INPUT_VALUE', () => { + it('should handle UPDATE_INPUT_VALUE', () => { expect( reducer(state, { type: 'UPDATE_INPUT_VALUE', @@ -149,7 +149,7 @@ describe('stops reducer', () => { ) }) - xit('should handle UPDATE_SELECT_VALUE', () => { + it('should handle UPDATE_SELECT_VALUE', () => { expect( reducer(state, { type :'UPDATE_SELECT_VALUE', @@ -160,9 +160,8 @@ describe('stops reducer', () => { ).toEqual( [ { - text: 'new value', + text: 'first', index: 0, - stoparea_id: 1, for_boarding: 'prohibited', for_alighting: 'normal' }, diff --git a/spec/javascripts/spec_helper.js b/spec/javascripts/spec_helper.js index 71d30ff8d..a2fde3860 100644 --- a/spec/javascripts/spec_helper.js +++ b/spec/javascripts/spec_helper.js @@ -4,6 +4,7 @@ // require support/jasmine-jquery-2.1.0 // require support/sinon // require support/your-support-file +require('es6-object-assign').polyfill(); // // PhantomJS (Teaspoons default driver) doesn't have support for Function.prototype.bind, which has caused confusion. // Use this polyfill to avoid the confusion. |
