mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-17 11:54:22 +01:00
Merge branch 'training' into dev
This commit is contained in:
parent
f5b435895e
commit
90142ae3bb
app
assets
controllers/api
models
views/api/trainings
config
initializers
locales
app.admin.en.ymlapp.admin.fr.ymlapp.logged.en.ymlapp.logged.fr.ymlapp.public.en.ymlapp.public.fr.ymlapp.shared.en.ymlapp.shared.fr.yml
routes.rbdb
vendor/assets/components
@ -1,7 +1,148 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
Application.Controllers.controller "TrainingsController", ["$scope", "$state", "$uibModal", 'Training', 'trainingsPromise', 'machinesPromise', '_t', 'growl'
|
### COMMON CODE ###
|
||||||
, ($scope, $state, $uibModal, Training, trainingsPromise, machinesPromise, _t, growl) ->
|
|
||||||
|
##
|
||||||
|
# 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) ->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -40,35 +181,6 @@ Application.Controllers.controller "TrainingsController", ["$scope", "$state", "
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Create a new empty training object and append it to the $scope.trainings list
|
|
||||||
##
|
|
||||||
$scope.addTraining = ->
|
|
||||||
$scope.inserted =
|
|
||||||
name: ''
|
|
||||||
machine_ids: []
|
|
||||||
$scope.trainings.push($scope.inserted)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Saves a new training / Update an existing training to the server (form validation callback)
|
|
||||||
# @param data {Object} training name, associated machine(s) and default places number
|
|
||||||
# @param id {number} training id, in case of update
|
|
||||||
##
|
|
||||||
$scope.saveTraining = (data, id) ->
|
|
||||||
if id?
|
|
||||||
Training.update {id: id},
|
|
||||||
training: data
|
|
||||||
else
|
|
||||||
Training.save
|
|
||||||
training: data
|
|
||||||
, (resp) ->
|
|
||||||
$scope.trainings[$scope.trainings.length-1] = resp
|
|
||||||
console.log(resp)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Removes the newly inserted but not saved training / Cancel the current training modification
|
# Removes the newly inserted but not saved training / Cancel the current training modification
|
||||||
# @param rowform {Object} see http://vitalets.github.io/angular-xeditable/
|
# @param rowform {Object} see http://vitalets.github.io/angular-xeditable/
|
||||||
@ -138,6 +250,12 @@ Application.Controllers.controller "TrainingsController", ["$scope", "$state", "
|
|||||||
# @param training {Object} training to delete
|
# @param training {Object} training to delete
|
||||||
##
|
##
|
||||||
$scope.removeTraining = (index, training)->
|
$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 ->
|
training.$delete ->
|
||||||
$scope.trainings.splice(index, 1)
|
$scope.trainings.splice(index, 1)
|
||||||
growl.info(_t('training_successfully_deleted'))
|
growl.info(_t('training_successfully_deleted'))
|
||||||
@ -146,25 +264,6 @@ Application.Controllers.controller "TrainingsController", ["$scope", "$state", "
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Open the modal to edit description of the training
|
|
||||||
# @param training {Object} Training to edit description
|
|
||||||
##
|
|
||||||
$scope.openModalToSetDescription = (training)->
|
|
||||||
$uibModal.open(
|
|
||||||
templateUrl: "<%= asset_path 'admin/trainings/modal_edit.html' %>"
|
|
||||||
controller: ['$scope', '$uibModalInstance', 'Training', 'growl', ($scope, $uibModalInstance, Training, growl)->
|
|
||||||
$scope.training = training
|
|
||||||
$scope.save = ->
|
|
||||||
Training.update id: training.id, { training: { description: $scope.training.description } }, (training)->
|
|
||||||
$uibModalInstance.close()
|
|
||||||
growl.success(_t('description_was_successfully_saved'))
|
|
||||||
return
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Takes a month number and return its localized literal name
|
# Takes a month number and return its localized literal name
|
||||||
# @param {Number} from 0 to 11
|
# @param {Number} from 0 to 11
|
||||||
|
@ -19,7 +19,7 @@ Application.Controllers.controller "MainNavController", ["$scope", "$location",
|
|||||||
linkIcon: 'calendar'
|
linkIcon: 'calendar'
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
state: 'app.logged.trainings_reserve'
|
state: 'app.public.trainings_list'
|
||||||
linkText: 'trainings_registrations'
|
linkText: 'trainings_registrations'
|
||||||
linkIcon: 'graduation-cap'
|
linkIcon: 'graduation-cap'
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,58 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
|
##
|
||||||
|
# Public listing of the trainings
|
||||||
|
##
|
||||||
|
Application.Controllers.controller "TrainingsController", ['$scope', '$state', 'trainingsPromise', ($scope, $state, trainingsPromise) ->
|
||||||
|
|
||||||
|
## List of trainings
|
||||||
|
$scope.trainings = trainingsPromise
|
||||||
|
|
||||||
|
##
|
||||||
|
# Callback for the 'reserve' button
|
||||||
|
##
|
||||||
|
$scope.reserveTraining = (training, event) ->
|
||||||
|
$state.go('app.logged.trainings_reserve', {id: training.id})
|
||||||
|
|
||||||
|
##
|
||||||
|
# Callback for the 'show' button
|
||||||
|
##
|
||||||
|
$scope.showTraining = (training) ->
|
||||||
|
$state.go('app.public.training_show', {id: training.id})
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Public view of a specific training
|
||||||
|
##
|
||||||
|
Application.Controllers.controller "ShowTrainingController", ['$scope', '$state', 'trainingPromise', ($scope, $state, trainingPromise) ->
|
||||||
|
|
||||||
|
## Current training
|
||||||
|
$scope.training = trainingPromise
|
||||||
|
|
||||||
|
##
|
||||||
|
# Callback for the 'reserve' button
|
||||||
|
##
|
||||||
|
$scope.reserveTraining = (training, event) ->
|
||||||
|
$state.go('app.logged.trainings_reserve', {id: training.id})
|
||||||
|
|
||||||
|
##
|
||||||
|
# Revert view to the full list of trainings ("<-" button)
|
||||||
|
##
|
||||||
|
$scope.cancel = (event) ->
|
||||||
|
$state.go('app.public.trainings_list')
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Controller used in the training reservation agenda page.
|
# Controller used in the training reservation agenda page.
|
||||||
# This controller is very similar to the machine reservation controller with one major difference: here, ONLY ONE
|
# This controller is very similar to the machine reservation controller with one major difference: here, ONLY ONE
|
||||||
# training can be reserved during the reservation process (the shopping cart may contains only one training and a subscription).
|
# training can be reserved during the reservation process (the shopping cart may contains only one training and a subscription).
|
||||||
##
|
##
|
||||||
|
|
||||||
Application.Controllers.controller "ReserveTrainingController", ["$scope", "$state", '$stateParams', "$uibModal", 'Auth', 'dialogs', '$timeout', 'Price', 'Availability', 'Slot', 'Member', 'Setting', 'CustomAsset', '$compile', 'availabilityTrainingsPromise', 'plansPromise', 'groupsPromise', 'growl', 'settingsPromise', '_t',
|
Application.Controllers.controller "ReserveTrainingController", ["$scope", "$state", '$stateParams', '$filter', '$compile', "$uibModal", 'Auth', 'dialogs', '$timeout', 'Price', 'Availability', 'Slot', 'Member', 'Setting', 'CustomAsset', 'availabilityTrainingsPromise', 'plansPromise', 'groupsPromise', 'growl', 'settingsPromise', 'trainingPromise', '_t'
|
||||||
($scope, $state, $stateParams, $uibModal, Auth, dialogs, $timeout, Price, Availability, Slot, Member, Setting, CustomAsset, $compile, availabilityTrainingsPromise, plansPromise, groupsPromise, growl, settingsPromise, _t) ->
|
, ($scope, $state, $stateParams, $filter, $compile, $uibModal, Auth, dialogs, $timeout, Price, Availability, Slot, Member, Setting, CustomAsset, availabilityTrainingsPromise, plansPromise, groupsPromise, growl, settingsPromise, trainingPromise, _t) ->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -71,6 +116,9 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
|
|||||||
## Once a training reservation was modified, will contains {newReservedSlot:{}, oldReservedSlot:{}}
|
## Once a training reservation was modified, will contains {newReservedSlot:{}, oldReservedSlot:{}}
|
||||||
$scope.modifiedSlots = null
|
$scope.modifiedSlots = null
|
||||||
|
|
||||||
|
## Selected training unless 'all' trainings are displayed
|
||||||
|
$scope.training = trainingPromise
|
||||||
|
|
||||||
## fullCalendar (v2) configuration
|
## fullCalendar (v2) configuration
|
||||||
$scope.calendarConfig =
|
$scope.calendarConfig =
|
||||||
timezone: Fablab.timezone
|
timezone: Fablab.timezone
|
||||||
@ -125,7 +173,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
|
|||||||
if $scope.ctrl.member
|
if $scope.ctrl.member
|
||||||
Member.get {id: $scope.ctrl.member.id}, (member) ->
|
Member.get {id: $scope.ctrl.member.id}, (member) ->
|
||||||
$scope.ctrl.member = member
|
$scope.ctrl.member = member
|
||||||
Availability.trainings {member_id: $scope.ctrl.member.id}, (trainings) ->
|
Availability.trainings {trainingId: $stateParams.id, member_id: $scope.ctrl.member.id}, (trainings) ->
|
||||||
$scope.calendar.fullCalendar 'removeEvents'
|
$scope.calendar.fullCalendar 'removeEvents'
|
||||||
$scope.eventSources.push
|
$scope.eventSources.push
|
||||||
events: trainings
|
events: trainings
|
||||||
@ -441,7 +489,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
|
|||||||
##
|
##
|
||||||
eventRenderCb = (event, element, view)->
|
eventRenderCb = (event, element, view)->
|
||||||
element.attr(
|
element.attr(
|
||||||
'uib-popover': event.training.description
|
'uib-popover': $filter('humanize')($filter('simpleText')(event.training.description), 70)
|
||||||
'popover-trigger': 'mouseenter'
|
'popover-trigger': 'mouseenter'
|
||||||
)
|
)
|
||||||
$compile(element)($scope)
|
$compile(element)($scope)
|
||||||
|
@ -115,6 +115,8 @@ Application.Filters.filter "simpleText", [ ->
|
|||||||
if text != undefined
|
if text != undefined
|
||||||
text = text.replace(/<br\s*\/?>/g, '\n')
|
text = text.replace(/<br\s*\/?>/g, '\n')
|
||||||
text.replace(/<\/?\w+[^>]*>/g, '')
|
text.replace(/<\/?\w+[^>]*>/g, '')
|
||||||
|
else
|
||||||
|
""
|
||||||
]
|
]
|
||||||
|
|
||||||
Application.Filters.filter "toTrusted", [ "$sce", ($sce) ->
|
Application.Filters.filter "toTrusted", [ "$sce", ($sce) ->
|
||||||
|
@ -363,8 +363,34 @@ angular.module('application.router', ['ui.router']).
|
|||||||
Translations.query(['app.admin.machines_edit', 'app.shared.machine']).$promise
|
Translations.query(['app.admin.machines_edit', 'app.shared.machine']).$promise
|
||||||
]
|
]
|
||||||
# trainings
|
# trainings
|
||||||
|
.state 'app.public.trainings_list',
|
||||||
|
url: '/trainings'
|
||||||
|
views:
|
||||||
|
'main@':
|
||||||
|
templateUrl: '<%= asset_path "trainings/index.html" %>'
|
||||||
|
controller: 'TrainingsController'
|
||||||
|
resolve:
|
||||||
|
trainingsPromise: ['Training', (Training)->
|
||||||
|
Training.query().$promise
|
||||||
|
]
|
||||||
|
translations: [ 'Translations', (Translations) ->
|
||||||
|
Translations.query(['app.public.trainings_list']).$promise
|
||||||
|
]
|
||||||
|
.state 'app.public.training_show',
|
||||||
|
url: '/trainings/:id'
|
||||||
|
views:
|
||||||
|
'main@':
|
||||||
|
templateUrl: '<%= asset_path "trainings/show.html" %>'
|
||||||
|
controller: 'ShowTrainingController'
|
||||||
|
resolve:
|
||||||
|
trainingPromise: ['Training', '$stateParams', (Training, $stateParams)->
|
||||||
|
Training.get({id: $stateParams.id}).$promise
|
||||||
|
]
|
||||||
|
translations: [ 'Translations', (Translations) ->
|
||||||
|
Translations.query(['app.public.training_show']).$promise
|
||||||
|
]
|
||||||
.state 'app.logged.trainings_reserve',
|
.state 'app.logged.trainings_reserve',
|
||||||
url: '/trainings/reserve'
|
url: '/trainings/:id/reserve'
|
||||||
views:
|
views:
|
||||||
'main@':
|
'main@':
|
||||||
templateUrl: '<%= asset_path "trainings/reserve.html" %>'
|
templateUrl: '<%= asset_path "trainings/reserve.html" %>'
|
||||||
@ -379,8 +405,11 @@ angular.module('application.router', ['ui.router']).
|
|||||||
groupsPromise: ['Group', (Group)->
|
groupsPromise: ['Group', (Group)->
|
||||||
Group.query().$promise
|
Group.query().$promise
|
||||||
]
|
]
|
||||||
availabilityTrainingsPromise: ['Availability', (Availability)->
|
availabilityTrainingsPromise: ['Availability', '$stateParams', (Availability, $stateParams)->
|
||||||
Availability.trainings().$promise
|
Availability.trainings({trainingId: $stateParams.id}).$promise
|
||||||
|
]
|
||||||
|
trainingPromise: ['Training', '$stateParams', (Training, $stateParams)->
|
||||||
|
Training.get({id: $stateParams.id}).$promise unless $stateParams.id == 'all'
|
||||||
]
|
]
|
||||||
settingsPromise: ['Setting', (Setting)->
|
settingsPromise: ['Setting', (Setting)->
|
||||||
Setting.query(names: "['booking_window_start',
|
Setting.query(names: "['booking_window_start',
|
||||||
@ -511,7 +540,7 @@ angular.module('application.router', ['ui.router']).
|
|||||||
views:
|
views:
|
||||||
'main@':
|
'main@':
|
||||||
templateUrl: '<%= asset_path "admin/trainings/index.html" %>'
|
templateUrl: '<%= asset_path "admin/trainings/index.html" %>'
|
||||||
controller: 'TrainingsController'
|
controller: 'TrainingsAdminController'
|
||||||
resolve:
|
resolve:
|
||||||
trainingsPromise: ['Training', (Training)->
|
trainingsPromise: ['Training', (Training)->
|
||||||
Training.query().$promise
|
Training.query().$promise
|
||||||
@ -520,9 +549,37 @@ angular.module('application.router', ['ui.router']).
|
|||||||
Machine.query().$promise
|
Machine.query().$promise
|
||||||
]
|
]
|
||||||
translations: [ 'Translations', (Translations) ->
|
translations: [ 'Translations', (Translations) ->
|
||||||
Translations.query('app.admin.trainings').$promise
|
Translations.query(['app.admin.trainings', 'app.shared.trainings']).$promise
|
||||||
|
]
|
||||||
|
.state 'app.admin.trainings_new',
|
||||||
|
url: '/admin/trainings/new'
|
||||||
|
views:
|
||||||
|
'main@':
|
||||||
|
templateUrl: '<%= asset_path "admin/trainings/new.html" %>'
|
||||||
|
controller: 'NewTrainingController'
|
||||||
|
resolve:
|
||||||
|
machinesPromise: ['Machine', (Machine)->
|
||||||
|
Machine.query().$promise
|
||||||
|
]
|
||||||
|
translations: [ 'Translations', (Translations) ->
|
||||||
|
Translations.query(['app.admin.trainings_new', 'app.shared.trainings']).$promise
|
||||||
|
]
|
||||||
|
.state 'app.admin.trainings_edit',
|
||||||
|
url: '/admin/trainings/:id/edit'
|
||||||
|
views:
|
||||||
|
'main@':
|
||||||
|
templateUrl: '<%= asset_path "admin/trainings/edit.html" %>'
|
||||||
|
controller: 'EditTrainingController'
|
||||||
|
resolve:
|
||||||
|
trainingPromise: ['Training', '$stateParams', (Training, $stateParams)->
|
||||||
|
Training.get(id: $stateParams.id).$promise
|
||||||
|
]
|
||||||
|
machinesPromise: ['Machine', (Machine)->
|
||||||
|
Machine.query().$promise
|
||||||
|
]
|
||||||
|
translations: [ 'Translations', (Translations) ->
|
||||||
|
Translations.query('app.shared.trainings').$promise
|
||||||
]
|
]
|
||||||
|
|
||||||
# events
|
# events
|
||||||
.state 'app.admin.events',
|
.state 'app.admin.events',
|
||||||
url: '/admin/events'
|
url: '/admin/events'
|
||||||
|
@ -14,7 +14,8 @@ Application.Services.factory 'Availability', ["$resource", ($resource)->
|
|||||||
isArray: true
|
isArray: true
|
||||||
trainings:
|
trainings:
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
url: '/api/availabilities/trainings'
|
url: '/api/availabilities/trainings/:trainingId'
|
||||||
|
params: {trainingId: "@trainingId"}
|
||||||
isArray: true
|
isArray: true
|
||||||
update:
|
update:
|
||||||
method: 'PUT'
|
method: 'PUT'
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<ng-include src="'<%= asset_path 'admin/plans/_form.html' %>'"></ng-include>
|
<ng-include src="'<%= asset_path 'admin/plans/_form.html' %>'"></ng-include>
|
||||||
|
|
||||||
<div class="panel-footer no-padder">
|
<div class="panel-footer no-padder">
|
||||||
<input type="submit" value="Enregistrer" class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c" ng-disabled="planForm.$invalid || !partnerIsValid()"/>
|
<input type="submit" value="{{ 'save' | translate }}" class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c" ng-disabled="planForm.$invalid || !partnerIsValid()"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
104
app/assets/templates/admin/trainings/_form.html.erb
Normal file
104
app/assets/templates/admin/trainings/_form.html.erb
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
<form role="form"
|
||||||
|
name="trainingForm"
|
||||||
|
class="form-horizontal"
|
||||||
|
ng-attr-action="{{ actionUrl }}"
|
||||||
|
ng-upload="submited(content)"
|
||||||
|
upload-options-enable-rails-csrf="true"
|
||||||
|
unsaved-warning-form
|
||||||
|
novalidate>
|
||||||
|
|
||||||
|
<input name="_method" type="hidden" ng-value="method">
|
||||||
|
|
||||||
|
<section class="panel panel-default bg-light m-lg">
|
||||||
|
<div class="panel-body m-r">
|
||||||
|
|
||||||
|
<uib-alert ng-repeat="alert in alerts" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</uib-alert>
|
||||||
|
|
||||||
|
<div class="form-group m-b-lg" ng-class="{'has-error': trainingForm['training[name]'].$dirty && trainingForm['training[name]'].$invalid}">
|
||||||
|
<label for="name" class="col-sm-2 control-label">{{ 'name' | translate }} *</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input name="training[name]"
|
||||||
|
ng-model="training.name"
|
||||||
|
type="text"
|
||||||
|
class="form-control"
|
||||||
|
id="training_name"
|
||||||
|
placeholder="{{'name' | translate}}"
|
||||||
|
required/>
|
||||||
|
<span class="help-block" ng-show="trainingForm['training[name]'].$dirty && trainingForm['training[name]'].$error.required" translate>{{ 'name_is_required' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group m-b-lg">
|
||||||
|
<label for="training_image" class="col-sm-2 control-label">{{ 'illustration' | translate }} *</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div class="fileinput" data-provides="fileinput" ng-class="fileinputClass(training.training_image)">
|
||||||
|
<div class="fileinput-new thumbnail" style="width: 334px; height: 250px;">
|
||||||
|
<img src="data:image/png;base64," data-src="holder.js/100%x100%/text:/font:FontAwesome/icon" bs-holder ng-if="!training.training_image">
|
||||||
|
</div>
|
||||||
|
<div class="fileinput-preview fileinput-exists thumbnail" style="max-width: 334px;">
|
||||||
|
<img ng-src="{{ training.training_image }}" alt="" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="btn btn-default btn-file">
|
||||||
|
<span class="fileinput-new">{{ 'add_an_illustration' | translate }} <i class="fa fa-upload fa-fw"></i></span>
|
||||||
|
<span class="fileinput-exists" translate>{{ 'change' }}</span>
|
||||||
|
<input type="file"
|
||||||
|
ng-model="training.training_image"
|
||||||
|
name="training[training_image_attributes][attachment]"
|
||||||
|
accept="image/*"
|
||||||
|
required
|
||||||
|
bs-jasny-fileinput>
|
||||||
|
</span>
|
||||||
|
<a href="#" class="btn btn-danger fileinput-exists" data-dismiss="fileinput" translate>{{ 'delete' }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group m-b-xl" ng-class="{'has-error': trainingForm['training[description]'].$dirty && trainingForm['training[description]'].$invalid}">
|
||||||
|
<label for="training_description" class="col-sm-2 control-label">{{ 'description' | translate }} *</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="hidden" name="training[description]" ng-value="training.description" />
|
||||||
|
<summernote ng-model="training.description" id="training_description" placeholder="" config="summernoteOpts" name="training[description]" required></summernote>
|
||||||
|
<span class="help-block" ng-show="trainingForm['training[description]'].$dirty && trainingForm['training[description]'].$error.required" translate>{{ 'description_is_required' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group m-b-lg" ng-class="{'has-error': trainingForm['training[machine_ids]'].$dirty && trainingForm['training[machine_ids]'].$invalid}">
|
||||||
|
<label for="training_machines" class="col-sm-2 control-label">{{ 'associated_machines' | translate }}</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<ui-select multiple ng-model="training.machine_ids" class="form-control" id="training_machines">
|
||||||
|
<ui-select-match>
|
||||||
|
<span ng-bind="$item.name"></span>
|
||||||
|
<input type="hidden" name="training[machine_ids][]" value="{{$item.id}}" />
|
||||||
|
</ui-select-match>
|
||||||
|
<ui-select-choices repeat="m.id as m in (machines | filter: $select.search)">
|
||||||
|
<span ng-bind-html="m.name | highlight: $select.search"></span>
|
||||||
|
</ui-select-choices>
|
||||||
|
</ui-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group m-b-lg" ng-class="{'has-error': trainingForm['training[nb_total_places]'].$dirty && trainingForm['training[nb_total_places]'].$invalid}">
|
||||||
|
<label for="training_nb_total_places" class="col-sm-2 control-label">{{ 'number_of_tickets' | translate }}</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input ng-model="training.nb_total_places"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
name="training[nb_total_places]"
|
||||||
|
class="form-control"
|
||||||
|
id="training_nb_total_places">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div> <!-- ./panel-body -->
|
||||||
|
|
||||||
|
<div class="panel-footer no-padder">
|
||||||
|
<input type="submit"
|
||||||
|
value="{{ 'validate_your_training' | translate }}"
|
||||||
|
class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c"
|
||||||
|
ng-disabled="trainingForm.$invalid"/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</form>
|
27
app/assets/templates/admin/trainings/edit.html.erb
Normal file
27
app/assets/templates/admin/trainings/edit.html.erb
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<section class="heading b-b">
|
||||||
|
<div class="row no-gutter">
|
||||||
|
<div class="col-xs-2 col-sm-2 col-md-1">
|
||||||
|
<section class="heading-btn">
|
||||||
|
<a ng-click="cancel()"><i class="fa fa-long-arrow-left"></i></a>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-10 col-sm-10 col-md-8 b-l b-r-md">
|
||||||
|
<section class="heading-title">
|
||||||
|
<h1>{{ training.name }}</h1>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xs-12 col-sm-12 col-md-3 b-t hide-b-md">
|
||||||
|
<section class="heading-actions wrapper">
|
||||||
|
<div class="btn btn-lg btn-block btn-default rounded m-t-xs" ng-click="cancel()" translate>{{ 'cancel' }}</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row no-gutter">
|
||||||
|
<div class="col-sm-12 col-md-12 col-lg-9 b-r-lg nopadding">
|
||||||
|
<ng-include src="'<%= asset_path 'admin/trainings/_form.html' %>'"></ng-include>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -21,11 +21,7 @@
|
|||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<uib-tabset justified="true">
|
<uib-tabset justified="true">
|
||||||
<uib-tab heading="{{ 'trainings' | translate }}">
|
<uib-tab heading="{{ 'trainings' | translate }}">
|
||||||
<button type="button" class="btn btn-warning m-t m-b" ng-click="addTraining()" translate>{{ 'add_a_new_training' }}</button>
|
<button type="button" class="btn btn-warning m-t m-b" ui-sref="app.admin.trainings_new" translate>{{ 'add_a_new_training' }}</button>
|
||||||
<div class="alert alert-warning" role="alert">
|
|
||||||
{{ 'beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero' | translate }}
|
|
||||||
{{ 'dont_forget_to_change_them_before_creating_slots_for_this_training' | translate }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -38,35 +34,12 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="training in trainings">
|
<tr ng-repeat="training in trainings">
|
||||||
|
<td>{{ training.name }}</td>
|
||||||
|
<td>{{ showMachines(training) }}</td>
|
||||||
|
<td>{{ training.nb_total_places }}</td>
|
||||||
<td>
|
<td>
|
||||||
<span editable-text="training.name" e-name="name" e-form="rowform" e-required>
|
<div class="buttons">
|
||||||
{{ training.name }}
|
<button class="btn btn-default" ui-sref="app.admin.trainings_edit({id:training.id})">
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span editable-checklist="training.machine_ids" e-ng-options="m.id as m.name for m in machines" e-name="machine_ids" e-form="rowform">
|
|
||||||
{{ showMachines(training) }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span editable-number="training.nb_total_places" e-name="nb_total_places" e-form="rowform" e-required>
|
|
||||||
{{ training.nb_total_places }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<form editable-form name="rowform" onbeforesave="saveTraining($data, training.id)" ng-show="rowform.$visible" class="form-buttons form-inline" shown="inserted == training">
|
|
||||||
<button type="submit" ng-disabled="rowform.$waiting" class="btn btn-warning">
|
|
||||||
<i class="fa fa-check"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" ng-disabled="rowform.$waiting" ng-click="cancelTraining(rowform, $index)" class="btn btn-default">
|
|
||||||
<i class="fa fa-times"></i>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
<div class="buttons" ng-show="!rowform.$visible">
|
|
||||||
<button ng-click="openModalToSetDescription(training)" class="btn btn-default">
|
|
||||||
<i class="fa fa-comment-o"></i>
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-default" ng-click="rowform.$show()">
|
|
||||||
<i class="fa fa-edit"></i> {{ 'edit' | translate }}
|
<i class="fa fa-edit"></i> {{ 'edit' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-danger" ng-click="removeTraining($index, training)">
|
<button class="btn btn-danger" ng-click="removeTraining($index, training)">
|
||||||
|
35
app/assets/templates/admin/trainings/new.html.erb
Normal file
35
app/assets/templates/admin/trainings/new.html.erb
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<section class="heading b-b">
|
||||||
|
<div class="row no-gutter">
|
||||||
|
<div class="col-md-1 hidden-xs">
|
||||||
|
<section class="heading-btn">
|
||||||
|
<a href="#" ng-click="cancel()"><i class="fa fa-long-arrow-left "></i></a>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8 b-l b-r">
|
||||||
|
<section class="heading-title">
|
||||||
|
<h1 translate>{{ 'add_a_new_training' }}</h1>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row no-gutter" >
|
||||||
|
|
||||||
|
<div class="col-md-9 b-r nopadding">
|
||||||
|
|
||||||
|
<div class="alert alert-warning m-lg" role="alert">
|
||||||
|
{{ 'beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero' | translate }}
|
||||||
|
{{ 'dont_forget_to_change_them_before_creating_slots_for_this_training' | translate }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-include src="'<%= asset_path 'admin/trainings/_form.html' %>'"></ng-include>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-3">
|
||||||
|
<!-- <button class="btn">TEST</button> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,4 +1,11 @@
|
|||||||
<form role="form" name="machineForm" class="form-horizontal" novalidate action="{{ actionUrl }}" ng-upload="submited(content)" upload-options-enable-rails-csrf="true" unsaved-warning-form>
|
<form role="form"
|
||||||
|
name="machineForm"
|
||||||
|
class="form-horizontal"
|
||||||
|
action="{{ actionUrl }}"
|
||||||
|
ng-upload="submited(content)"
|
||||||
|
upload-options-enable-rails-csrf="true"
|
||||||
|
unsaved-warning-form
|
||||||
|
novalidate>
|
||||||
|
|
||||||
<input name="_method" type="hidden" ng-value="method">
|
<input name="_method" type="hidden" ng-value="method">
|
||||||
|
|
||||||
@ -10,7 +17,13 @@
|
|||||||
<div class="form-group m-b-lg" ng-class="{'has-error': machineForm['machine[name]'].$dirty && machineForm['machine[name]'].$invalid}">
|
<div class="form-group m-b-lg" ng-class="{'has-error': machineForm['machine[name]'].$dirty && machineForm['machine[name]'].$invalid}">
|
||||||
<label for="name" class="col-sm-2 control-label">{{ 'name' | translate }} *</label>
|
<label for="name" class="col-sm-2 control-label">{{ 'name' | translate }} *</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input ng-model="machine.name" type="text" name="machine[name]" class="form-control" id="machine_name" placeholder="Nom :" required>
|
<input ng-model="machine.name"
|
||||||
|
type="text"
|
||||||
|
name="machine[name]"
|
||||||
|
class="form-control"
|
||||||
|
id="machine_name"
|
||||||
|
placeholder="{{'name' | translate}}"
|
||||||
|
required>
|
||||||
<span class="help-block" ng-show="machineForm['machine[name]'].$dirty && machineForm['machine[name]'].$error.required" translate>{{ 'name_is_required' }}</span>
|
<span class="help-block" ng-show="machineForm['machine[name]'].$dirty && machineForm['machine[name]'].$error.required" translate>{{ 'name_is_required' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -46,8 +59,16 @@
|
|||||||
<div class="form-group m-b-xl" ng-class="{'has-error': machineForm['machine[description]'].$dirty && machineForm['machine[description]'].$invalid}">
|
<div class="form-group m-b-xl" ng-class="{'has-error': machineForm['machine[description]'].$dirty && machineForm['machine[description]'].$invalid}">
|
||||||
<label for="description" class="col-sm-2 control-label">{{ 'description' | translate }} *</label>
|
<label for="description" class="col-sm-2 control-label">{{ 'description' | translate }} *</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input type="hidden" name="machine[description]" ng-value="machine.description" />
|
<input type="hidden"
|
||||||
<summernote ng-model="machine.description" id="machine_description" placeholder="" config="summernoteOpts" name="machine[description]" required></summernote>
|
name="machine[description]"
|
||||||
|
ng-value="machine.description" />
|
||||||
|
<summernote ng-model="machine.description"
|
||||||
|
id="machine_description"
|
||||||
|
placeholder=""
|
||||||
|
config="summernoteOpts"
|
||||||
|
name="machine[description]"
|
||||||
|
required>
|
||||||
|
</summernote>
|
||||||
<span class="help-block" ng-show="machineForm['machine[description]'].$dirty && machineForm['machine[description]'].$error.required" translate>{{ 'description_is_required' }}</span>
|
<span class="help-block" ng-show="machineForm['machine[description]'].$dirty && machineForm['machine[description]'].$error.required" translate>{{ 'description_is_required' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -55,8 +76,16 @@
|
|||||||
<div class="form-group m-b-xl" ng-class="{'has-error': machineForm['machine[spec]'].$dirty && machineForm['machine[spec]'].$invalid}">
|
<div class="form-group m-b-xl" ng-class="{'has-error': machineForm['machine[spec]'].$dirty && machineForm['machine[spec]'].$invalid}">
|
||||||
<label for="spec" class="col-sm-2 control-label">{{ 'technical_specifications' | translate }} *</label>
|
<label for="spec" class="col-sm-2 control-label">{{ 'technical_specifications' | translate }} *</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input type="hidden" name="machine[spec]" ng-value="machine.spec" />
|
<input type="hidden"
|
||||||
<summernote ng-model="machine.spec" id="machine_spec" placeholder="" config="summernoteOpts" name="machine[spec]" required></summernote>
|
name="machine[spec]"
|
||||||
|
ng-value="machine.spec" />
|
||||||
|
<summernote ng-model="machine.spec"
|
||||||
|
id="machine_spec"
|
||||||
|
placeholder=""
|
||||||
|
config="summernoteOpts"
|
||||||
|
name="machine[spec]"
|
||||||
|
required>
|
||||||
|
</summernote>
|
||||||
<span class="help-block" ng-show="machineForm['machine[spec]'].$dirty && machineForm['machine[spec]'].$error.required" translate>{{ 'technical_specifications_are_required' }}</span>
|
<span class="help-block" ng-show="machineForm['machine[spec]'].$dirty && machineForm['machine[spec]'].$error.required" translate>{{ 'technical_specifications_are_required' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -85,7 +114,10 @@
|
|||||||
</div> <!-- ./panel-body -->
|
</div> <!-- ./panel-body -->
|
||||||
|
|
||||||
<div class="panel-footer no-padder">
|
<div class="panel-footer no-padder">
|
||||||
<input type="submit" value="{{ 'validate_your_machine' | translate }}" class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c" ng-disabled="machineForm.$invalid"/>
|
<input type="submit"
|
||||||
|
value="{{ 'validate_your_machine' | translate }}"
|
||||||
|
class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c"
|
||||||
|
ng-disabled="machineForm.$invalid"/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
61
app/assets/templates/trainings/index.html.erb
Normal file
61
app/assets/templates/trainings/index.html.erb
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<section class="heading b-b">
|
||||||
|
<div class="row no-gutter">
|
||||||
|
<div class="col-xs-2 col-sm-2 col-md-1">
|
||||||
|
<section class="heading-btn">
|
||||||
|
<a href="#" ng-click="backPrevLocation($event)"><i class="fa fa-long-arrow-left "></i></a>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-10 col-sm-10 col-md-8 b-l b-r-md">
|
||||||
|
<section class="heading-title">
|
||||||
|
<h1 translate>{{ 'the_trainings' }}</h1>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<section class="m-lg">
|
||||||
|
|
||||||
|
<div class="row" ng-repeat="training in (trainings.length/3 | array)">
|
||||||
|
|
||||||
|
<div class="col-xs-12 col-sm-6 col-md-4" ng-repeat="training in trainings.slice(3*$index, 3*$index + 3)">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="widget panel panel-default">
|
||||||
|
<div class="panel-heading picture" ng-if="!training.training_image">
|
||||||
|
<img src="data:image/png;base64," data-src="holder.js/100%x100%/text:/font:FontAwesome/icon" bs-holder class="img-responsive">
|
||||||
|
</div>
|
||||||
|
<div class="panel-heading picture" style="background-image:url({{training.training_image}})" ng-if="training.training_image">
|
||||||
|
</div>
|
||||||
|
<div class="panel-body" style="heigth:170px;">
|
||||||
|
<h1 class="m-b">{{training.name}}</h1>
|
||||||
|
<div ng-if="training.description">
|
||||||
|
<p ng-bind-html="training.description | simpleText | humanize : 140 | breakFilter"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-footer no-padder">
|
||||||
|
|
||||||
|
<div class="text-center clearfix">
|
||||||
|
<div class="col-sm-6 b-r no-padder">
|
||||||
|
<div class="btn btn-default btn-block no-b padder-v red" ng-click="reserveTraining(training, $event)">
|
||||||
|
<i class="fa fa-bookmark"></i> {{ 'book' | translate }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 no-padder">
|
||||||
|
<div class="btn btn-default btn-block padder-v no-b red" ng-click="showTraining(training)">
|
||||||
|
<i class="fa fa-eye"></i> {{ 'consult' | translate }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
@ -5,11 +5,20 @@
|
|||||||
<a href="#" ng-click="backPrevLocation($event)"><i class="fa fa-long-arrow-left "></i></a>
|
<a href="#" ng-click="backPrevLocation($event)"><i class="fa fa-long-arrow-left "></i></a>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-10 col-sm-10 col-md-8 b-l">
|
<div class="col-xs-10 col-sm-10 col-md-8 b-l b-r-md">
|
||||||
<section class="heading-title">
|
<section class="heading-title">
|
||||||
<h1 translate>{{ 'trainings_planning' }}</h1>
|
<h1 ng-hide="training" translate>{{ 'trainings_planning' }}</h1>
|
||||||
|
<h1 ng-show="training"><span translate>{{ 'planning_of' }}</span> {{training.name}}</h1>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-sm-12 col-md-3 b-t hide-b-md">
|
||||||
|
<section class="heading-actions wrapper">
|
||||||
|
<a class="btn btn-lg btn-warning bg-white b-2x rounded m-t-xs"
|
||||||
|
ui-sref="app.logged.trainings_reserve({id:'all'})"
|
||||||
|
ng-show="training"
|
||||||
|
role="button"
|
||||||
|
translate>{{ 'all_trainings' }}</a>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -24,6 +33,10 @@
|
|||||||
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-3">
|
<div class="col-sm-12 col-md-12 col-lg-3">
|
||||||
|
|
||||||
|
<div class="text-center m-t">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div ng-if="currentUser.role === 'admin'">
|
<div ng-if="currentUser.role === 'admin'">
|
||||||
<select-member></select-member>
|
<select-member></select-member>
|
||||||
</div>
|
</div>
|
||||||
|
42
app/assets/templates/trainings/show.html.erb
Normal file
42
app/assets/templates/trainings/show.html.erb
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<div>
|
||||||
|
|
||||||
|
<section class="heading b-b">
|
||||||
|
<div class="row no-gutter">
|
||||||
|
<div class="col-xs-2 col-sm-2 col-md-1">
|
||||||
|
<section class="heading-btn">
|
||||||
|
<a href="#" ng-click="cancel($event)"><i class="fa fa-long-arrow-left "></i></a>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-10 col-sm-10 col-md-7 b-l b-r-md">
|
||||||
|
<section class="heading-title">
|
||||||
|
<h1>{{ training.name }}</h1>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xs-12 col-sm-12 col-md-4 b-t hide-b-md">
|
||||||
|
<section class="heading-actions wrapper">
|
||||||
|
<a ng-click="reserveTraining(training, $event)" class="btn btn-lg btn-warning bg-white b-2x rounded m-t-xs" translate>{{ 'book_this_training' }}</a>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="row no-gutter">
|
||||||
|
<div class="col-sm-12 col-md-12 col-lg-8 b-r-lg">
|
||||||
|
|
||||||
|
<div class="article wrapper-lg" >
|
||||||
|
|
||||||
|
<div class="article-thumbnail" ng-if="training.training_image">
|
||||||
|
<img ng-src="{{training.training_image}}" alt="{{training.name}}" class="img-responsive">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="intro" ng-bind-html="training.description | breakFilter"></p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
@ -78,14 +78,33 @@ class API::AvailabilitiesController < API::ApiController
|
|||||||
@user = current_user
|
@user = current_user
|
||||||
end
|
end
|
||||||
@slots = []
|
@slots = []
|
||||||
@reservations = @user.reservations.includes(:slots).references(:slots).where("reservable_type = 'Training' AND slots.start_at > ?", Time.now)
|
|
||||||
|
# first, we get the already-made reservations
|
||||||
|
@reservations = @user.reservations.where("reservable_type = 'Training'")
|
||||||
|
@reservations = @reservations.where('reservable_id = :id', id: params[:training_id].to_i) if params[:training_id].is_number?
|
||||||
|
@reservations = @reservations.joins(:slots).where('slots.start_at > ?', Time.now)
|
||||||
|
|
||||||
|
# what is requested?
|
||||||
|
# 1) a single training
|
||||||
|
if params[:training_id].is_number?
|
||||||
|
@availabilities = Training.find(params[:training_id]).availabilities
|
||||||
|
# 2) all trainings
|
||||||
|
else
|
||||||
|
@availabilities = Availability.trainings
|
||||||
|
end
|
||||||
|
|
||||||
|
# who made the request?
|
||||||
|
# 1) an admin (he can see all future availabilities)
|
||||||
if @user.is_admin?
|
if @user.is_admin?
|
||||||
@availabilities = Availability.includes(:tags, :slots, trainings: [:machines]).trainings.where('availabilities.start_at > ?', Time.now)
|
@availabilities = @availabilities.includes(:tags, :slots, trainings: [:machines]).where('availabilities.start_at > ?', Time.now)
|
||||||
|
# 2) an user (he cannot see availabilities further than 1 (or 3) months)
|
||||||
else
|
else
|
||||||
end_at = 1.month.since
|
end_at = 1.month.since
|
||||||
end_at = 3.months.since if can_show_slot_plus_three_months(@user)
|
end_at = 3.months.since if can_show_slot_plus_three_months(@user)
|
||||||
@availabilities = Availability.includes(:tags, :slots, trainings: [:machines]).trainings.where('availabilities.start_at > ? AND availabilities.start_at < ?', Time.now, end_at).where('availability_tags.tag_id' => @user.tag_ids.concat([nil]))
|
@availabilities = @availabilities.includes(:tags, :slots, :availability_tags, trainings: [:machines]).where('availabilities.start_at > ? AND availabilities.start_at < ?', Time.now, end_at).where('availability_tags.tag_id' => @user.tag_ids.concat([nil]))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# finally, we merge the availabilities with the reservations
|
||||||
@availabilities.each do |a|
|
@availabilities.each do |a|
|
||||||
a = verify_training_is_reserved(a, @reservations)
|
a = verify_training_is_reserved(a, @reservations)
|
||||||
end
|
end
|
||||||
|
@ -35,10 +35,15 @@ class API::TrainingsController < API::ApiController
|
|||||||
members.each do |m|
|
members.each do |m|
|
||||||
m.trainings << @training
|
m.trainings << @training
|
||||||
end
|
end
|
||||||
else
|
|
||||||
@training.update(training_params)
|
|
||||||
end
|
|
||||||
head :no_content
|
head :no_content
|
||||||
|
else
|
||||||
|
if @training.update(training_params)
|
||||||
|
render :show, status: :ok, location: @training
|
||||||
|
else
|
||||||
|
render json: @training.errors, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@ -57,6 +62,6 @@ class API::TrainingsController < API::ApiController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def training_params
|
def training_params
|
||||||
params.require(:training).permit(:id, :name, :description, :machine_ids, :plan_ids, :nb_total_places, machine_ids: [], plan_ids: [])
|
params.require(:training).permit(:id, :name, :description, :machine_ids, :plan_ids, :nb_total_places, training_image_attributes: [:attachment], machine_ids: [], plan_ids: [])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,6 +2,9 @@ class Training < ActiveRecord::Base
|
|||||||
extend FriendlyId
|
extend FriendlyId
|
||||||
friendly_id :name, use: :slugged
|
friendly_id :name, use: :slugged
|
||||||
|
|
||||||
|
has_one :training_image, as: :viewable, dependent: :destroy
|
||||||
|
accepts_nested_attributes_for :training_image, allow_destroy: true
|
||||||
|
|
||||||
has_and_belongs_to_many :machines, join_table: :trainings_machines
|
has_and_belongs_to_many :machines, join_table: :trainings_machines
|
||||||
|
|
||||||
has_many :trainings_availabilities
|
has_many :trainings_availabilities
|
||||||
@ -23,8 +26,6 @@ class Training < ActiveRecord::Base
|
|||||||
after_update :update_statistic_subtype, if: :name_changed?
|
after_update :update_statistic_subtype, if: :name_changed?
|
||||||
after_destroy :remove_statistic_subtype
|
after_destroy :remove_statistic_subtype
|
||||||
|
|
||||||
validates :description, length: { maximum: 255 }
|
|
||||||
|
|
||||||
def amount_by_group(group)
|
def amount_by_group(group)
|
||||||
trainings_pricings.where(group_id: group).first
|
trainings_pricings.where(group_id: group).first
|
||||||
end
|
end
|
||||||
|
4
app/models/training_image.rb
Normal file
4
app/models/training_image.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
class TrainingImage < Asset
|
||||||
|
mount_uploader :attachment, MachineImageUploader
|
||||||
|
end
|
@ -2,12 +2,8 @@ role = (current_user and current_user.is_admin?) ? 'admin' : 'user'
|
|||||||
|
|
||||||
json.cache! [@trainings, role] do
|
json.cache! [@trainings, role] do
|
||||||
json.array!(@trainings) do |training|
|
json.array!(@trainings) do |training|
|
||||||
json.id training.id
|
json.extract! training, :id, :name, :description, :machine_ids, :nb_total_places
|
||||||
json.name training.name
|
json.training_image training.training_image.attachment.large.url if training.training_image
|
||||||
json.description training.description
|
|
||||||
json.machine_ids training.machine_ids
|
|
||||||
json.nb_total_places training.nb_total_places
|
|
||||||
|
|
||||||
json.plan_ids training.plan_ids if role === 'admin'
|
json.plan_ids training.plan_ids if role === 'admin'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
json.extract! @training, :id, :name, :machine_ids, :nb_total_places
|
json.extract! @training, :id, :name, :description, :machine_ids, :nb_total_places
|
||||||
json.availabilities @training.availabilities do |a|
|
json.training_image @training.training_image.attachment.large.url if @training.training_image
|
||||||
|
json.availabilities @training.availabilities.order('start_at DESC') do |a|
|
||||||
json.id a.id
|
json.id a.id
|
||||||
json.start_at a.start_at.iso8601
|
json.start_at a.start_at.iso8601
|
||||||
json.end_at a.end_at.iso8601
|
json.end_at a.end_at.iso8601
|
||||||
|
12
config/initializers/is_number.rb
Normal file
12
config/initializers/is_number.rb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
## Helper method: will return true if the current string
|
||||||
|
## can be parsed as a number (float or integer), false otherwise
|
||||||
|
# exemples:
|
||||||
|
# "2" => true
|
||||||
|
# "4.5" => true
|
||||||
|
# "hello" => false
|
||||||
|
# "" => false
|
||||||
|
class String
|
||||||
|
def is_number?
|
||||||
|
true if Float(self) rescue false
|
||||||
|
end
|
||||||
|
end
|
@ -46,11 +46,6 @@ en:
|
|||||||
|
|
||||||
trainings:
|
trainings:
|
||||||
# track and monitor the trainings
|
# track and monitor the trainings
|
||||||
add_a_new_training: "Add a new training"
|
|
||||||
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Beware, when creating a training, its reservation prices are initialized at zero."
|
|
||||||
dont_forget_to_change_them_before_creating_slots_for_this_training: "Don't forget to change them before creating slots for this training."
|
|
||||||
associated_machines: "Associated machines"
|
|
||||||
number_of_tickets: "Number of tickets"
|
|
||||||
training: "Training"
|
training: "Training"
|
||||||
year_NUMBER: "Year {{NUMBER}}" # angular interpolation
|
year_NUMBER: "Year {{NUMBER}}" # angular interpolation
|
||||||
month_of_NAME: "Month of {{NAME}}" # angular interpolation
|
month_of_NAME: "Month of {{NAME}}" # angular interpolation
|
||||||
@ -67,6 +62,12 @@ en:
|
|||||||
description_was_successfully_saved: "Description was successfully saved."
|
description_was_successfully_saved: "Description was successfully saved."
|
||||||
training_successfully_deleted: "Training successfully deleted."
|
training_successfully_deleted: "Training successfully deleted."
|
||||||
unable_to_delete_the_training_because_some_users_alredy_booked_it: "Unable to delete the training because some users already booked it."
|
unable_to_delete_the_training_because_some_users_alredy_booked_it: "Unable to delete the training because some users already booked it."
|
||||||
|
do_you_really_want_to_delete_this_training: "Do you really want to delete this training?"
|
||||||
|
|
||||||
|
trainings_new:
|
||||||
|
# create a new training
|
||||||
|
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Beware, when creating a training, its reservation prices are initialized at zero."
|
||||||
|
dont_forget_to_change_them_before_creating_slots_for_this_training: "Don't forget to change them before creating slots for this training."
|
||||||
|
|
||||||
events:
|
events:
|
||||||
# courses and workshops tracking and management
|
# courses and workshops tracking and management
|
||||||
|
@ -46,11 +46,6 @@ fr:
|
|||||||
|
|
||||||
trainings:
|
trainings:
|
||||||
# suivre et surveiller les formations
|
# suivre et surveiller les formations
|
||||||
add_a_new_training: "Ajouter une nouvelle formation"
|
|
||||||
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Attention, lors de la création d'une formation, ses tarifs de réservation sont initialisés à zero."
|
|
||||||
dont_forget_to_change_them_before_creating_slots_for_this_training: "Pensez à les modifier avant de créer des créneaux pour cette formation."
|
|
||||||
associated_machines: "Machines associées"
|
|
||||||
number_of_tickets: "Nombre de places"
|
|
||||||
training: "Formation"
|
training: "Formation"
|
||||||
year_NUMBER: "Année {{NUMBER}}" # angular interpolation
|
year_NUMBER: "Année {{NUMBER}}" # angular interpolation
|
||||||
month_of_NAME: "Mois de {{NAME}}" # angular interpolation
|
month_of_NAME: "Mois de {{NAME}}" # angular interpolation
|
||||||
@ -67,6 +62,12 @@ fr:
|
|||||||
description_was_successfully_saved: "La description a bien été enregistrée."
|
description_was_successfully_saved: "La description a bien été enregistrée."
|
||||||
training_successfully_deleted: "La formation a bien été supprimée."
|
training_successfully_deleted: "La formation a bien été supprimée."
|
||||||
unable_to_delete_the_training_because_some_users_alredy_booked_it: "La formation ne peut pas être supprimée car elle a déjà été réservée par des utilisateurs."
|
unable_to_delete_the_training_because_some_users_alredy_booked_it: "La formation ne peut pas être supprimée car elle a déjà été réservée par des utilisateurs."
|
||||||
|
do_you_really_want_to_delete_this_training: "Êtes-vous sur de vouloir supprimer cette formation ?"
|
||||||
|
|
||||||
|
trainings_new:
|
||||||
|
# créer une nouvelle formation
|
||||||
|
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Attention, lors de la création d'une formation, ses tarifs de réservation sont initialisés à zero."
|
||||||
|
dont_forget_to_change_them_before_creating_slots_for_this_training: "Pensez à les modifier avant de créer des créneaux pour cette formation."
|
||||||
|
|
||||||
events:
|
events:
|
||||||
# gestion et suivi des stages et ateliers
|
# gestion et suivi des stages et ateliers
|
||||||
|
@ -128,6 +128,8 @@ en:
|
|||||||
trainings_reserve:
|
trainings_reserve:
|
||||||
# book a training
|
# book a training
|
||||||
trainings_planning: "Trainings planning"
|
trainings_planning: "Trainings planning"
|
||||||
|
planning_of: "Planning of" # followed by the training name (eg. "Planning of 3d printer training")
|
||||||
|
all_trainings: "All trainings"
|
||||||
select_a_slot_in_the_calendar: "Select a slot in the calendar"
|
select_a_slot_in_the_calendar: "Select a slot in the calendar"
|
||||||
you_ve_just_selected_the_slot: "You've just selected the slot:"
|
you_ve_just_selected_the_slot: "You've just selected the slot:"
|
||||||
datetime_to_time: "{{START_DATETIME}} to {{END_TIME}}" # angular interpolation, eg: Thursday, September 4 1986 8:30 PM to 10:00 PM
|
datetime_to_time: "{{START_DATETIME}} to {{END_TIME}}" # angular interpolation, eg: Thursday, September 4 1986 8:30 PM to 10:00 PM
|
||||||
|
@ -127,7 +127,9 @@ fr:
|
|||||||
|
|
||||||
trainings_reserve:
|
trainings_reserve:
|
||||||
# réserver une formation
|
# réserver une formation
|
||||||
trainings_planning: "Planning formation"
|
trainings_planning: "Planning formations"
|
||||||
|
planning_of: "Planning de la" # suivi du nom de la formation (eg. "Planning de la formation imprimante 3d")
|
||||||
|
all_trainings: "Toutes les formations"
|
||||||
select_a_slot_in_the_calendar: "Sélectionnez un créneau dans le calendrier"
|
select_a_slot_in_the_calendar: "Sélectionnez un créneau dans le calendrier"
|
||||||
you_ve_just_selected_the_slot: "Vous venez de sélectionner le créneau :"
|
you_ve_just_selected_the_slot: "Vous venez de sélectionner le créneau :"
|
||||||
datetime_to_time: "{{START_DATETIME}} à {{END_TIME}}" # angular interpolation, eg: Thursday, September 4 1986 8:30 PM to 10:00 PM
|
datetime_to_time: "{{START_DATETIME}} à {{END_TIME}}" # angular interpolation, eg: Thursday, September 4 1986 8:30 PM to 10:00 PM
|
||||||
|
@ -161,7 +161,6 @@ en:
|
|||||||
# list of machines
|
# list of machines
|
||||||
the_fablab_s_machines: "The FabLab's machines"
|
the_fablab_s_machines: "The FabLab's machines"
|
||||||
add_a_machine: "Add a machine"
|
add_a_machine: "Add a machine"
|
||||||
book: "Book"
|
|
||||||
_or_the_: " or the "
|
_or_the_: " or the "
|
||||||
|
|
||||||
machines_show:
|
machines_show:
|
||||||
@ -173,6 +172,14 @@ en:
|
|||||||
unauthorized_operation: "Unauthoried operation"
|
unauthorized_operation: "Unauthoried operation"
|
||||||
the_machine_cant_be_deleted_because_it_is_already_reserved_by_some_users: "The machine can't be deleted because it's already reserved by some users."
|
the_machine_cant_be_deleted_because_it_is_already_reserved_by_some_users: "The machine can't be deleted because it's already reserved by some users."
|
||||||
|
|
||||||
|
trainings_list:
|
||||||
|
# list of trainings
|
||||||
|
the_trainings: "The trainings"
|
||||||
|
|
||||||
|
training_show:
|
||||||
|
# details of a training
|
||||||
|
book_this_training: "Book this training"
|
||||||
|
|
||||||
plans:
|
plans:
|
||||||
# summary of the subscriptions
|
# summary of the subscriptions
|
||||||
subcriptions: "Subscriptions"
|
subcriptions: "Subscriptions"
|
||||||
|
@ -161,7 +161,6 @@ fr:
|
|||||||
# liste des machines
|
# liste des machines
|
||||||
the_fablab_s_machines: "Les machines du FabLab"
|
the_fablab_s_machines: "Les machines du FabLab"
|
||||||
add_a_machine: "Ajouter une machine"
|
add_a_machine: "Ajouter une machine"
|
||||||
book: "Réserver"
|
|
||||||
_or_the_: " ou la "
|
_or_the_: " ou la "
|
||||||
|
|
||||||
machines_show:
|
machines_show:
|
||||||
@ -173,6 +172,16 @@ fr:
|
|||||||
unauthorized_operation: "Opération non autorisée"
|
unauthorized_operation: "Opération non autorisée"
|
||||||
the_machine_cant_be_deleted_because_it_is_already_reserved_by_some_users: "La machine ne peut pas être supprimée car elle a déjà été réservée par des utilisateurs."
|
the_machine_cant_be_deleted_because_it_is_already_reserved_by_some_users: "La machine ne peut pas être supprimée car elle a déjà été réservée par des utilisateurs."
|
||||||
|
|
||||||
|
|
||||||
|
trainings_list:
|
||||||
|
# liste des formations
|
||||||
|
the_trainings: "Les formations"
|
||||||
|
|
||||||
|
training_show:
|
||||||
|
# détails d'une formation
|
||||||
|
book_this_training: "Réserver cette formation"
|
||||||
|
|
||||||
|
|
||||||
plans:
|
plans:
|
||||||
# page récapitulative des abonnements
|
# page récapitulative des abonnements
|
||||||
subcriptions: "Les abonnements"
|
subcriptions: "Les abonnements"
|
||||||
|
@ -87,6 +87,11 @@ en:
|
|||||||
_disconnect_then_reconnect_: "disconnect then reconnect"
|
_disconnect_then_reconnect_: "disconnect then reconnect"
|
||||||
_for_your_changes_to_take_effect: "for your changes to take effect."
|
_for_your_changes_to_take_effect: "for your changes to take effect."
|
||||||
add_a_project: "Add a project"
|
add_a_project: "Add a project"
|
||||||
|
illustration: "Illustration"
|
||||||
|
add_an_illustration: "Add an illustration."
|
||||||
|
book: "Book"
|
||||||
|
description_is_required: "Description is required."
|
||||||
|
name_is_required: "Name is required."
|
||||||
|
|
||||||
messages:
|
messages:
|
||||||
you_will_lose_any_unsaved_modification_if_you_quit_this_page: "You will lose any unsaved modification if you quit this page"
|
you_will_lose_any_unsaved_modification_if_you_quit_this_page: "You will lose any unsaved modification if you quit this page"
|
||||||
@ -110,12 +115,10 @@ en:
|
|||||||
|
|
||||||
project:
|
project:
|
||||||
# project edition form
|
# project edition form
|
||||||
name_is_required: "Name is required."
|
|
||||||
illustration: "Illustration"
|
illustration: "Illustration"
|
||||||
add_an_illustration: "Add an illustration"
|
add_an_illustration: "Add an illustration"
|
||||||
CAD_file: "CAD file"
|
CAD_file: "CAD file"
|
||||||
add_a_new_file: "Add a new file"
|
add_a_new_file: "Add a new file"
|
||||||
description_is_required: "Description is required."
|
|
||||||
steps: "Steps"
|
steps: "Steps"
|
||||||
step_title: "Step title"
|
step_title: "Step title"
|
||||||
add_a_picture: "Add a picture"
|
add_a_picture: "Add a picture"
|
||||||
@ -130,10 +133,6 @@ en:
|
|||||||
|
|
||||||
machine:
|
machine:
|
||||||
# machine edition form
|
# machine edition form
|
||||||
name_is_required: "The name is required."
|
|
||||||
illustration: "Illustration"
|
|
||||||
add_an_illustration: "Add an illustration."
|
|
||||||
description_is_required: "Description is required."
|
|
||||||
technical_specifications_are_required: "Technical specifications are required."
|
technical_specifications_are_required: "Technical specifications are required."
|
||||||
attached_files_(pdf): "Attached files (pdf)"
|
attached_files_(pdf): "Attached files (pdf)"
|
||||||
attach_a_file: "Attach a file"
|
attach_a_file: "Attach a file"
|
||||||
@ -168,7 +167,6 @@ en:
|
|||||||
title_is_required: "Title is required."
|
title_is_required: "Title is required."
|
||||||
matching_visual: "Matching visual"
|
matching_visual: "Matching visual"
|
||||||
choose_a_picture: "Choose a picture"
|
choose_a_picture: "Choose a picture"
|
||||||
description_is_required: "Description is required."
|
|
||||||
attachments: "Attachments"
|
attachments: "Attachments"
|
||||||
add_a_new_file: "Add a new file"
|
add_a_new_file: "Add a new file"
|
||||||
event_type: "Event type"
|
event_type: "Event type"
|
||||||
@ -188,7 +186,6 @@ en:
|
|||||||
plan:
|
plan:
|
||||||
# subscription plan edition form
|
# subscription plan edition form
|
||||||
general_informations: "General informations"
|
general_informations: "General informations"
|
||||||
name_is_required: "Name is required."
|
|
||||||
name_length_must_be_less_than_24_characters: "Name length must be less than 24 characters."
|
name_length_must_be_less_than_24_characters: "Name length must be less than 24 characters."
|
||||||
type_is_required: "Type is required."
|
type_is_required: "Type is required."
|
||||||
group: "Group"
|
group: "Group"
|
||||||
@ -213,6 +210,13 @@ en:
|
|||||||
new_partner: "New partner"
|
new_partner: "New partner"
|
||||||
email_address_is_required: "Email address is required."
|
email_address_is_required: "Email address is required."
|
||||||
|
|
||||||
|
trainings:
|
||||||
|
# training edition form
|
||||||
|
add_a_new_training: "Add a new training"
|
||||||
|
validate_your_training: "Validate your training"
|
||||||
|
associated_machines: "Associated machines"
|
||||||
|
number_of_tickets: "Number of tickets"
|
||||||
|
|
||||||
user_admin:
|
user_admin:
|
||||||
# partial form to edit/create an user (admin view)
|
# partial form to edit/create an user (admin view)
|
||||||
group: "Group"
|
group: "Group"
|
||||||
|
@ -87,6 +87,11 @@ fr:
|
|||||||
_disconnect_then_reconnect_: "déconnectez-vous puis re-connectez vous"
|
_disconnect_then_reconnect_: "déconnectez-vous puis re-connectez vous"
|
||||||
_for_your_changes_to_take_effect: "pour que les modifications soient prises en compte."
|
_for_your_changes_to_take_effect: "pour que les modifications soient prises en compte."
|
||||||
add_a_project: "Ajouter un projet"
|
add_a_project: "Ajouter un projet"
|
||||||
|
illustration: "Visuel"
|
||||||
|
add_an_illustration: "Ajouter un visuel"
|
||||||
|
book: "Réserver"
|
||||||
|
description_is_required: "La description est requise."
|
||||||
|
name_is_required: "Le nom est requis."
|
||||||
|
|
||||||
messages:
|
messages:
|
||||||
you_will_lose_any_unsaved_modification_if_you_quit_this_page: "Vous perdrez les modifications non enregistrées si vous quittez cette page"
|
you_will_lose_any_unsaved_modification_if_you_quit_this_page: "Vous perdrez les modifications non enregistrées si vous quittez cette page"
|
||||||
@ -110,12 +115,10 @@ fr:
|
|||||||
|
|
||||||
project:
|
project:
|
||||||
# formulaire d'étition d'un projet
|
# formulaire d'étition d'un projet
|
||||||
name_is_required: "Le nom est requis."
|
|
||||||
illustration: "Illustration"
|
illustration: "Illustration"
|
||||||
add_an_illustration: "Ajouter un visuel"
|
add_an_illustration: "Ajouter un visuel"
|
||||||
CAD_file: "Fichier CAO"
|
CAD_file: "Fichier CAO"
|
||||||
add_a_new_file: "Ajouter un nouveau fichier"
|
add_a_new_file: "Ajouter un nouveau fichier"
|
||||||
description_is_required: "La description est requise."
|
|
||||||
steps: "Étapes"
|
steps: "Étapes"
|
||||||
step_title: "Titre de l'étape"
|
step_title: "Titre de l'étape"
|
||||||
add_a_picture: "Ajouter une image"
|
add_a_picture: "Ajouter une image"
|
||||||
@ -130,10 +133,6 @@ fr:
|
|||||||
|
|
||||||
machine:
|
machine:
|
||||||
# formulaire d'édition d'une machine
|
# formulaire d'édition d'une machine
|
||||||
name_is_required: "Le nom est requis."
|
|
||||||
illustration: "Visuel"
|
|
||||||
add_an_illustration: "Ajouter un visuel"
|
|
||||||
description_is_required: "La description est requise."
|
|
||||||
technical_specifications_are_required: "Les caractéristiques techniques sont requises."
|
technical_specifications_are_required: "Les caractéristiques techniques sont requises."
|
||||||
attached_files_(pdf): "Pièces jointes (pdf)"
|
attached_files_(pdf): "Pièces jointes (pdf)"
|
||||||
attach_a_file: "Joindre un fichier"
|
attach_a_file: "Joindre un fichier"
|
||||||
@ -168,7 +167,6 @@ fr:
|
|||||||
title_is_required: "Le titre est requis."
|
title_is_required: "Le titre est requis."
|
||||||
matching_visual: "Visuel associé"
|
matching_visual: "Visuel associé"
|
||||||
choose_a_picture: "Choisir une image"
|
choose_a_picture: "Choisir une image"
|
||||||
description_is_required: "La description est requise."
|
|
||||||
attachments: "Pièces jointes"
|
attachments: "Pièces jointes"
|
||||||
add_a_new_file: "Ajouter un nouveau fichier"
|
add_a_new_file: "Ajouter un nouveau fichier"
|
||||||
event_type: "Type d'évènement"
|
event_type: "Type d'évènement"
|
||||||
@ -188,7 +186,6 @@ fr:
|
|||||||
plan:
|
plan:
|
||||||
# formulaire d'édition d'une formule d'abonnement
|
# formulaire d'édition d'une formule d'abonnement
|
||||||
general_informations: "Informations générales"
|
general_informations: "Informations générales"
|
||||||
name_is_required: "Le nom est requis."
|
|
||||||
name_length_must_be_less_than_24_characters: "Le nom doit faire moins de 24 caractères."
|
name_length_must_be_less_than_24_characters: "Le nom doit faire moins de 24 caractères."
|
||||||
type_is_required: "Le type est requis."
|
type_is_required: "Le type est requis."
|
||||||
group: "Groupe"
|
group: "Groupe"
|
||||||
@ -213,6 +210,13 @@ fr:
|
|||||||
new_partner: "Nouveau partenaire"
|
new_partner: "Nouveau partenaire"
|
||||||
email_address_is_required: "L'adresse e-mail est requise."
|
email_address_is_required: "L'adresse e-mail est requise."
|
||||||
|
|
||||||
|
trainings:
|
||||||
|
# formulaire d'édition d'une formation
|
||||||
|
add_a_new_training: "Ajouter une nouvelle formation"
|
||||||
|
validate_your_training: "Valider votre formation"
|
||||||
|
associated_machines: "Machines associées"
|
||||||
|
number_of_tickets: "Nombre de places"
|
||||||
|
|
||||||
user_admin:
|
user_admin:
|
||||||
# formulaire partiel d'édition/création utilisateur (vue admin)
|
# formulaire partiel d'édition/création utilisateur (vue admin)
|
||||||
group: "Groupe"
|
group: "Groupe"
|
||||||
|
@ -64,7 +64,7 @@ Rails.application.routes.draw do
|
|||||||
|
|
||||||
resources :availabilities do
|
resources :availabilities do
|
||||||
get 'machines/:machine_id', action: 'machine', on: :collection
|
get 'machines/:machine_id', action: 'machine', on: :collection
|
||||||
get 'trainings', on: :collection
|
get 'trainings/:training_id', action: 'trainings', on: :collection
|
||||||
get 'reservations', on: :member
|
get 'reservations', on: :member
|
||||||
end
|
end
|
||||||
|
|
||||||
|
10
db/seeds.rb
10
db/seeds.rb
@ -131,11 +131,11 @@ end
|
|||||||
|
|
||||||
if Training.count == 0
|
if Training.count == 0
|
||||||
Training.create!([
|
Training.create!([
|
||||||
{name: "Formation Imprimante 3D"},
|
{name: "Formation Imprimante 3D", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."},
|
||||||
{name: "Formation Laser / Vinyle"},
|
{name: "Formation Laser / Vinyle", description: "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."},
|
||||||
{name: "Formation Petite fraiseuse numerique"},
|
{name: "Formation Petite fraiseuse numerique", description: "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."},
|
||||||
{name: "Formation Shopbot Grande Fraiseuse"},
|
{name: "Formation Shopbot Grande Fraiseuse", description: "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."},
|
||||||
{name: "Formation logiciel 2D"}
|
{name: "Formation logiciel 2D", description: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo."}
|
||||||
])
|
])
|
||||||
|
|
||||||
TrainingsPricing.all.each do |p|
|
TrainingsPricing.all.each do |p|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"tag": "0.14.3",
|
"tag": "0.14.3",
|
||||||
"commit": "306d1a30b4a8e8144741bb9c0126331ac884126a"
|
"commit": "306d1a30b4a8e8144741bb9c0126331ac884126a"
|
||||||
},
|
},
|
||||||
"_source": "git://github.com/angular-ui/bootstrap-bower.git",
|
"_source": "https://github.com/angular-ui/bootstrap-bower.git",
|
||||||
"_target": ">=0.13.1",
|
"_target": "~0.14.3",
|
||||||
"_originalSource": "angular-bootstrap"
|
"_originalSource": "angular-bootstrap"
|
||||||
}
|
}
|
10
vendor/assets/components/ngUpload/.bower.json
vendored
10
vendor/assets/components/ngUpload/.bower.json
vendored
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ngUpload",
|
"name": "ngUpload",
|
||||||
"version": "0.5.17",
|
"version": "0.5.18",
|
||||||
"main": "ng-upload.js",
|
"main": "ng-upload.js",
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
@ -20,13 +20,13 @@
|
|||||||
"angular": ">=1.0.4"
|
"angular": ">=1.0.4"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/twilson63/ngUpload",
|
"homepage": "https://github.com/twilson63/ngUpload",
|
||||||
"_release": "0.5.17",
|
"_release": "0.5.18",
|
||||||
"_resolution": {
|
"_resolution": {
|
||||||
"type": "version",
|
"type": "version",
|
||||||
"tag": "v0.5.17",
|
"tag": "v0.5.18",
|
||||||
"commit": "df9f3edfdbcd1ca6d3f365ff85e32de229df3af1"
|
"commit": "da7fe2bb94eb6adb2cd26ab4f6f979aa020baf9c"
|
||||||
},
|
},
|
||||||
"_source": "git://github.com/twilson63/ngUpload.git",
|
"_source": "https://github.com/twilson63/ngUpload.git",
|
||||||
"_target": ">=0.5.11",
|
"_target": ">=0.5.11",
|
||||||
"_originalSource": "ngUpload"
|
"_originalSource": "ngUpload"
|
||||||
}
|
}
|
2
vendor/assets/components/ngUpload/bower.json
vendored
2
vendor/assets/components/ngUpload/bower.json
vendored
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ngUpload",
|
"name": "ngUpload",
|
||||||
"version": "0.5.17",
|
"version": "0.5.18",
|
||||||
"main": "ng-upload.js",
|
"main": "ng-upload.js",
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
@ -146,6 +146,9 @@ angular.module('ngUpload', [])
|
|||||||
}
|
}
|
||||||
// perform check before submit file
|
// perform check before submit file
|
||||||
if (options.beforeSubmit && options.beforeSubmit(scope, {}) === false) {
|
if (options.beforeSubmit && options.beforeSubmit(scope, {}) === false) {
|
||||||
|
if(!scope.$$phase){
|
||||||
|
scope.$apply();
|
||||||
|
}
|
||||||
$event.preventDefault();
|
$event.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
angular.module("ngUpload",[]).directive("uploadSubmit",["$parse",function(){function n(t,e){t=angular.element(t);var a=t.parent();return e=e.toLowerCase(),a&&a[0].tagName.toLowerCase()===e?a:a?n(a,e):null}return{restrict:"AC",link:function(t,e){e.bind("click",function(t){if(t&&(t.preventDefault(),t.stopPropagation()),!e.attr("disabled")){var a=n(e,"form");a.triggerHandler("submit"),a[0].submit()}})}}}]).directive("ngUpload",["$log","$parse","$document",function(n,t,e){function a(n){var t,a=e.find("head");return angular.forEach(a.find("meta"),function(e){e.getAttribute("name")===n&&(t=e)}),angular.element(t)}var r=1;return{restrict:"AC",link:function(e,o,i){function l(n){e.$isUploading=n}function u(){s.unbind("load"),e.$$phase?l(!1):e.$apply(function(){l(!1)});try{var t,a=(s[0].contentDocument||s[0].contentWindow.document).body;try{t=angular.fromJson(a.innerText||a.textContent),e.$$phase?p(e,{content:t}):e.$apply(function(){p(e,{content:t})})}catch(r){t=a.innerHTML;var o="ng-upload: Response is not valid JSON";n.warn(o),f&&(e.$$phase?f(e,{error:o}):e.$apply(function(){f(e,{error:o})}))}}catch(o){n.warn("ng-upload: Server error"),f&&(e.$$phase?f(e,{error:o}):e.$apply(function(){f(e,{error:o})}))}}r++;var d={},p=i.ngUpload?t(i.ngUpload):null,f=i.errorCatcher?t(i.errorCatcher):null,c=i.ngUploadLoading?t(i.ngUploadLoading):null;i.hasOwnProperty("uploadOptionsConvertHidden")&&(d.convertHidden="false"!=i.uploadOptionsConvertHidden),i.hasOwnProperty("uploadOptionsEnableRailsCsrf")&&(d.enableRailsCsrf="false"!=i.uploadOptionsEnableRailsCsrf),i.hasOwnProperty("uploadOptionsBeforeSubmit")&&(d.beforeSubmit=t(i.uploadOptionsBeforeSubmit)),o.attr({target:"upload-iframe-"+r,method:"post",enctype:"multipart/form-data",encoding:"multipart/form-data"});var s=angular.element('<iframe name="upload-iframe-'+r+'" '+'border="0" width="0" height="0" '+'style="width:0px;height:0px;border:none;display:none">');if(d.enableRailsCsrf){var m=angular.element("<input />");m.attr("class","upload-csrf-token"),m.attr("type","hidden"),m.attr("name",a("csrf-param").attr("content")),m.val(a("csrf-token").attr("content")),o.append(m)}o.after(s),l(!1),o.bind("submit",function(n){var t=e[i.name];return t&&t.$invalid?(n.preventDefault(),!1):d.beforeSubmit&&d.beforeSubmit(e,{})===!1?(n.preventDefault(),!1):(s.bind("load",u),d.convertHidden&&angular.forEach(o.find("input"),function(n){var t=angular.element(n);t.attr("ng-model")&&t.attr("type")&&"hidden"==t.attr("type")&&t.attr("value",e.$eval(t.attr("ng-model")))}),e.$$phase?(c&&c(e),l(!0)):e.$apply(function(){c&&c(e),l(!0)}),void 0)})}}}]);
|
angular.module("ngUpload",[]).directive("uploadSubmit",["$parse",function(){function n(t,e){t=angular.element(t);var a=t.parent();return e=e.toLowerCase(),a&&a[0].tagName.toLowerCase()===e?a:a?n(a,e):null}return{restrict:"AC",link:function(t,e){e.bind("click",function(t){if(t&&(t.preventDefault(),t.stopPropagation()),!e.attr("disabled")){var a=n(e,"form");a.triggerHandler("submit"),a[0].submit()}})}}}]).directive("ngUpload",["$log","$parse","$document",function(n,t,e){function a(n){var t,a=e.find("head");return angular.forEach(a.find("meta"),function(e){e.getAttribute("name")===n&&(t=e)}),angular.element(t)}var r=1;return{restrict:"AC",link:function(e,o,i){function l(n){e.$isUploading=n}function p(){c.unbind("load"),e.$$phase?l(!1):e.$apply(function(){l(!1)});try{var t,a=(c[0].contentDocument||c[0].contentWindow.document).body;try{t=angular.fromJson(a.innerText||a.textContent),e.$$phase?d(e,{content:t}):e.$apply(function(){d(e,{content:t})})}catch(r){t=a.innerHTML;var o="ng-upload: Response is not valid JSON";n.warn(o),f&&(e.$$phase?f(e,{error:o}):e.$apply(function(){f(e,{error:o})}))}}catch(o){n.warn("ng-upload: Server error"),f&&(e.$$phase?f(e,{error:o}):e.$apply(function(){f(e,{error:o})}))}}r++;var u={},d=i.ngUpload?t(i.ngUpload):null,f=i.errorCatcher?t(i.errorCatcher):null,s=i.ngUploadLoading?t(i.ngUploadLoading):null;i.hasOwnProperty("uploadOptionsConvertHidden")&&(u.convertHidden="false"!=i.uploadOptionsConvertHidden),i.hasOwnProperty("uploadOptionsEnableRailsCsrf")&&(u.enableRailsCsrf="false"!=i.uploadOptionsEnableRailsCsrf),i.hasOwnProperty("uploadOptionsBeforeSubmit")&&(u.beforeSubmit=t(i.uploadOptionsBeforeSubmit)),o.attr({target:"upload-iframe-"+r,method:"post",enctype:"multipart/form-data",encoding:"multipart/form-data"});var c=angular.element('<iframe name="upload-iframe-'+r+'" '+'border="0" width="0" height="0" '+'style="width:0px;height:0px;border:none;display:none">');if(u.enableRailsCsrf){var m=angular.element("<input />");m.attr("class","upload-csrf-token"),m.attr("type","hidden"),m.attr("name",a("csrf-param").attr("content")),m.val(a("csrf-token").attr("content")),o.append(m)}o.after(c),l(!1),o.bind("submit",function(n){var t=e[i.name];return t&&t.$invalid?(n.preventDefault(),!1):u.beforeSubmit&&u.beforeSubmit(e,{})===!1?(e.$$phase||e.$apply(),n.preventDefault(),!1):(c.bind("load",p),u.convertHidden&&angular.forEach(o.find("input"),function(n){var t=angular.element(n);t.attr("ng-model")&&t.attr("type")&&"hidden"==t.attr("type")&&t.attr("value",e.$eval(t.attr("ng-model")))}),e.$$phase?(s&&s(e),l(!0)):e.$apply(function(){s&&s(e),l(!0)}),void 0)})}}}]);
|
2
vendor/assets/components/ngUpload/readme.md
vendored
2
vendor/assets/components/ngUpload/readme.md
vendored
@ -133,7 +133,7 @@ angular.module('app', ['ngUpload'])
|
|||||||
|
|
||||||
* Working in IE
|
* Working in IE
|
||||||
|
|
||||||
In order, for ngUpload to respond correctly for IE, your server needs to return the response back as `html/text` not `application/json`
|
In order, for ngUpload to respond correctly for IE, your server needs to return the response back as `text/html` not `application/json`
|
||||||
|
|
||||||
|
|
||||||
## Directive Options
|
## Directive Options
|
||||||
|
Loading…
x
Reference in New Issue
Block a user