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/time_tables/actions/index.js | 324 +++++++++++++++++++++
.../time_tables/components/ConfirmModal.js | 50 ++++
.../time_tables/components/ErrorModal.js | 42 +++
.../time_tables/components/ExceptionsInDay.js | 71 +++++
app/javascript/time_tables/components/Metas.js | 139 +++++++++
app/javascript/time_tables/components/Navigate.js | 88 ++++++
.../time_tables/components/PeriodForm.js | 148 ++++++++++
.../time_tables/components/PeriodManager.js | 85 ++++++
.../time_tables/components/PeriodsInDay.js | 75 +++++
.../time_tables/components/SaveTimetable.js | 42 +++
.../time_tables/components/TagsSelect2.js | 77 +++++
.../time_tables/components/TimeTableDay.js | 31 ++
app/javascript/time_tables/components/Timetable.js | 115 ++++++++
app/javascript/time_tables/containers/App.js | 55 ++++
.../time_tables/containers/ConfirmModal.js | 31 ++
.../time_tables/containers/ErrorModal.js | 22 ++
app/javascript/time_tables/containers/Metas.js | 38 +++
app/javascript/time_tables/containers/Navigate.js | 18 ++
.../time_tables/containers/PeriodForm.js | 46 +++
.../time_tables/containers/SaveTimetable.js | 25 ++
app/javascript/time_tables/containers/Timetable.js | 44 +++
app/javascript/time_tables/reducers/index.js | 16 +
app/javascript/time_tables/reducers/metas.js | 40 +++
app/javascript/time_tables/reducers/modal.js | 64 ++++
app/javascript/time_tables/reducers/pagination.js | 44 +++
app/javascript/time_tables/reducers/status.js | 15 +
app/javascript/time_tables/reducers/timetable.js | 117 ++++++++
27 files changed, 1862 insertions(+)
create mode 100644 app/javascript/time_tables/actions/index.js
create mode 100644 app/javascript/time_tables/components/ConfirmModal.js
create mode 100644 app/javascript/time_tables/components/ErrorModal.js
create mode 100644 app/javascript/time_tables/components/ExceptionsInDay.js
create mode 100644 app/javascript/time_tables/components/Metas.js
create mode 100644 app/javascript/time_tables/components/Navigate.js
create mode 100644 app/javascript/time_tables/components/PeriodForm.js
create mode 100644 app/javascript/time_tables/components/PeriodManager.js
create mode 100644 app/javascript/time_tables/components/PeriodsInDay.js
create mode 100644 app/javascript/time_tables/components/SaveTimetable.js
create mode 100644 app/javascript/time_tables/components/TagsSelect2.js
create mode 100644 app/javascript/time_tables/components/TimeTableDay.js
create mode 100644 app/javascript/time_tables/components/Timetable.js
create mode 100644 app/javascript/time_tables/containers/App.js
create mode 100644 app/javascript/time_tables/containers/ConfirmModal.js
create mode 100644 app/javascript/time_tables/containers/ErrorModal.js
create mode 100644 app/javascript/time_tables/containers/Metas.js
create mode 100644 app/javascript/time_tables/containers/Navigate.js
create mode 100644 app/javascript/time_tables/containers/PeriodForm.js
create mode 100644 app/javascript/time_tables/containers/SaveTimetable.js
create mode 100644 app/javascript/time_tables/containers/Timetable.js
create mode 100644 app/javascript/time_tables/reducers/index.js
create mode 100644 app/javascript/time_tables/reducers/metas.js
create mode 100644 app/javascript/time_tables/reducers/modal.js
create mode 100644 app/javascript/time_tables/reducers/pagination.js
create mode 100644 app/javascript/time_tables/reducers/status.js
create mode 100644 app/javascript/time_tables/reducers/timetable.js
(limited to 'app/javascript/time_tables')
diff --git a/app/javascript/time_tables/actions/index.js b/app/javascript/time_tables/actions/index.js
new file mode 100644
index 000000000..5a02e8523
--- /dev/null
+++ b/app/javascript/time_tables/actions/index.js
@@ -0,0 +1,324 @@
+import _ from 'lodash'
+import clone from '../../helpers/clone'
+const I18n = clone(window, "I18n")
+
+const actions = {
+ weekDays: (index) => {
+ return _.range(1, 8).map(n => I18n.time_tables.edit.metas.days[n])
+ },
+ strToArrayDayTypes: (str) =>{
+ return actions.weekDays().map(day => str.indexOf(day) !== -1)
+ },
+ arrayToStrDayTypes: (dayTypes) => {
+ let newDayTypes = dayTypes.reduce((arr, dayActive, i) => {
+ if (dayActive) arr.push(actions.weekDays()[i])
+ return arr
+ }, [])
+
+ return newDayTypes.join(',')
+ },
+ fetchingApi: () =>({
+ type: 'FETCH_API'
+ }),
+ receiveErrors : (json) => ({
+ type: "RECEIVE_ERRORS",
+ json
+ }),
+ 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, val) => ({
+ type: 'CHANGE_PAGE',
+ dispatch,
+ page: val
+ }),
+ updateDayTypes: (dayTypes) => ({
+ type: 'UPDATE_DAY_TYPES',
+ dayTypes
+ }),
+ updateCurrentMonthFromDaytypes: (dayTypes) => ({
+ type: 'UPDATE_CURRENT_MONTH_FROM_DAYTYPES',
+ dayTypes
+ }),
+ 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'
+ }),
+ resetModalErrors: () => ({
+ type: 'RESET_MODAL_ERRORS'
+ }),
+ updatePeriodForm: (val, group, selectType) => ({
+ type: 'UPDATE_PERIOD_FORM',
+ val,
+ group,
+ selectType
+ }),
+ validatePeriodForm: (modalProps, timeTablePeriods, metas, timetableInDates, error) => ({
+ type: 'VALIDATE_PERIOD_FORM',
+ modalProps,
+ timeTablePeriods,
+ metas,
+ timetableInDates,
+ error
+ }),
+ addIncludedDate: (index, dayTypes, date) => ({
+ type: 'ADD_INCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }),
+ removeIncludedDate: (index, dayTypes, date) => ({
+ type: 'REMOVE_INCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }),
+ addExcludedDate: (index, dayTypes, date) => ({
+ type: 'ADD_EXCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }),
+ removeExcludedDate: (index, dayTypes, date) => ({
+ type: 'REMOVE_EXCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }),
+ openConfirmModal : (callback) => ({
+ type : 'OPEN_CONFIRM_MODAL',
+ callback
+ }),
+ showErrorModal: (error) => ({
+ type: 'OPEN_ERROR_MODAL',
+ error
+ }),
+ closeModal : () => ({
+ type : 'CLOSE_MODAL'
+ }),
+ monthName(strDate) {
+ let monthList = _.range(1,13).map(n => I18n.calendars.months[n])
+ let 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)
+ },
+ getLocaleDate(strDate) {
+ let date = new Date(strDate)
+ return date.toLocaleDateString()
+ },
+ updateSynthesis: ({current_month, time_table_dates: dates, time_table_periods: periods}) => {
+ let newPeriods = _.reject(periods, 'deleted')
+ let improvedCM = current_month.map((d, i) => {
+ let isInPeriod = actions.isInPeriod(newPeriods, d.date)
+ let isIncluded = _.some(dates, {'date': d.date, 'in_out': true})
+
+ return _.assign({}, current_month[i], {
+ in_periods: isInPeriod,
+ include_date: isIncluded,
+ excluded_date: !isInPeriod ? false : current_month[i].excluded_date
+ })
+ })
+ return improvedCM
+ },
+ isInPeriod: (periods, date) => {
+ date = new Date(date)
+
+ for (let period of periods) {
+ let begin = new Date(period.period_start)
+ let end = new Date(period.period_end)
+ if (date >= begin && date <= end) return true
+ }
+
+ return false
+ },
+ checkConfirmModal: (event, callback, stateChanged, dispatch, metas, timetable) => {
+ if(stateChanged){
+ const error = actions.errorModalKey(timetable.time_table_periods, metas.day_types)
+ if(error){
+ return actions.showErrorModal(error)
+ }else{
+ return actions.openConfirmModal(callback)
+ }
+ }else{
+ dispatch(actions.fetchingApi())
+ return callback
+ }
+ },
+ formatDate: (props) => {
+ return props.year + '-' + props.month + '-' + props.day
+ },
+ checkErrorsInPeriods: (start, end, index, periods) => {
+ let error = ''
+ start = new Date(start)
+ end = new Date(end)
+
+ for (let i = 0; i < periods.length; i++) {
+ let period = periods[i]
+ if (index !== i && !period.deleted) {
+ if (new Date(period.period_start) <= end && new Date(period.period_end) >= start) {
+ error = I18n.time_tables.edit.error_submit.periods_overlaps
+ break
+ }
+ }
+ }
+ return error
+ },
+ checkErrorsInDates: (start, end, in_days) => {
+ let error = ''
+ start = new Date(start)
+ end = new Date(end)
+
+ for (let day of in_days) {
+ if (start <= new Date(day.date) && end >= new Date(day.date)) {
+ error = I18n.time_tables.edit.error_submit.dates_overlaps
+ break
+ }
+ }
+ return error
+ },
+ fetchTimeTables: (dispatch, nextPage) => {
+ let urlJSON = window.location.pathname.split('/', 5).join('/')
+ 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))
+ }
+ }
+ })
+ },
+ submitTimetable: (dispatch, timetable, metas, next) => {
+ dispatch(actions.fetchingApi())
+ let strDayTypes = actions.arrayToStrDayTypes(metas.day_types)
+ metas.day_types= strDayTypes
+ let sentState = _.assign({}, timetable, metas)
+ let urlJSON = window.location.pathname.split('/', 5).join('/')
+ let hasError = false
+ fetch(urlJSON + '.json', {
+ credentials: 'same-origin',
+ method: 'PATCH',
+ contentType: 'application/json; charset=utf-8',
+ Accept: 'application/json',
+ body: JSON.stringify(sentState),
+ 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 {
+ dispatch(actions.receiveTimeTables(json))
+ }
+ }
+ })
+ },
+ errorModalKey: (periods, dayTypes) => {
+ const withoutPeriodsWithDaysTypes = _.reject(periods, 'deleted').length == 0 && _.some(dayTypes) && "withoutPeriodsWithDaysTypes"
+ const withPeriodsWithoutDayTypes = _.reject(periods, 'deleted').length > 0 && _.every(dayTypes, dt => dt == false) && "withPeriodsWithoutDayTypes"
+
+ return (withoutPeriodsWithDaysTypes || withPeriodsWithoutDayTypes) && (withoutPeriodsWithDaysTypes ? "withoutPeriodsWithDaysTypes" : "withPeriodsWithoutDayTypes")
+
+ },
+ errorModalMessage: (errorKey) => {
+ switch (errorKey) {
+ case "withoutPeriodsWithDaysTypes":
+ return I18n.time_tables.edit.error_modal.withoutPeriodsWithDaysTypes
+ case "withPeriodsWithoutDayTypes":
+ return I18n.time_tables.edit.error_modal.withPeriodsWithoutDayTypes
+ default:
+ return errorKey
+
+ }
+ }
+}
+
+export default actions
\ No newline at end of file
diff --git a/app/javascript/time_tables/components/ConfirmModal.js b/app/javascript/time_tables/components/ConfirmModal.js
new file mode 100644
index 000000000..d89170ee7
--- /dev/null
+++ b/app/javascript/time_tables/components/ConfirmModal.js
@@ -0,0 +1,50 @@
+import React, { PropTypes } from 'react'
+
+export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCancel, timetable, metas}, {I18n}) {
+ return (
+
+
+
+
+
+
{I18n.time_tables.edit.confirm_modal.title}
+
+
+
+
{I18n.time_tables.edit.confirm_modal.message}
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+ConfirmModal.propTypes = {
+ modal: PropTypes.object.isRequired,
+ onModalAccept: PropTypes.func.isRequired,
+ onModalCancel: PropTypes.func.isRequired
+}
+
+ConfirmModal.contextTypes = {
+ I18n: PropTypes.object
+}
\ No newline at end of file
diff --git a/app/javascript/time_tables/components/ErrorModal.js b/app/javascript/time_tables/components/ErrorModal.js
new file mode 100644
index 000000000..e810f49ab
--- /dev/null
+++ b/app/javascript/time_tables/components/ErrorModal.js
@@ -0,0 +1,42 @@
+import React, { PropTypes } from 'react'
+import actions from '../actions'
+
+export default function ErrorModal({dispatch, modal, onModalClose}, {I18n}) {
+ return (
+
+
+
+
+
+
{I18n.time_tables.edit.error_modal.title}
+
+
+
+
{actions.errorModalMessage(modal.modalProps.error)}
+
+
+
+
+
+
+
+
+
+ )
+}
+
+ErrorModal.propTypes = {
+ modal: PropTypes.object.isRequired,
+ onModalClose: PropTypes.func.isRequired
+}
+
+ErrorModal.contextTypes = {
+ I18n: PropTypes.object
+}
\ No newline at end of file
diff --git a/app/javascript/time_tables/components/ExceptionsInDay.js b/app/javascript/time_tables/components/ExceptionsInDay.js
new file mode 100644
index 000000000..3335ee89d
--- /dev/null
+++ b/app/javascript/time_tables/components/ExceptionsInDay.js
@@ -0,0 +1,71 @@
+import React, { PropTypes, Component } from 'react'
+import actions from '../actions'
+
+export default class ExceptionsInDay extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ handleClick() {
+ const {index, day, metas: {day_types} } = this.props
+ if (day.in_periods && day_types[day.wday]) {
+ day.excluded_date ? this.props.onRemoveExcludedDate(index, day_types, day.date) : this.props.onAddExcludedDate(index, day_types, day.date)
+ } else {
+ day.include_date ? this.props.onRemoveIncludedDate(index, day_types, day.date) : this.props.onAddIncludedDate(index, day_types, day.date)
+ }
+ }
+
+ render() {
+ {/* display add or remove link, only if true in daytypes */}
+ {/* 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 && this.props.blueDaytype == true) {
+ return (
+
+
+
+ )
+ } else {
+ return (
+
+
+
+ )
+ // } else if(this.props.value.current_month[this.props.index].in_periods == true && this.props.blueDaytype == false){
+ // return (
+ //
+ // )
+ // } else{
+ // return false
+ // }
+ }
+ }
+}
+
+ExceptionsInDay.propTypes = {
+ value: PropTypes.object.isRequired,
+ metas: PropTypes.object.isRequired,
+ blueDaytype: PropTypes.bool.isRequired,
+ onExcludeDateFromPeriod: PropTypes.func.isRequired,
+ onIncludeDateInPeriod: PropTypes.func.isRequired,
+ index: PropTypes.number.isRequired
+}
diff --git a/app/javascript/time_tables/components/Metas.js b/app/javascript/time_tables/components/Metas.js
new file mode 100644
index 000000000..7098d2b82
--- /dev/null
+++ b/app/javascript/time_tables/components/Metas.js
@@ -0,0 +1,139 @@
+import React, { PropTypes } from 'react'
+import actions from '../actions'
+import TagsSelect2 from './TagsSelect2'
+
+export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelect2Tags, onUnselect2Tags}, {I18n}) {
+ let colorList = ["", "#9B9B9B", "#FFA070", "#C67300", "#7F551B", "#41CCE3", "#09B09C", "#3655D7", "#6321A0", "#E796C6", "#DD2DAA"]
+ return (
+
+
+
+ {/* comment (name) */}
+
+
+
+ (onUpdateComment(e.currentTarget.value))}
+ />
+
+
+
+ {/* color */}
+
+
+
+
+
+
+
+ {colorList.map((c, i) =>
+ {onUpdateColor(c)}}
+ >
+
+
+ )}
+
+
+
+
+
+ {/* tags */}
+
+
+
+ onSelect2Tags(e)}
+ onUnselect2Tags={(e) => onUnselect2Tags(e)}
+ />
+
+
+
+ {/* calendar */}
+
+
+
+ {metas.calendar ? metas.calendar.name : I18n.time_tables.edit.metas.no_calendar}
+
+
+
+ {/* day_types */}
+
+
+
+
+ {metas.day_types.map((day, i) =>
+
+
+
+
+
+ )}
+
+
+
+
+
+
+ )
+}
+
+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
+}
+
+Metas.contextTypes = {
+ I18n: PropTypes.object
+}
diff --git a/app/javascript/time_tables/components/Navigate.js b/app/javascript/time_tables/components/Navigate.js
new file mode 100644
index 000000000..6ae80bce0
--- /dev/null
+++ b/app/javascript/time_tables/components/Navigate.js
@@ -0,0 +1,88 @@
+import React, { PropTypes, Component } from 'react'
+import _ from 'lodash'
+import actions from '../actions'
+
+export default function 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 (
+
+ )
+ } else {
+ return false
+ }
+}
+
+Navigate.propTypes = {
+ status: PropTypes.object.isRequired,
+ pagination: PropTypes.object.isRequired,
+ dispatch: PropTypes.func.isRequired
+}
\ No newline at end of file
diff --git a/app/javascript/time_tables/components/PeriodForm.js b/app/javascript/time_tables/components/PeriodForm.js
new file mode 100644
index 000000000..893a1fa6a
--- /dev/null
+++ b/app/javascript/time_tables/components/PeriodForm.js
@@ -0,0 +1,148 @@
+import React, { PropTypes } from 'react'
+import _ from 'lodash'
+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()
+ }
+ return arr
+}
+
+const makeMonthsOptions = (monthSelected) => {
+ let arr = []
+ for(let i = 1; i < 13; i++) {
+ arr.push()
+ }
+ return arr
+}
+
+const makeYearsOptions = (yearSelected) => {
+ let arr = []
+ let startYear = new Date().getFullYear() - 3
+ for(let i = startYear; i <= startYear + 6; i++) {
+ arr.push()
+ }
+ return arr
+}
+
+export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm, onClosePeriodForm, onUpdatePeriodForm, onValidatePeriodForm}, {I18n}) {
+ return (
+
+
+
+
+ {modal.modalProps.active &&
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {modal.modalProps.error}
+
+
+
+
+
+ }
+ {!modal.modalProps.active &&
+
+
+
+ }
+
+
+
+
+ )
+}
+
+PeriodForm.propTypes = {
+ modal: PropTypes.object.isRequired,
+ metas: PropTypes.object.isRequired,
+ onOpenAddPeriodForm: PropTypes.func.isRequired,
+ onClosePeriodForm: PropTypes.func.isRequired,
+ onUpdatePeriodForm: PropTypes.func.isRequired,
+ onValidatePeriodForm: PropTypes.func.isRequired,
+ timetable: PropTypes.object.isRequired
+}
+
+PeriodForm.contextTypes = {
+ I18n: PropTypes.object
+}
\ No newline at end of file
diff --git a/app/javascript/time_tables/components/PeriodManager.js b/app/javascript/time_tables/components/PeriodManager.js
new file mode 100644
index 000000000..9922ce2c4
--- /dev/null
+++ b/app/javascript/time_tables/components/PeriodManager.js
@@ -0,0 +1,85 @@
+import React, { PropTypes, Component } from 'react'
+import actions from '../actions'
+
+export default class PeriodManager extends Component {
+ constructor(props, context) {
+ super(props, context)
+ }
+
+ toEndPeriod(curr, end) {
+ let diff
+
+ let startCurrM = curr.split('-')[1]
+ let endPeriodM = end.split('-')[1]
+
+ let lastDayInM = new Date(curr.split('-')[2], startCurrM + 1, 0)
+ lastDayInM = lastDayInM.toJSON().substr(0, 10).split('-')[2]
+
+ if(startCurrM === endPeriodM) {
+ diff = (end.split('-')[2] - curr.split('-')[2])
+ } else {
+ diff = (lastDayInM - curr.split('-')[2])
+ }
+
+ return diff
+ }
+
+ render() {
+ return (
+
+
+ {actions.getLocaleDate(this.props.value.period_start) + ' > ' + actions.getLocaleDate(this.props.value.period_end)}
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
+ )
+ }
+}
+
+PeriodManager.propTypes = {
+ value: PropTypes.object.isRequired,
+ currentDate: PropTypes.object.isRequired,
+ onDeletePeriod: PropTypes.func.isRequired,
+ onOpenEditPeriodForm: PropTypes.func.isRequired
+}
+
+PeriodManager.contextTypes = {
+ I18n: PropTypes.object
+}
\ No newline at end of file
diff --git a/app/javascript/time_tables/components/PeriodsInDay.js b/app/javascript/time_tables/components/PeriodsInDay.js
new file mode 100644
index 000000000..888537579
--- /dev/null
+++ b/app/javascript/time_tables/components/PeriodsInDay.js
@@ -0,0 +1,75 @@
+import React, { PropTypes, Component } from 'react'
+import PeriodManager from './PeriodManager'
+
+export default 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 (
+
+ {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 (
+
+ )
+ } else {
+ return false
+ }
+ }
+ }else{
+ return false
+ }
+ })}
+
+ )
+ }
+}
+
+PeriodsInDay.propTypes = {
+ value: PropTypes.array.isRequired,
+ currentDate: PropTypes.object.isRequired,
+ index: PropTypes.number.isRequired,
+ onDeletePeriod: PropTypes.func.isRequired
+}
diff --git a/app/javascript/time_tables/components/SaveTimetable.js b/app/javascript/time_tables/components/SaveTimetable.js
new file mode 100644
index 000000000..0dffc7936
--- /dev/null
+++ b/app/javascript/time_tables/components/SaveTimetable.js
@@ -0,0 +1,42 @@
+import React, { PropTypes, Component } from 'react'
+import _ from 'lodash'
+import actions from '../actions'
+
+export default class SaveTimetable extends Component{
+ constructor(props){
+ super(props)
+ }
+
+ render() {
+ const error = actions.errorModalKey(this.props.timetable.time_table_periods, this.props.metas.day_types)
+
+ return (
+
+ )
+ }
+}
+
+SaveTimetable.propTypes = {
+ timetable: PropTypes.object.isRequired,
+ status: PropTypes.object.isRequired,
+ metas: PropTypes.object.isRequired
+}
\ No newline at end of file
diff --git a/app/javascript/time_tables/components/TagsSelect2.js b/app/javascript/time_tables/components/TagsSelect2.js
new file mode 100644
index 000000000..24f473f42
--- /dev/null
+++ b/app/javascript/time_tables/components/TagsSelect2.js
@@ -0,0 +1,77 @@
+import React, { PropTypes, Component } from 'react'
+import _ from 'lodash'
+import Select2 from 'react-select2-wrapper'
+
+// get JSON full path
+let origin = window.location.origin
+let path = window.location.pathname.split('/', 4).join('/')
+
+export default class TagsSelect2 extends Component {
+ constructor(props, context) {
+ super(props, context)
+ }
+
+ mapKeys(array){
+ return array.map((item) =>
+ _.mapKeys(item, (v, k) =>
+ ((k == 'name') ? 'text' : k)
+ )
+ )
+ }
+
+ render() {
+ return (
+ this.props.onSelect2Tags(e)}
+ onUnselect={(e) => setTimeout( () => this.props.onUnselect2Tags(e, 150))}
+ multiple={true}
+ ref='tags_id'
+ options={{
+ tags:true,
+ createTag: function(params) {
+ return {name: params.term, text: params.term, id: params.term}
+ },
+ allowClear: true,
+ theme: 'bootstrap',
+ width: '100%',
+ placeholder: this.context.I18n.time_tables.edit.select2.tag.placeholder,
+ ajax: {
+ url: origin + path + '/tags.json',
+ dataType: 'json',
+ delay: '500',
+ data: function(params) {
+ return {
+ tag: params.term,
+ };
+ },
+ processResults: function(data, params) {
+ let items = _.filter(data, ({name}) => name.includes(params.term) )
+ return {
+ results: items.map(
+ item => _.assign(
+ {},
+ item,
+ {text: item.name}
+ )
+ )
+ };
+ },
+ cache: true
+ },
+ minimumInputLength: 1,
+ templateResult: formatRepo
+ }}
+ />
+ )
+ }
+}
+
+const formatRepo = (props) => {
+ if(props.name) return props.name
+}
+
+TagsSelect2.contextTypes = {
+ I18n: PropTypes.object
+}
\ No newline at end of file
diff --git a/app/javascript/time_tables/components/TimeTableDay.js b/app/javascript/time_tables/components/TimeTableDay.js
new file mode 100644
index 000000000..165c7b848
--- /dev/null
+++ b/app/javascript/time_tables/components/TimeTableDay.js
@@ -0,0 +1,31 @@
+import React, { PropTypes, Component } from 'react'
+
+export default class TimeTableDay extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ render() {
+ return (
+
+
+ {((this.props.value.day).charAt(0) == 'm') ? (this.props.value.day).substr(0, 2) : (this.props.value.day).charAt(0)}
+
+
+ {this.props.value.mday}
+
+
+ )
+ }
+}
+
+TimeTableDay.propTypes = {
+ value: PropTypes.object.isRequired,
+ index: PropTypes.number.isRequired,
+ dayTypeActive: PropTypes.bool.isRequired
+}
diff --git a/app/javascript/time_tables/components/Timetable.js b/app/javascript/time_tables/components/Timetable.js
new file mode 100644
index 000000000..df6e6016b
--- /dev/null
+++ b/app/javascript/time_tables/components/Timetable.js
@@ -0,0 +1,115 @@
+import React, { PropTypes, Component } from 'react'
+import actions from '../actions'
+import TimeTableDay from './TimeTableDay'
+import PeriodsInDay from './PeriodsInDay'
+import ExceptionsInDay from './ExceptionsInDay'
+
+
+export default class Timetable extends Component {
+ constructor(props, context){
+ super(props, context)
+ }
+
+ 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() {
+ if(this.props.status.isFetching == true) {
+ return (
+
+ )
+ } else {
+ return (
+
+
+
+
{this.context.I18n.time_tables.synthesis}
+
+
{this.context.I18n.time_tables.edit.day_types}
+
{this.context.I18n.time_tables.edit.periods}
+
{this.context.I18n.time_tables.edit.exceptions}
+
+
+
+
+
+
+ {actions.monthName(this.props.timetable.current_periode_range)}
+
+
+
+ {this.props.timetable.current_month.map((d, i) =>
+
+ )}
+
+
+
+ {this.props.timetable.current_month.map((d, i) =>
+
+ {/* day_types */}
+
+
+ {/* periods */}
+
+
+ {/* exceptions */}
+
+
+ )}
+
+
+
+
+ )
+ }
+ }
+}
+
+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
+}
+
+Timetable.contextTypes = {
+ I18n: PropTypes.object
+}
diff --git a/app/javascript/time_tables/containers/App.js b/app/javascript/time_tables/containers/App.js
new file mode 100644
index 000000000..235dccb50
--- /dev/null
+++ b/app/javascript/time_tables/containers/App.js
@@ -0,0 +1,55 @@
+import React, { PropTypes, Component } from 'react'
+import { connect } from'react-redux'
+import actions from '../actions'
+import Metas from './Metas'
+import Timetable from './Timetable'
+import Navigate from './Navigate'
+import PeriodForm from './PeriodForm'
+import SaveTimetable from './SaveTimetable'
+import ConfirmModal from './ConfirmModal'
+import ErrorModal from './ErrorModal'
+import clone from '../../helpers/clone'
+const I18n = clone(window, "I18n", true)
+
+class App extends Component {
+ componentDidMount(){
+ this.props.onLoadFirstPage()
+ }
+
+ getChildContext() {
+ return { I18n }
+ }
+
+ render(){
+ return(
+
+ )
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onLoadFirstPage: () =>{
+ dispatch(actions.fetchingApi())
+ actions.fetchTimeTables(dispatch)
+ }
+ }
+}
+
+App.childContextTypes = {
+ I18n: PropTypes.object
+}
+
+const timeTableApp = connect(null, mapDispatchToProps)(App)
+
+export default timeTableApp
diff --git a/app/javascript/time_tables/containers/ConfirmModal.js b/app/javascript/time_tables/containers/ConfirmModal.js
new file mode 100644
index 000000000..f3742b038
--- /dev/null
+++ b/app/javascript/time_tables/containers/ConfirmModal.js
@@ -0,0 +1,31 @@
+import { connect } from 'react-redux'
+import actions from '../actions'
+import ConfirmModal from '../components/ConfirmModal'
+
+const mapStateToProps = (state) => {
+ return {
+ modal: state.modal,
+ timetable: state.timetable,
+ metas: state.metas
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onModalAccept: (next, timetable, metas) =>{
+ dispatch(actions.fetchingApi())
+ actions.submitTimetable(dispatch, timetable, metas, 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/time_tables/containers/ErrorModal.js b/app/javascript/time_tables/containers/ErrorModal.js
new file mode 100644
index 000000000..37099073b
--- /dev/null
+++ b/app/javascript/time_tables/containers/ErrorModal.js
@@ -0,0 +1,22 @@
+import { connect } from 'react-redux'
+import actions from '../actions'
+import ErrorModal from '../components/ErrorModal'
+
+const mapStateToProps = (state) => {
+ return {
+ modal: state.modal
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onModalClose: () =>{
+ dispatch(actions.closeModal())
+ dispatch(actions.resetModalErrors())
+ }
+ }
+}
+
+const ErrorModalContainer = connect(mapStateToProps, mapDispatchToProps)(ErrorModal)
+
+export default ErrorModalContainer
diff --git a/app/javascript/time_tables/containers/Metas.js b/app/javascript/time_tables/containers/Metas.js
new file mode 100644
index 000000000..ebccf556e
--- /dev/null
+++ b/app/javascript/time_tables/containers/Metas.js
@@ -0,0 +1,38 @@
+import { connect } from 'react-redux'
+import actions from '../actions'
+import MetasComponent from '../components/Metas'
+
+const mapStateToProps = (state) => {
+ return {
+ metas: state.metas
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onUpdateDayTypes: (index, dayTypes) => {
+ let newDayTypes = dayTypes.slice(0)
+ newDayTypes[index] = !newDayTypes[index]
+ dispatch(actions.updateDayTypes(newDayTypes))
+ dispatch(actions.updateCurrentMonthFromDaytypes(newDayTypes))
+ },
+ onUpdateComment: (comment) => {
+ dispatch(actions.updateComment(comment))
+ },
+ onUpdateColor: (color) => {
+ dispatch(actions.updateColor(color))
+ },
+ onSelect2Tags: (e) => {
+ e.preventDefault()
+ dispatch(actions.select2Tags(e.params.data))
+ },
+ onUnselect2Tags: (e) => {
+ e.preventDefault()
+ dispatch(actions.unselect2Tags(e.params.data))
+ }
+ }
+}
+
+const Metas = connect(mapStateToProps, mapDispatchToProps)(MetasComponent)
+
+export default Metas
diff --git a/app/javascript/time_tables/containers/Navigate.js b/app/javascript/time_tables/containers/Navigate.js
new file mode 100644
index 000000000..8d163659c
--- /dev/null
+++ b/app/javascript/time_tables/containers/Navigate.js
@@ -0,0 +1,18 @@
+import React from 'react'
+import { connect } from 'react-redux'
+import actions from '../actions'
+import NavigateComponent from '../components/Navigate'
+
+const mapStateToProps = (state) => {
+ return {
+ metas: state.metas,
+ timetable: state.timetable,
+ status: state.status,
+ pagination: state.pagination
+ }
+}
+
+
+const Navigate = connect(mapStateToProps)(NavigateComponent)
+
+export default Navigate
diff --git a/app/javascript/time_tables/containers/PeriodForm.js b/app/javascript/time_tables/containers/PeriodForm.js
new file mode 100644
index 000000000..49e79f348
--- /dev/null
+++ b/app/javascript/time_tables/containers/PeriodForm.js
@@ -0,0 +1,46 @@
+import { connect } from 'react-redux'
+import _ from 'lodash'
+import actions from '../actions'
+import PeriodFormComponent from '../components/PeriodForm'
+
+
+
+const mapStateToProps = (state) => {
+ return {
+ modal: state.modal,
+ timetable: state.timetable,
+ metas: state.metas,
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onOpenAddPeriodForm: () => {
+ dispatch(actions.openAddPeriodForm())
+ },
+ onClosePeriodForm: () => {
+ dispatch(actions.closePeriodForm())
+ },
+ onUpdatePeriodForm: (e, group, selectType, modalProps) => {
+ dispatch(actions.updatePeriodForm(e.currentTarget.value, group, selectType))
+ let mProps = _.assign({}, modalProps)
+ mProps[group][selectType] = e.currentTarget.value
+ let val = window.correctDay([parseInt(mProps[group]['day']), parseInt(mProps[group]['month']), parseInt(mProps[group]['year'])])
+ val = (val < 10) ? '0' + String(val) : String(val)
+ dispatch(actions.updatePeriodForm(val, group, 'day'))
+ },
+ onValidatePeriodForm: (modalProps, timeTablePeriods, metas, timetableInDates) => {
+ let period_start = actions.formatDate(modalProps.begin)
+ let period_end = actions.formatDate(modalProps.end)
+ let error = ''
+ if (new Date(period_end) <= new Date(period_start)) error = 'La date de départ doit être antérieure à la date de fin'
+ if (error == '') error = actions.checkErrorsInPeriods(period_start, period_end, modalProps.index, timeTablePeriods)
+ if (error == '') error = actions.checkErrorsInDates(period_start, period_end, timetableInDates)
+ dispatch(actions.validatePeriodForm(modalProps, timeTablePeriods, metas, timetableInDates, error))
+ }
+ }
+}
+
+const PeriodForm = connect(mapStateToProps, mapDispatchToProps)(PeriodFormComponent)
+
+export default PeriodForm
diff --git a/app/javascript/time_tables/containers/SaveTimetable.js b/app/javascript/time_tables/containers/SaveTimetable.js
new file mode 100644
index 000000000..7574dc5cc
--- /dev/null
+++ b/app/javascript/time_tables/containers/SaveTimetable.js
@@ -0,0 +1,25 @@
+import { connect } from 'react-redux'
+import actions from '../actions'
+import SaveTimetableComponent from '../components/SaveTimetable'
+
+const mapStateToProps = (state) => {
+ return {
+ timetable: state.timetable,
+ metas: state.metas,
+ status: state.status
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onShowErrorModal: (errorKey) => {
+ dispatch(actions.showErrorModal(errorKey))
+ },
+ getDispatch: () => {
+ return dispatch
+ }
+ }
+}
+const SaveTimetable = connect(mapStateToProps, mapDispatchToProps)(SaveTimetableComponent)
+
+export default SaveTimetable
diff --git a/app/javascript/time_tables/containers/Timetable.js b/app/javascript/time_tables/containers/Timetable.js
new file mode 100644
index 000000000..e78e8840a
--- /dev/null
+++ b/app/javascript/time_tables/containers/Timetable.js
@@ -0,0 +1,44 @@
+import { connect } from 'react-redux'
+import actions from '../actions'
+import TimetableComponent from '../components/Timetable'
+
+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))
+ },
+ onAddIncludedDate: (index, dayTypes, date) => {
+ dispatch(actions.addIncludedDate(index, dayTypes, date))
+ },
+ onRemoveIncludedDate: (index, dayTypes, date) => {
+ dispatch(actions.removeIncludedDate(index, dayTypes, date))
+ },
+ onAddExcludedDate: (index, dayTypes, date) => {
+ dispatch(actions.addExcludedDate(index, dayTypes, date))
+ },
+ onRemoveExcludedDate: (index, dayTypes, date) => {
+ dispatch(actions.removeExcludedDate(index, dayTypes, date))
+ },
+ onExcludeDateFromPeriod: (index, dayTypes, date) => {
+ dispatch(actions.excludeDateFromPeriod(index, dayTypes, date))
+ },
+ onIncludeDateInPeriod: (index, dayTypes, date) => {
+ dispatch(actions.includeDateInPeriod(index, dayTypes, date))
+ },
+ onOpenEditPeriodForm: (period, index) => {
+ dispatch(actions.openEditPeriodForm(period, index))
+ }
+ }
+}
+
+const Timetable = connect(mapStateToProps, mapDispatchToProps)(TimetableComponent)
+
+export default Timetable
diff --git a/app/javascript/time_tables/reducers/index.js b/app/javascript/time_tables/reducers/index.js
new file mode 100644
index 000000000..aed9035b5
--- /dev/null
+++ b/app/javascript/time_tables/reducers/index.js
@@ -0,0 +1,16 @@
+import { combineReducers } from 'redux'
+import status from './status'
+import pagination from './pagination'
+import modal from './modal'
+import timetable from './timetable'
+import metas from './metas'
+
+const timeTablesApp = combineReducers({
+ timetable,
+ metas,
+ status,
+ pagination,
+ modal
+})
+
+export default timeTablesApp
diff --git a/app/javascript/time_tables/reducers/metas.js b/app/javascript/time_tables/reducers/metas.js
new file mode 100644
index 000000000..548798012
--- /dev/null
+++ b/app/javascript/time_tables/reducers/metas.js
@@ -0,0 +1,40 @@
+import _ from 'lodash'
+import actions from '../actions'
+
+export default function 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,
+ initial_tags: action.json.tags,
+ color: action.json.color,
+ calendar: action.json.calendar ? action.json.calendar : null
+ })
+ case 'RECEIVE_MONTH':
+ let dt = (typeof state.day_types === 'string') ? actions.strToArrayDayTypes(state.day_types) : state.day_types
+ return _.assign({}, state, {day_types: dt})
+ case 'ADD_INCLUDED_DATE':
+ case 'REMOVE_INCLUDED_DATE':
+ case 'ADD_EXCLUDED_DATE':
+ case 'REMOVE_EXCLUDED_DATE':
+ case 'DELETE_PERIOD':
+ case 'VALIDATE_PERIOD_FORM':
+ return _.assign({}, state, {calendar: null})
+ case 'UPDATE_DAY_TYPES':
+ return _.assign({}, state, {day_types: action.dayTypes, calendar : null})
+ 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
+ }
+}
\ No newline at end of file
diff --git a/app/javascript/time_tables/reducers/modal.js b/app/javascript/time_tables/reducers/modal.js
new file mode 100644
index 000000000..a530b2717
--- /dev/null
+++ b/app/javascript/time_tables/reducers/modal.js
@@ -0,0 +1,64 @@
+import _ from 'lodash'
+import actions from '../actions'
+
+let newModalProps = {}
+let emptyDate = {
+ day: '01',
+ month: '01',
+ year: String(new Date().getFullYear())
+}
+let period_start = '', period_end = ''
+
+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 'OPEN_ERROR_MODAL':
+ $('#ErrorModal').modal('show')
+ newModalProps = _.assign({}, state.modalProps, {error: action.error})
+ return _.assign({}, state, {type: 'error'}, {modalProps: newModalProps})
+ case 'RESET_MODAL_ERRORS':
+ newModalProps = _.assign({}, state.modalProps, {error: ''})
+ return _.assign({}, state, {type: ''}, {modalProps: newModalProps})
+ case 'CLOSE_PERIOD_FORM':
+ newModalProps = _.assign({}, state.modalProps, {active: false, error: ""})
+ return _.assign({}, state, {modalProps: newModalProps})
+ case 'OPEN_EDIT_PERIOD_FORM':
+ period_start = action.period.period_start.split('-')
+ 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
+ newModalProps.error = ''
+ return _.assign({}, state, {modalProps: newModalProps})
+ case 'OPEN_ADD_PERIOD_FORM':
+ newModalProps = _.assign({}, state.modalProps, {active: true, begin: emptyDate, end: emptyDate, index: false, error: ''})
+ 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})
+ case 'VALIDATE_PERIOD_FORM':
+ newModalProps = JSON.parse(JSON.stringify(state.modalProps))
+ newModalProps.error = action.error
+ newModalProps.active = (newModalProps.error == '') ? false : true
+ return _.assign({}, state, {modalProps: newModalProps})
+ default:
+ return state
+ }
+}
\ No newline at end of file
diff --git a/app/javascript/time_tables/reducers/pagination.js b/app/javascript/time_tables/reducers/pagination.js
new file mode 100644
index 000000000..e9ca9e1ec
--- /dev/null
+++ b/app/javascript/time_tables/reducers/pagination.js
@@ -0,0 +1,44 @@
+import _ from 'lodash'
+
+export default function 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,
+ stateChanged: false
+ })
+ case 'RECEIVE_MONTH':
+ case 'RECEIVE_ERRORS':
+ return _.assign({}, state, {stateChanged: false})
+ 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})
+ case 'ADD_INCLUDED_DATE':
+ case 'REMOVE_INCLUDED_DATE':
+ case 'ADD_EXCLUDED_DATE':
+ case 'REMOVE_EXCLUDED_DATE':
+ case 'DELETE_PERIOD':
+ case 'VALIDATE_PERIOD_FORM':
+ case 'UPDATE_COMMENT':
+ case 'UPDATE_COLOR':
+ case 'UPDATE_DAY_TYPES':
+ case 'UPDATE_CURRENT_MONTH_FROM_DAYTYPES':
+ toggleOnConfirmModal('modal')
+ return _.assign({}, state, {stateChanged: true})
+ default:
+ return state
+ }
+}
+
+const toggleOnConfirmModal = (arg = '') =>{
+ $('.confirm').each(function(){
+ $(this).data('toggle','')
+ })
+}
\ No newline at end of file
diff --git a/app/javascript/time_tables/reducers/status.js b/app/javascript/time_tables/reducers/status.js
new file mode 100644
index 000000000..8d93bc2e2
--- /dev/null
+++ b/app/javascript/time_tables/reducers/status.js
@@ -0,0 +1,15 @@
+import _ from 'lodash'
+
+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_TIME_TABLES':
+ case 'RECEIVE_MONTH':
+ return _.assign({}, state, {fetchSuccess: true, isFetching: false})
+ default:
+ return state
+ }
+}
\ No newline at end of file
diff --git a/app/javascript/time_tables/reducers/timetable.js b/app/javascript/time_tables/reducers/timetable.js
new file mode 100644
index 000000000..274153a69
--- /dev/null
+++ b/app/javascript/time_tables/reducers/timetable.js
@@ -0,0 +1,117 @@
+import _ from 'lodash'
+import actions from '../actions'
+let newState, newPeriods, newDates, newCM
+
+export default function 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,
+ time_table_dates: _.sortBy(action.json.time_table_dates, ['date'])
+ })
+ return _.assign({}, fetchedState, {current_month: actions.updateSynthesis(fetchedState)})
+ case 'RECEIVE_MONTH':
+ newState = _.assign({}, state, {
+ current_month: action.json.days
+ })
+ return _.assign({}, newState, {current_month: actions.updateSynthesis(newState)})
+ 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':
+ newPeriods = state.time_table_periods.map((period, i) =>{
+ if(i == action.index){
+ period.deleted = true
+ }
+ return period
+ })
+ let deletedPeriod = Array.of(state.time_table_periods[action.index])
+ newDates = _.reject(state.time_table_dates, d => actions.isInPeriod(deletedPeriod, d.date) && !d.in_out)
+ newState = _.assign({}, state, {time_table_periods : newPeriods, time_table_dates: newDates})
+ return _.assign({}, newState, { current_month: actions.updateSynthesis(newState)})
+ case 'ADD_INCLUDED_DATE':
+ newDates = state.time_table_dates.concat({date: action.date, in_out: true})
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.include_date = true
+ return d
+ })
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
+ case 'REMOVE_INCLUDED_DATE':
+ newDates = _.reject(state.time_table_dates, ['date', action.date])
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.include_date = false
+ return d
+ })
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
+ case 'ADD_EXCLUDED_DATE':
+ newDates = state.time_table_dates.concat({date: action.date, in_out: false})
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.excluded_date = true
+ return d
+ })
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
+ case 'REMOVE_EXCLUDED_DATE':
+ newDates = _.reject(state.time_table_dates, ['date', action.date])
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.excluded_date = false
+ return d
+ })
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
+ case 'UPDATE_DAY_TYPES':
+ // We get the week days of the activated day types to reject the out_dates that that are out of newDayTypes
+ let weekDays = _.reduce(action.dayTypes, (array, dt, i) => {
+ if (dt) array.push(i)
+ return array
+ }, [])
+
+ newDates = _.reject(state.time_table_dates, (d) => {
+ let weekDay = new Date(d.date).getDay()
+
+ if (d.in_out) {
+ return actions.isInPeriod(state.time_table_periods, d.date) && weekDays.includes(weekDay)
+ } else {
+ return !weekDays.includes(weekDay)
+ }
+ })
+ return _.assign({}, state, {time_table_dates: newDates})
+ case 'UPDATE_CURRENT_MONTH_FROM_DAYTYPES':
+ return _.assign({}, state, {current_month: actions.updateSynthesis(state)})
+ case 'VALIDATE_PERIOD_FORM':
+ if (action.error != '') return state
+
+ let period_start = actions.formatDate(action.modalProps.begin)
+ let period_end = actions.formatDate(action.modalProps.end)
+
+ let newPeriods = JSON.parse(JSON.stringify(action.timeTablePeriods))
+
+ if (action.modalProps.index !== false){
+ let updatedPeriod = newPeriods[action.modalProps.index]
+ updatedPeriod.period_start = period_start
+ updatedPeriod.period_end = period_end
+ newDates = _.reject(state.time_table_dates, d => actions.isInPeriod(newPeriods, d.date) && !d.in_out)
+ }else{
+ let newPeriod = {
+ period_start: period_start,
+ period_end: period_end
+ }
+ newPeriods.push(newPeriod)
+ }
+
+ newDates = newDates || state.time_table_dates
+ newState =_.assign({}, state, {time_table_periods: newPeriods, time_table_dates: newDates})
+ return _.assign({}, newState, {current_month: actions.updateSynthesis(newState)})
+ default:
+ return state
+ }
+}
\ No newline at end of file
--
cgit v1.2.3
From 08b002abfb101b1edce9750231c989591e049bf7 Mon Sep 17 00:00:00 2001
From: cedricnjanga
Date: Mon, 9 Oct 2017 17:14:27 +0200
Subject: Working standard webpacker config
---
app/javascript/time_tables/components/TagsSelect2.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'app/javascript/time_tables')
diff --git a/app/javascript/time_tables/components/TagsSelect2.js b/app/javascript/time_tables/components/TagsSelect2.js
index 24f473f42..22dc7aa9c 100644
--- a/app/javascript/time_tables/components/TagsSelect2.js
+++ b/app/javascript/time_tables/components/TagsSelect2.js
@@ -1,6 +1,6 @@
import React, { PropTypes, Component } from 'react'
import _ from 'lodash'
-import Select2 from 'react-select2-wrapper'
+import Select2 from 'react-select2'
// get JSON full path
let origin = window.location.origin
--
cgit v1.2.3
From 91af53dce7183146f79313df48f7e58b4d950598 Mon Sep 17 00:00:00 2001
From: cedricnjanga
Date: Tue, 10 Oct 2017 01:23:01 +0200
Subject: Add plugins to webpack config
---
app/javascript/time_tables/actions/index.js | 24 +++++-----
app/javascript/time_tables/components/Navigate.js | 4 +-
.../time_tables/components/PeriodForm.js | 4 +-
.../time_tables/components/SaveTimetable.js | 1 -
.../time_tables/components/TagsSelect2.js | 13 +++---
.../time_tables/containers/PeriodForm.js | 4 +-
app/javascript/time_tables/reducers/metas.js | 19 ++++----
app/javascript/time_tables/reducers/modal.js | 26 +++++------
app/javascript/time_tables/reducers/pagination.js | 12 ++---
app/javascript/time_tables/reducers/status.js | 8 ++--
app/javascript/time_tables/reducers/timetable.js | 51 ++++++++++++----------
11 files changed, 88 insertions(+), 78 deletions(-)
(limited to 'app/javascript/time_tables')
diff --git a/app/javascript/time_tables/actions/index.js b/app/javascript/time_tables/actions/index.js
index 5a02e8523..13cb96b64 100644
--- a/app/javascript/time_tables/actions/index.js
+++ b/app/javascript/time_tables/actions/index.js
@@ -1,10 +1,14 @@
-import _ from 'lodash'
+import range from 'lodash/range'
+import assign from 'lodash/assign'
+import reject from 'lodash/reject'
+import some from 'lodash/some'
+import every from 'lodash/every'
import clone from '../../helpers/clone'
const I18n = clone(window, "I18n")
const actions = {
weekDays: (index) => {
- return _.range(1, 8).map(n => I18n.time_tables.edit.metas.days[n])
+ return range(1, 8).map(n => I18n.time_tables.edit.metas.days[n])
},
strToArrayDayTypes: (str) =>{
return actions.weekDays().map(day => str.indexOf(day) !== -1)
@@ -151,7 +155,7 @@ const actions = {
type : 'CLOSE_MODAL'
}),
monthName(strDate) {
- let monthList = _.range(1,13).map(n => I18n.calendars.months[n])
+ let monthList = range(1,13).map(n => I18n.calendars.months[n])
let date = new Date(strDate)
return monthList[date.getMonth()]
},
@@ -172,12 +176,12 @@ const actions = {
return date.toLocaleDateString()
},
updateSynthesis: ({current_month, time_table_dates: dates, time_table_periods: periods}) => {
- let newPeriods = _.reject(periods, 'deleted')
+ let newPeriods = reject(periods, 'deleted')
let improvedCM = current_month.map((d, i) => {
let isInPeriod = actions.isInPeriod(newPeriods, d.date)
- let isIncluded = _.some(dates, {'date': d.date, 'in_out': true})
+ let isIncluded = some(dates, {'date': d.date, 'in_out': true})
- return _.assign({}, current_month[i], {
+ return assign({}, current_month[i], {
in_periods: isInPeriod,
include_date: isIncluded,
excluded_date: !isInPeriod ? false : current_month[i].excluded_date
@@ -271,8 +275,8 @@ const actions = {
submitTimetable: (dispatch, timetable, metas, next) => {
dispatch(actions.fetchingApi())
let strDayTypes = actions.arrayToStrDayTypes(metas.day_types)
- metas.day_types= strDayTypes
- let sentState = _.assign({}, timetable, metas)
+ metas.day_types = strDayTypes
+ let sentState = assign({}, timetable, metas)
let urlJSON = window.location.pathname.split('/', 5).join('/')
let hasError = false
fetch(urlJSON + '.json', {
@@ -302,8 +306,8 @@ const actions = {
})
},
errorModalKey: (periods, dayTypes) => {
- const withoutPeriodsWithDaysTypes = _.reject(periods, 'deleted').length == 0 && _.some(dayTypes) && "withoutPeriodsWithDaysTypes"
- const withPeriodsWithoutDayTypes = _.reject(periods, 'deleted').length > 0 && _.every(dayTypes, dt => dt == false) && "withPeriodsWithoutDayTypes"
+ const withoutPeriodsWithDaysTypes = reject(periods, 'deleted').length == 0 && some(dayTypes) && "withoutPeriodsWithDaysTypes"
+ const withPeriodsWithoutDayTypes = reject(periods, 'deleted').length > 0 && every(dayTypes, dt => dt == false) && "withPeriodsWithoutDayTypes"
return (withoutPeriodsWithDaysTypes || withPeriodsWithoutDayTypes) && (withoutPeriodsWithDaysTypes ? "withoutPeriodsWithDaysTypes" : "withPeriodsWithoutDayTypes")
diff --git a/app/javascript/time_tables/components/Navigate.js b/app/javascript/time_tables/components/Navigate.js
index 6ae80bce0..7307d819b 100644
--- a/app/javascript/time_tables/components/Navigate.js
+++ b/app/javascript/time_tables/components/Navigate.js
@@ -1,5 +1,5 @@
import React, { PropTypes, Component } from 'react'
-import _ from 'lodash'
+import map from 'lodash/map'
import actions from '../actions'
export default function Navigate({ dispatch, metas, timetable, pagination, status, filters}) {
@@ -30,7 +30,7 @@ export default function Navigate({ dispatch, metas, timetable, pagination, statu
className='dropdown-menu'
aria-labelledby='date_selector'
>
- {_.map(pagination.periode_range, (month, i) => (
+ {map(pagination.periode_range, (month, i) => (