From b6f08e58fae35d5dd8a610af31c2950b37746695 Mon Sep 17 00:00:00 2001 From: cedricnjanga Date: Fri, 6 Oct 2017 10:17:17 +0200 Subject: Add webpacker gem and migrate the React apps --- app/javascript/journey_patterns/actions/index.js | 220 +++++++++++++++++++++ app/javascript/journey_patterns/components/App.js | 21 ++ .../journey_patterns/components/ConfirmModal.js | 46 +++++ .../journey_patterns/components/CreateModal.js | 122 ++++++++++++ .../journey_patterns/components/EditModal.js | 110 +++++++++++ .../journey_patterns/components/JourneyPattern.js | 131 ++++++++++++ .../journey_patterns/components/JourneyPatterns.js | 155 +++++++++++++++ .../journey_patterns/components/Navigate.js | 62 ++++++ .../components/SaveJourneyPattern.js | 39 ++++ .../containers/AddJourneyPattern.js | 30 +++ .../journey_patterns/containers/ConfirmModal.js | 30 +++ .../containers/JourneyPatternList.js | 34 ++++ .../journey_patterns/containers/Modal.js | 26 +++ .../journey_patterns/containers/Navigate.js | 15 ++ .../containers/SaveJourneyPattern.js | 27 +++ .../journey_patterns/reducers/editMode.js | 10 + app/javascript/journey_patterns/reducers/index.js | 18 ++ .../journey_patterns/reducers/journeyPatterns.js | 90 +++++++++ app/javascript/journey_patterns/reducers/modal.js | 41 ++++ .../journey_patterns/reducers/pagination.js | 35 ++++ app/javascript/journey_patterns/reducers/status.js | 21 ++ .../journey_patterns/reducers/stopPointsList.js | 6 + 22 files changed, 1289 insertions(+) create mode 100644 app/javascript/journey_patterns/actions/index.js create mode 100644 app/javascript/journey_patterns/components/App.js create mode 100644 app/javascript/journey_patterns/components/ConfirmModal.js create mode 100644 app/javascript/journey_patterns/components/CreateModal.js create mode 100644 app/javascript/journey_patterns/components/EditModal.js create mode 100644 app/javascript/journey_patterns/components/JourneyPattern.js create mode 100644 app/javascript/journey_patterns/components/JourneyPatterns.js create mode 100644 app/javascript/journey_patterns/components/Navigate.js create mode 100644 app/javascript/journey_patterns/components/SaveJourneyPattern.js create mode 100644 app/javascript/journey_patterns/containers/AddJourneyPattern.js create mode 100644 app/javascript/journey_patterns/containers/ConfirmModal.js create mode 100644 app/javascript/journey_patterns/containers/JourneyPatternList.js create mode 100644 app/javascript/journey_patterns/containers/Modal.js create mode 100644 app/javascript/journey_patterns/containers/Navigate.js create mode 100644 app/javascript/journey_patterns/containers/SaveJourneyPattern.js create mode 100644 app/javascript/journey_patterns/reducers/editMode.js create mode 100644 app/javascript/journey_patterns/reducers/index.js create mode 100644 app/javascript/journey_patterns/reducers/journeyPatterns.js create mode 100644 app/javascript/journey_patterns/reducers/modal.js create mode 100644 app/javascript/journey_patterns/reducers/pagination.js create mode 100644 app/javascript/journey_patterns/reducers/status.js create mode 100644 app/javascript/journey_patterns/reducers/stopPointsList.js (limited to 'app/javascript/journey_patterns') diff --git a/app/javascript/journey_patterns/actions/index.js b/app/javascript/journey_patterns/actions/index.js new file mode 100644 index 000000000..0c1cb5f5c --- /dev/null +++ b/app/javascript/journey_patterns/actions/index.js @@ -0,0 +1,220 @@ +import Promise from 'promise-polyfill' + +// To add to window +if (!window.Promise) { + window.Promise = Promise; +} + +const actions = { + enterEditMode: () => ({ + type: "ENTER_EDIT_MODE" + }), + exitEditMode: () => ({ + type: "EXIT_EDIT_MODE" + }), + receiveJourneyPatterns : (json) => ({ + type: "RECEIVE_JOURNEY_PATTERNS", + json + }), + receiveErrors : (json) => ({ + type: "RECEIVE_ERRORS", + json + }), + unavailableServer : () => ({ + type: 'UNAVAILABLE_SERVER' + }), + goToPreviousPage : (dispatch, pagination) => ({ + type: 'GO_TO_PREVIOUS_PAGE', + dispatch, + pagination, + nextPage : false + }), + goToNextPage : (dispatch, pagination) => ({ + type: 'GO_TO_NEXT_PAGE', + dispatch, + pagination, + nextPage : true + }), + updateCheckboxValue : (e, index) => ({ + type : 'UPDATE_CHECKBOX_VALUE', + id : e.currentTarget.id, + index + }), + checkConfirmModal : (event, callback, stateChanged,dispatch) => { + if(stateChanged === true){ + return actions.openConfirmModal(callback) + }else{ + dispatch(actions.fetchingApi()) + return callback + } + }, + openConfirmModal : (callback) => ({ + type : 'OPEN_CONFIRM_MODAL', + callback + }), + openEditModal : (index, journeyPattern) => ({ + type : 'EDIT_JOURNEYPATTERN_MODAL', + index, + journeyPattern + }), + openCreateModal : () => ({ + type : 'CREATE_JOURNEYPATTERN_MODAL' + }), + deleteJourneyPattern : (index) => ({ + type : 'DELETE_JOURNEYPATTERN', + index, + }), + closeModal : () => ({ + type : 'CLOSE_MODAL' + }), + saveModal : (index, data) => ({ + type: 'SAVE_MODAL', + data, + index + }), + addJourneyPattern : (data) => ({ + type: 'ADD_JOURNEYPATTERN', + data, + }), + savePage : (dispatch, currentPage) => ({ + type: 'SAVE_PAGE', + dispatch + }), + updateTotalCount: (diff) => ({ + type: 'UPDATE_TOTAL_COUNT', + diff + }), + fetchingApi: () =>({ + type: 'FETCH_API' + }), + resetValidation: (target) => { + $(target).parent().removeClass('has-error').children('.help-block').remove() + }, + humanOID : (oid) => oid.split(':')[2].split("-").pop(), + validateFields : (fields) => { + const test = [] + + Object.keys(fields).map(function(key) { + test.push(fields[key].validity.valid) + }) + if(test.indexOf(false) >= 0) { + // Form is invalid + test.map(function(item, i) { + if(item == false) { + const k = Object.keys(fields)[i] + $(fields[k]).parent().addClass('has-error').children('.help-block').remove() + $(fields[k]).parent().append("" + fields[k].validationMessage + "") + } + }) + return false + } else { + // Form is valid + return true + } + }, + submitJourneyPattern : (dispatch, state, next) => { + dispatch(actions.fetchingApi()) + let urlJSON = window.location.pathname + ".json" + let hasError = false + fetch(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') + } + }).then(response => { + if(!response.ok) { + hasError = true + } + return response.json() + }).then((json) => { + if(hasError == true) { + dispatch(actions.receiveErrors(json)) + } else { + if(next) { + dispatch(next) + } else { + if(json.length != window.currentItemsLength){ + dispatch(actions.updateTotalCount(window.currentItemsLength - json.length)) + } + window.currentItemsLength = json.length + dispatch(actions.exitEditMode()) + dispatch(actions.receiveJourneyPatterns(json)) + } + } + }) + }, + 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 hasError = false + fetch(urlJSON, { + credentials: 'same-origin', + }).then(response => { + if(response.status == 500) { + hasError = true + } + return response.json() + }).then((json) => { + if(hasError == true) { + dispatch(actions.unavailableServer()) + } else { + if(json.length != 0){ + 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 + }) + } + } + window.currentItemsLength = journeyPatterns.length + dispatch(actions.receiveJourneyPatterns(journeyPatterns)) + } + }) + }, + getChecked : (jp) => { + return jp.filter((obj) => { + return obj.checked + }) + } +} + +export default actions \ No newline at end of file diff --git a/app/javascript/journey_patterns/components/App.js b/app/javascript/journey_patterns/components/App.js new file mode 100644 index 000000000..ac6214cc1 --- /dev/null +++ b/app/javascript/journey_patterns/components/App.js @@ -0,0 +1,21 @@ +import React from 'react' +import AddJourneyPattern from '../containers/AddJourneyPattern' +import Navigate from '../containers/Navigate' +import Modal from '../containers/Modal' +import ConfirmModal from '../containers/ConfirmModal' +import SaveJourneyPattern from '../containers/SaveJourneyPattern' +import JourneyPatternList from '../containers/JourneyPatternList' + +const App = () => ( +
+ + + + + + + +
+) + +export default App diff --git a/app/javascript/journey_patterns/components/ConfirmModal.js b/app/javascript/journey_patterns/components/ConfirmModal.js new file mode 100644 index 000000000..2cc1bef44 --- /dev/null +++ b/app/javascript/journey_patterns/components/ConfirmModal.js @@ -0,0 +1,46 @@ +import React, { PropTypes } from 'react' + +export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCancel, journeyPatterns}) { + return ( +
+
+
+
+
+

Confirmation

+
+
+
+

Vous vous apprêtez à changer de page. Voulez-vous valider vos modifications avant cela ?

+
+
+
+ + +
+
+
+
+
+ ) +} + +ConfirmModal.propTypes = { + modal: PropTypes.object.isRequired, + onModalAccept: PropTypes.func.isRequired, + onModalCancel: PropTypes.func.isRequired +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/components/CreateModal.js b/app/javascript/journey_patterns/components/CreateModal.js new file mode 100644 index 000000000..d0eff6e57 --- /dev/null +++ b/app/javascript/journey_patterns/components/CreateModal.js @@ -0,0 +1,122 @@ +import React, { PropTypes, Component } from 'react' +import actions from '../actions' + +export default class CreateModal extends Component { + constructor(props) { + super(props) + } + + handleSubmit() { + if(actions.validateFields(this.refs) == true) { + this.props.onAddJourneyPattern(this.refs) + this.props.onModalClose() + $('#NewJourneyPatternModal').modal('hide') + } + } + + render() { + if(this.props.status.isFetching == true || this.props.status.policy['journey_patterns.create'] == false || this.props.editMode == false) { + return false + } + if(this.props.status.fetchSuccess == true) { + return ( +
+ +
+ ) + } else { + return false + } + } +} + +CreateModal.propTypes = { + index: PropTypes.number, + modal: PropTypes.object.isRequired, + status: PropTypes.object.isRequired, + onOpenCreateModal: PropTypes.func.isRequired, + onModalClose: PropTypes.func.isRequired, + onAddJourneyPattern: PropTypes.func.isRequired +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/components/EditModal.js b/app/javascript/journey_patterns/components/EditModal.js new file mode 100644 index 000000000..699f89b85 --- /dev/null +++ b/app/javascript/journey_patterns/components/EditModal.js @@ -0,0 +1,110 @@ +import React, { PropTypes, Component } from 'react' +import actions from '../actions' + +export default class EditModal extends Component { + constructor(props) { + super(props) + } + + handleSubmit() { + if(actions.validateFields(this.refs) == true) { + this.props.saveModal(this.props.modal.modalProps.index, this.refs) + $('#JourneyPatternModal').modal('hide') + } + } + + render() { + return ( +
+
+
+
+
+

+ Editer la mission + {(this.props.modal.type == 'edit') && ( + "{this.props.modal.modalProps.journeyPattern.name}" + )} +

+
+ + {(this.props.modal.type == 'edit') && ( +
+
+
+ + actions.resetValidation(e.currentTarget)} + required + /> +
+ +
+
+
+ + actions.resetValidation(e.currentTarget)} + required + /> +
+
+
+
+ + actions.resetValidation(e.currentTarget)} + /> +
+
+
+
+ +
+ + +
+
+ )} +
+
+
+
+ ) + } +} + +EditModal.propTypes = { + index: PropTypes.number, + modal: PropTypes.object, + onModalClose: PropTypes.func.isRequired, + saveModal: PropTypes.func.isRequired +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/components/JourneyPattern.js b/app/javascript/journey_patterns/components/JourneyPattern.js new file mode 100644 index 000000000..dde73a957 --- /dev/null +++ b/app/javascript/journey_patterns/components/JourneyPattern.js @@ -0,0 +1,131 @@ +import React, { PropTypes, Component } from 'react' +import actions from '../actions' + +export default class JourneyPattern extends Component{ + constructor(props){ + super(props) + this.previousCity = undefined + } + + vehicleJourneyURL(jpOid) { + let routeURL = window.location.pathname.split('/', 7).join('/') + let vjURL = routeURL + '/vehicle_journeys?jp=' + jpOid + + return ( + Horaires des courses + ) + } + + cityNameChecker(sp) { + let bool = false + if(sp.city_name != this.previousCity){ + bool = true + this.previousCity = sp.city_name + } + return ( +
+ + this.props.onCheckboxChange(e)} + type='checkbox' + id={sp.id} + checked={sp.checked} + disabled={(this.props.value.deletable || this.props.status.policy['journey_patterns.update'] == false || this.props.editMode == false) ? 'disabled' : ''} + > + + + +
+ ) + } + + getErrors(errors) { + let err = Object.keys(errors).map((key, index) => { + return ( +
  • + {key} { errors[key] } +
  • + ) + }) + + return ( + + ) + } + + isDisabled(action) { + return !this.props.status.policy[`journey_patterns.${action}`] && !this.props.editMode + } + + render() { + this.previousCity = undefined + + return ( +
    + {/* Errors */} + {/* this.props.value.errors ? this.getErrors(this.props.value.errors) : '' */} + +
    +
    {this.props.value.object_id ? actions.humanOID(this.props.value.object_id) : '-'}
    +
    {this.props.value.registration_number}
    +
    {actions.getChecked(this.props.value.stop_points).length} arrêt(s)
    + +
    +
    + +
    +
      +
    • + +
    • +
    • + {this.vehicleJourneyURL(this.props.value.object_id)} +
    • +
    • + +
    • +
    +
    +
    + + {this.props.value.stop_points.map((stopPoint, i) =>{ + return ( +
    + {this.cityNameChecker(stopPoint)} +
    + ) + })} +
    + ) + } +} + +JourneyPattern.propTypes = { + value: PropTypes.object, + index: PropTypes.number, + onCheckboxChange: PropTypes.func.isRequired, + onOpenEditModal: PropTypes.func.isRequired, + onDeleteJourneyPattern: PropTypes.func.isRequired +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/components/JourneyPatterns.js b/app/javascript/journey_patterns/components/JourneyPatterns.js new file mode 100644 index 000000000..4b2badabb --- /dev/null +++ b/app/javascript/journey_patterns/components/JourneyPatterns.js @@ -0,0 +1,155 @@ +import React, { PropTypes, Component } from 'react' +import _ from 'lodash' +import JourneyPattern from './JourneyPattern' + + +export default class JourneyPatterns extends Component { + constructor(props){ + super(props) + this.previousCity = undefined + } + componentDidMount() { + this.props.onLoadFirstPage() + } + componentDidUpdate(prevProps, prevState) { + if(this.props.status.isFetching == false){ + $('.table-2entries').each(function() { + var refH = [] + var refCol = [] + + $(this).find('.t2e-head').children('div').each(function() { + var h = $(this).outerHeight(); + refH.push(h) + }); + + var i = 0 + $(this).find('.t2e-item').children('div').each(function() { + var h = $(this).outerHeight(); + if(refCol.length < refH.length){ + refCol.push(h) + } else { + if(h > refCol[i]) { + refCol[i] = h + } + } + if(i == (refH.length - 1)){ + i = 0 + } else { + i++ + } + }); + + for(var n = 0; n < refH.length; n++) { + if(refCol[n] < refH[n]) { + refCol[n] = refH[n] + } + } + + $(this).find('.th').css('height', refCol[0]); + + for(var nth = 1; nth < refH.length; nth++) { + $(this).find('.td:nth-child('+ (nth + 1) +')').css('height', refCol[nth]); + } + }); + } + } + + cityNameChecker(sp) { + let bool = false + if(sp.city_name != this.previousCity){ + bool = true + this.previousCity = sp.city_name + } + return ( +
    + {sp.name} +
    + ) + } + + render() { + this.previousCity = undefined + + if(this.props.status.isFetching == true) { + return ( +
    +
    +
    + ) + } else { + return ( +
    +
    + {(this.props.status.fetchSuccess == false) && ( +
    + Erreur : + la récupération des missions a rencontré un problème. Rechargez la page pour tenter de corriger le problème +
    + )} + + { _.some(this.props.journeyPatterns, 'errors') && ( +
    + Erreur : + {this.props.journeyPatterns.map((jp, index) => + jp.errors && jp.errors.map((err, i) => { + return ( +
      +
    • {err}
    • +
    + ) + }) + )} +
    + )} + +
    0) ? '' : ' no_result')}> +
    +
    +
    ID Mission
    +
    Code mission
    +
    Nb arrêts
    +
    + {this.props.stopPointsList.map((sp, i) =>{ + return ( +
    + {this.cityNameChecker(sp)} +
    + ) + })} +
    + +
    +
    + {this.props.journeyPatterns.map((journeyPattern, index) => + this.props.onCheckboxChange(e, index)} + onOpenEditModal= {() => this.props.onOpenEditModal(index, journeyPattern)} + onDeleteJourneyPattern={() => this.props.onDeleteJourneyPattern(index)} + status= {this.props.status} + editMode= {this.props.editMode} + /> + )} +
    +
    +
    +
    +
    + ) + } + } +} + +JourneyPatterns.propTypes = { + journeyPatterns: PropTypes.array.isRequired, + stopPointsList: PropTypes.array.isRequired, + status: PropTypes.object.isRequired, + onCheckboxChange: PropTypes.func.isRequired, + onLoadFirstPage: PropTypes.func.isRequired, + onOpenEditModal: PropTypes.func.isRequired +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/components/Navigate.js b/app/javascript/journey_patterns/components/Navigate.js new file mode 100644 index 000000000..f2fdd668f --- /dev/null +++ b/app/javascript/journey_patterns/components/Navigate.js @@ -0,0 +1,62 @@ +import React, { PropTypes, Component } from 'react' +import actions from '../actions' + +export default function Navigate({ dispatch, journeyPatterns, pagination, status }) { + let firstPage = 1 + let lastPage = Math.ceil(pagination.totalCount / window.journeyPatternsPerPage) + + let firstItemOnPage = firstPage + (pagination.perPage * (pagination.page - firstPage)) + let lastItemOnPage = firstItemOnPage + (pagination.perPage - firstPage) + + if(status.isFetching == true) { + return false + } + if(status.fetchSuccess == true) { + return ( +
    +
    +
    + Liste des missions {firstItemOnPage} à {(lastItemOnPage < pagination.totalCount) ? lastItemOnPage : pagination.totalCount} sur {pagination.totalCount} +
    { + e.preventDefault() + }}> + + +
    +
    +
    +
    + ) + } else { + return false + } +} + +Navigate.propTypes = { + journeyPatterns: PropTypes.array.isRequired, + status: PropTypes.object.isRequired, + pagination: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/components/SaveJourneyPattern.js b/app/javascript/journey_patterns/components/SaveJourneyPattern.js new file mode 100644 index 000000000..d071fa542 --- /dev/null +++ b/app/javascript/journey_patterns/components/SaveJourneyPattern.js @@ -0,0 +1,39 @@ +import React, { PropTypes, Component } from 'react' +import actions from '../actions' + +export default class SaveJourneyPattern extends Component { + constructor(props){ + super(props) + } + + render() { + if(this.props.status.policy['journey_patterns.update'] == false) { + return false + }else{ + return ( +
    +
    +
    {e.preventDefault()}}> + +
    +
    +
    + ) + } + } +} + +SaveJourneyPattern.propTypes = { + journeyPatterns: PropTypes.array.isRequired, + status: PropTypes.object.isRequired, + page: PropTypes.number.isRequired +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/containers/AddJourneyPattern.js b/app/javascript/journey_patterns/containers/AddJourneyPattern.js new file mode 100644 index 000000000..b093fd111 --- /dev/null +++ b/app/javascript/journey_patterns/containers/AddJourneyPattern.js @@ -0,0 +1,30 @@ +import { connect } from 'react-redux' +import actions from '../actions' +import CreateModal from '../components/CreateModal' + +const mapStateToProps = (state) => { + return { + modal: state.modal, + journeyPatterns: state.journeyPatterns, + editMode: state.editMode, + status: state.status + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onModalClose: () =>{ + dispatch(actions.closeModal()) + }, + onAddJourneyPattern: (data) =>{ + dispatch(actions.addJourneyPattern(data)) + }, + onOpenCreateModal: () =>{ + dispatch(actions.openCreateModal()) + } + } +} + +const AddJourneyPattern = connect(mapStateToProps, mapDispatchToProps)(CreateModal) + +export default AddJourneyPattern diff --git a/app/javascript/journey_patterns/containers/ConfirmModal.js b/app/javascript/journey_patterns/containers/ConfirmModal.js new file mode 100644 index 000000000..92ce09f33 --- /dev/null +++ b/app/javascript/journey_patterns/containers/ConfirmModal.js @@ -0,0 +1,30 @@ +import { connect } from 'react-redux' +import actions from '../actions' +import ConfirmModal from '../components/ConfirmModal' + +const mapStateToProps = (state) => { + return { + modal: state.modal, + journeyPatterns: state.journeyPatterns + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onModalAccept: (next, state) =>{ + dispatch(actions.fetchingApi()) + actions.submitJourneyPattern(dispatch, state, next) + }, + onModalCancel: (next) =>{ + dispatch(actions.fetchingApi()) + dispatch(next) + }, + onModalClose: () =>{ + dispatch(actions.closeModal()) + } + } +} + +const ConfirmModalContainer = connect(mapStateToProps, mapDispatchToProps)(ConfirmModal) + +export default ConfirmModalContainer diff --git a/app/javascript/journey_patterns/containers/JourneyPatternList.js b/app/javascript/journey_patterns/containers/JourneyPatternList.js new file mode 100644 index 000000000..d98734407 --- /dev/null +++ b/app/javascript/journey_patterns/containers/JourneyPatternList.js @@ -0,0 +1,34 @@ +import { connect } from 'react-redux' +import actions from '../actions' +import JourneyPatterns from '../components/JourneyPatterns' + +const mapStateToProps = (state) => { + return { + journeyPatterns: state.journeyPatterns, + status: state.status, + editMode: state.editMode, + stopPointsList: state.stopPointsList + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onLoadFirstPage: () =>{ + dispatch(actions.fetchingApi()) + actions.fetchJourneyPatterns(dispatch) + }, + onCheckboxChange: (e, index) =>{ + dispatch(actions.updateCheckboxValue(e, index)) + }, + onOpenEditModal: (index, journeyPattern) =>{ + dispatch(actions.openEditModal(index, journeyPattern)) + }, + onDeleteJourneyPattern: (index) =>{ + dispatch(actions.deleteJourneyPattern(index)) + } + } +} + +const JourneyPatternList = connect(mapStateToProps, mapDispatchToProps)(JourneyPatterns) + +export default JourneyPatternList diff --git a/app/javascript/journey_patterns/containers/Modal.js b/app/javascript/journey_patterns/containers/Modal.js new file mode 100644 index 000000000..ace71a857 --- /dev/null +++ b/app/javascript/journey_patterns/containers/Modal.js @@ -0,0 +1,26 @@ +import { connect } from 'react-redux' +import actions from '../actions' +import EditModal from '../components/EditModal' +import CreateModal from '../components/CreateModal' + +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)) + } + } +} + +const ModalContainer = connect(mapStateToProps, mapDispatchToProps)(EditModal, CreateModal) + +export default ModalContainer diff --git a/app/javascript/journey_patterns/containers/Navigate.js b/app/javascript/journey_patterns/containers/Navigate.js new file mode 100644 index 000000000..d34e0b4c5 --- /dev/null +++ b/app/javascript/journey_patterns/containers/Navigate.js @@ -0,0 +1,15 @@ +import { connect } from 'react-redux' +import actions from '../actions' +import NavigateComponent from '../components/Navigate' + +const mapStateToProps = (state) => { + return { + journeyPatterns: state.journeyPatterns, + status: state.status, + pagination: state.pagination + } +} + +const Navigate = connect(mapStateToProps)(NavigateComponent) + +export default Navigate \ No newline at end of file diff --git a/app/javascript/journey_patterns/containers/SaveJourneyPattern.js b/app/javascript/journey_patterns/containers/SaveJourneyPattern.js new file mode 100644 index 000000000..b630c121c --- /dev/null +++ b/app/javascript/journey_patterns/containers/SaveJourneyPattern.js @@ -0,0 +1,27 @@ +import { connect } from 'react-redux' +import actions from '../actions' +import SaveJourneyPatternComponent from '../components/SaveJourneyPattern' + +const mapStateToProps = (state) => { + return { + journeyPatterns: state.journeyPatterns, + editMode: state.editMode, + page: state.pagination.page, + status: state.status + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onEnterEditMode: () => { + dispatch(actions.enterEditMode()) + }, + onSubmitJourneyPattern: (next, state) => { + actions.submitJourneyPattern(dispatch, state, next) + } + } +} + +const SaveJourneyPattern = connect(mapStateToProps, mapDispatchToProps)(SaveJourneyPatternComponent) + +export default SaveJourneyPattern diff --git a/app/javascript/journey_patterns/reducers/editMode.js b/app/javascript/journey_patterns/reducers/editMode.js new file mode 100644 index 000000000..bff976804 --- /dev/null +++ b/app/javascript/journey_patterns/reducers/editMode.js @@ -0,0 +1,10 @@ +export default function editMode(state = {}, action ) { + switch (action.type) { + case "ENTER_EDIT_MODE": + return true + case "EXIT_EDIT_MODE": + return false + default: + return state + } +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/reducers/index.js b/app/javascript/journey_patterns/reducers/index.js new file mode 100644 index 000000000..2ffaf86d4 --- /dev/null +++ b/app/javascript/journey_patterns/reducers/index.js @@ -0,0 +1,18 @@ +import { combineReducers } from 'redux' +import editMode from './editMode' +import status from './status' +import journeyPatterns from './journeyPatterns' +import pagination from './pagination' +import modal from './modal' +import stopPointsList from './stopPointsList' + +const journeyPatternsApp = combineReducers({ + editMode, + status, + journeyPatterns, + pagination, + stopPointsList, + modal +}) + +export default journeyPatternsApp diff --git a/app/javascript/journey_patterns/reducers/journeyPatterns.js b/app/javascript/journey_patterns/reducers/journeyPatterns.js new file mode 100644 index 000000000..7702e21bc --- /dev/null +++ b/app/javascript/journey_patterns/reducers/journeyPatterns.js @@ -0,0 +1,90 @@ +import _ from 'lodash' +import actions from "../actions" + +export default function journeyPattern(state = {}, action) { + switch (action.type) { + case 'ADD_JOURNEYPATTERN': + let stopPoints = window.stopPoints + + if(stopPoints != undefined) { + stopPoints.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: stopPoints, + deletable: false + } + case 'UPDATE_CHECKBOX_VALUE': + var updatedStopPoints = state.stop_points.map((s) => { + if (String(s.id) == action.id) { + return _.assign({}, s, {checked : !s.checked}) + }else { + return s + } + }) + return _.assign({}, state, {stop_points: updatedStopPoints}) + default: + return state + } +} + +const journeyPatterns = (state = [], action) => { + switch (action.type) { + case 'RECEIVE_JOURNEY_PATTERNS': + return [...action.json] + case 'RECEIVE_ERRORS': + return [...action.json] + case 'GO_TO_PREVIOUS_PAGE': + $('#ConfirmModal').modal('hide') + if(action.pagination.page > 1){ + actions.fetchJourneyPatterns(action.dispatch, action.pagination.page, action.nextPage) + } + return state + case 'GO_TO_NEXT_PAGE': + $('#ConfirmModal').modal('hide') + if (action.pagination.totalCount - (action.pagination.page * action.pagination.perPage) > 0){ + actions.fetchJourneyPatterns(action.dispatch, action.pagination.page, 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 _.assign({}, j, {deletable: true}) + } else { + return j + } + }) + case 'ADD_JOURNEYPATTERN': + return [ + journeyPattern(state, action), + ...state + ] + case 'SAVE_MODAL': + return state.map((j, i) =>{ + if(i == action.index) { + return _.assign({}, j, { + name: action.data.name.value, + published_name: action.data.published_name.value, + registration_number: action.data.registration_number.value + }) + } else { + return j + } + }) + default: + return state + } +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/reducers/modal.js b/app/javascript/journey_patterns/reducers/modal.js new file mode 100644 index 000000000..0a96f1679 --- /dev/null +++ b/app/javascript/journey_patterns/reducers/modal.js @@ -0,0 +1,41 @@ +import _ from 'lodash' + +export default function modal(state = {}, action) { + switch (action.type) { + case 'OPEN_CONFIRM_MODAL': + $('#ConfirmModal').modal('show') + return _.assign({}, state, { + type: 'confirm', + confirmModal: { + callback: action.callback, + } + }) + case 'EDIT_JOURNEYPATTERN_MODAL': + return { + type: 'edit', + modalProps: { + index: action.index, + journeyPattern: action.journeyPattern + }, + confirmModal: {} + } + case 'CREATE_JOURNEYPATTERN_MODAL': + return { + type: 'create', + modalProps: {}, + confirmModal: {} + } + case 'DELETE_JOURNEYPATTERN': + return _.assign({}, state, { type: '' }) + case 'SAVE_MODAL': + return _.assign({}, state, { type: '' }) + case 'CLOSE_MODAL': + return { + type: '', + modalProps: {}, + confirmModal: {} + } + default: + return state + } +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/reducers/pagination.js b/app/javascript/journey_patterns/reducers/pagination.js new file mode 100644 index 000000000..01fdf21d4 --- /dev/null +++ b/app/javascript/journey_patterns/reducers/pagination.js @@ -0,0 +1,35 @@ +import _ from 'lodash' + +export default function pagination (state = {}, action) { + switch (action.type) { + case 'RECEIVE_JOURNEY_PATTERNS': + return _.assign({}, state, {stateChanged: false}) + case 'GO_TO_PREVIOUS_PAGE': + if (action.pagination.page > 1){ + toggleOnConfirmModal() + return _.assign({}, state, {page : action.pagination.page - 1, stateChanged: false}) + } + return state + case 'GO_TO_NEXT_PAGE': + if (state.totalCount - (action.pagination.page * action.pagination.perPage) > 0){ + toggleOnConfirmModal() + return _.assign({}, state, {page : action.pagination.page + 1, stateChanged: false}) + } + return state + case 'UPDATE_CHECKBOX_VALUE': + case 'ADD_JOURNEYPATTERN': + case 'SAVE_MODAL': + toggleOnConfirmModal('modal') + return _.assign({}, state, {stateChanged: true}) + case 'UPDATE_TOTAL_COUNT': + return _.assign({}, state, {totalCount : state.totalCount - action.diff }) + default: + return state + } +} + +const toggleOnConfirmModal = (arg = '') =>{ + $('.confirm').each(function(){ + $(this).data('toggle','') + }) +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/reducers/status.js b/app/javascript/journey_patterns/reducers/status.js new file mode 100644 index 000000000..88c75966d --- /dev/null +++ b/app/javascript/journey_patterns/reducers/status.js @@ -0,0 +1,21 @@ +import _ from 'lodash' +import actions from '../actions' + +export default function status (state = {}, action) { + switch (action.type) { + case 'UNAVAILABLE_SERVER': + return _.assign({}, state, {fetchSuccess: false}) + case 'FETCH_API': + return _.assign({}, state, {isFetching: true}) + case 'RECEIVE_JOURNEY_PATTERNS': + return _.assign({}, state, {fetchSuccess: true, isFetching: false}) + case 'RECEIVE_ERRORS': + return _.assign({}, state, {isFetching: false}) + case 'ENTER_EDIT_MODE': + return _.assign({}, state, {editMode: true}) + case 'EXIT_EDIT_MODE': + return _.assign({}, state, {editMode: false}) + default: + return state + } +} \ No newline at end of file diff --git a/app/javascript/journey_patterns/reducers/stopPointsList.js b/app/javascript/journey_patterns/reducers/stopPointsList.js new file mode 100644 index 000000000..ee5eb1a80 --- /dev/null +++ b/app/javascript/journey_patterns/reducers/stopPointsList.js @@ -0,0 +1,6 @@ +export default function stopPointsList (state = [], action) { + switch (action.type) { + default: + return state + } +} \ No newline at end of file -- cgit v1.2.3