'use strict' ### COMMON CODE ### ## # Provides a set of common callback methods to the $scope parameter. These methods are used # in the various trainings' admin controllers. # # Provides : # - $scope.submited(content) # - $scope.fileinputClass(v) # # Requires : # - $state (Ui-Router) [ 'app.admin.trainings' ] ## class TrainingsController constructor: ($scope, $state) -> ## # For use with ngUpload (https://github.com/twilson63/ngUpload). # Intended to be the callback when the upload is done: any raised error will be stacked in the # $scope.alerts array. If everything goes fine, the user is redirected to the trainings list. # @param content {Object} JSON - The upload's result ## $scope.submited = (content) -> if !content.id? $scope.alerts = [] angular.forEach content, (v, k)-> angular.forEach v, (err)-> $scope.alerts.push msg: k+': '+err type: 'danger' else $state.go('app.admin.trainings') ## # Changes the current user's view, redirecting him to the machines list ## $scope.cancel = -> $state.go('app.admin.trainings') ## # For use with 'ng-class', returns the CSS class name for the uploads previews. # The preview may show a placeholder or the content of the file depending on the upload state. # @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules) ## $scope.fileinputClass = (v)-> if v 'fileinput-exists' else 'fileinput-new' ## # Controller used in the training creation page (admin) ## Application.Controllers.controller "NewTrainingController", [ '$scope', '$state', 'machinesPromise', 'CSRF' , ($scope, $state, machinesPromise, CSRF) -> ### PUBLIC SCOPE ### ## Form action on the following URL $scope.method = 'post' ## API URL where the form will be posted $scope.actionUrl = '/api/trainings/' ## list of machines $scope.machines = machinesPromise ### PRIVATE SCOPE ### ## # Kind of constructor: these actions will be realized first when the controller is loaded ## initialize = -> CSRF.setMetaTags() ## Using the TrainingsController new TrainingsController($scope, $state) ## !!! MUST BE CALLED AT THE END of the controller initialize() ] ## # Controller used in the training edition page (admin) ## Application.Controllers.controller "EditTrainingController", [ '$scope', '$state', '$stateParams', 'trainingPromise', 'machinesPromise', 'CSRF' , ($scope, $state, $stateParams, trainingPromise, machinesPromise, CSRF) -> ### PUBLIC SCOPE ### ## Form action on the following URL $scope.method = 'patch' ## API URL where the form will be posted $scope.actionUrl = '/api/trainings/' + $stateParams.id ## Details of the training to edit (id in URL) $scope.training = trainingPromise ## list of machines $scope.machines = machinesPromise ### PRIVATE SCOPE ### ## # Kind of constructor: these actions will be realized first when the controller is loaded ## initialize = -> CSRF.setMetaTags() ## Using the TrainingsController new TrainingsController($scope, $state) ## !!! MUST BE CALLED AT THE END of the controller initialize() ] ## # Controller used in the trainings management page, allowing admins users to see and manage the list of trainings and reservations. ## Application.Controllers.controller "TrainingsAdminController", ["$scope", "$state", "$uibModal", 'Training', 'trainingsPromise', 'machinesPromise', '_t', 'growl', 'dialogs' , ($scope, $state, $uibModal, Training, trainingsPromise, machinesPromise, _t, growl, dialogs) -> ### PUBLIC SCOPE ### ## list of trainings $scope.trainings = trainingsPromise ## simplified list of machines $scope.machines = machinesPromise ## Training to monitor, binded with drop-down selection $scope.monitoring = training: null ## list of training availabilies, grouped by date $scope.groupedAvailabilities = {} ## default: accordions are not open $scope.accordions = {} ## Binding for the parseInt function $scope.parseInt = parseInt ## # In the trainings listing tab, return the stringified list of machines associated with the provided training # @param training {Object} Training object, inherited from $resource # @returns {string} ## $scope.showMachines = (training) -> selected = [] angular.forEach $scope.machines, (m) -> if (training.machine_ids.indexOf(m.id) >= 0) selected.push(m.name) return if selected.length then selected.join(', ') else _t('none') ## # Removes the newly inserted but not saved training / Cancel the current training modification # @param rowform {Object} see http://vitalets.github.io/angular-xeditable/ # @param index {number} training index in the $scope.trainings array ## $scope.cancelTraining = (rowform, index) -> if $scope.trainings[index].id? rowform.$cancel() else $scope.trainings.splice(index, 1) ## # In the trainings monitoring tab, callback to open a modal window displaying the current bookings for the # provided training slot. The admin will be then able to validate the training for the users that followed # the training. # @param training {Object} Training object, inherited from $resource # @param availability {Object} time slot when the training occurs ## $scope.showReservations = (training, availability) -> $uibModal.open templateUrl: '<%= asset_path "admin/trainings/validTrainingModal.html" %>' controller: ['$scope', '$uibModalInstance', ($scope, $uibModalInstance) -> $scope.availability = availability $scope.usersToValid = [] ## # Mark/unmark the provided user for training validation # @param user {Object} from the availability.reservation_users list ## $scope.toggleSelection = (user) -> index = $scope.usersToValid.indexOf(user) if index > -1 $scope.usersToValid.splice(index, 1) else $scope.usersToValid.push user ## # Validates the modifications (training validations) and save them to the server ## $scope.ok = -> users = $scope.usersToValid.map (u) -> u.id Training.update {id: training.id}, training: users: users , -> # success angular.forEach $scope.usersToValid, (u) -> u.is_valid = true $scope.usersToValid = [] $uibModalInstance.close(training) ## # Cancel the modifications and close the modal window ## $scope.cancel = -> $uibModalInstance.dismiss('cancel') ] ## # Delete the provided training and, in case of sucess, remove it from the trainings list afterwards # @param index {number} index of the provided training in $scope.trainings # @param training {Object} training to delete ## $scope.removeTraining = (index, training)-> dialogs.confirm resolve: object: -> title: _t('confirmation_required') msg: _t('do_you_really_want_to_delete_this_training') , -> # deletion confirmed training.$delete -> $scope.trainings.splice(index, 1) growl.info(_t('training_successfully_deleted')) , (error)-> growl.warning(_t('unable_to_delete_the_training_because_some_users_alredy_booked_it')) ## # Takes a month number and return its localized literal name # @param {Number} from 0 to 11 # @returns {String} eg. 'janvier' ## $scope.formatMonth = (number) -> number = parseInt(number) moment().month(number).format('MMMM') ## # Given a day, month and year, return a localized literal name for the day # @param day {Number} from 1 to 31 # @param month {Number} from 0 to 11 # @param year {Number} Gregorian's year number # @returns {String} eg. 'mercredi 12' ## $scope.formatDay = (day, month, year) -> day = parseInt(day) month = parseInt(month) year = parseInt(year) moment({year: year, month:month, day:day}).format('dddd D') ## # Callback when the drop-down selection is changed. # The selected training details will be loaded from the API and rendered into the accordions. ## $scope.selectTrainingToMonitor = -> Training.availabilities {id: $scope.monitoring.training.id}, (training) -> $scope.groupedAvailabilities = groupAvailabilities([training]) # we open current year/month by default now = moment() $scope.accordions[training.name] = {} $scope.accordions[training.name][now.year()] = isOpenFirst: true $scope.accordions[training.name][now.year()][now.month()] = isOpenFirst: true ### PRIVATE SCOPE ### ## # Group the trainings availabilites by trainings and by dates and return the resulting tree # @param trainings {Array} $scope.trainings is expected here # @returns {Object} Tree constructed as /training_name/year/month/day/[availabilities] ## groupAvailabilities = (trainings) -> tree = {} for training in trainings tree[training.name] = {} tree[training.name].training = training for availability in training.availabilities start = moment(availability.start_at) # init the tree structure if typeof tree[training.name][start.year()] == 'undefined' tree[training.name][start.year()] = {} if typeof tree[training.name][start.year()][start.month()] == 'undefined' tree[training.name][start.year()][start.month()] = {} if typeof tree[training.name][start.year()][start.month()][start.date()] == 'undefined' tree[training.name][start.year()][start.month()][start.date()] = [] # add the availability at its right place tree[training.name][start.year()][start.month()][start.date()].push( availability ) tree ]