diff options
Diffstat (limited to 'app/assets/javascripts')
52 files changed, 1632 insertions, 113 deletions
diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js b/app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js index 709686f21..54d62f999 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js @@ -130,9 +130,10 @@ const actions = { if(next) { dispatch(next) } else { - if(json.length != window.journeyPatternsPerPage){ - dispatch(actions.updateTotalCount(window.journeyPatternsPerPage - json.length)) + if(json.length != window.currentItemsLength){ + dispatch(actions.updateTotalCount(window.currentItemsLength - json.length)) } + window.currentItemsLength = json.length dispatch(actions.receiveJourneyPatterns(json)) } } @@ -196,6 +197,7 @@ const actions = { }) } } + window.currentItemsLength = journeyPatterns.length dispatch(actions.receiveJourneyPatterns(journeyPatterns)) } }) diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js index 573ebf228..aa2d208df 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js @@ -17,7 +17,7 @@ class CreateModal extends Component { } render() { - if(this.props.status.isFetching == true) { + if(this.props.status.isFetching == true || this.props.status.policy['journey_patterns.edit'] == false) { return false } if(this.props.status.fetchSuccess == true) { diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js index 3dae38d74..d9f6d5550 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js @@ -14,7 +14,7 @@ class JourneyPattern extends Component{ let vjURL = routeURL + '/vehicle_journeys?jp=' + jpOid return ( - <a href={vjURL}>Horaires des courses</a> + <a data-no-turbolink="true" href={vjURL}>Horaires des courses</a> ) } @@ -34,7 +34,7 @@ class JourneyPattern extends Component{ type='checkbox' id={sp.id} checked={sp.checked} - disabled={this.props.value.deletable ? 'disabled' : ''} + disabled={(this.props.value.deletable || this.props.status.policy['journey_patterns.edit'] == false) ? 'disabled' : ''} > </input> <span className='radio-label'></span> @@ -74,29 +74,30 @@ class JourneyPattern extends Component{ <span className='fa fa-cog'></span> </div> <ul className='dropdown-menu'> - <li className={this.props.value.deletable ? 'disabled' : ''}> - <a - href='#' + <li className={(this.props.value.deletable || this.props.status.policy['journey_patterns.edit'] == false) ? 'disabled' : ''}> + <button + type='button' onClick={this.props.onOpenEditModal} data-toggle='modal' data-target='#JourneyPatternModal' > Editer - </a> + </button> </li> <li className={this.props.value.object_id ? '' : 'disabled'}> {this.vehicleJourneyURL(this.props.value.object_id)} </li> - <li className='delete-action'> - <a - href='#' + <li className={'delete-action' + ((this.props.status.policy['journey_patterns.edit'] == false)? ' disabled' : '')}> + <button + type='button' + disabled={(this.props.status.policy['journey_patterns.edit'] == false)? 'disabled' : ''} onClick={(e) => { e.preventDefault() this.props.onDeleteJourneyPattern(this.props.index)} } > - <span className='fa fa-trash'></span>Supprimer - </a> + <span className='fa fa-trash'></span>Supprimer + </button> </li> </ul> </div> diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js index 37a0a5126..e0557d651 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js @@ -116,6 +116,7 @@ class JourneyPatterns extends Component{ onCheckboxChange= {(e) => this.props.onCheckboxChange(e, index)} onOpenEditModal= {() => this.props.onOpenEditModal(index, journeyPattern)} onDeleteJourneyPattern={() => this.props.onDeleteJourneyPattern(index)} + status= {this.props.status} /> )} </div> diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/Navigate.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/Navigate.js index 3ca860e2e..5747aa5ce 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/components/Navigate.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/Navigate.js @@ -31,7 +31,7 @@ let Navigate = ({ dispatch, journeyPatterns, pagination, status }) => { data-toggle='' data-target='#ConfirmModal' className={'previous_page' + (pagination.page == firstPage ? ' disabled' : '')} - disabled={'previous_page' + (pagination.page == firstPage ? ' disabled' : '')} + disabled={(pagination.page == firstPage ? ' disabled' : '')} > </button> <button @@ -43,7 +43,7 @@ let Navigate = ({ dispatch, journeyPatterns, pagination, status }) => { data-toggle='' data-target='#ConfirmModal' className={'next_page' + (pagination.page == lastPage ? ' disabled' : '')} - disabled={'next_page' + (pagination.page == lastPage ? ' disabled' : '')} + disabled={(pagination.page == lastPage ? 'disabled' : '')} > </button> </form> diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js index 6e09430a0..93dfa8c6b 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js @@ -15,7 +15,7 @@ class SaveJourneyPattern extends Component{ } render() { - if(this.props.status.isFetching == true) { + if(this.props.status.isFetching == true || (this.props.status.policy['journey_patterns.edit'] == false)) { return false } if(this.props.status.fetchSuccess == true) { diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/index.js b/app/assets/javascripts/es6_browserified/journey_patterns/index.js index a2e1c2fb6..b06957e0f 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/index.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/index.js @@ -13,6 +13,7 @@ var App = require('./components/App') var initialState = { status: { + policy: window.perms, fetchSuccess: true, isFetching: false }, diff --git a/app/assets/javascripts/es6_browserified/time_tables/actions/index.js b/app/assets/javascripts/es6_browserified/time_tables/actions/index.js new file mode 100644 index 000000000..a9fbb94cf --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/actions/index.js @@ -0,0 +1,195 @@ +const _ = require('lodash') + +const actions = { + strToArrayDayTypes: (str) =>{ + let weekDays = ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'] + return weekDays.map((day, i) => str.indexOf(day) !== -1) + }, + + fetchingApi: () =>({ + type: 'FETCH_API' + }), + unavailableServer: () => ({ + type: 'UNAVAILABLE_SERVER' + }), + receiveMonth: (json) => ({ + type: 'RECEIVE_MONTH', + json + }), + receiveTimeTables: (json) => ({ + type: 'RECEIVE_TIME_TABLES', + json + }), + goToPreviousPage : (dispatch, pagination) => ({ + type: 'GO_TO_PREVIOUS_PAGE', + dispatch, + pagination, + nextPage : false + }), + goToNextPage : (dispatch, pagination) => ({ + type: 'GO_TO_NEXT_PAGE', + dispatch, + pagination, + nextPage : true + }), + changePage : (dispatch, pagination, val) => ({ + type: 'CHANGE_PAGE', + dispatch, + page: val + }), + updateDayTypes: (index) => ({ + type: 'UPDATE_DAY_TYPES', + index + }), + updateComment: (comment) => ({ + type: 'UPDATE_COMMENT', + comment + }), + updateColor: (color) => ({ + type: 'UPDATE_COLOR', + color + }), + select2Tags: (selectedTag) => ({ + type: 'UPDATE_SELECT_TAG', + selectedItem: { + id: selectedTag.id, + name: selectedTag.name + } + }), + unselect2Tags: (selectedTag) => ({ + type: 'UPDATE_UNSELECT_TAG', + selectedItem: { + id: selectedTag.id, + name: selectedTag.name + } + }), + deletePeriod: (index, dayTypes) => ({ + type: 'DELETE_PERIOD', + index, + dayTypes + }), + openAddPeriodForm: () => ({ + type: 'OPEN_ADD_PERIOD_FORM' + }), + openEditPeriodForm: (period, index) => ({ + type: 'OPEN_EDIT_PERIOD_FORM', + period, + index + }), + closePeriodForm: () => ({ + type: 'CLOSE_PERIOD_FORM' + }), + updatePeriodForm: (val, group, selectType) => ({ + type: 'UPDATE_PERIOD_FORM', + val, + group, + selectType + }), + includeDateInPeriod: (index, day, dayTypes) => ({ + type: 'INCLUDE_DATE_IN_PERIOD', + index, + day, + dayTypes + }), + excludeDateFromPeriod: (index, day, dayTypes) => ({ + type: 'EXCLUDE_DATE_FROM_PERIOD', + index, + day, + dayTypes + }), + + monthName(strDate) { + let monthList = ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"] + var date = new Date(strDate) + return monthList[date.getMonth()] + }, + getHumanDate(strDate, mLimit) { + let origin = strDate.split('-') + let D = origin[2] + let M = actions.monthName(strDate).toLowerCase() + let Y = origin[0] + + if(mLimit && M.length > mLimit) { + M = M.substr(0, mLimit) + '.' + } + + return (D + ' ' + M + ' ' + Y) + }, + + updateSynthesis: (state, daytypes) => { + let periods = state.time_table_periods + + let isInPeriod = function(d){ + let currentMonth = state.current_periode_range.split('-') + let twodigitsDay = d.mday < 10 ? ('0' + d.mday) : d.mday + let currentDate = new Date(currentMonth[0] + '-' + currentMonth[1] + '-' + twodigitsDay) + + // We compare periods & currentDate, to determine if it is included or not + let testDate = false + periods.map((p, i) => { + if(p.deleted){ + return false + } + let begin = new Date(p.period_start) + let end = new Date(p.period_end) + + if(testDate === false){ + if(currentDate >= begin && currentDate <= end) { + if(daytypes[d.wday] === false) { + testDate = false + } else { + testDate = true + } + } + } + }) + return testDate + } + + let improvedCM = state.current_month.map((d, i) => { + return _.assign({}, state.current_month[i], { + in_periods: isInPeriod(state.current_month[i]) + }) + }) + return improvedCM + }, + + checkConfirmModal: (event, callback, stateChanged,dispatch) => { + if(stateChanged === true){ + return actions.openConfirmModal(callback) + }else{ + dispatch(actions.fetchingApi()) + return callback + } + }, + fetchTimeTables: (dispatch, nextPage) => { + let urlJSON = window.location.pathname.split('/', 5).join('/') + // console.log(nextPage) + if(nextPage) { + urlJSON += "/month.json?date=" + nextPage + }else{ + urlJSON += ".json" + } + 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(nextPage){ + dispatch(actions.receiveMonth(json)) + }else{ + dispatch(actions.receiveTimeTables(json)) + } + } + }) + }, +} + +module.exports = actions diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js b/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js new file mode 100644 index 000000000..13615a6ef --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js @@ -0,0 +1,65 @@ +var React = require('react') +var Component = require('react').Component +var PropTypes = require('react').PropTypes +var actions = require('../actions') + +class ExceptionsInDay extends Component { + constructor(props) { + super(props) + } + + render() { + {/* display add or remove link, only if true in daytypes */} + if(this.props.outFromDaytypes == true) { + {/* display add or remove link, according to context (presence in period, or not) */} + if(this.props.value.current_month[this.props.index].in_periods == true) { + return ( + <div className='td'> + <button + type='button' + className='btn btn-circle' + data-actiontype='remove' + onClick={(e) => { + $(e.currentTarget).toggleClass('active') + this.props.onExcludeDateFromPeriod(this.props.index, this.props.value.current_month[this.props.index], this.props.metas.day_types) + }} + > + <span className='fa fa-times'></span> + </button> + </div> + ) + } else { + return ( + <div className='td'> + <button + type='button' + className='btn btn-circle' + data-actiontype='add' + onClick={(e) => { + $(e.currentTarget).toggleClass('active') + this.props.onIncludeDateInPeriod(this.props.index, this.props.value.current_month[this.props.index], this.props.metas.day_types) + }} + > + <span className='fa fa-plus'></span> + </button> + </div> + ) + } + } else { + return ( + <div className='td'></div> + ) + } + } +} + +ExceptionsInDay.propTypes = { + value: PropTypes.object.isRequired, + metas: PropTypes.object.isRequired, + outFromDaytypes: PropTypes.bool.isRequired, + onExcludeDateFromPeriod: PropTypes.func.isRequired, + onIncludeDateInPeriod: PropTypes.func.isRequired, + index: PropTypes.number.isRequired +} + +module.exports = ExceptionsInDay diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/Metas.js b/app/assets/javascripts/es6_browserified/time_tables/components/Metas.js new file mode 100644 index 000000000..943b781f5 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/components/Metas.js @@ -0,0 +1,139 @@ +var React = require('react') +var PropTypes = require('react').PropTypes +let weekDays = ['D', 'L', 'Ma', 'Me', 'J', 'V', 'S'] +var TagsSelect2 = require('./TagsSelect2') + +const Metas = ({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelect2Tags, onUnselect2Tags}) => { + let colorList = ["", "#9B9B9B", "#FFA070", "#C67300", "#7F551B", "#41CCE3", "#09B09C", "#3655D7", "#6321A0", "#E796C6", "#DD2DAA"] + return ( + <div className="row"> + <div className="col-lg-6 col-lg-offset-3 col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1"> + <div className='form-horizontal'> + <div className="row"> + <div className="col-lg-12"> + {/* comment (name) */} + <div className="form-group"> + <label htmlFor="" className="control-label col-sm-4 required"> + Nom <abbr title="Champ requis">*</abbr> + </label> + <div className="col-sm-8"> + <input + type='text' + className='form-control' + value={metas.comment} + onChange={(e) => (onUpdateComment(e.currentTarget.value))} + /> + </div> + </div> + + {/* color */} + <div className="form-group"> + <label htmlFor="" className="control-label col-sm-4">Couleur associée</label> + <div className="col-sm-8"> + <div className="dropdown color_selector"> + <button + type='button' + className="btn btn-default dropdown-toggle" + id='dpdwn_color' + data-toggle='dropdown' + aria-haspopup='true' + aria-expanded='true' + > + <span + className='fa fa-circle mr-xs' + style={{color: (metas.color == '') ? 'transparent' : metas.color}} + ></span> + <span className='caret'></span> + </button> + + <div className="form-group dropdown-menu" aria-labelledby='dpdwn_color'> + {colorList.map((c, i) => + <span + className="radio" + key={i} + onClick={() => {onUpdateColor(c)}} + > + <label htmlFor=""> + <input + type='radio' + className='color_selector' + value={c} + /> + <span + className='fa fa-circle' + style={{color: ((c == '') ? 'transparent' : c)}} + ></span> + </label> + </span> + )} + </div> + </div> + </div> + </div> + + {/* tags */} + {/* <div className="form-group"> + <label htmlFor="" className="control-label col-sm-4">Etiquettes</label> + <div className="col-sm-8"> + <TagsSelect2 + tags={metas.tags} + onSelect2Tags={(e) => onSelect2Tags(e)} + onUnselect2Tags={(e) => onUnselect2Tags(e)} + /> + <input type="text" value='ton papa' className='form-control'/> + </div> + </div> + */} + + {/* calendar */} + <div className="form-group"> + <label htmlFor="" className="control-label col-sm-4">Modèle de calendrier associé</label> + <div className="col-sm-8"> + <span>{metas.calendar.name}</span> + </div> + </div> + {/* day_types */} + <div className="form-group"> + <label htmlFor="" className="control-label col-sm-4"> + Journées d'applications pour les périodes ci-dessous + </label> + <div className="col-sm-8"> + <div className="form-group labelled-checkbox-group"> + {metas.day_types.map((day, i) => + <div className="lcbx-group-item" + key={i} + > + <div className="checkbox"> + <label> + <input + onChange={(e) => {onUpdateDayTypes(i)}} + id={i} + type="checkbox" + checked={day ? 'checked' : ''} + /> + <span className='lcbx-group-item-label'>{weekDays[i]}</span> + </label> + </div> + </div> + )} + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + ) +} + +Metas.propTypes = { + metas: PropTypes.object.isRequired, + onUpdateDayTypes: PropTypes.func.isRequired, + onUpdateColor: PropTypes.func.isRequired, + onUpdateColor: PropTypes.func.isRequired, + onSelect2Tags: PropTypes.func.isRequired, + onUnselect2Tags: PropTypes.func.isRequired +} + +module.exports = Metas diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/Navigate.js b/app/assets/javascripts/es6_browserified/time_tables/components/Navigate.js new file mode 100644 index 000000000..5db373f9c --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/components/Navigate.js @@ -0,0 +1,96 @@ +var React = require('react') +var Component = require('react').Component +var PropTypes = require('react').PropTypes +var actions = require('../actions') +var _ = require('lodash') + +let Navigate = ({ dispatch, metas, timetable, pagination, status, filters}) => { + if(status.isFetching == true) { + return false + } + if(status.fetchSuccess == true) { + let pageIndex = pagination.periode_range.indexOf(pagination.currentPage) + let firstPage = pageIndex == 0 + let lastPage = pageIndex == pagination.periode_range.length - 1 + return ( + <div className="row mt-md"> + <div className="col-lg-8 col-lg-offset-2 col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 text-right"> + <div className="pagination"> + <form className='form-inline' onSubmit={e => {e.preventDefault()}}> + {/* date selector */} + <div className="form-group"> + <div className="dropdown month_selector" style={{display: 'inline-block'}}> + <div + className='btn btn-default dropdown-toggle' + id='date_selector' + data-toggle='dropdown' + aria-haspopup='true' + aria-expanded='true' + > + {pagination.currentPage ? (actions.monthName(pagination.currentPage) + ' ' + new Date(pagination.currentPage).getFullYear()) : ''} + <span className='caret'></span> + </div> + <ul + className='dropdown-menu' + aria-labelledby='date_selector' + > + {_.map(pagination.periode_range, (month, i) => ( + <li key={i}> + <button + type='button' + value={month} + onClick={e => { + e.preventDefault() + dispatch(actions.checkConfirmModal(e, actions.changePage(dispatch, pagination, e.currentTarget.value), pagination.stateChanged, dispatch)) + }} + > + {actions.monthName(month) + ' ' + new Date(month).getFullYear()} + </button> + </li> + ))} + </ul> + </div> + </div> + + {/* prev/next */} + <div className="form-group"> + <div className="page_links"> + <button + onClick={e => { + e.preventDefault() + dispatch(actions.checkConfirmModal(e, actions.goToPreviousPage(dispatch, pagination), pagination.stateChanged, dispatch)) + }} + type='button' + data-target='#ConfirmModal' + className={(firstPage ? 'disabled ' : '') + 'previous_page'} + disabled={(firstPage ? 'disabled' : '')} + ></button> + <button + onClick={e => { + e.preventDefault() + dispatch(actions.checkConfirmModal(e, actions.goToNextPage(dispatch, pagination), pagination.stateChanged, dispatch)) + }} + type='button' + data-target='#ConfirmModal' + className={(lastPage ? 'disabled ' : '') + 'next_page'} + disabled={(lastPage ? 'disabled' : '')} + ></button> + </div> + </div> + </form> + </div> + </div> + </div> + ) + } else { + return false + } +} + +Navigate.propTypes = { + status: PropTypes.object.isRequired, + pagination: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired +} + +module.exports = Navigate diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js new file mode 100644 index 000000000..274429af8 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js @@ -0,0 +1,90 @@ +var React = require('react') +var PropTypes = require('react').PropTypes +let monthsArray = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'] + +const formatNumber = (val) => { + return ("0" + val).slice(-2) +} + +const makeDaysOptions = (daySelected) => { + let arr = [] + for(let i = 1; i < 32; i++) { + arr.push(<option value={formatNumber(i)} key={i}>{formatNumber(i)}</option>) + } + return arr +} + +const makeMonthsOptions = (monthSelected) => { + let arr = [] + for(let i = 1; i < 13; i++) { + arr.push(<option value={formatNumber(i)} key={i}>{monthsArray[i - 1]}</option>) + } + return arr +} + +const makeYearsOptions = (yearSelected) => { + let arr = [] + let startYear = new Date().getFullYear() - 3 + for(let i = startYear; i <= startYear + 6; i++) { + arr.push(<option key={i}>{i}</option>) + } + return arr +} + +const PeriodForm = ({modal, timetable, onOpenAddPeriodForm, onClosePeriodForm, onUpdatePeriodForm}) => ( + <div> + {modal.modalProps.active && + <div className="form-group date filter_menu-item"> + <label className="date required control-label" >Du <abbr title="Champ requis">*</abbr></label> + <div className="form-inline"> + <select value={formatNumber(modal.modalProps.begin.day)} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'begin', 'day')} id="q_validity_period_begin_gteq_3i" className="date required form-control"> + {makeDaysOptions(modal.modalProps.begin.day)} + </select> + <select value={formatNumber(modal.modalProps.begin.month)} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'begin', 'month')} id="q_validity_period_begin_gteq_2i" className="date required form-control"> + {makeMonthsOptions(modal.modalProps.begin.month)} + </select> + <select value={modal.modalProps.begin.year} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'begin', 'year')} id="q_validity_period_begin_gteq_1i" className="date required form-control"> + {makeYearsOptions(modal.modalProps.begin.year)} + </select> + </div> + <label className="date required control-label" >Au <abbr title="Champ requis">*</abbr></label> + <div className="form-inline"> + <select value={formatNumber(modal.modalProps.end.day)} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'end', 'day')} id="q_validity_period_end_gteq_3i" className="date required form-control"> + {makeDaysOptions(modal.modalProps.end.day)} + </select> + <select value={formatNumber(modal.modalProps.end.month)} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'end', 'month')} id="q_validity_period_end_gteq_2i" className="date required form-control"> + {makeMonthsOptions(modal.modalProps.end.month)} + </select> + <select value={modal.modalProps.end.year} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'end', 'year')} id="q_validity_period_end_gteq_1i" className="date required form-control"> + {makeYearsOptions(modal.modalProps.end.year)} + </select> + </div> + <div> + <button + onClick={onClosePeriodForm} + > + Annuler + </button> + <button>Valider</button> + </div> + </div> + } + {!modal.modalProps.active && + <button + onClick={onOpenAddPeriodForm} + > + Ajouter une période + </button> + } + </div> +) + +PeriodForm.propTypes = { + modal: PropTypes.object.isRequired, + onOpenAddPeriodForm: PropTypes.func.isRequired, + onClosePeriodForm: PropTypes.func.isRequired, + onUpdatePeriodForm: PropTypes.func.isRequired, + timetable: PropTypes.object.isRequired +} + +module.exports = PeriodForm diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js new file mode 100644 index 000000000..de3f31ee0 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js @@ -0,0 +1,65 @@ +var React = require('react') +var Component = require('react').Component +var PropTypes = require('react').PropTypes +var actions = require('../actions') + +class PeriodManager extends Component { + constructor(props) { + super(props) + } + + render() { + return ( + <div + className='period_manager' + id={this.props.value.id} + > + <p className='strong'> + {actions.getHumanDate(this.props.value.period_start, 3).substr(0, 7) + ' > ' + actions.getHumanDate(this.props.value.period_end, 3)} + </p> + + <div className='dropdown'> + <div + className='btn dropdown-toggle' + id='period_actions' + data-toggle='dropdown' + aria-haspopup='true' + aria-expanded='true' + > + <span className='fa fa-cog'></span> + </div> + <ul + className='dropdown-menu' + aria-labelledby='date_selector' + > + <li> + <button + type='button' + onClick={() => this.props.onOpenEditPeriodForm(this.props.value, this.props.index)} + > + Modifier + </button> + </li> + <li className='delete-action'> + <button + type='button' + onClick={() => this.props.onDeletePeriod(this.props.index, this.props.metas.day_types)} + > + <span className='fa fa-trash'></span> + Supprimer + </button> + </li> + </ul> + </div> + </div> + ) + } +} + +PeriodManager.propTypes = { + value: PropTypes.object.isRequired, + onDeletePeriod: PropTypes.func.isRequired, + onOpenEditPeriodForm: PropTypes.func.isRequired +} + +module.exports = PeriodManager diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js new file mode 100644 index 000000000..93a8fe433 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js @@ -0,0 +1,78 @@ +var React = require('react') +var Component = require('react').Component +var PropTypes = require('react').PropTypes +var PeriodManager = require('./PeriodManager') + +class PeriodsInDay extends Component { + constructor(props) { + super(props) + } + + isIn(date) { + let currentDate = date.getTime() + let cls = 'td' + let periods = this.props.value + + periods.map((p, i) => { + if (!p.deleted){ + let begin = new Date(p.period_start).getTime() + let end = new Date(p.period_end).getTime() + + if(currentDate >= begin && currentDate <= end) { + if(currentDate == begin) { + cls += ' in_periods start_period' + } else if(currentDate == end) { + cls += ' in_periods end_period' + } else { + cls += ' in_periods' + } + } + } + }) + return cls + } + + render() { + return ( + <div + className={this.isIn(this.props.currentDate)} + > + {this.props.value.map((p, i) => { + if(!p.deleted){ + let begin = new Date(p.period_start).getTime() + let end = new Date(p.period_end).getTime() + let d = this.props.currentDate.getTime() + + if(d >= begin && d <= end) { + if(d == begin || (this.props.currentDate.getUTCDate() == 1)) { + return ( + <PeriodManager + key={i} + index={i} + value={p} + onDeletePeriod={this.props.onDeletePeriod} + onOpenEditPeriodForm={this.props.onOpenEditPeriodForm} + metas={this.props.metas} + /> + ) + } else { + return false + } + } + }else{ + return false + } + })} + </div> + ) + } +} + +PeriodsInDay.propTypes = { + value: PropTypes.array.isRequired, + currentDate: PropTypes.object.isRequired, + index: PropTypes.number.isRequired, + onDeletePeriod: PropTypes.func.isRequired +} + +module.exports = PeriodsInDay diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js b/app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js new file mode 100644 index 000000000..16ebc250a --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js @@ -0,0 +1,73 @@ +var _ = require('lodash') +var React = require('react') +var PropTypes = require('react').PropTypes +var Select2 = require('react-select2') + +// get JSON full path +var origin = window.location.origin +var path = window.location.pathname.split('/', 4).join('/') +var _ = require('lodash') + +class TagsSelect2 extends React.Component{ + constructor(props) { + super(props) + } + + mapKeys(array){ + return array.map((item) => + _.mapKeys(item, (v, k) => + ((k == 'name') ? 'text' : k) + ) + ) + } + + render() { + return ( + <Select2 + value={(this.props.tags.length) ? _.map(this.props.tags, 'id') : undefined} + data={(this.props.tags.length) ? this.mapKeys(this.props.tags) : undefined} + onSelect={(e) => this.props.onSelect2Tags(e)} + onUnselect={(e) => setTimeout( () => this.props.onUnselect2Tags(e, 150))} + multiple={true} + ref='tags_id' + options={{ + allowClear: true, + theme: 'bootstrap', + width: '100%', + placeholder: 'Cherchez un tag...', + ajax: { + url: origin + path + '/tags.json', + dataType: 'json', + delay: '500', + data: function(params) { + return { + tag: params.term, + }; + }, + processResults: function(data, params) { + + return { + results: data.map( + item => _.assign( + {}, + item, + {text: item.name} + ) + ) + }; + }, + cache: true + }, + minimumInputLength: 3, + templateResult: formatRepo + }} + /> + ) + } +} + +const formatRepo = (props) => { + if(props.name) return props.name +} + +module.exports = TagsSelect2 diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js b/app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js new file mode 100644 index 000000000..29c894565 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js @@ -0,0 +1,35 @@ +var React = require('react') +var Component = require('react').Component +var PropTypes = require('react').PropTypes + +class TimeTableDay extends Component { + constructor(props) { + super(props) + } + + render() { + return ( + <span + className={'day' + (this.props.value.wday == 0 ? ' last_wday' : '')} + data-wday={'S' + this.props.value.wnumber} + > + <span className='dayname'> + {((this.props.value.day).charAt(0) == 'm') ? (this.props.value.day).substr(0, 2) : (this.props.value.day).charAt(0)} + </span> + <span + className={'daynumber' + (((this.props.value.in_periods && this.props.dayTypeActive && !this.props.value.excluded_date) || (this.props.value.include_date && this.props.dayTypeActive)) ? ' included' : '')} + > + {this.props.value.mday} + </span> + </span> + ) + } +} + +TimeTableDay.propTypes = { + value: PropTypes.object.isRequired, + index: PropTypes.number.isRequired, + dayTypeActive: PropTypes.bool.isRequired +} + +module.exports = TimeTableDay diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js b/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js new file mode 100644 index 000000000..65aae0e11 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js @@ -0,0 +1,103 @@ +var React = require('react') +var Component = require('react').Component +var PropTypes = require('react').PropTypes +var TimeTableDay = require('./TimeTableDay') +var PeriodsInDay = require('./PeriodsInDay') +var ExceptionsInDay = require('./ExceptionsInDay') +var actions = require('../actions') + +class Timetable extends Component{ + constructor(props){ + super(props) + } + + currentDate(mFirstday, day) { + let currentMonth = mFirstday.split('-') + let twodigitsDay = day < 10 ? ('0' + day) : day + let currentDate = new Date(currentMonth[0] + '-' + currentMonth[1] + '-' + twodigitsDay) + + return currentDate + } + + render() { + return ( + <div className='row'> + <div className="col-lg-8 col-lg-offset-2 col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1"> + <div className="table table-2entries mb-sm"> + <div className="t2e-head w20"> + <div className="th"> + <div className="strong">Synthèse</div> + </div> + <div className="td"><span>Journées d'application</span></div> + <div className="td"><span>Périodes</span></div> + <div className="td"><span>Exceptions</span></div> + </div> + <div className="t2e-item-list w80"> + <div> + <div className="t2e-item"> + <div className="th"> + <div className="strong monthName"> + {actions.monthName(this.props.timetable.current_periode_range)} + </div> + + <div className='monthDays'> + {this.props.timetable.current_month.map((d, i) => + <TimeTableDay + key={i} + index={i} + value={d} + dayTypeActive={this.props.metas.day_types[d.wday]} + /> + )} + </div> + </div> + + {this.props.timetable.current_month.map((d, i) => + <div + key={i} + className={'td-group' + (this.props.metas.day_types[d.wday] ? '' : ' out_from_daytypes') + (d.wday == 0 ? ' last_wday' : '')} + > + {/* day_types */} + <div className="td"></div> + + {/* periods */} + <PeriodsInDay + index={i} + value={this.props.timetable.time_table_periods} + currentDate={this.currentDate(this.props.timetable.current_periode_range, d.mday)} + onDeletePeriod={this.props.onDeletePeriod} + onOpenEditPeriodForm={this.props.onOpenEditPeriodForm} + metas={this.props.metas} + /> + + {/* exceptions */} + <ExceptionsInDay + index={i} + value={this.props.timetable} + metas={this.props.metas} + outFromDaytypes={this.props.metas.day_types[d.wday]} + onExcludeDateFromPeriod={this.props.onExcludeDateFromPeriod} + onIncludeDateInPeriod={this.props.onIncludeDateInPeriod} + /> + </div> + )} + </div> + </div> + </div> + </div> + </div> + </div> + ) + } +} + +Timetable.propTypes = { + metas: PropTypes.object.isRequired, + timetable: PropTypes.object.isRequired, + status: PropTypes.object.isRequired, + onDeletePeriod: PropTypes.func.isRequired, + onExcludeDateFromPeriod: PropTypes.func.isRequired, + onIncludeDateInPeriod: PropTypes.func.isRequired +} + +module.exports = Timetable diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/App.js b/app/assets/javascripts/es6_browserified/time_tables/containers/App.js new file mode 100644 index 000000000..fede03aec --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/containers/App.js @@ -0,0 +1,38 @@ +var React = require('react') +var connect = require('react-redux').connect +var Component = require('react').Component +var actions = require('../actions') +var Metas = require('./Metas') +var Timetable = require('./Timetable') +var Navigate = require('./Navigate') +var PeriodForm = require('./PeriodForm') + +class App extends Component { + componentDidMount(){ + this.props.onLoadFirstPage() + } + + render(){ + return( + <div> + <Metas /> + <Navigate /> + <Timetable /> + <PeriodForm /> + </div> + ) + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onLoadFirstPage: () =>{ + dispatch(actions.fetchingApi()) + actions.fetchTimeTables(dispatch) + } + } +} + +const timeTableApp = connect(null, mapDispatchToProps)(App) + +module.exports = timeTableApp diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/Metas.js b/app/assets/javascripts/es6_browserified/time_tables/containers/Metas.js new file mode 100644 index 000000000..514ed2347 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/containers/Metas.js @@ -0,0 +1,33 @@ +var actions = require('../actions') +var connect = require('react-redux').connect +var MetasComponent = require('../components/Metas') + +const mapStateToProps = (state) => { + return { + metas: state.metas + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onUpdateDayTypes: (index) => { + dispatch(actions.updateDayTypes(index)) + }, + onUpdateComment: (comment) => { + dispatch(actions.updateComment(comment)) + }, + onUpdateColor: (color) => { + dispatch(actions.updateColor(color)) + }, + onSelect2Tags: (e) => { + dispatch(actions.select2Tags(e.params.data)) + }, + onUnselect2Tags: (e) => { + dispatch(actions.unselect2Tags(e.params.data)) + } + } +} + +const Metas = connect(mapStateToProps, mapDispatchToProps)(MetasComponent) + +module.exports = Metas diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/Navigate.js b/app/assets/javascripts/es6_browserified/time_tables/containers/Navigate.js new file mode 100644 index 000000000..c70583c25 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/containers/Navigate.js @@ -0,0 +1,18 @@ +var React = require('react') +var connect = require('react-redux').connect +var actions = require('../actions') +var NavigateComponent = require('../components/Navigate') + +const mapStateToProps = (state) => { + return { + metas: state.metas, + timetable: state.timetable, + status: state.status, + pagination: state.pagination + } +} + + +const Navigate = connect(mapStateToProps)(NavigateComponent) + +module.exports = Navigate diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/PeriodForm.js b/app/assets/javascripts/es6_browserified/time_tables/containers/PeriodForm.js new file mode 100644 index 000000000..0a785c680 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/containers/PeriodForm.js @@ -0,0 +1,28 @@ +var connect = require('react-redux').connect +var PeriodFormComponent = require('../components/PeriodForm') +var actions = require('../actions') + +const mapStateToProps = (state) => { + return { + modal: state.modal, + timetable: state.timetable + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onOpenAddPeriodForm: () => { + dispatch(actions.openAddPeriodForm()) + }, + onClosePeriodForm: () => { + dispatch(actions.closePeriodForm()) + }, + onUpdatePeriodForm: (val, group, selectType) => { + dispatch(actions.updatePeriodForm(val, group, selectType)) + } + } +} + +const PeriodForm = connect(mapStateToProps, mapDispatchToProps)(PeriodFormComponent) + +module.exports = PeriodForm diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js b/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js new file mode 100644 index 000000000..2a17d3dea --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js @@ -0,0 +1,32 @@ +var connect = require('react-redux').connect +var TimetableComponent = require('../components/Timetable') +var actions = require('../actions') + +const mapStateToProps = (state) => { + return { + metas: state.metas, + timetable: state.timetable, + status: state.status + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onDeletePeriod: (index, dayTypes) =>{ + dispatch(actions.deletePeriod(index, dayTypes)) + }, + onExcludeDateFromPeriod: (index, day, dayTypes) => { + dispatch(actions.excludeDateFromPeriod(index, day, dayTypes)) + }, + onIncludeDateInPeriod: (index, day, dayTypes) => { + dispatch(actions.includeDateInPeriod(index, day, dayTypes)) + }, + onOpenEditPeriodForm: (period, index) => { + dispatch(actions.openEditPeriodForm(period, index)) + } + } +} + +const Timetable = connect(mapStateToProps, mapDispatchToProps)(TimetableComponent) + +module.exports = Timetable diff --git a/app/assets/javascripts/es6_browserified/time_tables/index.js b/app/assets/javascripts/es6_browserified/time_tables/index.js new file mode 100644 index 000000000..69b7fdd7c --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/index.js @@ -0,0 +1,69 @@ +var React = require('react') +var render = require('react-dom').render +var Provider = require('react-redux').Provider +var createStore = require('redux').createStore +var timeTablesApp = require('./reducers') +var App = require('./containers/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 = { + status: { + policy: window.perms, + fetchSuccess: true, + isFetching: false + }, + timetable: { + current_month: [], + current_periode_range: '', + periode_range: [], + time_table_periods: [] + }, + metas: { + comment: '', + day_types: [], + tags: [], + color: '', + calendar: {} + }, + pagination: { + stateChanged: false, + currentPage: '', + periode_range: [] + }, + modal: { + type: '', + modalProps: { + active: false, + begin: { + day: '01', + month: '01', + year: String(new Date().getFullYear()) + }, + end: { + day: '01', + month: '01', + year: String(new Date().getFullYear()) + } + }, + confirmModal: {} + } +} +const loggerMiddleware = createLogger() + +let store = createStore( + timeTablesApp, + initialState, + applyMiddleware(thunkMiddleware, promise, loggerMiddleware) +) + +render( + <Provider store={store}> + <App /> + </Provider>, + document.getElementById('periods') +) diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/index.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/index.js new file mode 100644 index 000000000..5b05aadda --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/index.js @@ -0,0 +1,16 @@ +var combineReducers = require('redux').combineReducers +var status = require('./status') +var pagination = require('./pagination') +var modal = require('./modal') +var timetable = require('./timetable') +var metas = require('./metas') + +const timeTablesApp = combineReducers({ + timetable, + metas, + status, + pagination, + modal +}) + +module.exports = timeTablesApp diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js new file mode 100644 index 000000000..555730908 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js @@ -0,0 +1,33 @@ +const _ = require('lodash') +const actions = require('../actions') + +const metas = (state = {}, action) => { + switch (action.type) { + case 'RECEIVE_TIME_TABLES': + return _.assign({}, state, { + comment: action.json.comment, + day_types: actions.strToArrayDayTypes(action.json.day_types), + tags: action.json.tags, + color: action.json.color, + calendar: action.json.calendar ? action.json.calendar : {name : 'Aucun'} + }) + case 'UPDATE_DAY_TYPES': + let dayTypes = state.day_types.slice(0) + dayTypes[action.index] = !dayTypes[action.index] + return _.assign({}, state, {day_types: dayTypes}) + case 'UPDATE_COMMENT': + return _.assign({}, state, {comment: action.comment}) + case 'UPDATE_COLOR': + return _.assign({}, state, {color: action.color}) + case 'UPDATE_SELECT_TAG': + let tags = [...state.tags] + tags.push(action.selectedItem) + return _.assign({}, state, {tags: tags}) + case 'UPDATE_UNSELECT_TAG': + return _.assign({}, state, {tags: _.filter(state.tags, (t) => (t.id != action.selectedItem.id))}) + default: + return state + } +} + +module.exports = metas diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/modal.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/modal.js new file mode 100644 index 000000000..e9c0c2fb9 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/modal.js @@ -0,0 +1,42 @@ +var _ = require('lodash') +let newModalProps = {} + +const modal = (state = {}, action) => { + switch (action.type) { + case 'CLOSE_PERIOD_FORM': + let emptyDate = { + begin: '', + month: '', + year: '' + } + newModalProps = _.assign({}, state.modalProps, {active: false, begin: emptyDate, end: emptyDate, index: false}) + return _.assign({}, state, {modalProps: newModalProps}) + case 'OPEN_EDIT_PERIOD_FORM': + let period_start = action.period.period_start.split('-') + let period_end = action.period.period_end.split('-') + newModalProps = JSON.parse(JSON.stringify(state.modalProps)) + + newModalProps.begin.year = period_start[0] + newModalProps.begin.month = period_start[1] + newModalProps.begin.day = period_start[2] + + newModalProps.end.year = period_end[0] + newModalProps.end.month = period_end[1] + newModalProps.end.day = period_end[2] + + newModalProps.active = true + newModalProps.index = action.index + return _.assign({}, state, {modalProps: newModalProps}) + case 'OPEN_ADD_PERIOD_FORM': + newModalProps = _.assign({}, state.modalProps, {active: true}) + return _.assign({}, state, {modalProps: newModalProps}) + case 'UPDATE_PERIOD_FORM': + newModalProps = JSON.parse(JSON.stringify(state.modalProps)) + newModalProps[action.group][action.selectType] = action.val + return _.assign({}, state, {modalProps: newModalProps}) + default: + return state + } +} + +module.exports = modal diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js new file mode 100644 index 000000000..35b9b3cd8 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js @@ -0,0 +1,30 @@ +var _ = require('lodash') + +const pagination = (state = {}, action) => { + switch (action.type) { + case 'RECEIVE_TIME_TABLES': + return _.assign({}, state, { + currentPage: action.json.current_periode_range, + periode_range: action.json.periode_range + }) + case 'GO_TO_PREVIOUS_PAGE': + case 'GO_TO_NEXT_PAGE': + let nextPage = action.nextPage ? 1 : -1 + let newPage = action.pagination.periode_range[action.pagination.periode_range.indexOf(action.pagination.currentPage) + nextPage] + toggleOnConfirmModal() + return _.assign({}, state, {currentPage : newPage, stateChanged: false}) + case 'CHANGE_PAGE': + toggleOnConfirmModal() + return _.assign({}, state, {currentPage : action.page, stateChanged: false}) + default: + return state + } +} + +const toggleOnConfirmModal = (arg = '') =>{ + $('.confirm').each(function(){ + $(this).data('toggle','') + }) +} + +module.exports = pagination diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/status.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/status.js new file mode 100644 index 000000000..fc205d0ae --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/status.js @@ -0,0 +1,17 @@ +var _ = require('lodash') + +const status = (state = {}, action) => { + switch (action.type) { + case 'UNAVAILABLE_SERVER': + return _.assign({}, state, {fetchSuccess: false}) + case 'FETCH_API': + return _.assign({}, state, {isFetching: true}) + case 'RECEIVE_TIME_TABLES': + case 'RECEIVE_MONTH': + return _.assign({}, state, {fetchSuccess: true, isFetching: false}) + default: + return state + } +} + +module.exports = status diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js new file mode 100644 index 000000000..b052b5fcc --- /dev/null +++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js @@ -0,0 +1,63 @@ +const _ = require('lodash') +var actions = require('../actions') +let newState = {} + +const timetable = (state = {}, action) => { + switch (action.type) { + case 'RECEIVE_TIME_TABLES': + let fetchedState = _.assign({}, state, { + current_month: action.json.current_month, + current_periode_range: action.json.current_periode_range, + periode_range: action.json.periode_range, + time_table_periods: action.json.time_table_periods + }) + return _.assign({}, fetchedState, {current_month: actions.updateSynthesis(fetchedState, actions.strToArrayDayTypes(action.json.day_types))}) + case 'RECEIVE_MONTH': + newState = _.assign({}, state, { + current_month: action.json.days + }) + return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, actions.strToArrayDayTypes(action.json.day_types))}) + case 'GO_TO_PREVIOUS_PAGE': + case 'GO_TO_NEXT_PAGE': + let nextPage = action.nextPage ? 1 : -1 + let newPage = action.pagination.periode_range[action.pagination.periode_range.indexOf(action.pagination.currentPage) + nextPage] + $('#ConfirmModal').modal('hide') + actions.fetchTimeTables(action.dispatch, newPage) + return _.assign({}, state, {current_periode_range: newPage}) + case 'CHANGE_PAGE': + $('#ConfirmModal').modal('hide') + actions.fetchTimeTables(action.dispatch, action.page) + return _.assign({}, state, {current_periode_range: action.page}) + case 'DELETE_PERIOD': + let ttperiods = state.time_table_periods.map((period, i) =>{ + if(i == action.index){ + period.deleted = true + } + return period + }) + newState = _.assign({}, state, {time_table_periods : ttperiods}) + return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)}) + case 'INCLUDE_DATE_IN_PERIOD': + let newCMi = state.current_month.map((d, i) => { + if(i == action.index){ + d.include_date = !d.include_date + } + return d + }) + newState = _.assign({}, state, {current_month: newCMi}) + return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)}) + case 'EXCLUDE_DATE_FROM_PERIOD': + let newCMe = state.current_month.map((d, i) => { + if(i == action.index){ + d.excluded_date = !d.excluded_date + } + return d + }) + newState = _.assign({}, state, {current_month: newCMe}) + return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)}) + default: + return state + } +} + +module.exports = timetable diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js index 4e67482da..81bbcdbb0 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js @@ -315,9 +315,12 @@ const actions = { selected: false, published_journey_name: val.published_journey_name || 'non renseigné', published_journey_identifier: val.published_journey_name || 'non renseigné', - company_id: val.published_journey_name || 'non renseigné' + company_id: val.published_journey_name || 'non renseigné', + transport_mode: val.route.line.transport_mode || 'non renseigné', + transport_mode: val.route.line.transport_submode || 'non renseigné' }) } + window.currentItemsLength = vehicleJourneys.length dispatch(actions.receiveVehicleJourneys(vehicleJourneys)) dispatch(actions.receiveTotalCount(json.total)) } @@ -348,9 +351,10 @@ const actions = { if(next) { dispatch(next) } else { - if(json.length != window.vehicleJourneysPerPage){ - dispatch(actions.updateTotalCount(window.vehicleJourneysPerPage - json.length)) + if(json.length != window.currentItemsLength){ + dispatch(actions.updateTotalCount(window.currentItemsLength - json.length)) } + window.currentItemsLength = json.length dispatch(actions.receiveVehicleJourneys(json)) } } @@ -362,13 +366,29 @@ const actions = { return obj.selected }) }, - pad: (d) => { + simplePad: (d) => { if(d.toString().length == 1){ return (d < 10) ? '0' + d.toString() : d.toString(); }else{ return d.toString() } }, + pad: (d, timeUnit) => { + let val = d.toString() + if(d.toString().length == 1){ + val = (d < 10) ? '0' + d.toString() : d.toString(); + } + if(val.length > 2){ + val = val.substr(1) + } + if(timeUnit == 'minute' && parseInt(val) > 59){ + val = '59' + } + if(timeUnit == 'hour' && parseInt(val) > 23){ + val = '23' + } + return val + }, encodeParams: (params) => { let esc = encodeURIComponent let queryString = Object.keys(params).map((k) => esc(k) + '=' + esc(params[k])).join('&') @@ -390,20 +410,61 @@ const actions = { return vjas }, checkSchedules: (schedule) => { + let hours = 0 + let minutes = 0 if (parseInt(schedule.departure_time.minute) > 59){ - schedule.departure_time.minute = actions.pad(parseInt(schedule.departure_time.minute) - 60) - schedule.departure_time.hour = actions.pad(parseInt(schedule.departure_time.hour) + 1) + hours = Math.floor(parseInt(schedule.departure_time.minute) / 60) + minutes = parseInt(schedule.departure_time.minute) % 60 + schedule.departure_time.minute = actions.simplePad(minutes, 'minute') + schedule.departure_time.hour = parseInt(schedule.departure_time.hour) + hours } if (parseInt(schedule.arrival_time.minute) > 59){ - schedule.arrival_time.minute = actions.pad(parseInt(schedule.arrival_time.minute) - 60) - schedule.arrival_time.hour = actions.pad(parseInt(schedule.arrival_time.hour) + 1) + hours = Math.floor(parseInt(schedule.arrival_time.minute) / 60) + minutes = parseInt(schedule.arrival_time.minute) % 60 + schedule.arrival_time.minute = actions.simplePad(minutes, 'minute') + schedule.arrival_time.hour = parseInt(schedule.arrival_time.hour) + hours } - if (parseInt(schedule.departure_time.hour) > 23){ - schedule.departure_time.hour = actions.pad(parseInt(schedule.departure_time.hour) - 24) + if (parseInt(schedule.departure_time.minute) < 0){ + hours = Math.floor(parseInt(schedule.departure_time.minute) / 60) + minutes = (parseInt(schedule.departure_time.minute) % 60) + 60 + schedule.departure_time.minute = actions.simplePad(minutes, 'minute') + schedule.departure_time.hour = parseInt(schedule.departure_time.hour) + hours } - if (parseInt(schedule.arrival_time.hour) > 23){ - schedule.arrival_time.hour = actions.pad(parseInt(schedule.arrival_time.hour) - 24) + if (parseInt(schedule.arrival_time.minute) < 0){ + hours = Math.floor(parseInt(schedule.arrival_time.minute) / 60) + minutes = (parseInt(schedule.arrival_time.minute) % 60) + 60 + schedule.arrival_time.minute = actions.simplePad(minutes, 'minute') + schedule.arrival_time.hour = parseInt(schedule.arrival_time.hour) + hours } + + if(schedule.departure_time.hour > 23){ + schedule.departure_time.hour = '23' + schedule.departure_time.minute = '59' + } + if(schedule.arrival_time.hour > 23){ + schedule.arrival_time.hour = '23' + schedule.arrival_time.minute = '59' + } + + if(schedule.departure_time.hour < 0){ + schedule.departure_time.hour = '00' + schedule.departure_time.minute = '00' + } + if(schedule.arrival_time.hour > 23){ + schedule.arrival_time.hour = '00' + schedule.arrival_time.minute = '00' + } + + schedule.departure_time.hour = actions.simplePad(parseInt(schedule.departure_time.hour), 'hour') + schedule.arrival_time.hour = actions.simplePad(parseInt(schedule.arrival_time.hour), 'hour') + // if (parseInt(schedule.departure_time.hour) > 23){ + // schedule.departure_time.hour = parseInt(schedule.departure_time.hour) - 24 + // } + // if (parseInt(schedule.arrival_time.hour) > 23){ + // schedule.arrival_time.hour = parseInt(schedule.arrival_time.hour) - 24 + // } + // schedule.departure_time.hour = actions.pad(schedule.departure_time.hour, 'hour') + // schedule.arrival_time.hour = actions.pad(schedule.arrival_time.hour, 'hour') } } diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Filters.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Filters.js index bddb29434..6f07dd880 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Filters.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Filters.js @@ -97,7 +97,7 @@ const Filters = ({filters, pagination, onFilter, onResetFilters, onUpdateStartTi onChange={onToggleWithoutSchedule} checked={filters.query.withoutSchedule} ></input> - <span className='switch-label' data-checkedvalue='Oui' data-uncheckedvalue='Non'></span> + <span className='switch-label' data-checkedvalue='Non' data-uncheckedvalue='Oui'></span> </label> </div> </div> diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Navigate.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Navigate.js index 2d5923a4d..a62e034ae 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Navigate.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Navigate.js @@ -29,7 +29,7 @@ let Navigate = ({ dispatch, vehicleJourneys, pagination, status, filters}) => { type='button' data-target='#ConfirmModal' className={(pagination.page == firstPage ? 'disabled ' : '') + 'previous_page'} - disabled={(pagination.page == firstPage ? true : false)} + disabled={(pagination.page == firstPage ? 'disabled' : '')} ></button> <button onClick={e => { @@ -39,7 +39,7 @@ let Navigate = ({ dispatch, vehicleJourneys, pagination, status, filters}) => { type='button' data-target='#ConfirmModal' className={(pagination.page == lastPage ? 'disabled ' : '') + 'next_page'} - disabled={(pagination.page == lastPage ? true : false)} + disabled={(pagination.page == lastPage ? 'disabled' : '')} ></button> </form> </div> diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js index b22e1d826..bd34ae114 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js @@ -15,7 +15,7 @@ class SaveVehicleJourneys extends Component{ } render() { - if(this.props.status.isFetching == true) { + if(this.props.status.isFetching == true || this.props.filters.policy['vehicle_journeys.edit'] == false) { return false } if(this.props.status.fetchSuccess == true) { @@ -46,7 +46,8 @@ class SaveVehicleJourneys extends Component{ SaveVehicleJourneys.propTypes = { vehicleJourneys: PropTypes.array.isRequired, page: PropTypes.number.isRequired, - status: PropTypes.object.isRequired + status: PropTypes.object.isRequired, + filters: PropTypes.object.isRequired } module.exports = SaveVehicleJourneys diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js index dc0621f76..0645fdd19 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js @@ -54,7 +54,7 @@ class VehicleJourney extends Component { <div key={i}>{this.timeTableURL(tt.id)}</div> )} - {this.isDisabled(this.props.filters.policy['vehicle_journeys.edit'], this.props.filters.policy['vehicle_journeys.destroy']) && + {(this.props.filters.policy['vehicle_journeys.edit'] == true) && <div className={(this.props.value.deletable ? 'disabled ' : '') + 'checkbox'}> <input id={this.props.index} @@ -73,14 +73,14 @@ class VehicleJourney extends Component { <div key={i} className='td text-center'> <div className={'cellwrap' + (vj.dummy ? ' headlined' : '') + (this.cityNameChecker(vj) ? ' headlined' : '')}> {this.props.filters.toggleArrivals && - <div data-headline='Départ à'> - <span className={((this.props.value.deletable && (!vj.dummy)) ? 'disabled ' : '') + 'input-group time'}> + <div data-headline='Arrivée à'> + <span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false) ? 'disabled ' : '') + 'input-group time'}> <input type='number' min='00' max='23' className='form-control' - disabled={(this.props.value.deletable && (!vj.dummy))} + disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)} onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', false, false)}} value={vj.arrival_time['hour']} /> @@ -90,7 +90,7 @@ class VehicleJourney extends Component { min='00' max='59' className='form-control' - disabled={((this.props.value.deletable) && (!vj.dummy))} + disabled={((this.isDisabled(this.props.value.deletable), vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)} onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'minute', false, false)}} value={vj.arrival_time['minute']} /> @@ -102,14 +102,14 @@ class VehicleJourney extends Component { <span className='sb sb-chrono sb-lg text-warning' data-textinside={vj.delta}></span> } </div> - <div data-headline='Arrivée à'> - <span className={(this.isDisabled(this.props.value.deletable, vj.dummy) ? 'disabled ' : '') + 'input-group time'}> + <div data-headline='Départ à'> + <span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false) ? 'disabled ' : '') + 'input-group time'}> <input type='number' min='00' max='23' className='form-control' - disabled={this.isDisabled(this.props.value.deletable, vj.dummy)} + disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)} onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', true, this.props.filters.toggleArrivals)}} value={vj.departure_time['hour']} /> @@ -119,7 +119,7 @@ class VehicleJourney extends Component { min='00' max='59' className='form-control' - disabled={this.isDisabled(this.props.value.deletable, vj.dummy)} + disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)} onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, "minute", true, this.props.filters.toggleArrivals)}} value={vj.departure_time['minute']} /> diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CalendarsEditVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CalendarsEditVehicleJourney.js index 19a5af869..e32c873e6 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CalendarsEditVehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CalendarsEditVehicleJourney.js @@ -22,15 +22,15 @@ class CalendarsEditVehicleJourney extends Component { if(this.props.status.fetchSuccess == true) { return ( <li className='st_action'> - <a - href='#' - className={(actions.getSelected(this.props.vehicleJourneys).length > 0 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} + <button + type='button' + disabled={(actions.getSelected(this.props.vehicleJourneys).length > 0 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} data-toggle='modal' data-target='#CalendarsEditVehicleJourneyModal' onClick={() => this.props.onOpenCalendarsEditModal(actions.getSelected(this.props.vehicleJourneys))} > <span className='fa fa-calendar'></span> - </a> + </button> <div className={ 'modal fade ' + ((this.props.modal.type == 'duplicate') ? 'in' : '') } id='CalendarsEditVehicleJourneyModal'> <div className='modal-container'> diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js index 1a1588f85..1273921e7 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js @@ -25,15 +25,15 @@ class CreateModal extends Component { if(this.props.status.fetchSuccess == true) { return ( <li className='st_action'> - <a - href='#' - className={((this.props.filters.policy['vehicle_journeys.create']) ? '' : 'disabled')} + <button + type='button' + disabled={((this.props.filters.policy['vehicle_journeys.edit'] == true) ? '' : 'disabled')} data-toggle='modal' data-target='#NewVehicleJourneyModal' onClick={this.props.onOpenCreateModal} > <span className='fa fa-plus'></span> - </a> + </button> <div className={ 'modal fade ' + ((this.props.modal.type == 'create') ? 'in' : '') } id='NewVehicleJourneyModal'> <div className='modal-container'> diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DeleteVehicleJourneys.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DeleteVehicleJourneys.js index e2425cc22..c98b794a8 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DeleteVehicleJourneys.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DeleteVehicleJourneys.js @@ -5,9 +5,9 @@ var actions = require('../../actions') const DeleteVehicleJourneys = ({onDeleteVehicleJourneys, vehicleJourneys, filters}) => { return ( <li className='st_action'> - <a - href='#' - className={(actions.getSelected(vehicleJourneys).length > 0 && filters.policy['vehicle_journeys.destroy']) ? '' : 'disabled'} + <button + type='button' + disabled={(actions.getSelected(vehicleJourneys).length > 0 && filters.policy['vehicle_journeys.destroy']) ? '' : 'disabled'} onClick={e => { e.preventDefault() onDeleteVehicleJourneys() @@ -15,7 +15,7 @@ const DeleteVehicleJourneys = ({onDeleteVehicleJourneys, vehicleJourneys, filter title='Supprimer' > <span className='fa fa-trash'></span> - </a> + </button> </li> ) } diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js index b0cb1c850..7448aa06e 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js @@ -23,15 +23,15 @@ class DuplicateVehicleJourney extends Component { if(this.props.status.fetchSuccess == true) { return ( <li className='st_action'> - <a - href='#' - className={((actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled')} + <button + type='button' + disabled={((actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled')} data-toggle='modal' data-target='#DuplicateVehicleJourneyModal' onClick={this.props.onOpenDuplicateModal} > <span className='fa fa-files-o'></span> - </a> + </button> <div className={ 'modal fade ' + ((this.props.modal.type == 'duplicate') ? 'in' : '') } id='DuplicateVehicleJourneyModal'> <div className='modal-container'> @@ -68,7 +68,7 @@ class DuplicateVehicleJourney extends Component { <input type='number' ref='additional_time' - min='0' + min='-59' max='59' className='form-control' onKeyDown={(e) => actions.resetValidation(e.currentTarget)} diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js index f7726dad9..9a4790051 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js @@ -24,15 +24,15 @@ class EditVehicleJourney extends Component { if(this.props.status.fetchSuccess == true) { return ( <li className='st_action'> - <a - href='#' - className={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} + <button + type='button' + disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} data-toggle='modal' data-target='#EditVehicleJourneyModal' onClick={() => this.props.onOpenEditModal(actions.getSelected(this.props.vehicleJourneys)[0])} > <span className='fa fa-info'></span> - </a> + </button> <div className={ 'modal fade ' + ((this.props.modal.type == 'duplicate') ? 'in' : '') } id='EditVehicleJourneyModal'> <div className='modal-container'> @@ -74,22 +74,51 @@ class EditVehicleJourney extends Component { <div className='row'> <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'> - <label className='control-label is-required'>Numéro de train</label> - <input - type='text' - ref='published_journey_identifier' - className='form-control' - defaultValue={this.props.modal.modalProps.vehicleJourney.published_journey_identifier} - onKeyDown={(e) => actions.resetValidation(e.currentTarget)} - required + <div className='form-group'> + <label className='control-label is-required'>Numéro de train</label> + <input + type='text' + ref='published_journey_identifier' + className='form-control' + defaultValue={this.props.modal.modalProps.vehicleJourney.published_journey_identifier} + onKeyDown={(e) => actions.resetValidation(e.currentTarget)} + required /> + </div> </div> <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'> - <label className='control-label'>Transporteur</label> + <div className='form-group'> + <label className='control-label'>Transporteur</label> <CompanySelect2 company = {this.props.modal.modalProps.vehicleJourney.company} onSelect2Company = {(e) => this.props.onSelect2Company(e)} /> + </div> + </div> + </div> + + <div className='row'> + <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'> + <div className='form-group'> + <label className='control-label'>Mode de transport</label> + <input + type='text' + className='form-control' + value={(this.props.modal.modalProps.vehicleJourney.transport_mode || 'non renseigné')} + disabled={true} + /> + </div> + </div> + <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'> + <div className='form-group'> + <label className='control-label'>Sous mode de transport</label> + <input + type='text' + className='form-control' + value={(this.props.modal.modalProps.vehicleJourney.transport_submode || 'non renseigné')} + disabled={true} + /> + </div> </div> </div> </div> diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js index 7c5df3333..ca8b2ec7d 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js @@ -44,15 +44,15 @@ class NotesEditVehicleJourney extends Component { if(this.props.status.fetchSuccess == true) { return ( <li className='st_action'> - <a - href='#' - className={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} + <button + type='button' + disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} data-toggle='modal' data-target='#NotesEditVehicleJourneyModal' onClick={() => this.props.onOpenNotesEditModal(actions.getSelected(this.props.vehicleJourneys)[0])} > <span className='fa fa-sticky-note'></span> - </a> + </button> <div className={ 'modal fade ' + ((this.props.modal.type == 'duplicate') ? 'in' : '') } id='NotesEditVehicleJourneyModal'> <div className='modal-container'> diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js index a373ed1e5..ee7d01cf5 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js @@ -23,15 +23,15 @@ class ShiftVehicleJourney extends Component { if(this.props.status.fetchSuccess == true) { return ( <li className='st_action'> - <a - href='#' - className={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} + <button + type='button' + disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} data-toggle='modal' data-target='#ShiftVehicleJourneyModal' onClick={this.props.onOpenShiftModal} > <span className='sb sb-update-vj'></span> - </a> + </button> <div className={ 'modal fade ' + ((this.props.modal.type == 'shift') ? 'in' : '') } id='ShiftVehicleJourneyModal'> <div className='modal-container'> @@ -54,7 +54,7 @@ class ShiftVehicleJourney extends Component { <input type='number' ref='additional_time' - min='0' + min='-59' max='59' className='form-control' onKeyDown={(e) => actions.resetValidation(e.currentTarget)} diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js index 7837cdbff..1f5e5e98f 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js @@ -6,6 +6,7 @@ var Select2 = require('react-select2') // get JSON full path var origin = window.location.origin var path = window.location.pathname.split('/', 3).join('/') +var line = window.location.pathname.split('/')[4] class BSelect4 extends React.Component{ @@ -27,7 +28,7 @@ class BSelect4 extends React.Component{ width: '100%', placeholder: 'Filtrer par transporteur...', ajax: { - url: origin + path + '/companies.json', + url: origin + path + '/companies.json' + '?line_id=' + line, dataType: 'json', delay: '500', data: function(params) { diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/containers/SaveVehicleJourneys.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/containers/SaveVehicleJourneys.js index 5af30ab82..87bbe5353 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/containers/SaveVehicleJourneys.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/containers/SaveVehicleJourneys.js @@ -7,7 +7,8 @@ const mapStateToProps = (state) => { return { vehicleJourneys: state.vehicleJourneys, page: state.pagination.page, - status: state.status + status: state.status, + filters: state.filters } } diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/index.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/index.js index 1b9ff8f41..4c9423c1f 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/index.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/index.js @@ -21,7 +21,7 @@ if (window.journeyPatternId) var initialState = { filters: { selectedJourneyPatterns : selectedJP, - policy: perms, + policy: window.perms, toggleArrivals: false, queryString: '', query: { @@ -44,7 +44,7 @@ var initialState = { timetable: { comment: '' }, - withoutSchedule: false + withoutSchedule: true } }, diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/filters.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/filters.js index 4b67dc4df..cd065e362 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/filters.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/filters.js @@ -15,14 +15,14 @@ const filters = (state = {}, action) => { minute: '59' } } - newQuery = _.assign({}, state.query, {interval: interval, journeyPattern: {}, timetable: {}, withoutSchedule: false }) + newQuery = _.assign({}, state.query, {interval: interval, journeyPattern: {}, timetable: {}, withoutSchedule: true }) return _.assign({}, state, {query: newQuery, queryString: ''}) case 'TOGGLE_WITHOUT_SCHEDULE': newQuery = _.assign({}, state.query, {withoutSchedule: !state.query.withoutSchedule}) return _.assign({}, state, {query: newQuery}) case 'UPDATE_END_TIME_FILTER': newInterval = JSON.parse(JSON.stringify(state.query.interval)) - newInterval.end[action.unit] = actions.pad(action.val) + newInterval.end[action.unit] = actions.pad(action.val, action.unit) if(parseInt(newInterval.start.hour + newInterval.start.minute) < parseInt(newInterval.end.hour + newInterval.end.minute)){ newQuery = _.assign({}, state.query, {interval: newInterval}) return _.assign({}, state, {query: newQuery}) @@ -31,7 +31,7 @@ const filters = (state = {}, action) => { } case 'UPDATE_START_TIME_FILTER': newInterval = JSON.parse(JSON.stringify(state.query.interval)) - newInterval.start[action.unit] = actions.pad(action.val) + newInterval.start[action.unit] = actions.pad(action.val, action.unit) if(parseInt(newInterval.start.hour + newInterval.start.minute) < parseInt(newInterval.end.hour + newInterval.end.minute)){ newQuery = _.assign({}, state.query, {interval: newInterval}) return _.assign({}, state, {query: newQuery}) @@ -54,7 +54,8 @@ const filters = (state = {}, action) => { 'q[journey_pattern_id_eq]': state.query.journeyPattern.id || undefined, 'q[time_tables_id_eq]': state.query.timetable.id || undefined, 'q[vehicle_journey_at_stops_departure_time_gteq]': (state.query.interval.start.hour + ':' + state.query.interval.start.minute), - 'q[vehicle_journey_at_stops_departure_time_lteq]': (state.query.interval.end.hour + ':' + state.query.interval.end.minute) + 'q[vehicle_journey_at_stops_departure_time_lteq]': (state.query.interval.end.hour + ':' + state.query.interval.end.minute), + 'q[vehicle_journey_without_departure_time]' : state.query.withoutSchedule } let queryString = actions.encodeParams(params) return _.assign({}, state, {queryString: queryString}) diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/vehicleJourneys.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/vehicleJourneys.js index 5924f5cc7..2db76deae 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/vehicleJourneys.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/vehicleJourneys.js @@ -47,19 +47,26 @@ const vehicleJourney= (state = {}, action) => { case 'SHIFT_VEHICLEJOURNEY': let shiftedArray, shiftedSchedule, shiftedVjas shiftedArray = state.vehicle_journey_at_stops.map((vjas, i) => { - shiftedSchedule = { - departure_time: { - hour: vjas.departure_time.hour, - minute: String(parseInt(vjas.departure_time.minute) + parseInt(action.data.additional_time.value)) - }, - arrival_time: { - hour: vjas.arrival_time.hour, - minute: String(parseInt(vjas.arrival_time.minute) + parseInt(action.data.additional_time.value)) + if (!vjas.dummy){ + shiftedSchedule = { + departure_time: { + hour: vjas.departure_time.hour, + minute: actions.simplePad(parseInt(vjas.departure_time.minute) + parseInt(action.data.additional_time.value)) + }, + arrival_time: { + hour: vjas.arrival_time.hour, + minute: actions.simplePad(parseInt(vjas.arrival_time.minute) + parseInt(action.data.additional_time.value)) + } } + actions.checkSchedules(shiftedSchedule) + shiftedVjas = _.assign({}, state.vehicle_journey_at_stops[i], shiftedSchedule) + vjas = _.assign({}, state.vehicle_journey_at_stops[i], shiftedVjas) + delete vjas['id'] + return vjas + }else { + delete vjas['id'] + return vjas } - actions.checkSchedules(shiftedSchedule) - shiftedVjas = _.assign({}, state.vehicle_journey_at_stops[i], shiftedSchedule) - return _.assign({}, state.vehicle_journey_at_stops[i], shiftedVjas) }) return _.assign({}, state, {vehicle_journey_at_stops: shiftedArray}) case 'UPDATE_TIME': @@ -71,14 +78,20 @@ const vehicleJourney= (state = {}, action) => { arrival_time: _.assign({}, vjas.arrival_time) } if (action.isDeparture){ - newSchedule.departure_time[action.timeUnit] = actions.pad(action.val) + newSchedule.departure_time[action.timeUnit] = actions.pad(action.val, action.timeUnit) if(!action.isArrivalsToggled) - newSchedule.arrival_time[action.timeUnit] = actions.pad(action.val) + newSchedule.arrival_time[action.timeUnit] = actions.pad(action.val, action.timeUnit) newSchedule = actions.getDelta(newSchedule) + if(newSchedule.delta < 0){ + return vjas + } return _.assign({}, state.vehicle_journey_at_stops[action.subIndex], {arrival_time: newSchedule.arrival_time, departure_time: newSchedule.departure_time, delta: newSchedule.delta}) }else{ - newSchedule.arrival_time[action.timeUnit] = actions.pad(action.val) + newSchedule.arrival_time[action.timeUnit] = actions.pad(action.val, action.timeUnit) newSchedule = actions.getDelta(newSchedule) + if(newSchedule.delta < 0){ + return vjas + } return _.assign({}, state.vehicle_journey_at_stops[action.subIndex], {arrival_time: newSchedule.arrival_time, departure_time: newSchedule.departure_time, delta: newSchedule.delta}) } }else{ @@ -160,11 +173,12 @@ const vehicleJourneys = (state = [], action) => { let dupeVj let dupes = [] let selectedIndex + let val = action.data.additional_time.value state.map((vj, i) => { if(vj.selected){ selectedIndex = i for (i = 0; i< action.data.duplicate_number.value; i++){ - action.data.additional_time.value *= (i + 1) + action.data.additional_time.value = val * (i + 1) dupeVj = vehicleJourney(vj, action) dupeVj.published_journey_name = dupeVj.published_journey_name + '-' + i dupeVj.selected = false diff --git a/app/assets/javascripts/forms.coffee b/app/assets/javascripts/forms.coffee index 9d884edcd..6b00e9c26 100644 --- a/app/assets/javascripts/forms.coffee +++ b/app/assets/javascripts/forms.coffee @@ -30,9 +30,21 @@ isEdge = !isIE && !!window.StyleMedia if isIE || isEdge $('.formSubmitr').off() -$(document).on 'ready page:load', togglableFilter -$(document).on 'ready page:load', submitMover -$(document).on 'ready page:load', switchInput +@colorSelector = -> + $('.form-group .dropdown.color_selector').each -> + selectedStatus = $(this).children('.dropdown-toggle').children('.fa-circle') + + $(this).on 'click', "input[type='radio']", (e) -> + selectedValue = e.currentTarget.value + if selectedValue == '' + $(selectedStatus).css('color', 'transparent') + else + $(selectedStatus).css('color', selectedValue) + +$(document).on 'turbolinks:load', togglableFilter +$(document).on 'turbolinks:load', submitMover +$(document).on 'turbolinks:load', switchInput +$(document).on 'turbolinks:load', colorSelector if isIE || isEdge $(document).on 'click', '.formSubmitr', (e)-> diff --git a/app/assets/javascripts/main_menu.coffee b/app/assets/javascripts/main_menu.coffee index 9357cff34..2e0cd3470 100644 --- a/app/assets/javascripts/main_menu.coffee +++ b/app/assets/javascripts/main_menu.coffee @@ -1,4 +1,4 @@ -$(document).on 'ready page:load', -> +$(document).on 'turbolinks:load', -> link = [] ptitleCont = "" @@ -49,5 +49,6 @@ $(document).on 'ready page:load', -> $('#main_nav').removeClass 'sticky' if $('#menu_top').find('.sticky-content').length > 0 - $('.page-action .small').after(link) + if !$('.page-action').find('.formSubmitr').length + $('.page-action .small').after(link) $('.sticky-content').remove() diff --git a/app/assets/javascripts/nav_panels.coffee b/app/assets/javascripts/nav_panels.coffee index b254b9f94..829db5ad0 100644 --- a/app/assets/javascripts/nav_panels.coffee +++ b/app/assets/javascripts/nav_panels.coffee @@ -1,4 +1,4 @@ -$(document).on 'ready page:load', -> +$(document).on 'turbolinks:load', -> $('#menu_top [data-panel="toggle"]').on 'click', (e) -> e.preventDefault() $(this).siblings().removeClass 'active' diff --git a/app/assets/javascripts/routing_constraint_zones.coffee b/app/assets/javascripts/routing_constraint_zones.coffee new file mode 100644 index 000000000..458189b36 --- /dev/null +++ b/app/assets/javascripts/routing_constraint_zones.coffee @@ -0,0 +1,27 @@ +fill_stop_points_options = -> + stop_point_select = $('#routing_constraint_zone_stop_point_ids') + stop_point_select.empty() + referential_id = document.location.pathname.match(/\d+/g)[0] + line_id = document.location.pathname.match(/\d+/g)[1] + route_id = $('#routing_constraint_zone_route_id').val() + if errors_on_form() + stop_point_ids = eval($('#stop_point_ids').val()) + $.ajax + url: "/referentials/#{referential_id}/lines/#{line_id}/routes/#{route_id}/stop_points" + dataType: 'json' + success: (data, textStatus, jqXHR) -> + for stop_point in data + selected = $.inArray(stop_point.id, stop_point_ids) != -1 + stop_point_select.append "<option value='#{stop_point.id}'" + "#{if selected then ' selected' else ''}" + ">#{stop_point.name}</option>" + error: (jqXHR, textStatus, errorThrown) -> + console.log textStatus + console.log errorThrown + +errors_on_form = -> + document.location.pathname.endsWith('routing_constraint_zones') && $('#new_routing_constraint_zone').length + +$(document).on 'turbolinks:load', -> + if document.location.pathname.endsWith('new') || errors_on_form() + fill_stop_points_options() + $('#routing_constraint_zone_route_id').change(fill_stop_points_options) + diff --git a/app/assets/javascripts/select2.coffee b/app/assets/javascripts/select2.coffee index edd4c476d..1870f7f9a 100644 --- a/app/assets/javascripts/select2.coffee +++ b/app/assets/javascripts/select2.coffee @@ -7,5 +7,13 @@ placeholder: target.data('select2ed-placeholder') allowClear: true + $('select.form-control.tags').each -> + target = $(this) + target.select2 + theme: 'bootstrap' + language: 'fr' + allowClear: true + tags: true + -$(document).on 'ready page:load', select_2 +$(document).on 'turbolinks:load', select_2 diff --git a/app/assets/javascripts/selectable_table.coffee b/app/assets/javascripts/selectable_table.coffee index 4d9f5122a..4086bf6c2 100644 --- a/app/assets/javascripts/selectable_table.coffee +++ b/app/assets/javascripts/selectable_table.coffee @@ -53,4 +53,4 @@ .addClass 'noselect' .children('.info-msg').children('span').text(selection.length) -$(document).on 'ready page:load', selectTable +$(document).on 'turbolinks:load', selectTable |
