1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-30 19:52:20 +01:00

Merge branch 'erb' into es6

This commit is contained in:
Sylvain 2018-11-19 16:20:46 +01:00
commit 185ea30db3
21 changed files with 2037 additions and 2046 deletions

View File

@ -15,27 +15,27 @@
/* COMMON CODE */ /* COMMON CODE */
// # list of supported authentication methods // list of supported authentication methods
const METHODS = { const METHODS = {
'DatabaseProvider': 'local_database', 'DatabaseProvider': 'local_database',
'OAuth2Provider': 'o_auth2' 'OAuth2Provider': 'o_auth2'
} }
// # /**
// Iterate through the provided array and return the index of the requested element * Iterate through the provided array and return the index of the requested element
// @param elements {Array<{id:*}>} * @param elements {Array<{id:*}>}
// @param id {*} id of the element to retrieve in the list * @param id {*} id of the element to retrieve in the list
// @returns {number} index of the requested element, in the provided array * @returns {number} index of the requested element, in the provided array
// # */
const findIdxById = (elements, id) => const findIdxById = (elements, id) =>
(elements.map(elem => elem.id)).indexOf(id) (elements.map(elem => elem.id)).indexOf(id)
// # /**
// For OAuth2 ententications, mapping the user's ID is mendatory. This function will check that this mapping * For OAuth2 ententications, mapping the user's ID is mendatory. This function will check that this mapping
// is effective and will return false otherwise * is effective and will return false otherwise
// @param mappings {Array<Object>} expected: $scope.provider.providable_attributes.o_auth2_mappings_attributes * @param mappings {Array<Object>} expected: $scope.provider.providable_attributes.o_auth2_mappings_attributes
// @returns {Boolean} true if the mapping is declared * @returns {Boolean} true if the mapping is declared
// # */
const check_oauth2_id_is_mapped = function (mappings) { const check_oauth2_id_is_mapped = function (mappings) {
for (let mapping of Array.from(mappings)) { for (let mapping of Array.from(mappings)) {
if ((mapping.local_model === 'user') && (mapping.local_field === 'uid') && !mapping._destroy) { if ((mapping.local_model === 'user') && (mapping.local_field === 'uid') && !mapping._destroy) {
@ -45,36 +45,36 @@ const check_oauth2_id_is_mapped = function (mappings) {
return false return false
} }
// # /**
// Provides a set of common callback methods and data to the $scope parameter. These methods are used * Provides a set of common callback methods and data to the $scope parameter. These methods are used
// in the various authentication providers' controllers. * in the various authentication providers' controllers.
// *
// Provides : * Provides :
// - $scope.authMethods * - $scope.authMethods
// - $scope.mappingFields * - $scope.mappingFields
// - $scope.cancel() * - $scope.cancel()
// - $scope.defineDataMapping(mapping) * - $scope.defineDataMapping(mapping)
// *
// Requires : * Requires :
// - mappingFieldsPromise: retrieved by AuthProvider.mapping_fields() * - mappingFieldsPromise: retrieved by AuthProvider.mapping_fields()
// - $state (Ui-Router) [ 'app.admin.members' ] * - $state (Ui-Router) [ 'app.admin.members' ]
// # */
class AuthenticationController { class AuthenticationController {
constructor ($scope, $state, $uibModal, mappingFieldsPromise) { constructor ($scope, $state, $uibModal, mappingFieldsPromise) {
// # list of supported authentication methods // list of supported authentication methods
$scope.authMethods = METHODS $scope.authMethods = METHODS
// # list of fields that can be mapped through the SSO // list of fields that can be mapped through the SSO
$scope.mappingFields = mappingFieldsPromise $scope.mappingFields = mappingFieldsPromise
// # /**
// Changes the admin's view to the members list page * Changes the admin's view to the members list page
// # */
$scope.cancel = () => $state.go('app.admin.members') $scope.cancel = () => $state.go('app.admin.members')
// # /**
// Open a modal allowing to specify the data mapping for the given field * Open a modal allowing to specify the data mapping for the given field
// # */
$scope.defineDataMapping = mapping => $scope.defineDataMapping = mapping =>
$uibModal.open({ $uibModal.open({
templateUrl: '<%= asset_path "admin/authentications/_data_mapping.html" %>', templateUrl: '<%= asset_path "admin/authentications/_data_mapping.html" %>',
@ -91,14 +91,14 @@ class AuthenticationController {
}, },
controller: ['$scope', '$uibModalInstance', 'field', 'datatype', function ($scope, $uibModalInstance, field, datatype) { controller: ['$scope', '$uibModalInstance', 'field', 'datatype', function ($scope, $uibModalInstance, field, datatype) {
// # parent field // parent field
$scope.field = field $scope.field = field
// # expected data type // expected data type
$scope.datatype = datatype $scope.datatype = datatype
// # data transformation rules // data transformation rules
$scope.transformation = $scope.transformation =
{ rules: field.transformation || { type: datatype } } { rules: field.transformation || { type: datatype } }
// # available transformation formats // available transformation formats
$scope.formats = { $scope.formats = {
date: [ date: [
{ {
@ -124,7 +124,7 @@ class AuthenticationController {
] ]
} }
// # Create a new mapping between anything and an expected integer // Create a new mapping between anything and an expected integer
$scope.addIntegerMapping = function () { $scope.addIntegerMapping = function () {
if (!angular.isArray($scope.transformation.rules.mapping)) { if (!angular.isArray($scope.transformation.rules.mapping)) {
$scope.transformation.rules.mapping = [] $scope.transformation.rules.mapping = []
@ -132,10 +132,10 @@ class AuthenticationController {
return $scope.transformation.rules.mapping.push({ from: '', to: 0 }) return $scope.transformation.rules.mapping.push({ from: '', to: 0 })
} }
// # close and save the modifications // close and save the modifications
$scope.ok = () => $uibModalInstance.close($scope.transformation.rules) $scope.ok = () => $uibModalInstance.close($scope.transformation.rules)
// # do not save the modifications // do not save the modifications
return $scope.cancel = () => $uibModalInstance.dismiss() return $scope.cancel = () => $uibModalInstance.dismiss()
} }
] }) ] })
@ -143,21 +143,21 @@ class AuthenticationController {
} }
} }
// # /**
// Page listing all authentication providers * Page listing all authentication providers
// # */
Application.Controllers.controller('AuthentificationController', ['$scope', '$state', '$rootScope', 'dialogs', 'growl', 'authProvidersPromise', 'AuthProvider', '_t', Application.Controllers.controller('AuthentificationController', ['$scope', '$state', '$rootScope', 'dialogs', 'growl', 'authProvidersPromise', 'AuthProvider', '_t',
function ($scope, $state, $rootScope, dialogs, growl, authProvidersPromise, AuthProvider, _t) { function ($scope, $state, $rootScope, dialogs, growl, authProvidersPromise, AuthProvider, _t) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # full list of authentication providers // full list of authentication providers
$scope.providers = authProvidersPromise $scope.providers = authProvidersPromise
// # /**
// Translate the classname into an explicit textual message * Translate the classname into an explicit textual message
// @param type {string} Ruby polymorphic model classname * @param type {string} Ruby polymorphic model classname
// @returns {string} * @returns {string}
// # */
$scope.getType = function (type) { $scope.getType = function (type) {
const text = METHODS[type] const text = METHODS[type]
if (typeof text !== 'undefined') { if (typeof text !== 'undefined') {
@ -167,11 +167,11 @@ Application.Controllers.controller('AuthentificationController', ['$scope', '$st
} }
} }
// # /**
// Translate the status string into an explicit textual message * Translate the status string into an explicit textual message
// @param status {string} active | pending | previous * @param status {string} active | pending | previous
// @returns {string} * @returns {string}
// # */
$scope.getState = function (status) { $scope.getState = function (status) {
switch (status) { switch (status) {
case 'active': return _t('active') case 'active': return _t('active')
@ -181,11 +181,11 @@ Application.Controllers.controller('AuthentificationController', ['$scope', '$st
} }
} }
// # /**
// Ask for confirmation then delete the specified provider * Ask for confirmation then delete the specified provider
// @param providers {Array} full list of authentication providers * @param providers {Array} full list of authentication providers
// @param provider {Object} provider to delete * @param provider {Object} provider to delete
// # */
return $scope.destroyProvider = (providers, provider) => return $scope.destroyProvider = (providers, provider) =>
dialogs.confirm({ dialogs.confirm({
resolve: { resolve: {
@ -210,23 +210,23 @@ Application.Controllers.controller('AuthentificationController', ['$scope', '$st
]) ])
// # /**
// Page to add a new authentication provider * Page to add a new authentication provider
// # */
Application.Controllers.controller('NewAuthenticationController', ['$scope', '$state', '$rootScope', '$uibModal', 'dialogs', 'growl', 'mappingFieldsPromise', 'authProvidersPromise', 'AuthProvider', '_t', Application.Controllers.controller('NewAuthenticationController', ['$scope', '$state', '$rootScope', '$uibModal', 'dialogs', 'growl', 'mappingFieldsPromise', 'authProvidersPromise', 'AuthProvider', '_t',
function ($scope, $state, $rootScope, $uibModal, dialogs, growl, mappingFieldsPromise, authProvidersPromise, AuthProvider, _t) { function ($scope, $state, $rootScope, $uibModal, dialogs, growl, mappingFieldsPromise, authProvidersPromise, AuthProvider, _t) {
$scope.mode = 'creation' $scope.mode = 'creation'
// # default parameters for the new authentication provider // default parameters for the new authentication provider
$scope.provider = { $scope.provider = {
name: '', name: '',
providable_type: '', providable_type: '',
providable_attributes: {} providable_attributes: {}
} }
// # /**
// Initialize some provider's specific properties when selecting the provider type * Initialize some provider's specific properties when selecting the provider type
// # */
$scope.updateProvidable = function () { $scope.updateProvidable = function () {
// === OAuth2Provider === // === OAuth2Provider ===
if ($scope.provider.providable_type === 'OAuth2Provider') { if ($scope.provider.providable_type === 'OAuth2Provider') {
@ -237,9 +237,9 @@ Application.Controllers.controller('NewAuthenticationController', ['$scope', '$s
} }
// Add others providers initializers here if needed ... // Add others providers initializers here if needed ...
// # /**
// Validate and save the provider parameters in database * Validate and save the provider parameters in database
// # */
$scope.registerProvider = function () { $scope.registerProvider = function () {
// === DatabaseProvider === // === DatabaseProvider ===
let provider let provider
@ -292,24 +292,24 @@ Application.Controllers.controller('NewAuthenticationController', ['$scope', '$s
} }
} }
// # Using the AuthenticationController // Using the AuthenticationController
return new AuthenticationController($scope, $state, $uibModal, mappingFieldsPromise) return new AuthenticationController($scope, $state, $uibModal, mappingFieldsPromise)
} }
]) ])
// # /**
// Page to edit an already added authentication provider * Page to edit an already added authentication provider
// # */
Application.Controllers.controller('EditAuthenticationController', ['$scope', '$state', '$stateParams', '$rootScope', '$uibModal', 'dialogs', 'growl', 'providerPromise', 'mappingFieldsPromise', 'AuthProvider', '_t', Application.Controllers.controller('EditAuthenticationController', ['$scope', '$state', '$stateParams', '$rootScope', '$uibModal', 'dialogs', 'growl', 'providerPromise', 'mappingFieldsPromise', 'AuthProvider', '_t',
function ($scope, $state, $stateParams, $rootScope, $uibModal, dialogs, growl, providerPromise, mappingFieldsPromise, AuthProvider, _t) { function ($scope, $state, $stateParams, $rootScope, $uibModal, dialogs, growl, providerPromise, mappingFieldsPromise, AuthProvider, _t) {
// # parameters of the currently edited authentication provider // parameters of the currently edited authentication provider
$scope.provider = providerPromise $scope.provider = providerPromise
$scope.mode = 'edition' $scope.mode = 'edition'
// # /**
// Update the current provider with the new inputs * Update the current provider with the new inputs
// # */
$scope.updateProvider = function () { $scope.updateProvider = function () {
// check the ID mapping // check the ID mapping
if (!check_oauth2_id_is_mapped($scope.provider.providable_attributes.o_auth2_mappings_attributes)) { if (!check_oauth2_id_is_mapped($scope.provider.providable_attributes.o_auth2_mappings_attributes)) {
@ -323,7 +323,7 @@ Application.Controllers.controller('EditAuthenticationController', ['$scope', '$
, () => growl.error(_t('an_error_occurred_unable_to_update_the_provider'))) , () => growl.error(_t('an_error_occurred_unable_to_update_the_provider')))
} }
// # Using the AuthenticationController // Using the AuthenticationController
return new AuthenticationController($scope, $state, $uibModal, mappingFieldsPromise) return new AuthenticationController($scope, $state, $uibModal, mappingFieldsPromise)
} }
]) ])

View File

@ -14,9 +14,9 @@
*/ */
'use strict' 'use strict'
// # /**
// Controller used in the calendar management page * Controller used in the calendar management page
// # */
Application.Controllers.controller('AdminCalendarController', ['$scope', '$state', '$uibModal', 'moment', 'Availability', 'Slot', 'Setting', 'Export', 'growl', 'dialogs', 'bookingWindowStart', 'bookingWindowEnd', 'machinesPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', Application.Controllers.controller('AdminCalendarController', ['$scope', '$state', '$uibModal', 'moment', 'Availability', 'Slot', 'Setting', 'Export', 'growl', 'dialogs', 'bookingWindowStart', 'bookingWindowEnd', 'machinesPromise', '_t', 'uiCalendarConfig', 'CalendarConfig',
function ($scope, $state, $uibModal, moment, Availability, Slot, Setting, Export, growl, dialogs, bookingWindowStart, bookingWindowEnd, machinesPromise, _t, uiCalendarConfig, CalendarConfig) { function ($scope, $state, $uibModal, moment, Availability, Slot, Setting, Export, growl, dialogs, bookingWindowStart, bookingWindowEnd, machinesPromise, _t, uiCalendarConfig, CalendarConfig) {
@ -34,20 +34,20 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # list of the FabLab machines // list of the FabLab machines
$scope.machines = machinesPromise $scope.machines = machinesPromise
// # currently selected availability // currently selected availability
$scope.availability = null $scope.availability = null
// # bind the availabilities slots with full-Calendar events // bind the availabilities slots with full-Calendar events
$scope.eventSources = [] $scope.eventSources = []
$scope.eventSources.push({ $scope.eventSources.push({
url: '/api/availabilities', url: '/api/availabilities',
textColor: 'black' textColor: 'black'
}) })
// # fullCalendar (v2) configuration // fullCalendar (v2) configuration
$scope.calendarConfig = CalendarConfig({ $scope.calendarConfig = CalendarConfig({
slotDuration: BASE_SLOT, slotDuration: BASE_SLOT,
snapDuration: BOOKING_SNAP, snapDuration: BOOKING_SNAP,
@ -69,10 +69,10 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
} }
}) })
// # /**
// Open a confirmation modal to cancel the booking of a user for the currently selected event. * Open a confirmation modal to cancel the booking of a user for the currently selected event.
// @param slot {Object} reservation slot of a user, inherited from $resource * @param slot {Object} reservation slot of a user, inherited from $resource
// # */
$scope.cancelBooking = slot => $scope.cancelBooking = slot =>
// open a confirmation dialog // open a confirmation dialog
dialogs.confirm({ dialogs.confirm({
@ -106,11 +106,11 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
) )
) )
// # /**
// Open a confirmation modal to remove a machine for the currently selected availability, * Open a confirmation modal to remove a machine for the currently selected availability,
// except if it is the last machine of the reservation. * except if it is the last machine of the reservation.
// @param machine {Object} must contain the machine ID and name * @param machine {Object} must contain the machine ID and name
// # */
$scope.removeMachine = function (machine) { $scope.removeMachine = function (machine) {
if ($scope.availability.machine_ids.length === 1) { if ($scope.availability.machine_ids.length === 1) {
return growl.error(_t('admin_calendar.unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather')) return growl.error(_t('admin_calendar.unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather'))
@ -154,10 +154,10 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
} }
} }
// # /**
// Callback to alert the admin that the export request was acknowledged and is * Callback to alert the admin that the export request was acknowledged and is
// processing right now. * processing right now.
// # */
$scope.alertExport = type => $scope.alertExport = type =>
Export.status({ category: 'availabilities', type }).then(function (res) { Export.status({ category: 'availabilities', type }).then(function (res) {
if (!res.data.exists) { if (!res.data.exists) {
@ -165,9 +165,9 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
} }
}) })
// # /**
// Mark the selected slot as unavailable for new reservations or allow reservations again on it * Mark the selected slot as unavailable for new reservations or allow reservations again on it
// # */
$scope.toggleLockReservations = function () { $scope.toggleLockReservations = function () {
// first, define a shortcut to the lock property // first, define a shortcut to the lock property
const locked = $scope.availability.lock const locked = $scope.availability.lock
@ -210,9 +210,9 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
} }
} }
// # /**
// Confirm and destroy the slot in $scope.availability * Confirm and destroy the slot in $scope.availability
// # */
$scope.removeSlot = () => $scope.removeSlot = () =>
// open a confirmation dialog // open a confirmation dialog
dialogs.confirm({ dialogs.confirm({
@ -238,11 +238,11 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Return an enumerable meaninful string for the gender of the provider user * Return an enumerable meaninful string for the gender of the provider user
// @param user {Object} Database user record * @param user {Object} Database user record
// @return {string} 'male' or 'female' * @return {string} 'male' or 'female'
// # */
var getGender = function (user) { var getGender = function (user) {
if (user.profile) { if (user.profile) {
if (user.profile.gender === 'true') { return 'male' } else { return 'female' } if (user.profile.gender === 'true') { return 'male' } else { return 'female' }
@ -251,7 +251,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
// Triggered when the admin drag on the agenda to create a new reservable slot. // Triggered when the admin drag on the agenda to create a new reservable slot.
// @see http://fullcalendar.io/docs/selection/select_callback/ // @see http://fullcalendar.io/docs/selection/select_callback/
// # //
var calendarSelectCb = function (start, end, jsEvent, view) { var calendarSelectCb = function (start, end, jsEvent, view) {
start = moment.tz(start.toISOString(), Fablab.timezone) start = moment.tz(start.toISOString(), Fablab.timezone)
end = moment.tz(end.toISOString(), Fablab.timezone) end = moment.tz(end.toISOString(), Fablab.timezone)
@ -296,10 +296,10 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
return uiCalendarConfig.calendars.calendar.fullCalendar('unselect') return uiCalendarConfig.calendars.calendar.fullCalendar('unselect')
} }
// # /**
// Triggered when the admin clicks on a availability slot in the agenda. * Triggered when the admin clicks on a availability slot in the agenda.
// @see http://fullcalendar.io/docs/mouse/eventClick/ * @see http://fullcalendar.io/docs/mouse/eventClick/
// # */
var calendarEventClickCb = function (event, jsEvent, view) { var calendarEventClickCb = function (event, jsEvent, view) {
$scope.availability = event $scope.availability = event
@ -312,11 +312,11 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
} }
} }
// # /**
// Triggered when fullCalendar tries to graphicaly render an event block. * Triggered when fullCalendar tries to graphicaly render an event block.
// Append the event tag into the block, just after the event title. * Append the event tag into the block, just after the event title.
// @see http://fullcalendar.io/docs/event_rendering/eventRender/ * @see http://fullcalendar.io/docs/event_rendering/eventRender/
// # */
var eventRenderCb = function (event, element) { var eventRenderCb = function (event, element) {
element.find('.fc-content').prepend('<span class="remove-event">x&nbsp;</span>') element.find('.fc-content').prepend('<span class="remove-event">x&nbsp;</span>')
if (event.tags.length > 0) { if (event.tags.length > 0) {
@ -329,10 +329,10 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
// force return to prevent coffee-script auto-return to return random value (possiblity falsy) // force return to prevent coffee-script auto-return to return random value (possiblity falsy)
} }
// # /**
// Triggered when resource fetching starts/stops. * Triggered when resource fetching starts/stops.
// @see https://fullcalendar.io/docs/resource_data/loading/ * @see https://fullcalendar.io/docs/resource_data/loading/
// # */
return loadingCb = function (isLoading, view) { return loadingCb = function (isLoading, view) {
if (isLoading) { if (isLoading) {
// we remove existing events when fetching starts to prevent duplicates // we remove existing events when fetching starts to prevent duplicates
@ -343,42 +343,42 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
]) ])
// # /**
// Controller used in the slot creation modal window * Controller used in the slot creation modal window
// # */
Application.Controllers.controller('CreateEventModalController', ['$scope', '$uibModalInstance', 'moment', 'start', 'end', 'machinesPromise', 'Availability', 'trainingsPromise', 'spacesPromise', 'Tag', 'growl', '_t', Application.Controllers.controller('CreateEventModalController', ['$scope', '$uibModalInstance', 'moment', 'start', 'end', 'machinesPromise', 'Availability', 'trainingsPromise', 'spacesPromise', 'Tag', 'growl', '_t',
function ($scope, $uibModalInstance, moment, start, end, machinesPromise, Availability, trainingsPromise, spacesPromise, Tag, growl, _t) { function ($scope, $uibModalInstance, moment, start, end, machinesPromise, Availability, trainingsPromise, spacesPromise, Tag, growl, _t) {
// # $uibModal parameter // $uibModal parameter
$scope.start = start $scope.start = start
// # $uibModal parameter // $uibModal parameter
$scope.end = end $scope.end = end
// # machines list // machines list
$scope.machines = machinesPromise.filter(m => !m.disabled) $scope.machines = machinesPromise.filter(m => !m.disabled)
// # trainings list // trainings list
$scope.trainings = trainingsPromise.filter(t => !t.disabled) $scope.trainings = trainingsPromise.filter(t => !t.disabled)
// # spaces list // spaces list
$scope.spaces = spacesPromise.filter(s => !s.disabled) $scope.spaces = spacesPromise.filter(s => !s.disabled)
// # machines associated with the created slot // machines associated with the created slot
$scope.selectedMachines = [] $scope.selectedMachines = []
// # training associated with the created slot // training associated with the created slot
$scope.selectedTraining = null $scope.selectedTraining = null
// # space associated with the created slot // space associated with the created slot
$scope.selectedSpace = null $scope.selectedSpace = null
// # UI step // UI step
$scope.step = 1 $scope.step = 1
// # the user is not able to edit the ending time of the availability, unless he set the type to 'training' // the user is not able to edit the ending time of the availability, unless he set the type to 'training'
$scope.endDateReadOnly = true $scope.endDateReadOnly = true
// # timepickers configuration // timepickers configuration
$scope.timepickers = { $scope.timepickers = {
start: { start: {
hstep: 1, hstep: 1,
@ -390,17 +390,17 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
} }
} }
// # slot details // slot details
$scope.availability = { $scope.availability = {
start_at: start, start_at: start,
end_at: end, end_at: end,
available_type: 'machines' // default available_type: 'machines' // default
} }
// # /**
// Adds or removes the provided machine from the current slot * Adds or removes the provided machine from the current slot
// @param machine {Object} * @param machine {Object}
// # */
$scope.toggleSelection = function (machine) { $scope.toggleSelection = function (machine) {
const index = $scope.selectedMachines.indexOf(machine) const index = $scope.selectedMachines.indexOf(machine)
if (index > -1) { if (index > -1) {
@ -410,9 +410,9 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
} }
} }
// # /**
// Callback for the modal window validation: save the slot and closes the modal * Callback for the modal window validation: save the slot and closes the modal
// # */
$scope.ok = function () { $scope.ok = function () {
if ($scope.availability.available_type === 'machines') { if ($scope.availability.available_type === 'machines') {
if ($scope.selectedMachines.length > 0) { if ($scope.selectedMachines.length > 0) {
@ -431,27 +431,27 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
, availability => $uibModalInstance.close(availability)) , availability => $uibModalInstance.close(availability))
} }
// # /**
// Move the modal UI to the next step * Move the modal UI to the next step
// # */
$scope.next = function () { $scope.next = function () {
if ($scope.step === 1) { $scope.setNbTotalPlaces() } if ($scope.step === 1) { $scope.setNbTotalPlaces() }
return $scope.step++ return $scope.step++
} }
// # /**
// Move the modal UI to the next step * Move the modal UI to the next step
// # */
$scope.previous = () => $scope.step-- $scope.previous = () => $scope.step--
// # /**
// Callback to cancel the slot creation * Callback to cancel the slot creation
// # */
$scope.cancel = () => $uibModalInstance.dismiss('cancel') $scope.cancel = () => $uibModalInstance.dismiss('cancel')
// # /**
// For training avaiabilities, set the maximum number of people allowed to register on this slot * For training avaiabilities, set the maximum number of people allowed to register on this slot
// # */
$scope.setNbTotalPlaces = function () { $scope.setNbTotalPlaces = function () {
if ($scope.availability.available_type === 'training') { if ($scope.availability.available_type === 'training') {
return $scope.availability.nb_total_places = $scope.selectedTraining.nb_total_places return $scope.availability.nb_total_places = $scope.selectedTraining.nb_total_places
@ -462,9 +462,9 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
if ($scope.trainings.length > 0) { if ($scope.trainings.length > 0) {
$scope.selectedTraining = $scope.trainings[0] $scope.selectedTraining = $scope.trainings[0]
@ -475,9 +475,9 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
Tag.query().$promise.then(data => $scope.tags = data) Tag.query().$promise.then(data => $scope.tags = data)
// # When we configure a machine availability, do not let the user change the end time, as the total // When we configure a machine availability, do not let the user change the end time, as the total
// # time must be dividable by 60 minutes (base slot duration). For training availabilities, the user // time must be dividable by 60 minutes (base slot duration). For training availabilities, the user
// # can configure any duration as it does not matters. // can configure any duration as it does not matters.
$scope.$watch('availability.available_type', function (newValue, oldValue, scope) { $scope.$watch('availability.available_type', function (newValue, oldValue, scope) {
if ((newValue === 'machines') || (newValue === 'space')) { if ((newValue === 'machines') || (newValue === 'space')) {
$scope.endDateReadOnly = true $scope.endDateReadOnly = true
@ -489,8 +489,8 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
} }
}) })
// # When the start date is changed, if we are configuring a machine availability, // When the start date is changed, if we are configuring a machine availability,
// # maintain the relative length of the slot (ie. change the end time accordingly) // maintain the relative length of the slot (ie. change the end time accordingly)
$scope.$watch('start', function (newValue, oldValue, scope) { $scope.$watch('start', function (newValue, oldValue, scope) {
// for machine or space availabilities, adjust the end time // for machine or space availabilities, adjust the end time
if (($scope.availability.available_type === 'machines') || ($scope.availability.available_type === 'space')) { if (($scope.availability.available_type === 'machines') || ($scope.availability.available_type === 'space')) {
@ -507,9 +507,9 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
return $scope.availability.start_at = $scope.start return $scope.availability.start_at = $scope.start
}) })
// # Maintain consistency between the end time and the date object in the availability object // Maintain consistency between the end time and the date object in the availability object
return $scope.$watch('end', function (newValue, oldValue, scope) { return $scope.$watch('end', function (newValue, oldValue, scope) {
// # we prevent the admin from setting the end of the availability before its begining // we prevent the admin from setting the end of the availability before its begining
if (moment($scope.start).add(1, 'hour').isAfter(newValue)) { if (moment($scope.start).add(1, 'hour').isAfter(newValue)) {
$scope.end = oldValue $scope.end = oldValue
} }
@ -518,7 +518,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
}) })
} }
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])

View File

@ -15,30 +15,30 @@
/* COMMON CODE */ /* COMMON CODE */
// # /**
// Provides a set of common properties and methods to the $scope parameter. They are used * Provides a set of common properties and methods to the $scope parameter. They are used
// in the various events' admin controllers. * in the various events' admin controllers.
// *
// Provides : * Provides :
// - $scope.datePicker = {} * - $scope.datePicker = {}
// - $scope.submited(content) * - $scope.submited(content)
// - $scope.cancel() * - $scope.cancel()
// - $scope.addFile() * - $scope.addFile()
// - $scope.deleteFile(file) * - $scope.deleteFile(file)
// - $scope.fileinputClass(v) * - $scope.fileinputClass(v)
// - $scope.toggleStartDatePicker($event) * - $scope.toggleStartDatePicker($event)
// - $scope.toggleEndDatePicker($event) * - $scope.toggleEndDatePicker($event)
// - $scope.toggleRecurrenceEnd(e) * - $scope.toggleRecurrenceEnd(e)
// - $scope.addPrice() * - $scope.addPrice()
// - $scope.removePrice(price, $event) * - $scope.removePrice(price, $event)
// *
// Requires : * Requires :
// - $scope.event.event_files_attributes = [] * - $scope.event.event_files_attributes = []
// - $state (Ui-Router) [ 'app.public.events_list' ] * - $state (Ui-Router) [ 'app.public.events_list' ]
// # */
class EventsController { class EventsController {
constructor ($scope, $state) { constructor ($scope, $state) {
// # default parameters for AngularUI-Bootstrap datepicker // default parameters for AngularUI-Bootstrap datepicker
$scope.datePicker = { $scope.datePicker = {
format: Fablab.uibDateFormat, format: Fablab.uibDateFormat,
startOpened: false, // default: datePicker is not shown startOpened: false, // default: datePicker is not shown
@ -49,12 +49,12 @@ class EventsController {
} }
} }
// # /**
// For use with ngUpload (https://github.com/twilson63/ngUpload). * For use with ngUpload (https://github.com/twilson63/ngUpload).
// Intended to be the callback when an upload is done: any raised error will be stacked in the * Intended to be the callback when an upload is done: any raised error will be stacked in the
// $scope.alerts array. If everything goes fine, the user is redirected to the project page. * $scope.alerts array. If everything goes fine, the user is redirected to the project page.
// @param content {Object} JSON - The upload's result * @param content {Object} JSON - The upload's result
// # */
$scope.submited = function (content) { $scope.submited = function (content) {
if ((content.id == null)) { if ((content.id == null)) {
$scope.alerts = [] $scope.alerts = []
@ -66,16 +66,16 @@ class EventsController {
} }
} }
// # /**
// Changes the user's view to the events list page * Changes the user's view to the events list page
// # */
$scope.cancel = () => $state.go('app.public.events_list') $scope.cancel = () => $state.go('app.public.events_list')
// # /**
// For use with 'ng-class', returns the CSS class name for the uploads previews. * 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. * 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) * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)
// # */
$scope.fileinputClass = function (v) { $scope.fileinputClass = function (v) {
if (v) { if (v) {
return 'fileinput-exists' return 'fileinput-exists'
@ -84,17 +84,17 @@ class EventsController {
} }
} }
// # /**
// This will create a single new empty entry into the event's attachements list. * This will create a single new empty entry into the event's attachements list.
// # */
$scope.addFile = () => $scope.event.event_files_attributes.push({}) $scope.addFile = () => $scope.event.event_files_attributes.push({})
// # /**
// This will remove the given file from the event's attachements list. If the file was previously uploaded * This will remove the given file from the event's attachements list. If the file was previously uploaded
// to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from * to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from
// the attachements array. * the attachements array.
// @param file {Object} the file to delete * @param file {Object} the file to delete
// # */
$scope.deleteFile = function (file) { $scope.deleteFile = function (file) {
const index = $scope.event.event_files_attributes.indexOf(file) const index = $scope.event.event_files_attributes.indexOf(file)
if (file.id != null) { if (file.id != null) {
@ -104,45 +104,45 @@ class EventsController {
} }
} }
// # /**
// Show/Hide the "start" datepicker (open the drop down/close it) * Show/Hide the "start" datepicker (open the drop down/close it)
// # */
$scope.toggleStartDatePicker = function ($event) { $scope.toggleStartDatePicker = function ($event) {
$event.preventDefault() $event.preventDefault()
$event.stopPropagation() $event.stopPropagation()
return $scope.datePicker.startOpened = !$scope.datePicker.startOpened return $scope.datePicker.startOpened = !$scope.datePicker.startOpened
} }
// # /**
// Show/Hide the "end" datepicker (open the drop down/close it) * Show/Hide the "end" datepicker (open the drop down/close it)
// # */
$scope.toggleEndDatePicker = function ($event) { $scope.toggleEndDatePicker = function ($event) {
$event.preventDefault() $event.preventDefault()
$event.stopPropagation() $event.stopPropagation()
return $scope.datePicker.endOpened = !$scope.datePicker.endOpened return $scope.datePicker.endOpened = !$scope.datePicker.endOpened
} }
// # /**
// Masks/displays the recurrence pane allowing the admin to set the current event as recursive * Masks/displays the recurrence pane allowing the admin to set the current event as recursive
// # */
$scope.toggleRecurrenceEnd = function (e) { $scope.toggleRecurrenceEnd = function (e) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
return $scope.datePicker.recurrenceEndOpened = !$scope.datePicker.recurrenceEndOpened return $scope.datePicker.recurrenceEndOpened = !$scope.datePicker.recurrenceEndOpened
} }
// # /**
// Initialize a new price item in the additional prices list * Initialize a new price item in the additional prices list
// # */
$scope.addPrice = () => $scope.addPrice = () =>
$scope.event.prices.push({ $scope.event.prices.push({
category: null, category: null,
amount: null amount: null
}) })
// # /**
// Remove the price or mark it as 'to delete' * Remove the price or mark it as 'to delete'
// # */
$scope.removePrice = function (price, event) { $scope.removePrice = function (price, event) {
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
@ -156,48 +156,48 @@ class EventsController {
} }
} }
// # /**
// Controller used in the events listing page (admin view) * Controller used in the events listing page (admin view)
// # */
Application.Controllers.controller('AdminEventsController', ['$scope', '$state', 'dialogs', '$uibModal', 'growl', 'Event', 'Category', 'EventTheme', 'AgeRange', 'PriceCategory', 'eventsPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '_t', Application.Controllers.controller('AdminEventsController', ['$scope', '$state', 'dialogs', '$uibModal', 'growl', 'Event', 'Category', 'EventTheme', 'AgeRange', 'PriceCategory', 'eventsPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '_t',
function ($scope, $state, dialogs, $uibModal, growl, Event, Category, EventTheme, AgeRange, PriceCategory, eventsPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, _t) { function ($scope, $state, dialogs, $uibModal, growl, Event, Category, EventTheme, AgeRange, PriceCategory, eventsPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, _t) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # By default, the pagination mode is activated to limit the page size // By default, the pagination mode is activated to limit the page size
$scope.paginateActive = true $scope.paginateActive = true
// # The events displayed on the page // The events displayed on the page
$scope.events = eventsPromise $scope.events = eventsPromise
// # Current virtual page // Current virtual page
$scope.page = 1 $scope.page = 1
// # Temporary datastore for creating new elements // Temporary datastore for creating new elements
$scope.inserted = { $scope.inserted = {
category: null, category: null,
theme: null, theme: null,
age_range: null age_range: null
} }
// # List of categories for the events // List of categories for the events
$scope.categories = categoriesPromise $scope.categories = categoriesPromise
// # List of events themes // List of events themes
$scope.themes = themesPromise $scope.themes = themesPromise
// # List of age ranges // List of age ranges
$scope.ageRanges = ageRangesPromise $scope.ageRanges = ageRangesPromise
// # List of price categories for the events // List of price categories for the events
$scope.priceCategories = priceCategoriesPromise $scope.priceCategories = priceCategoriesPromise
// # Default: we display all events (no restriction) // Default: we display all events (no restriction)
$scope.eventsScope = $scope.eventsScope =
{ selected: '' } { selected: '' }
// # /**
// Adds a bucket of events to the bottom of the page, grouped by month * Adds a bucket of events to the bottom of the page, grouped by month
// # */
$scope.loadMoreEvents = function () { $scope.loadMoreEvents = function () {
$scope.page += 1 $scope.page += 1
return Event.query({ page: $scope.page, scope: $scope.eventsScope.selected }, function (data) { return Event.query({ page: $scope.page, scope: $scope.eventsScope.selected }, function (data) {
@ -206,12 +206,12 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
}) })
} }
// # /**
// Saves a new element / Update an existing one to the server (form validation callback) * Saves a new element / Update an existing one to the server (form validation callback)
// @param model {string} model name * @param model {string} model name
// @param data {Object} element name * @param data {Object} element name
// @param [id] {number} element id, in case of update * @param [id] {number} element id, in case of update
// # */
$scope.saveElement = function (model, data, id) { $scope.saveElement = function (model, data, id) {
if (id != null) { if (id != null) {
return getModel(model)[0].update({ id }, data) return getModel(model)[0].update({ id }, data)
@ -220,11 +220,11 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
} }
} }
// # /**
// Deletes the element at the specified index * Deletes the element at the specified index
// @param model {string} model name * @param model {string} model name
// @param index {number} element index in the $scope[model] array * @param index {number} element index in the $scope[model] array
// # */
$scope.removeElement = function (model, index) { $scope.removeElement = function (model, index) {
if ((model === 'category') && (getModel(model)[1].length === 1)) { if ((model === 'category') && (getModel(model)[1].length === 1)) {
growl.error(_t('at_least_one_category_is_required') + ' ' + _t('unable_to_delete_the_last_one')) growl.error(_t('at_least_one_category_is_required') + ' ' + _t('unable_to_delete_the_last_one'))
@ -250,10 +250,10 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
) )
} }
// # /**
// Creates a new empty entry in the $scope[model] array * Creates a new empty entry in the $scope[model] array
// @param model {string} model name * @param model {string} model name
// # */
$scope.addElement = function (model) { $scope.addElement = function (model) {
$scope.inserted[model] = { $scope.inserted[model] = {
name: '', name: '',
@ -262,12 +262,12 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
return getModel(model)[1].push($scope.inserted[model]) return getModel(model)[1].push($scope.inserted[model])
} }
// # /**
// Removes the newly inserted but not saved element / Cancel the current element modification * Removes the newly inserted but not saved element / Cancel the current element modification
// @param model {string} model name * @param model {string} model name
// @param rowform {Object} see http://vitalets.github.io/angular-xeditable/ * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/
// @param index {number} element index in the $scope[model] array * @param index {number} element index in the $scope[model] array
// # */
$scope.cancelElement = function (model, rowform, index) { $scope.cancelElement = function (model, rowform, index) {
if (getModel(model)[1][index].id != null) { if (getModel(model)[1][index].id != null) {
return rowform.$cancel() return rowform.$cancel()
@ -276,10 +276,10 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
} }
} }
// # /**
// Open a modal dialog allowing the definition of a new price category. * Open a modal dialog allowing the definition of a new price category.
// Save it once filled and handle the result. * Save it once filled and handle the result.
// # */
$scope.newPriceCategory = () => $scope.newPriceCategory = () =>
$uibModal.open({ $uibModal.open({
templateUrl: '<%= asset_path "admin/events/price_form.html" %>', templateUrl: '<%= asset_path "admin/events/price_form.html" %>',
@ -299,12 +299,12 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
}) })
) )
// # /**
// Update the given price category with the new properties * Update the given price category with the new properties
// to specify in a modal dialog * to specify in a modal dialog
// @param index {number} index of the caterory in the $scope.priceCategories array * @param index {number} index of the caterory in the $scope.priceCategories array
// @param id {number} price category ID, must match the ID of the category at the index specified above * @param id {number} price category ID, must match the ID of the category at the index specified above
// # */
$scope.editPriceCategory = function (id, index) { $scope.editPriceCategory = function (id, index) {
if ($scope.priceCategories[index].id !== id) { if ($scope.priceCategories[index].id !== id) {
return growl.error(_t('unexpected_error_occurred_please_refresh')) return growl.error(_t('unexpected_error_occurred_please_refresh'))
@ -329,11 +329,11 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
} }
} }
// # /**
// Delete the given price category from the API * Delete the given price category from the API
// @param index {number} index of the caterory in the $scope.priceCategories array * @param index {number} index of the caterory in the $scope.priceCategories array
// @param id {number} price category ID, must match the ID of the category at the index specified above * @param id {number} price category ID, must match the ID of the category at the index specified above
// # */
$scope.removePriceCategory = function (id, index) { $scope.removePriceCategory = function (id, index) {
if ($scope.priceCategories[index].id !== id) { if ($scope.priceCategories[index].id !== id) {
return growl.error(_t('unexpected_error_occurred_please_refresh')) return growl.error(_t('unexpected_error_occurred_please_refresh'))
@ -360,10 +360,10 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
} }
} }
// # /**
// Triggered when the admin changes the events filter (all, passed, future). * Triggered when the admin changes the events filter (all, passed, future).
// We request the first page of corresponding events to the API * We request the first page of corresponding events to the API
// # */
$scope.changeScope = function () { $scope.changeScope = function () {
Event.query({ page: 1, scope: $scope.eventsScope.selected }, function (data) { Event.query({ page: 1, scope: $scope.eventsScope.selected }, function (data) {
$scope.events = data $scope.events = data
@ -374,17 +374,17 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = () => paginationCheck(eventsPromise, $scope.events) const initialize = () => paginationCheck(eventsPromise, $scope.events)
// # /**
// Check if all events are already displayed OR if the button 'load more events' * Check if all events are already displayed OR if the button 'load more events'
// is required * is required
// @param lastEvents {Array} last events loaded onto the diplay (ie. last "page") * @param lastEvents {Array} last events loaded onto the diplay (ie. last "page")
// @param events {Array} full list of events displayed on the page (not only the last retrieved) * @param events {Array} full list of events displayed on the page (not only the last retrieved)
// # */
var paginationCheck = function (lastEvents, events) { var paginationCheck = function (lastEvents, events) {
if (lastEvents.length > 0) { if (lastEvents.length > 0) {
if (events.length >= lastEvents[0].nb_total_events) { if (events.length >= lastEvents[0].nb_total_events) {
@ -397,11 +397,11 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
} }
} }
// # /**
// Return the model and the datastore matching the given name * Return the model and the datastore matching the given name
// @param name {string} 'category', 'theme' or 'age_range' * @param name {string} 'category', 'theme' or 'age_range'
// @return {[Object, Array]} model and datastore * @return {[Object, Array]} model and datastore
// # */
var getModel = function (name) { var getModel = function (name) {
switch (name) { switch (name) {
case 'category': return [Category, $scope.categories] case 'category': return [Category, $scope.categories]
@ -417,44 +417,44 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
]) ])
// # /**
// Controller used in the reservations listing page for a specific event * Controller used in the reservations listing page for a specific event
// # */
Application.Controllers.controller('ShowEventReservationsController', ['$scope', 'eventPromise', 'reservationsPromise', function ($scope, eventPromise, reservationsPromise) { Application.Controllers.controller('ShowEventReservationsController', ['$scope', 'eventPromise', 'reservationsPromise', function ($scope, eventPromise, reservationsPromise) {
// # retrieve the event from the ID provided in the current URL // retrieve the event from the ID provided in the current URL
$scope.event = eventPromise $scope.event = eventPromise
// # list of reservations for the current event // list of reservations for the current event
return $scope.reservations = reservationsPromise return $scope.reservations = reservationsPromise
} }
]) ])
// # /**
// Controller used in the event creation page * Controller used in the event creation page
// # */
Application.Controllers.controller('NewEventController', ['$scope', '$state', 'CSRF', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '_t', Application.Controllers.controller('NewEventController', ['$scope', '$state', 'CSRF', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '_t',
function ($scope, $state, CSRF, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, _t) { function ($scope, $state, CSRF, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, _t) {
CSRF.setMetaTags() CSRF.setMetaTags()
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = '/api/events/' $scope.actionUrl = '/api/events/'
// # Form action on the above URL // Form action on the above URL
$scope.method = 'post' $scope.method = 'post'
// # List of categories for the events // List of categories for the events
$scope.categories = categoriesPromise $scope.categories = categoriesPromise
// # List of events themes // List of events themes
$scope.themes = themesPromise $scope.themes = themesPromise
// # List of age ranges // List of age ranges
$scope.ageRanges = ageRangesPromise $scope.ageRanges = ageRangesPromise
// # List of availables price's categories // List of availables price's categories
$scope.priceCategories = priceCategoriesPromise $scope.priceCategories = priceCategoriesPromise
// # Default event parameters // Default event parameters
$scope.event = { $scope.event = {
event_files_attributes: [], event_files_attributes: [],
start_date: new Date(), start_date: new Date(),
@ -467,7 +467,7 @@ Application.Controllers.controller('NewEventController', ['$scope', '$state', 'C
prices: [] prices: []
} }
// # Possible types of recurrences for an event // Possible types of recurrences for an event
$scope.recurrenceTypes = [ $scope.recurrenceTypes = [
{ label: _t('none'), value: 'none' }, { label: _t('none'), value: 'none' },
{ label: _t('every_days'), value: 'day' }, { label: _t('every_days'), value: 'day' },
@ -476,44 +476,44 @@ Application.Controllers.controller('NewEventController', ['$scope', '$state', 'C
{ label: _t('every_year'), value: 'year' } { label: _t('every_year'), value: 'year' }
] ]
// # Using the EventsController // Using the EventsController
return new EventsController($scope, $state) return new EventsController($scope, $state)
} }
]) ])
// # /**
// Controller used in the events edition page * Controller used in the events edition page
// # */
Application.Controllers.controller('EditEventController', ['$scope', '$state', '$stateParams', 'CSRF', 'eventPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', Application.Controllers.controller('EditEventController', ['$scope', '$state', '$stateParams', 'CSRF', 'eventPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise',
function ($scope, $state, $stateParams, CSRF, eventPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise) { function ($scope, $state, $stateParams, CSRF, eventPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = `/api/events/${$stateParams.id}` $scope.actionUrl = `/api/events/${$stateParams.id}`
// # Form action on the above URL // Form action on the above URL
$scope.method = 'put' $scope.method = 'put'
// # Retrieve the event details, in case of error the user is redirected to the events listing // Retrieve the event details, in case of error the user is redirected to the events listing
$scope.event = eventPromise $scope.event = eventPromise
// # List of categories for the events // List of categories for the events
$scope.categories = categoriesPromise $scope.categories = categoriesPromise
// # List of availables price's categories // List of availables price's categories
$scope.priceCategories = priceCategoriesPromise $scope.priceCategories = priceCategoriesPromise
// # List of events themes // List of events themes
$scope.themes = themesPromise $scope.themes = themesPromise
// # List of age ranges // List of age ranges
$scope.ageRanges = ageRangesPromise $scope.ageRanges = ageRangesPromise
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
CSRF.setMetaTags() CSRF.setMetaTags()
@ -521,11 +521,11 @@ Application.Controllers.controller('EditEventController', ['$scope', '$state', '
$scope.event.start_date = moment($scope.event.start_date).toDate() $scope.event.start_date = moment($scope.event.start_date).toDate()
$scope.event.end_date = moment($scope.event.end_date).toDate() $scope.event.end_date = moment($scope.event.end_date).toDate()
// # Using the EventsController // Using the EventsController
return new EventsController($scope, $state) return new EventsController($scope, $state)
} }
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])

View File

@ -14,9 +14,9 @@
*/ */
'use strict' 'use strict'
// # /**
// Controller used in the admin invoices listing page * Controller used in the admin invoices listing page
// # */
Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'Invoice', 'invoices', '$uibModal', 'growl', '$filter', 'Setting', 'settings', '_t', Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'Invoice', 'invoices', '$uibModal', 'growl', '$filter', 'Setting', 'settings', '_t',
function ($scope, $state, Invoice, invoices, $uibModal, growl, $filter, Setting, settings, _t) { function ($scope, $state, Invoice, invoices, $uibModal, growl, $filter, Setting, settings, _t) {
/* PRIVATE STATIC CONSTANTS */ /* PRIVATE STATIC CONSTANTS */
@ -26,7 +26,7 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # List of all users invoices // List of all users invoices
$scope.invoices = invoices $scope.invoices = invoices
// Invoices filters // Invoices filters
@ -42,10 +42,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
// true when all invoices are loaded // true when all invoices are loaded
$scope.noMoreResults = false $scope.noMoreResults = false
// # Default invoices ordering/sorting // Default invoices ordering/sorting
$scope.orderInvoice = '-reference' $scope.orderInvoice = '-reference'
// # Invoices parameters // Invoices parameters
$scope.invoice = { $scope.invoice = {
logo: null, logo: null,
reference: { reference: {
@ -76,19 +76,19 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
} }
} }
// # Placeholding date for the invoice creation // Placeholding date for the invoice creation
$scope.today = moment() $scope.today = moment()
// # Placeholding date for the reservation begin // Placeholding date for the reservation begin
$scope.inOneWeek = moment().add(1, 'week').startOf('hour') $scope.inOneWeek = moment().add(1, 'week').startOf('hour')
// # Placeholding date for the reservation end // Placeholding date for the reservation end
$scope.inOneWeekAndOneHour = moment().add(1, 'week').add(1, 'hour').startOf('hour') $scope.inOneWeekAndOneHour = moment().add(1, 'week').add(1, 'hour').startOf('hour')
// # /**
// Change the invoices ordering criterion to the one provided * Change the invoices ordering criterion to the one provided
// @param orderBy {string} ordering criterion * @param orderBy {string} ordering criterion
// # */
$scope.setOrderInvoice = function (orderBy) { $scope.setOrderInvoice = function (orderBy) {
if ($scope.orderInvoice === orderBy) { if ($scope.orderInvoice === orderBy) {
$scope.orderInvoice = `-${orderBy}` $scope.orderInvoice = `-${orderBy}`
@ -100,10 +100,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
return invoiceSearch() return invoiceSearch()
} }
// # /**
// Open a modal window asking the admin the details to refund the user about the provided invoice * Open a modal window asking the admin the details to refund the user about the provided invoice
// @param invoice {Object} invoice inherited from angular's $resource * @param invoice {Object} invoice inherited from angular's $resource
// # */
$scope.generateAvoirForInvoice = function (invoice) { $scope.generateAvoirForInvoice = function (invoice) {
// open modal // open modal
const modalInstance = $uibModal.open({ const modalInstance = $uibModal.open({
@ -124,10 +124,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
}) })
} }
// # /**
// Generate an invoice reference sample from the parametrized model * Generate an invoice reference sample from the parametrized model
// @returns {string} invoice reference sample * @returns {string} invoice reference sample
// # */
$scope.mkReference = function () { $scope.mkReference = function () {
let sample = $scope.invoice.reference.model let sample = $scope.invoice.reference.model
if (sample) { if (sample) {
@ -149,10 +149,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
return sample return sample
} }
// # /**
// Generate an order nmuber sample from the parametrized model * Generate an order nmuber sample from the parametrized model
// @returns {string} invoice reference sample * @returns {string} invoice reference sample
// # */
$scope.mkNumber = function () { $scope.mkNumber = function () {
let sample = $scope.invoice.number.model let sample = $scope.invoice.number.model
if (sample) { if (sample) {
@ -170,9 +170,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
return sample return sample
} }
// # /**
// Open a modal dialog allowing the user to edit the invoice reference generation template * Open a modal dialog allowing the user to edit the invoice reference generation template
// # */
$scope.openEditReference = function () { $scope.openEditReference = function () {
const modalInstance = $uibModal.open({ const modalInstance = $uibModal.open({
animation: true, animation: true,
@ -202,9 +202,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
) )
} }
// # /**
// Open a modal dialog allowing the user to edit the invoice code * Open a modal dialog allowing the user to edit the invoice code
// # */
$scope.openEditCode = function () { $scope.openEditCode = function () {
const modalInstance = $uibModal.open({ const modalInstance = $uibModal.open({
animation: true, animation: true,
@ -254,9 +254,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
}) })
} }
// # /**
// Open a modal dialog allowing the user to edit the invoice number * Open a modal dialog allowing the user to edit the invoice number
// # */
$scope.openEditInvoiceNb = function () { $scope.openEditInvoiceNb = function () {
const modalInstance = $uibModal.open({ const modalInstance = $uibModal.open({
animation: true, animation: true,
@ -286,10 +286,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
) )
} }
// # /**
// Open a modal dialog allowing the user to edit the VAT parameters for the invoices * Open a modal dialog allowing the user to edit the VAT parameters for the invoices
// The VAT can be disabled and its rate can be configured * The VAT can be disabled and its rate can be configured
// # */
$scope.openEditVAT = function () { $scope.openEditVAT = function () {
const modalInstance = $uibModal.open({ const modalInstance = $uibModal.open({
animation: true, animation: true,
@ -339,9 +339,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
}) })
} }
// # /**
// Callback to save the value of the text zone when editing is done * Callback to save the value of the text zone when editing is done
// # */
$scope.textEditEnd = function (event) { $scope.textEditEnd = function (event) {
const parsed = parseHtml($scope.invoice.text.content) const parsed = parseHtml($scope.invoice.text.content)
return Setting.update({ name: 'invoice_text' }, { value: parsed }, function (data) { return Setting.update({ name: 'invoice_text' }, { value: parsed }, function (data) {
@ -354,9 +354,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
}) })
} }
// # /**
// Callback to save the value of the legal information zone when editing is done * Callback to save the value of the legal information zone when editing is done
// # */
$scope.legalsEditEnd = function (event) { $scope.legalsEditEnd = function (event) {
const parsed = parseHtml($scope.invoice.legals.content) const parsed = parseHtml($scope.invoice.legals.content)
return Setting.update({ name: 'invoice_legals' }, { value: parsed }, function (data) { return Setting.update({ name: 'invoice_legals' }, { value: parsed }, function (data) {
@ -369,19 +369,19 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
}) })
} }
// # /**
// Callback when any of the filters changes. * Callback when any of the filters changes.
// Full reload the results list * Full reload the results list
// # */
$scope.handleFilterChange = function () { $scope.handleFilterChange = function () {
resetSearchInvoice() resetSearchInvoice()
return invoiceSearch() return invoiceSearch()
} }
// # /**
// Callback for the 'load more' button. * Callback for the 'load more' button.
// Will load the next results of the current search, if any * Will load the next results of the current search, if any
// # */
$scope.showNextInvoices = function () { $scope.showNextInvoices = function () {
$scope.page += 1 $scope.page += 1
return invoiceSearch(true) return invoiceSearch(true)
@ -389,9 +389,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
if (!invoices[0] || (invoices[0].maxInvoices <= $scope.invoices.length)) { if (!invoices[0] || (invoices[0].maxInvoices <= $scope.invoices.length)) {
$scope.noMoreResults = true $scope.noMoreResults = true
@ -424,20 +424,20 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
}) })
} }
// # /**
// Output the given integer with leading zeros. If the given value is longer than the given * Output the given integer with leading zeros. If the given value is longer than the given
// length, it will be truncated. * length, it will be truncated.
// @param value {number} the integer to pad * @param value {number} the integer to pad
// @param length {number} the length of the resulting string. * @param length {number} the length of the resulting string.
// # */
var padWithZeros = (value, length) => (1e15 + value + '').slice(-length) var padWithZeros = (value, length) => (1e15 + value + '').slice(-length)
// # /**
// Remove every unsupported html tag from the given html text (like <p>, <span>, ...). * Remove every unsupported html tag from the given html text (like <p>, <span>, ...).
// The supported tags are <b>, <u>, <i> and <br>. * The supported tags are <b>, <u>, <i> and <br>.
// @param html {string} single line html text * @param html {string} single line html text
// @return {string} multi line simplified html text * @return {string} multi line simplified html text
// # */
var parseHtml = html => var parseHtml = html =>
html = html.replace(/<\/?(\w+)((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)\/?>/g, function (match, p1, offset, string) { html = html.replace(/<\/?(\w+)((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)\/?>/g, function (match, p1, offset, string) {
if (['b', 'u', 'i', 'br'].includes(p1)) { if (['b', 'u', 'i', 'br'].includes(p1)) {
@ -447,19 +447,19 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
} }
}) })
// # /**
// Reinitialize the context of invoices' search to display new results set * Reinitialize the context of invoices' search to display new results set
// # */
var resetSearchInvoice = function () { var resetSearchInvoice = function () {
$scope.page = 1 $scope.page = 1
return $scope.noMoreResults = false return $scope.noMoreResults = false
} }
// # /**
// Run a search query with the current parameters set concerning invoices, then affect or concat the results * Run a search query with the current parameters set concerning invoices, then affect or concat the results
// to $scope.invoices * to $scope.invoices
// @param concat {boolean} if true, the result will be append to $scope.invoices instead of being affected * @param concat {boolean} if true, the result will be append to $scope.invoices instead of being affected
// # */
var invoiceSearch = concat => var invoiceSearch = concat =>
Invoice.list({ Invoice.list({
query: { query: {
@ -482,32 +482,32 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
} }
}) })
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])
// # /**
// Controller used in the invoice refunding modal window * Controller used in the invoice refunding modal window
// # */
Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModalInstance', 'invoice', 'Invoice', 'growl', '_t', Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModalInstance', 'invoice', 'Invoice', 'growl', '_t',
function ($scope, $uibModalInstance, invoice, Invoice, growl, _t) { function ($scope, $uibModalInstance, invoice, Invoice, growl, _t) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # invoice linked to the current refund // invoice linked to the current refund
$scope.invoice = invoice $scope.invoice = invoice
// # Associative array containing invoice_item ids associated with boolean values // Associative array containing invoice_item ids associated with boolean values
$scope.partial = {} $scope.partial = {}
// # Default refund parameters // Default refund parameters
$scope.avoir = { $scope.avoir = {
invoice_id: invoice.id, invoice_id: invoice.id,
subscription_to_expire: false, subscription_to_expire: false,
invoice_items_ids: [] invoice_items_ids: []
} }
// # Possible refunding methods // Possible refunding methods
$scope.avoirModes = [ $scope.avoirModes = [
{ name: _t('none'), value: 'none' }, { name: _t('none'), value: 'none' },
{ name: _t('by_cash'), value: 'cash' }, { name: _t('by_cash'), value: 'cash' },
@ -516,12 +516,12 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
{ name: _t('by_wallet'), value: 'wallet' } { name: _t('by_wallet'), value: 'wallet' }
] ]
// # If a subscription was took with the current invoice, should it be canceled or not // If a subscription was took with the current invoice, should it be canceled or not
$scope.subscriptionExpireOptions = {} $scope.subscriptionExpireOptions = {}
$scope.subscriptionExpireOptions[_t('yes')] = true $scope.subscriptionExpireOptions[_t('yes')] = true
$scope.subscriptionExpireOptions[_t('no')] = false $scope.subscriptionExpireOptions[_t('no')] = false
// # AngularUI-Bootstrap datepicker parameters to define when to refund // AngularUI-Bootstrap datepicker parameters to define when to refund
$scope.datePicker = { $scope.datePicker = {
format: Fablab.uibDateFormat, format: Fablab.uibDateFormat,
opened: false, // default: datePicker is not shown opened: false, // default: datePicker is not shown
@ -530,18 +530,18 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
} }
} }
// # /**
// Callback to open the datepicker * Callback to open the datepicker
// # */
$scope.openDatePicker = function ($event) { $scope.openDatePicker = function ($event) {
$event.preventDefault() $event.preventDefault()
$event.stopPropagation() $event.stopPropagation()
return $scope.datePicker.opened = true return $scope.datePicker.opened = true
} }
// # /**
// Validate the refunding and generate a refund invoice * Validate the refunding and generate a refund invoice
// # */
$scope.ok = function () { $scope.ok = function () {
// check that at least 1 element of the invoice is refunded // check that at least 1 element of the invoice is refunded
$scope.avoir.invoice_items_ids = [] $scope.avoir.invoice_items_ids = []
@ -564,18 +564,18 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
} }
} }
// # /**
// Cancel the refund, dismiss the modal window * Cancel the refund, dismiss the modal window
// # */
$scope.cancel = () => $uibModalInstance.dismiss('cancel') $scope.cancel = () => $uibModalInstance.dismiss('cancel')
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
// # if the invoice was payed with stripe, allow to refund through stripe // if the invoice was payed with stripe, allow to refund through stripe
Invoice.get({ id: invoice.id }, function (data) { Invoice.get({ id: invoice.id }, function (data) {
$scope.invoice = data $scope.invoice = data
// default : all elements of the invoice are refund // default : all elements of the invoice are refund
@ -588,7 +588,7 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
} }
} }
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])

View File

@ -17,30 +17,30 @@
/* COMMON CODE */ /* COMMON CODE */
// # /**
// Provides a set of common properties and methods to the $scope parameter. They are used * Provides a set of common properties and methods to the $scope parameter. They are used
// in the various members' admin controllers. * in the various members' admin controllers.
// *
// Provides : * Provides :
// - $scope.groups = [{Group}] * - $scope.groups = [{Group}]
// - $scope.trainings = [{Training}] * - $scope.trainings = [{Training}]
// - $scope.plans = [] * - $scope.plans = []
// - $scope.datePicker = {} * - $scope.datePicker = {}
// - $scope.submited(content) * - $scope.submited(content)
// - $scope.cancel() * - $scope.cancel()
// - $scope.fileinputClass(v) * - $scope.fileinputClass(v)
// - $scope.openDatePicker($event) * - $scope.openDatePicker($event)
// - $scope.openSubscriptionDatePicker($event) * - $scope.openSubscriptionDatePicker($event)
// *
// Requires : * Requires :
// - $state (Ui-Router) [ 'app.admin.members' ] * - $state (Ui-Router) [ 'app.admin.members' ]
// # */
class MembersController { class MembersController {
constructor ($scope, $state, Group, Training) { constructor ($scope, $state, Group, Training) {
// # Retrieve the profiles groups (eg. students ...) // Retrieve the profiles groups (eg. students ...)
Group.query(groups => $scope.groups = groups.filter(g => (g.slug !== 'admins') && !g.disabled)) Group.query(groups => $scope.groups = groups.filter(g => (g.slug !== 'admins') && !g.disabled))
// # Retrieve the list of available trainings // Retrieve the list of available trainings
Training.query().$promise.then(data => Training.query().$promise.then(data =>
$scope.trainings = data.map(d => $scope.trainings = data.map(d =>
({ ({
@ -51,7 +51,7 @@ class MembersController {
) )
) )
// # Default parameters for AngularUI-Bootstrap datepicker // Default parameters for AngularUI-Bootstrap datepicker
$scope.datePicker = { $scope.datePicker = {
format: Fablab.uibDateFormat, format: Fablab.uibDateFormat,
opened: false, // default: datePicker is not shown opened: false, // default: datePicker is not shown
@ -61,32 +61,32 @@ class MembersController {
} }
} }
// # /**
// Shows the birth day datepicker * Shows the birth day datepicker
// @param $event {Object} jQuery event object * @param $event {Object} jQuery event object
// # */
$scope.openDatePicker = function ($event) { $scope.openDatePicker = function ($event) {
$event.preventDefault() $event.preventDefault()
$event.stopPropagation() $event.stopPropagation()
return $scope.datePicker.opened = true return $scope.datePicker.opened = true
} }
// # /**
// Shows the end of subscription datepicker * Shows the end of subscription datepicker
// @param $event {Object} jQuery event object * @param $event {Object} jQuery event object
// # */
$scope.openSubscriptionDatePicker = function ($event) { $scope.openSubscriptionDatePicker = function ($event) {
$event.preventDefault() $event.preventDefault()
$event.stopPropagation() $event.stopPropagation()
return $scope.datePicker.subscription_date_opened = true return $scope.datePicker.subscription_date_opened = true
} }
// # /**
// For use with ngUpload (https://github.com/twilson63/ngUpload). * For use with ngUpload (https://github.com/twilson63/ngUpload).
// Intended to be the callback when an upload is done: any raised error will be stacked in the * Intended to be the callback when an upload is done: any raised error will be stacked in the
// $scope.alerts array. If everything goes fine, the user is redirected to the members listing page. * $scope.alerts array. If everything goes fine, the user is redirected to the members listing page.
// @param content {Object} JSON - The upload's result * @param content {Object} JSON - The upload's result
// # */
$scope.submited = function (content) { $scope.submited = function (content) {
if ((content.id == null)) { if ((content.id == null)) {
$scope.alerts = [] $scope.alerts = []
@ -103,16 +103,16 @@ class MembersController {
} }
} }
// # /**
// Changes the admin's view to the members list page * Changes the admin's view to the members list page
// # */
$scope.cancel = () => $state.go('app.admin.members') $scope.cancel = () => $state.go('app.admin.members')
// # /**
// For use with 'ng-class', returns the CSS class name for the uploads previews. * 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. * 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) * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)
// # */
$scope.fileinputClass = function (v) { $scope.fileinputClass = function (v) {
if (v) { if (v) {
return 'fileinput-exists' return 'fileinput-exists'
@ -123,9 +123,9 @@ class MembersController {
} }
} }
// # /**
// Controller used in the members/groups management page * Controller used in the members/groups management page
// # */
Application.Controllers.controller('AdminMembersController', ['$scope', '$sce', 'membersPromise', 'adminsPromise', 'growl', 'Admin', 'dialogs', '_t', 'Member', 'Export', Application.Controllers.controller('AdminMembersController', ['$scope', '$sce', 'membersPromise', 'adminsPromise', 'growl', 'Admin', 'dialogs', '_t', 'Member', 'Export',
function ($scope, $sce, membersPromise, adminsPromise, growl, Admin, dialogs, _t, Member, Export) { function ($scope, $sce, membersPromise, adminsPromise, growl, Admin, dialogs, _t, Member, Export) {
/* PRIVATE STATIC CONSTANTS */ /* PRIVATE STATIC CONSTANTS */
@ -135,30 +135,30 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # members list // members list
$scope.members = membersPromise $scope.members = membersPromise
$scope.member = { $scope.member = {
// # Members plain-text filtering. Default: not filtered // Members plain-text filtering. Default: not filtered
searchText: '', searchText: '',
// # Members ordering/sorting. Default: not sorted // Members ordering/sorting. Default: not sorted
order: 'id', order: 'id',
// # currently displayed page of members // currently displayed page of members
page: 1, page: 1,
// # true when all members where loaded // true when all members where loaded
noMore: false noMore: false
} }
// # admins list // admins list
$scope.admins = adminsPromise.admins $scope.admins = adminsPromise.admins
// # Admins ordering/sorting. Default: not sorted // Admins ordering/sorting. Default: not sorted
$scope.orderAdmin = null $scope.orderAdmin = null
// # /**
// Change the members ordering criterion to the one provided * Change the members ordering criterion to the one provided
// @param orderBy {string} ordering criterion * @param orderBy {string} ordering criterion
// # */
$scope.setOrderMember = function (orderBy) { $scope.setOrderMember = function (orderBy) {
if ($scope.member.order === orderBy) { if ($scope.member.order === orderBy) {
$scope.member.order = `-${orderBy}` $scope.member.order = `-${orderBy}`
@ -170,10 +170,10 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
return memberSearch() return memberSearch()
} }
// # /**
// Change the admins ordering criterion to the one provided * Change the admins ordering criterion to the one provided
// @param orderBy {string} ordering criterion * @param orderBy {string} ordering criterion
// # */
$scope.setOrderAdmin = function (orderAdmin) { $scope.setOrderAdmin = function (orderAdmin) {
if ($scope.orderAdmin === orderAdmin) { if ($scope.orderAdmin === orderAdmin) {
return $scope.orderAdmin = `-${orderAdmin}` return $scope.orderAdmin = `-${orderAdmin}`
@ -182,11 +182,11 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
} }
} }
// # /**
// Ask for confirmation then delete the specified administrator * Ask for confirmation then delete the specified administrator
// @param admins {Array} full list of administrators * @param admins {Array} full list of administrators
// @param admin {Object} administrator to delete * @param admin {Object} administrator to delete
// # */
$scope.destroyAdmin = (admins, admin) => $scope.destroyAdmin = (admins, admin) =>
dialogs.confirm({ dialogs.confirm({
resolve: { resolve: {
@ -206,27 +206,27 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
, error => growl.error(_t('unable_to_delete_the_administrator'))) , error => growl.error(_t('unable_to_delete_the_administrator')))
) )
// # /**
// Callback for the 'load more' button. * Callback for the 'load more' button.
// Will load the next results of the current search, if any * Will load the next results of the current search, if any
// # */
$scope.showNextMembers = function () { $scope.showNextMembers = function () {
$scope.member.page += 1 $scope.member.page += 1
return memberSearch(true) return memberSearch(true)
} }
// # /**
// Callback when the search field content changes: reload the search results * Callback when the search field content changes: reload the search results
// # */
$scope.updateTextSearch = function () { $scope.updateTextSearch = function () {
resetSearchMember() resetSearchMember()
return memberSearch() return memberSearch()
} }
// # /**
// Callback to alert the admin that the export request was acknowledged and is * Callback to alert the admin that the export request was acknowledged and is
// processing right now. * processing right now.
// # */
$scope.alertExport = type => $scope.alertExport = type =>
Export.status({ category: 'users', type }).then(function (res) { Export.status({ category: 'users', type }).then(function (res) {
if (!res.data.exists) { if (!res.data.exists) {
@ -236,37 +236,37 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
if (!membersPromise[0] || (membersPromise[0].maxMembers <= $scope.members.length)) { if (!membersPromise[0] || (membersPromise[0].maxMembers <= $scope.members.length)) {
return $scope.member.noMore = true return $scope.member.noMore = true
} }
} }
// # /**
// Iterate through the provided array and return the index of the requested admin * Iterate through the provided array and return the index of the requested admin
// @param admins {Array} full list of users with role 'admin' * @param admins {Array} full list of users with role 'admin'
// @param id {Number} user id of the admin to retrieve in the list * @param id {Number} user id of the admin to retrieve in the list
// @returns {Number} index of the requested admin, in the provided array * @returns {Number} index of the requested admin, in the provided array
// # */
var findAdminIdxById = (admins, id) => var findAdminIdxById = (admins, id) =>
(admins.map(admin => admin.id)).indexOf(id) (admins.map(admin => admin.id)).indexOf(id)
// # /**
// Reinitialize the context of members's search to display new results set * Reinitialize the context of members's search to display new results set
// # */
var resetSearchMember = function () { var resetSearchMember = function () {
$scope.member.noMore = false $scope.member.noMore = false
return $scope.member.page = 1 return $scope.member.page = 1
} }
// # /**
// Run a search query with the current parameters set ($scope.member[searchText,order,page]) * Run a search query with the current parameters set ($scope.member[searchText,order,page])
// and affect or append the result in $scope.members, depending on the concat parameter * and affect or append the result in $scope.members, depending on the concat parameter
// @param concat {boolean} if true, the result will be append to $scope.members instead of being affected * @param concat {boolean} if true, the result will be append to $scope.members instead of being affected
// # */
var memberSearch = concat => var memberSearch = concat =>
Member.list({ query: { search: $scope.member.searchText, order_by: $scope.member.order, page: $scope.member.page, size: USERS_PER_PAGE } }, function (members) { Member.list({ query: { search: $scope.member.searchText, order_by: $scope.member.order, page: $scope.member.page, size: USERS_PER_PAGE } }, function (members) {
if (concat) { if (concat) {
@ -280,35 +280,35 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
} }
}) })
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])
// # /**
// Controller used in the member edition page * Controller used in the member edition page
// # */
Application.Controllers.controller('EditMemberController', ['$scope', '$state', '$stateParams', 'Member', 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise', 'activeProviderPromise', 'Wallet', Application.Controllers.controller('EditMemberController', ['$scope', '$state', '$stateParams', 'Member', 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise', 'activeProviderPromise', 'Wallet',
function ($scope, $state, $stateParams, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, activeProviderPromise, Wallet) { function ($scope, $state, $stateParams, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, activeProviderPromise, Wallet) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = `/api/members/${$stateParams.id}` $scope.actionUrl = `/api/members/${$stateParams.id}`
// # Form action on the above URL // Form action on the above URL
$scope.method = 'patch' $scope.method = 'patch'
// # List of tags associables with user // List of tags associables with user
$scope.tags = tagsPromise $scope.tags = tagsPromise
// # The user to edit // The user to edit
$scope.user = memberPromise $scope.user = memberPromise
// # Should the passord be modified? // Should the passord be modified?
$scope.password = $scope.password =
{ change: false } { change: false }
// # the user subscription // the user subscription
if (($scope.user.subscribed_plan != null) && ($scope.user.subscription != null)) { if (($scope.user.subscribed_plan != null) && ($scope.user.subscription != null)) {
$scope.subscription = $scope.user.subscription $scope.subscription = $scope.user.subscription
$scope.subscription.expired_at = $scope.subscription.expired_at $scope.subscription.expired_at = $scope.subscription.expired_at
@ -320,29 +320,29 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
}) })
} }
// # Available trainings list // Available trainings list
$scope.trainings = [] $scope.trainings = []
// # Profiles types (student/standard/...) // Profiles types (student/standard/...)
$scope.groups = [] $scope.groups = []
// # the user wallet // the user wallet
$scope.wallet = walletPromise $scope.wallet = walletPromise
// # user wallet transactions // user wallet transactions
$scope.transactions = transactionsPromise $scope.transactions = transactionsPromise
// # used in wallet partial template to identify parent view // used in wallet partial template to identify parent view
$scope.view = 'member_edit' $scope.view = 'member_edit'
// current active authentication provider // current active authentication provider
$scope.activeProvider = activeProviderPromise $scope.activeProvider = activeProviderPromise
// # /**
// Open a modal dialog, allowing the admin to extend the current user's subscription (freely or not) * Open a modal dialog, allowing the admin to extend the current user's subscription (freely or not)
// @param subscription {Object} User's subscription object * @param subscription {Object} User's subscription object
// @param free {boolean} True if the extent is offered, false otherwise * @param free {boolean} True if the extent is offered, false otherwise
// # */
$scope.updateSubscriptionModal = function (subscription, free) { $scope.updateSubscriptionModal = function (subscription, free) {
const modalInstance = $uibModal.open({ const modalInstance = $uibModal.open({
animation: true, animation: true,
@ -380,36 +380,36 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
return modalInstance.result.then(subscription => $scope.subscription.expired_at = subscription.expired_at) return modalInstance.result.then(subscription => $scope.subscription.expired_at = subscription.expired_at)
} }
// # /**
// Open a modal dialog allowing the admin to set a subscription for the given user. * Open a modal dialog allowing the admin to set a subscription for the given user.
// @param user {Object} User object, user currently reviewed, as recovered from GET /api/members/:id * @param user {Object} User object, user currently reviewed, as recovered from GET /api/members/:id
// @param plans {Array} List of plans, availables for the currently reviewed user, as recovered from GET /api/plans * @param plans {Array} List of plans, availables for the currently reviewed user, as recovered from GET /api/plans
// # */
$scope.createSubscriptionModal = function (user, plans) { $scope.createSubscriptionModal = function (user, plans) {
const modalInstance = $uibModal.open({ const modalInstance = $uibModal.open({
animation: true, animation: true,
templateUrl: '<%= asset_path "admin/subscriptions/create_modal.html" %>', templateUrl: '<%= asset_path "admin/subscriptions/create_modal.html" %>',
size: 'lg', size: 'lg',
controller: ['$scope', '$uibModalInstance', 'Subscription', 'Group', function ($scope, $uibModalInstance, Subscription, Group) { controller: ['$scope', '$uibModalInstance', 'Subscription', 'Group', function ($scope, $uibModalInstance, Subscription, Group) {
// # selected user // selected user
$scope.user = user $scope.user = user
// # available plans for the selected user // available plans for the selected user
$scope.plans = plans $scope.plans = plans
// # /**
// Generate a string identifying the given plan by literal humain-readable name * Generate a string identifying the given plan by literal humain-readable name
// @param plan {Object} Plan object, as recovered from GET /api/plan/:id * @param plan {Object} Plan object, as recovered from GET /api/plan/:id
// @param groups {Array} List of Groups objects, as recovered from GET /api/groups * @param groups {Array} List of Groups objects, as recovered from GET /api/groups
// @param short {boolean} If true, the generated name will contains the group slug, otherwise the group full name * @param short {boolean} If true, the generated name will contains the group slug, otherwise the group full name
// will be included. * will be included.
// @returns {String} * @returns {String}
// # */
$scope.humanReadablePlanName = (plan, groups, short) => `${$filter('humanReadablePlanName')(plan, groups, short)}` $scope.humanReadablePlanName = (plan, groups, short) => `${$filter('humanReadablePlanName')(plan, groups, short)}`
// # /**
// Modal dialog validation callback * Modal dialog validation callback
// # */
$scope.ok = function () { $scope.ok = function () {
$scope.subscription.user_id = user.id $scope.subscription.user_id = user.id
return Subscription.save({ }, { subscription: $scope.subscription }, function (_subscription) { return Subscription.save({ }, { subscription: $scope.subscription }, function (_subscription) {
@ -420,9 +420,9 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
, error => growl.error(_t('a_problem_occurred_while_taking_the_subscription'))) , error => growl.error(_t('a_problem_occurred_while_taking_the_subscription')))
} }
// # /**
// Modal dialog cancellation callback * Modal dialog cancellation callback
// # */
return $scope.cancel = () => $uibModalInstance.dismiss('cancel') return $scope.cancel = () => $uibModalInstance.dismiss('cancel')
} }
] }) ] })
@ -453,18 +453,18 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
} }
} }
// # /**
// Callback to open/close the date picker * Callback to open/close the date picker
// # */
$scope.toggleDatePicker = function ($event) { $scope.toggleDatePicker = function ($event) {
$event.preventDefault() $event.preventDefault()
$event.stopPropagation() $event.stopPropagation()
return $scope.datePicker.opened = !$scope.datePicker.opened return $scope.datePicker.opened = !$scope.datePicker.opened
} }
// # /**
// Modal dialog validation callback * Modal dialog validation callback
// # */
$scope.ok = () => $scope.ok = () =>
Wallet.credit({ id: wallet.id }, { Wallet.credit({ id: wallet.id }, {
amount: $scope.amount, amount: $scope.amount,
@ -478,9 +478,9 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
} }
, error => growl.error(_t('a_problem_occurred_for_wallet_credit'))) , error => growl.error(_t('a_problem_occurred_for_wallet_credit')))
// # /**
// Modal dialog cancellation callback * Modal dialog cancellation callback
// # */
return $scope.cancel = () => $uibModalInstance.dismiss('cancel') return $scope.cancel = () => $uibModalInstance.dismiss('cancel')
} }
] }) ] })
@ -491,23 +491,23 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
}) })
} }
// # /**
// To use as callback in Array.prototype.filter to get only enabled plans * To use as callback in Array.prototype.filter to get only enabled plans
// # */
$scope.filterDisabledPlans = plan => !plan.disabled $scope.filterDisabledPlans = plan => !plan.disabled
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
CSRF.setMetaTags() CSRF.setMetaTags()
// init the birth date to JS object // init the birth date to JS object
$scope.user.profile.birthday = moment($scope.user.profile.birthday).toDate() $scope.user.profile.birthday = moment($scope.user.profile.birthday).toDate()
// # the user subscription // the user subscription
if (($scope.user.subscribed_plan != null) && ($scope.user.subscription != null)) { if (($scope.user.subscribed_plan != null) && ($scope.user.subscription != null)) {
$scope.subscription = $scope.user.subscription $scope.subscription = $scope.user.subscription
$scope.subscription.expired_at = $scope.subscription.expired_at $scope.subscription.expired_at = $scope.subscription.expired_at
@ -523,36 +523,36 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
return new MembersController($scope, $state, Group, Training) return new MembersController($scope, $state, Group, Training)
} }
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])
// # /**
// Controller used in the member's creation page (admin view) * Controller used in the member's creation page (admin view)
// # */
Application.Controllers.controller('NewMemberController', ['$scope', '$state', '$stateParams', 'Member', 'Training', 'Group', 'CSRF', Application.Controllers.controller('NewMemberController', ['$scope', '$state', '$stateParams', 'Member', 'Training', 'Group', 'CSRF',
function ($scope, $state, $stateParams, Member, Training, Group, CSRF) { function ($scope, $state, $stateParams, Member, Training, Group, CSRF) {
CSRF.setMetaTags() CSRF.setMetaTags()
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = '/api/members' $scope.actionUrl = '/api/members'
// # Form action on the above URL // Form action on the above URL
$scope.method = 'post' $scope.method = 'post'
// # Should the passord be set manually or generated? // Should the passord be set manually or generated?
$scope.password = $scope.password =
{ change: false } { change: false }
// # Default member's profile parameters // Default member's profile parameters
$scope.user = $scope.user =
{ plan_interval: '' } { plan_interval: '' }
// # Callback when the admin check/unckeck the box telling that the new user is an organization. // Callback when the admin check/unckeck the box telling that the new user is an organization.
// # Disable or enable the organization fields in the form, accordingly // Disable or enable the organization fields in the form, accordingly
$scope.toggleOrganization = function () { $scope.toggleOrganization = function () {
if ($scope.user.organization) { if ($scope.user.organization) {
if (!$scope.user.profile) { $scope.user.profile = {} } if (!$scope.user.profile) { $scope.user.profile = {} }
@ -562,16 +562,16 @@ Application.Controllers.controller('NewMemberController', ['$scope', '$state', '
} }
} }
// # Using the MembersController // Using the MembersController
return new MembersController($scope, $state, Group, Training) return new MembersController($scope, $state, Group, Training)
} }
]) ])
// # /**
// Controller used in the admin's creation page (admin view) * Controller used in the admin's creation page (admin view)
// # */
Application.Controllers.controller('NewAdminController', ['$state', '$scope', 'Admin', 'growl', '_t', function ($state, $scope, Admin, growl, _t) { Application.Controllers.controller('NewAdminController', ['$state', '$scope', 'Admin', 'growl', '_t', function ($state, $scope, Admin, growl, _t) {
// # default admin profile // default admin profile
let getGender let getGender
$scope.admin = { $scope.admin = {
profile_attributes: { profile_attributes: {
@ -579,7 +579,7 @@ Application.Controllers.controller('NewAdminController', ['$state', '$scope', 'A
} }
} }
// # Default parameters for AngularUI-Bootstrap datepicker // Default parameters for AngularUI-Bootstrap datepicker
$scope.datePicker = { $scope.datePicker = {
format: Fablab.uibDateFormat, format: Fablab.uibDateFormat,
opened: false, opened: false,
@ -588,15 +588,15 @@ Application.Controllers.controller('NewAdminController', ['$state', '$scope', 'A
} }
} }
// # /**
// Shows the birth day datepicker * Shows the birth day datepicker
// @param $event {Object} jQuery event object * @param $event {Object} jQuery event object
// # */
$scope.openDatePicker = $event => $scope.datePicker.opened = true $scope.openDatePicker = $event => $scope.datePicker.opened = true
// # /**
// Send the new admin, currently stored in $scope.admin, to the server for database saving * Send the new admin, currently stored in $scope.admin, to the server for database saving
// # */
$scope.saveAdmin = () => $scope.saveAdmin = () =>
Admin.save({}, { admin: $scope.admin }, function () { Admin.save({}, { admin: $scope.admin }, function () {
growl.success(_t('administrator_successfully_created_he_will_receive_his_connection_directives_by_email', { GENDER: getGender($scope.admin) }, 'messageformat')) growl.success(_t('administrator_successfully_created_he_will_receive_his_connection_directives_by_email', { GENDER: getGender($scope.admin) }, 'messageformat'))
@ -606,11 +606,11 @@ Application.Controllers.controller('NewAdminController', ['$state', '$scope', 'A
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Return an enumerable meaninful string for the gender of the provider user * Return an enumerable meaninful string for the gender of the provider user
// @param user {Object} Database user record * @param user {Object} Database user record
// @return {string} 'male' or 'female' * @return {string} 'male' or 'female'
// # */
return getGender = function (user) { return getGender = function (user) {
if (user.profile_attributes) { if (user.profile_attributes) {
if (user.profile_attributes.gender) { return 'male' } else { return 'female' } if (user.profile_attributes.gender) { return 'male' } else { return 'female' }

View File

@ -25,20 +25,20 @@ class PlanController {
// protection against request forgery // protection against request forgery
CSRF.setMetaTags() CSRF.setMetaTags()
// # groups list // groups list
$scope.groups = groups.filter(g => (g.slug !== 'admins') && !g.disabled) $scope.groups = groups.filter(g => (g.slug !== 'admins') && !g.disabled)
// # users with role 'partner', notifiables for a partner plan // users with role 'partner', notifiables for a partner plan
$scope.partners = partners.users $scope.partners = partners.users
// # Subscriptions prices, machines prices and training prices, per groups // Subscriptions prices, machines prices and training prices, per groups
$scope.group_pricing = prices $scope.group_pricing = prices
// # /**
// For use with 'ng-class', returns the CSS class name for the uploads previews. * 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. * 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) * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)
// # */
$scope.fileinputClass = function (v) { $scope.fileinputClass = function (v) {
if (v) { if (v) {
return 'fileinput-exists' return 'fileinput-exists'
@ -47,10 +47,10 @@ class PlanController {
} }
} }
// # /**
// Mark the provided file for deletion * Mark the provided file for deletion
// @param file {Object} * @param file {Object}
// # */
$scope.deleteFile = function (file) { $scope.deleteFile = function (file) {
if ((file != null) && (file.id != null)) { if ((file != null) && (file.id != null)) {
return file._destroy = true return file._destroy = true
@ -59,30 +59,30 @@ class PlanController {
} }
} }
// # /**
// Controller used in the plan creation form * Controller used in the plan creation form
// # */
Application.Controllers.controller('NewPlanController', ['$scope', '$uibModal', 'groups', 'prices', 'partners', 'CSRF', '$state', 'growl', '_t', Application.Controllers.controller('NewPlanController', ['$scope', '$uibModal', 'groups', 'prices', 'partners', 'CSRF', '$state', 'growl', '_t',
function ($scope, $uibModal, groups, prices, partners, CSRF, $state, growl, _t) { function ($scope, $uibModal, groups, prices, partners, CSRF, $state, growl, _t) {
({ ({
/* PRIVATE STATIC CONSTANTS */ /* PRIVATE STATIC CONSTANTS */
// # when creating a new contact for a partner plan, this ID will be sent to the server // when creating a new contact for a partner plan, this ID will be sent to the server
NEW_PARTNER_ID: null NEW_PARTNER_ID: null
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
}) })
// # current form is used to create a new plan // current form is used to create a new plan
$scope.mode = 'creation' $scope.mode = 'creation'
// # prices bindings // prices bindings
$scope.prices = { $scope.prices = {
training: {}, training: {},
machine: {} machine: {}
} }
// # form inputs bindings // form inputs bindings
$scope.plan = { $scope.plan = {
type: null, type: null,
group_id: null, group_id: null,
@ -95,21 +95,21 @@ Application.Controllers.controller('NewPlanController', ['$scope', '$uibModal',
ui_weight: 0 ui_weight: 0
} }
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = '/api/plans/' $scope.actionUrl = '/api/plans/'
// # HTTP method for the rest API // HTTP method for the rest API
$scope.method = 'POST' $scope.method = 'POST'
// # /**
// Checks if the partner contact is a valid data. Used in the form validation process * Checks if the partner contact is a valid data. Used in the form validation process
// @returns {boolean} * @returns {boolean}
// # */
$scope.partnerIsValid = () => ($scope.plan.type === 'Plan') || ($scope.plan.partnerId || ($scope.plan.partnerContact && $scope.plan.partnerContact.email)) $scope.partnerIsValid = () => ($scope.plan.type === 'Plan') || ($scope.plan.partnerId || ($scope.plan.partnerContact && $scope.plan.partnerContact.email))
// # /**
// Open a modal dialog allowing the admin to create a new partner user * Open a modal dialog allowing the admin to create a new partner user
// # */
$scope.openPartnerNewModal = function (subscription) { $scope.openPartnerNewModal = function (subscription) {
const modalInstance = $uibModal.open({ const modalInstance = $uibModal.open({
animation: true, animation: true,
@ -136,11 +136,11 @@ Application.Controllers.controller('NewPlanController', ['$scope', '$uibModal',
}) })
} }
// # /**
// Display some messages and redirect the user, once the form was submitted, depending on the result status * Display some messages and redirect the user, once the form was submitted, depending on the result status
// (failed/succeeded). * (failed/succeeded).
// @param content {Object} * @param content {Object}
// # */
$scope.afterSubmit = function (content) { $scope.afterSubmit = function (content) {
if ((content.id == null) && (content.plan_ids == null)) { if ((content.id == null) && (content.plan_ids == null)) {
return growl.error(_t('new_plan.unable_to_create_the_subscription_please_try_again')) return growl.error(_t('new_plan.unable_to_create_the_subscription_please_try_again'))
@ -160,43 +160,43 @@ Application.Controllers.controller('NewPlanController', ['$scope', '$uibModal',
} }
]) ])
// # /**
// Controller used in the plan edition form * Controller used in the plan edition form
// # */
Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'plans', 'planPromise', 'machines', 'spaces', 'prices', 'partners', 'CSRF', '$state', '$stateParams', 'growl', '$filter', '_t', 'Plan', Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'plans', 'planPromise', 'machines', 'spaces', 'prices', 'partners', 'CSRF', '$state', '$stateParams', 'growl', '$filter', '_t', 'Plan',
function ($scope, groups, plans, planPromise, machines, spaces, prices, partners, CSRF, $state, $stateParams, growl, $filter, _t, Plan) { function ($scope, groups, plans, planPromise, machines, spaces, prices, partners, CSRF, $state, $stateParams, growl, $filter, _t, Plan) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # List of spaces // List of spaces
$scope.spaces = spaces $scope.spaces = spaces
// # List of plans // List of plans
$scope.plans = plans $scope.plans = plans
// # List of machines // List of machines
$scope.machines = machines $scope.machines = machines
// # List of groups // List of groups
$scope.groups = groups $scope.groups = groups
// # current form is used for edition mode // current form is used for edition mode
$scope.mode = 'edition' $scope.mode = 'edition'
// # edited plan data // edited plan data
$scope.plan = planPromise $scope.plan = planPromise
if ($scope.plan.type === null) { $scope.plan.type = 'Plan' } if ($scope.plan.type === null) { $scope.plan.type = 'Plan' }
if ($scope.plan.disabled) { $scope.plan.disabled = 'true' } if ($scope.plan.disabled) { $scope.plan.disabled = 'true' }
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = `/api/plans/${$stateParams.id}` $scope.actionUrl = `/api/plans/${$stateParams.id}`
// # HTTP method for the rest API // HTTP method for the rest API
$scope.method = 'PATCH' $scope.method = 'PATCH'
// # /**
// If a parent plan was set ($scope.plan.parent), the prices will be copied from this parent plan into * If a parent plan was set ($scope.plan.parent), the prices will be copied from this parent plan into
// the current plan prices list. Otherwise, the current plan prices will be erased. * the current plan prices list. Otherwise, the current plan prices will be erased.
// # */
$scope.copyPricesFromPlan = function () { $scope.copyPricesFromPlan = function () {
if ($scope.plan.parent) { if ($scope.plan.parent) {
return Plan.get({ id: $scope.plan.parent }, parentPlan => return Plan.get({ id: $scope.plan.parent }, parentPlan =>
@ -229,10 +229,10 @@ Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'p
} }
} }
// # /**
// Display some messages once the form was submitted, depending on the result status (failed/succeeded) * Display some messages once the form was submitted, depending on the result status (failed/succeeded)
// @param content {Object} * @param content {Object}
// # */
$scope.afterSubmit = function (content) { $scope.afterSubmit = function (content) {
if ((content.id == null) && (content.plan_ids == null)) { if ((content.id == null) && (content.plan_ids == null)) {
return growl.error(_t('edit_plan.unable_to_save_subscription_changes_please_try_again')) return growl.error(_t('edit_plan.unable_to_save_subscription_changes_please_try_again'))
@ -242,21 +242,21 @@ Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'p
} }
} }
// # /**
// Generate a string identifying the given plan by literal humain-readable name * Generate a string identifying the given plan by literal humain-readable name
// @param plan {Object} Plan object, as recovered from GET /api/plan/:id * @param plan {Object} Plan object, as recovered from GET /api/plan/:id
// @param groups {Array} List of Groups objects, as recovered from GET /api/groups * @param groups {Array} List of Groups objects, as recovered from GET /api/groups
// @param short {boolean} If true, the generated name will contains the group slug, otherwise the group full name * @param short {boolean} If true, the generated name will contains the group slug, otherwise the group full name
// will be included. * will be included.
// @returns {String} * @returns {String}
// # */
$scope.humanReadablePlanName = (plan, groups, short) => `${$filter('humanReadablePlanName')(plan, groups, short)}` $scope.humanReadablePlanName = (plan, groups, short) => `${$filter('humanReadablePlanName')(plan, groups, short)}`
// # /**
// Retrieve the machine from its ID * Retrieve the machine from its ID
// @param machine_id {number} machine identifier * @param machine_id {number} machine identifier
// @returns {Object} Machine * @returns {Object} Machine
// # */
$scope.getMachine = function (machine_id) { $scope.getMachine = function (machine_id) {
for (let machine of Array.from($scope.machines)) { for (let machine of Array.from($scope.machines)) {
if (machine.id === machine_id) { if (machine.id === machine_id) {
@ -265,11 +265,11 @@ Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'p
} }
} }
// # /**
// Retrieve the space from its ID * Retrieve the space from its ID
// @param space_id {number} space identifier * @param space_id {number} space identifier
// @returns {Object} Space * @returns {Object} Space
// # */
$scope.getSpace = function (space_id) { $scope.getSpace = function (space_id) {
for (let space of Array.from($scope.spaces)) { for (let space of Array.from($scope.spaces)) {
if (space.id === space_id) { if (space.id === space_id) {
@ -280,14 +280,14 @@ Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'p
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = () => const initialize = () =>
// Using the PlansController // Using the PlansController
new PlanController($scope, groups, prices, partners, CSRF) new PlanController($scope, groups, prices, partners, CSRF)
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])

View File

@ -15,66 +15,66 @@
*/ */
'use strict' 'use strict'
// # /**
// Controller used in the prices edition page * Controller used in the prices edition page
// # */
Application.Controllers.controller('EditPricingController', ['$scope', '$state', '$uibModal', '$filter', 'TrainingsPricing', 'Credit', 'Pricing', 'Plan', 'Coupon', 'plans', 'groups', 'growl', 'machinesPricesPromise', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', 'couponsPromise', 'spacesPromise', 'spacesPricesPromise', 'spacesCreditsPromise', '_t', Application.Controllers.controller('EditPricingController', ['$scope', '$state', '$uibModal', '$filter', 'TrainingsPricing', 'Credit', 'Pricing', 'Plan', 'Coupon', 'plans', 'groups', 'growl', 'machinesPricesPromise', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', 'couponsPromise', 'spacesPromise', 'spacesPricesPromise', 'spacesCreditsPromise', '_t',
function ($scope, $state, $uibModal, $filter, TrainingsPricing, Credit, Pricing, Plan, Coupon, plans, groups, growl, machinesPricesPromise, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, couponsPromise, spacesPromise, spacesPricesPromise, spacesCreditsPromise, _t) { function ($scope, $state, $uibModal, $filter, TrainingsPricing, Credit, Pricing, Plan, Coupon, plans, groups, growl, machinesPricesPromise, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, couponsPromise, spacesPromise, spacesPricesPromise, spacesCreditsPromise, _t) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # List of machines prices (not considering any plan) // List of machines prices (not considering any plan)
$scope.machinesPrices = machinesPricesPromise $scope.machinesPrices = machinesPricesPromise
// # List of trainings pricing // List of trainings pricing
$scope.trainingsPricings = trainingsPricingsPromise $scope.trainingsPricings = trainingsPricingsPromise
// # List of available subscriptions plans (eg. student/month, PME/year ...) // List of available subscriptions plans (eg. student/month, PME/year ...)
$scope.plans = plans $scope.plans = plans
$scope.enabledPlans = plans.filter(p => !p.disabled) $scope.enabledPlans = plans.filter(p => !p.disabled)
// # List of groups (eg. normal, student ...) // List of groups (eg. normal, student ...)
$scope.groups = groups.filter(g => g.slug !== 'admins') $scope.groups = groups.filter(g => g.slug !== 'admins')
$scope.enabledGroups = groups.filter(g => (g.slug !== 'admins') && !g.disabled) $scope.enabledGroups = groups.filter(g => (g.slug !== 'admins') && !g.disabled)
// # Associate free machine hours with subscriptions // Associate free machine hours with subscriptions
$scope.machineCredits = machineCreditsPromise $scope.machineCredits = machineCreditsPromise
// # Array of associations (plan <-> training) // Array of associations (plan <-> training)
$scope.trainingCredits = trainingCreditsPromise $scope.trainingCredits = trainingCreditsPromise
// # Associate a plan with all its trainings ids // Associate a plan with all its trainings ids
$scope.trainingCreditsGroups = {} $scope.trainingCreditsGroups = {}
// # List of trainings // List of trainings
$scope.trainings = trainingsPromise.filter(t => !t.disabled) $scope.trainings = trainingsPromise.filter(t => !t.disabled)
// # List of machines // List of machines
$scope.machines = machinesPromise $scope.machines = machinesPromise
$scope.enabledMachines = machinesPromise.filter(m => !m.disabled) $scope.enabledMachines = machinesPromise.filter(m => !m.disabled)
// # List of coupons // List of coupons
$scope.coupons = couponsPromise $scope.coupons = couponsPromise
// # List of spaces // List of spaces
$scope.spaces = spacesPromise $scope.spaces = spacesPromise
$scope.enabledSpaces = spacesPromise.filter(s => !s.disabled) $scope.enabledSpaces = spacesPromise.filter(s => !s.disabled)
// # Associate free space hours with subscriptions // Associate free space hours with subscriptions
$scope.spaceCredits = spacesCreditsPromise $scope.spaceCredits = spacesCreditsPromise
// # List of spaces prices (not considering any plan) // List of spaces prices (not considering any plan)
$scope.spacesPrices = spacesPricesPromise $scope.spacesPrices = spacesPricesPromise
// # The plans list ordering. Default: by group // The plans list ordering. Default: by group
$scope.orderPlans = 'group_id' $scope.orderPlans = 'group_id'
// # Status of the drop-down menu in Credits tab // Status of the drop-down menu in Credits tab
$scope.status = $scope.status =
{ isopen: false } { isopen: false }
// # Default: we show only enabled plans // Default: we show only enabled plans
$scope.planFiltering = 'enabled' $scope.planFiltering = 'enabled'
// # Available options for filtering plans by status // Available options for filtering plans by status
$scope.filterDisabled = [ $scope.filterDisabled = [
'enabled', 'enabled',
'disabled', 'disabled',
@ -97,11 +97,11 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Retrieve a plan from its given identifier and returns it * Retrieve a plan from its given identifier and returns it
// @param id {number} plan ID * @param id {number} plan ID
// @returns {Object} Plan, inherits from $resource * @returns {Object} Plan, inherits from $resource
// # */
$scope.getPlanFromId = function (id) { $scope.getPlanFromId = function (id) {
for (let plan of Array.from($scope.plans)) { for (let plan of Array.from($scope.plans)) {
if (plan.id === parseInt(id)) { if (plan.id === parseInt(id)) {
@ -110,11 +110,11 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Retrieve a group from its given identifier and returns it * Retrieve a group from its given identifier and returns it
// @param id {number} group ID * @param id {number} group ID
// @returns {Object} Group, inherits from $resource * @returns {Object} Group, inherits from $resource
// # */
$scope.getGroupFromId = function (groups, id) { $scope.getGroupFromId = function (groups, id) {
for (let group of Array.from(groups)) { for (let group of Array.from(groups)) {
if (group.id === parseInt(id)) { if (group.id === parseInt(id)) {
@ -123,12 +123,12 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Returns a human readable string of named trainings, according to the provided array. * Returns a human readable string of named trainings, according to the provided array.
// $scope.trainings may contains the full list of training. The returned string will only contains the trainings * $scope.trainings may contains the full list of training. The returned string will only contains the trainings
// whom ID are given in the provided parameter * whom ID are given in the provided parameter
// @param trainings {Array<number>} trainings IDs array * @param trainings {Array<number>} trainings IDs array
// # */
$scope.showTrainings = function (trainings) { $scope.showTrainings = function (trainings) {
if (!angular.isArray(trainings) || !(trainings.length > 0)) { if (!angular.isArray(trainings) || !(trainings.length > 0)) {
return _t('pricing.none') return _t('pricing.none')
@ -143,11 +143,11 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
if (selected.length) { return selected.join(' | ') } else { return _t('pricing.none') } if (selected.length) { return selected.join(' | ') } else { return _t('pricing.none') }
} }
// # /**
// Validation callback when editing training's credits. Save the changes. * Validation callback when editing training's credits. Save the changes.
// @param newdata {Object} training and associated plans * @param newdata {Object} training and associated plans
// @param planId {number|string} plan id * @param planId {number|string} plan id
// # */
$scope.saveTrainingCredits = function (newdata, planId) { $scope.saveTrainingCredits = function (newdata, planId) {
// save the number of credits // save the number of credits
Plan.update({ id: planId }, Plan.update({ id: planId },
@ -202,16 +202,16 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
}) })
} }
// # /**
// Cancel the current training credit modification * Cancel the current training credit modification
// @param rowform {Object} see http://vitalets.github.io/angular-xeditable/ * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/
// # */
$scope.cancelTrainingCredit = rowform => rowform.$cancel() $scope.cancelTrainingCredit = rowform => rowform.$cancel()
// # /**
// Create a new empty entry in the $scope.machineCredits array * Create a new empty entry in the $scope.machineCredits array
// @param e {Object} see https://docs.angularjs.org/guide/expression#-event- * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
$scope.addMachineCredit = function (e) { $scope.addMachineCredit = function (e) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
@ -221,11 +221,11 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
return $scope.status.isopen = !$scope.status.isopen return $scope.status.isopen = !$scope.status.isopen
} }
// # /**
// In the Credits tab, return the name of the machine/space associated with the given credit * In the Credits tab, return the name of the machine/space associated with the given credit
// @param credit {Object} credit object, inherited from $resource * @param credit {Object} credit object, inherited from $resource
// @returns {String} * @returns {String}
// # */
$scope.showCreditableName = function (credit) { $scope.showCreditableName = function (credit) {
let selected = _t('pricing.not_set') let selected = _t('pricing.not_set')
if (credit && credit.creditable_id) { if (credit && credit.creditable_id) {
@ -238,11 +238,11 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
return selected return selected
} }
// # /**
// In the Credits tab, return the machine/space associated with the given credit * In the Credits tab, return the machine/space associated with the given credit
// @param credit {Object} credit object, inherited from $resource * @param credit {Object} credit object, inherited from $resource
// @returns {Object} * @returns {Object}
// # */
$scope.getCreditable = function (credit) { $scope.getCreditable = function (credit) {
let selected let selected
if (credit && credit.creditable_id) { if (credit && credit.creditable_id) {
@ -263,12 +263,12 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
return selected return selected
} }
// # /**
// Validation callback when editing machine's credits. Save the changes. * Validation callback when editing machine's credits. Save the changes.
// This will prevent the creation of two credits associating the same machine and plan. * This will prevent the creation of two credits associating the same machine and plan.
// @param data {Object} machine, associated plan and number of credit hours. * @param data {Object} machine, associated plan and number of credit hours.
// @param [id] {number} credit id for edition, create a new credit object if not provided * @param [id] {number} credit id for edition, create a new credit object if not provided
// # */
$scope.saveMachineCredit = function (data, id) { $scope.saveMachineCredit = function (data, id) {
for (let mc of Array.from($scope.machineCredits)) { for (let mc of Array.from($scope.machineCredits)) {
if ((mc.plan_id === data.plan_id) && (mc.creditable_id === data.creditable_id) && ((id === null) || (mc.id !== id))) { if ((mc.plan_id === data.plan_id) && (mc.creditable_id === data.creditable_id) && ((id === null) || (mc.id !== id))) {
@ -297,11 +297,11 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Removes the newly inserted but not saved machine credit / Cancel the current machine credit modification * Removes the newly inserted but not saved machine credit / Cancel the current machine credit modification
// @param rowform {Object} see http://vitalets.github.io/angular-xeditable/ * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/
// @param index {number} credit index in the $scope.machineCredits array * @param index {number} credit index in the $scope.machineCredits array
// # */
$scope.cancelMachineCredit = function (rowform, index) { $scope.cancelMachineCredit = function (rowform, index) {
if ($scope.machineCredits[index].id != null) { if ($scope.machineCredits[index].id != null) {
return rowform.$cancel() return rowform.$cancel()
@ -310,19 +310,19 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Deletes the machine credit at the specified index * Deletes the machine credit at the specified index
// @param index {number} machine credit index in the $scope.machineCredits array * @param index {number} machine credit index in the $scope.machineCredits array
// # */
$scope.removeMachineCredit = function (index) { $scope.removeMachineCredit = function (index) {
Credit.delete($scope.machineCredits[index]) Credit.delete($scope.machineCredits[index])
return $scope.machineCredits.splice(index, 1) return $scope.machineCredits.splice(index, 1)
} }
// # /**
// Create a new empty entry in the $scope.spaceCredits array * Create a new empty entry in the $scope.spaceCredits array
// @param e {Object} see https://docs.angularjs.org/guide/expression#-event- * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
$scope.addSpaceCredit = function (e) { $scope.addSpaceCredit = function (e) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
@ -332,12 +332,12 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
return $scope.status.isopen = !$scope.status.isopen return $scope.status.isopen = !$scope.status.isopen
} }
// # /**
// Validation callback when editing space's credits. Save the changes. * Validation callback when editing space's credits. Save the changes.
// This will prevent the creation of two credits associated with the same space and plan. * This will prevent the creation of two credits associated with the same space and plan.
// @param data {Object} space, associated plan and number of credit hours. * @param data {Object} space, associated plan and number of credit hours.
// @param [id] {number} credit id for edition, create a new credit object if not provided * @param [id] {number} credit id for edition, create a new credit object if not provided
// # */
$scope.saveSpaceCredit = function (data, id) { $scope.saveSpaceCredit = function (data, id) {
for (let sc of Array.from($scope.spaceCredits)) { for (let sc of Array.from($scope.spaceCredits)) {
if ((sc.plan_id === data.plan_id) && (sc.creditable_id === data.creditable_id) && ((id === null) || (sc.id !== id))) { if ((sc.plan_id === data.plan_id) && (sc.creditable_id === data.creditable_id) && ((id === null) || (sc.id !== id))) {
@ -366,11 +366,11 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Removes the newly inserted but not saved space credit / Cancel the current space credit modification * Removes the newly inserted but not saved space credit / Cancel the current space credit modification
// @param rowform {Object} see http://vitalets.github.io/angular-xeditable/ * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/
// @param index {number} credit index in the $scope.spaceCredits array * @param index {number} credit index in the $scope.spaceCredits array
// # */
$scope.cancelSpaceCredit = function (rowform, index) { $scope.cancelSpaceCredit = function (rowform, index) {
if ($scope.spaceCredits[index].id != null) { if ($scope.spaceCredits[index].id != null) {
return rowform.$cancel() return rowform.$cancel()
@ -379,30 +379,30 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Deletes the space credit at the specified index * Deletes the space credit at the specified index
// @param index {number} space credit index in the $scope.spaceCredits array * @param index {number} space credit index in the $scope.spaceCredits array
// # */
$scope.removeSpaceCredit = function (index) { $scope.removeSpaceCredit = function (index) {
Credit.delete($scope.spaceCredits[index]) Credit.delete($scope.spaceCredits[index])
return $scope.spaceCredits.splice(index, 1) return $scope.spaceCredits.splice(index, 1)
} }
// # /**
// If the plan does not have a type, return a default value for display purposes * If the plan does not have a type, return a default value for display purposes
// @param type {string|undefined|null} plan's type (eg. 'partner') * @param type {string|undefined|null} plan's type (eg. 'partner')
// @returns {string} * @returns {string}
// # */
$scope.getPlanType = function (type) { $scope.getPlanType = function (type) {
if (type === 'PartnerPlan') { if (type === 'PartnerPlan') {
return _t('pricing.partner') return _t('pricing.partner')
} else { return _t('pricing.standard') } } else { return _t('pricing.standard') }
} }
// # /**
// Change the plans ordering criterion to the one provided * Change the plans ordering criterion to the one provided
// @param orderBy {string} ordering criterion * @param orderBy {string} ordering criterion
// # */
$scope.setOrderPlans = function (orderBy) { $scope.setOrderPlans = function (orderBy) {
if ($scope.orderPlans === orderBy) { if ($scope.orderPlans === orderBy) {
return $scope.orderPlans = `-${orderBy}` return $scope.orderPlans = `-${orderBy}`
@ -411,9 +411,9 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Retrieve a price from prices array by a machineId and a groupId * Retrieve a price from prices array by a machineId and a groupId
// # */
$scope.findPriceBy = function (prices, machineId, groupId) { $scope.findPriceBy = function (prices, machineId, groupId) {
for (let price of Array.from(prices)) { for (let price of Array.from(prices)) {
if ((price.priceable_id === machineId) && (price.group_id === groupId)) { if ((price.priceable_id === machineId) && (price.group_id === groupId)) {
@ -422,9 +422,9 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// update a price for a machine and a group, not considering any plan * update a price for a machine and a group, not considering any plan
// # */
$scope.updatePrice = function (data, price) { $scope.updatePrice = function (data, price) {
if (data != null) { if (data != null) {
return Price.update({ id: price.id }, { price: { amount: data } }).$promise return Price.update({ id: price.id }, { price: { amount: data } }).$promise
@ -433,10 +433,10 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Delete the specified subcription plan * Delete the specified subcription plan
// @param id {number} plan id * @param id {number} plan id
// # */
$scope.deletePlan = function (plans, id) { $scope.deletePlan = function (plans, id) {
if (typeof id !== 'number') { if (typeof id !== 'number') {
return console.error('[EditPricingController::deletePlan] Error: invalid id parameter') return console.error('[EditPricingController::deletePlan] Error: invalid id parameter')
@ -467,21 +467,21 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Generate a string identifying the given plan by literal humain-readable name * Generate a string identifying the given plan by literal humain-readable name
// @param plan {Object} Plan object, as recovered from GET /api/plan/:id * @param plan {Object} Plan object, as recovered from GET /api/plan/:id
// @param groups {Array} List of Groups objects, as recovered from GET /api/groups * @param groups {Array} List of Groups objects, as recovered from GET /api/groups
// @param short {boolean} If true, the generated name will contains the group slug, otherwise the group full name * @param short {boolean} If true, the generated name will contains the group slug, otherwise the group full name
// will be included. * will be included.
// @returns {String} * @returns {String}
// # */
$scope.humanReadablePlanName = (plan, groups, short) => `${$filter('humanReadablePlanName')(plan, groups, short)}` $scope.humanReadablePlanName = (plan, groups, short) => `${$filter('humanReadablePlanName')(plan, groups, short)}`
// # /**
// Delete a coupon from the server's database and, in case of success, from the list in memory * Delete a coupon from the server's database and, in case of success, from the list in memory
// @param coupons {Array<Object>} should be called with $scope.coupons * @param coupons {Array<Object>} should be called with $scope.coupons
// @param id {number} ID of the coupon to delete * @param id {number} ID of the coupon to delete
// # */
$scope.deleteCoupon = function (coupons, id) { $scope.deleteCoupon = function (coupons, id) {
if (typeof id !== 'number') { if (typeof id !== 'number') {
return console.error('[EditPricingController::deleteCoupon] Error: invalid id parameter') return console.error('[EditPricingController::deleteCoupon] Error: invalid id parameter')
@ -516,10 +516,10 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Open a modal allowing to select an user and send him the details of the provided coupon * Open a modal allowing to select an user and send him the details of the provided coupon
// @param coupon {Object} The coupon to send * @param coupon {Object} The coupon to send
// # */
$scope.sendCouponToUser = coupon => $scope.sendCouponToUser = coupon =>
$uibModal.open({ $uibModal.open({
templateUrl: '<%= asset_path "admin/pricing/sendCoupon.html" %>', templateUrl: '<%= asset_path "admin/pricing/sendCoupon.html" %>',
@ -528,14 +528,14 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
}, },
size: 'md', size: 'md',
controller: ['$scope', '$uibModalInstance', 'Coupon', 'coupon', '_t', function ($scope, $uibModalInstance, Coupon, coupon, _t) { controller: ['$scope', '$uibModalInstance', 'Coupon', 'coupon', '_t', function ($scope, $uibModalInstance, Coupon, coupon, _t) {
// # Member, receiver of the coupon // Member, receiver of the coupon
$scope.ctrl = $scope.ctrl =
{ member: null } { member: null }
// # Details of the coupon to send // Details of the coupon to send
$scope.coupon = coupon $scope.coupon = coupon
// # Callback to validate sending of the coupon // Callback to validate sending of the coupon
$scope.ok = () => $scope.ok = () =>
Coupon.send({ coupon_code: coupon.code, user_id: $scope.ctrl.member.id }, function (res) { Coupon.send({ coupon_code: coupon.code, user_id: $scope.ctrl.member.id }, function (res) {
growl.success(_t('pricing.coupon_successfully_sent_to_USER', { USER: $scope.ctrl.member.name })) growl.success(_t('pricing.coupon_successfully_sent_to_USER', { USER: $scope.ctrl.member.name }))
@ -543,20 +543,20 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
, err => growl.error(_t('pricing.an_error_occurred_unable_to_send_the_coupon'))) , err => growl.error(_t('pricing.an_error_occurred_unable_to_send_the_coupon')))
// # Callback to close the modal and cancel the sending process // Callback to close the modal and cancel the sending process
return $scope.cancel = () => $uibModalInstance.dismiss('cancel') return $scope.cancel = () => $uibModalInstance.dismiss('cancel')
} }
] }) ] })
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
$scope.trainingCreditsGroups = groupCreditsByPlan($scope.trainingCredits) $scope.trainingCreditsGroups = groupCreditsByPlan($scope.trainingCredits)
// # adds empty array for plan which hasn't any credits yet // adds empty array for plan which hasn't any credits yet
return (() => { return (() => {
const result = [] const result = []
for (let plan of Array.from($scope.plans)) { for (let plan of Array.from($scope.plans)) {
@ -570,19 +570,19 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
})() })()
} }
// # /**
// Retrieve an item index by its ID from the given array of objects * Retrieve an item index by its ID from the given array of objects
// @param items {Array<{id:number}>} * @param items {Array<{id:number}>}
// @param id {number} * @param id {number}
// @returns {number} item index in the provided array * @returns {number} item index in the provided array
// # */
var findItemIdxById = (items, id) => var findItemIdxById = (items, id) =>
(items.map(item => item.id)).indexOf(id) (items.map(item => item.id)).indexOf(id)
// # /**
// Group the given credits array into a map associating the plan ID with its associated trainings/machines * Group the given credits array into a map associating the plan ID with its associated trainings/machines
// @return {Object} the association map * @return {Object} the association map
// # */
var groupCreditsByPlan = function (credits) { var groupCreditsByPlan = function (credits) {
const creditsMap = {} const creditsMap = {}
angular.forEach(credits, function (c) { angular.forEach(credits, function (c) {
@ -594,11 +594,11 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
return creditsMap return creditsMap
} }
// # /**
// Iterate through $scope.traininfCredits to find the credit matching the given criterion * Iterate through $scope.traininfCredits to find the credit matching the given criterion
// @param trainingId {number|string} training ID * @param trainingId {number|string} training ID
// @param planId {number|string} plan ID * @param planId {number|string} plan ID
// # */
var findTrainingCredit = function (trainingId, planId) { var findTrainingCredit = function (trainingId, planId) {
trainingId = parseInt(trainingId) trainingId = parseInt(trainingId)
planId = parseInt(planId) planId = parseInt(planId)
@ -610,11 +610,11 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # /**
// Retrieve a training from its given identifier and returns it * Retrieve a training from its given identifier and returns it
// @param id {number} training ID * @param id {number} training ID
// @returns {Object} Training inherited from $resource * @returns {Object} Training inherited from $resource
// # */
var getTrainingFromId = function (id) { var getTrainingFromId = function (id) {
for (let training of Array.from($scope.trainings)) { for (let training of Array.from($scope.trainings)) {
if (training.id === parseInt(id)) { if (training.id === parseInt(id)) {
@ -623,7 +623,7 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
} }
} }
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])

View File

@ -19,70 +19,70 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
function ($scope, $state, $rootScope, $uibModal, es, Member, _t, membersPromise, statisticsPromise) { function ($scope, $state, $rootScope, $uibModal, es, Member, _t, membersPromise, statisticsPromise) {
/* PRIVATE STATIC CONSTANTS */ /* PRIVATE STATIC CONSTANTS */
// # search window size // search window size
const RESULTS_PER_PAGE = 20 const RESULTS_PER_PAGE = 20
// # keep search context for (delay in minutes) ... // keep search context for (delay in minutes) ...
const ES_SCROLL_TIME = 1 const ES_SCROLL_TIME = 1
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # ui-view transitions optimization: if true, the stats will never be refreshed // ui-view transitions optimization: if true, the stats will never be refreshed
$scope.preventRefresh = false $scope.preventRefresh = false
// # statistics structure in elasticSearch // statistics structure in elasticSearch
$scope.statistics = statisticsPromise $scope.statistics = statisticsPromise
// # fablab users list // fablab users list
$scope.members = membersPromise $scope.members = membersPromise
// # statistics data recovered from elasticSearch // statistics data recovered from elasticSearch
$scope.data = null $scope.data = null
// # when did the search was triggered // when did the search was triggered
$scope.searchDate = null $scope.searchDate = null
// # id of the elastic search context // id of the elastic search context
$scope.scrollId = null $scope.scrollId = null
// # total number of results for the current query // total number of results for the current query
$scope.totalHits = null $scope.totalHits = null
// # configuration of the widget allowing to pick the ages range // configuration of the widget allowing to pick the ages range
$scope.agePicker = { $scope.agePicker = {
show: false, show: false,
start: null, start: null,
end: null end: null
} }
// # total CA for the current view // total CA for the current view
$scope.sumCA = 0 $scope.sumCA = 0
// # average users' age for the current view // average users' age for the current view
$scope.averageAge = 0 $scope.averageAge = 0
// # total of the stat field for non simple types // total of the stat field for non simple types
$scope.sumStat = 0 $scope.sumStat = 0
// # Results of custom aggregations for the current type // Results of custom aggregations for the current type
$scope.customAggs = {} $scope.customAggs = {}
// # default: results are not sorted // default: results are not sorted
$scope.sorting = { $scope.sorting = {
ca: 'none', ca: 'none',
date: 'desc' date: 'desc'
} }
// # active tab will be set here // active tab will be set here
$scope.selectedIndex = null $scope.selectedIndex = null
// # type filter binding // type filter binding
$scope.type = { $scope.type = {
selected: null, selected: null,
active: null active: null
} }
// # selected custom filter // selected custom filter
$scope.customFilter = { $scope.customFilter = {
show: false, show: false,
criterion: {}, criterion: {},
@ -99,14 +99,14 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
} // France: the week starts on monday } // France: the week starts on monday
} }
// # available custom filters // available custom filters
$scope.filters = [] $scope.filters = []
// # default: we do not open the datepicker menu // default: we do not open the datepicker menu
$scope.datePicker = $scope.datePicker =
{ show: false } { show: false }
// # datePicker parameters for interval beginning // datePicker parameters for interval beginning
$scope.datePickerStart = { $scope.datePickerStart = {
format: Fablab.uibDateFormat, format: Fablab.uibDateFormat,
opened: false, // default: datePicker is not shown opened: false, // default: datePicker is not shown
@ -118,7 +118,7 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
} }
} }
// # datePicker parameters for interval ending // datePicker parameters for interval ending
$scope.datePickerEnd = { $scope.datePickerEnd = {
format: Fablab.uibDateFormat, format: Fablab.uibDateFormat,
opened: false, // default: datePicker is not shown opened: false, // default: datePicker is not shown
@ -130,29 +130,29 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
} }
} }
// # /**
// Callback to open the datepicker (interval start) * Callback to open the datepicker (interval start)
// @param $event {Object} jQuery event object * @param $event {Object} jQuery event object
// # */
$scope.toggleStartDatePicker = $event => toggleDatePicker($event, $scope.datePickerStart) $scope.toggleStartDatePicker = $event => toggleDatePicker($event, $scope.datePickerStart)
// # /**
// Callback to open the datepicker (interval end) * Callback to open the datepicker (interval end)
// @param $event {Object} jQuery event object * @param $event {Object} jQuery event object
// # */
$scope.toggleEndDatePicker = $event => toggleDatePicker($event, $scope.datePickerEnd) $scope.toggleEndDatePicker = $event => toggleDatePicker($event, $scope.datePickerEnd)
// # /**
// Callback to open the datepicker (custom filter) * Callback to open the datepicker (custom filter)
// @param $event {Object} jQuery event object * @param $event {Object} jQuery event object
// # */
$scope.toggleCustomDatePicker = $event => toggleDatePicker($event, $scope.customFilter.datePicker) $scope.toggleCustomDatePicker = $event => toggleDatePicker($event, $scope.customFilter.datePicker)
// # /**
// Callback called when the active tab is changed. * Callback called when the active tab is changed.
// recover the current tab and store its value in $scope.selectedIndex * recover the current tab and store its value in $scope.selectedIndex
// @param tab {Object} elasticsearch statistic structure (from statistic_indices table) * @param tab {Object} elasticsearch statistic structure (from statistic_indices table)
// # */
$scope.setActiveTab = function (tab) { $scope.setActiveTab = function (tab) {
$scope.selectedIndex = tab $scope.selectedIndex = tab
$scope.type.selected = tab.types[0] $scope.type.selected = tab.types[0]
@ -166,10 +166,10 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
return refreshStats() return refreshStats()
} }
// # /**
// Returns true if the provided tab must be hidden due to some global or local configuration * Returns true if the provided tab must be hidden due to some global or local configuration
// @param tab {Object} elasticsearch statistic structure (from statistic_indices table) * @param tab {Object} elasticsearch statistic structure (from statistic_indices table)
// # */
$scope.hiddenTab = function (tab) { $scope.hiddenTab = function (tab) {
if (tab.table) { if (tab.table) {
if ((tab.es_type_key === 'subscription') && $rootScope.fablabWithoutPlans) { if ((tab.es_type_key === 'subscription') && $rootScope.fablabWithoutPlans) {
@ -184,9 +184,9 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
} }
} }
// # /**
// Callback to validate the filters and send a new request to elastic * Callback to validate the filters and send a new request to elastic
// # */
$scope.validateFilterChange = function () { $scope.validateFilterChange = function () {
$scope.agePicker.show = false $scope.agePicker.show = false
$scope.customFilter.show = false $scope.customFilter.show = false
@ -195,24 +195,24 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
return refreshStats() return refreshStats()
} }
// # /**
// Callback to validate the dates range and refresh the data from elastic * Callback to validate the dates range and refresh the data from elastic
// # */
$scope.validateDateChange = function () { $scope.validateDateChange = function () {
$scope.datePicker.show = false $scope.datePicker.show = false
return refreshStats() return refreshStats()
} }
// # /**
// Parse the given date and return a user-friendly string * Parse the given date and return a user-friendly string
// @param date {Date} JS date or ant moment.js compatible date string * @param date {Date} JS date or ant moment.js compatible date string
// # */
$scope.formatDate = date => moment(date).format('LL') $scope.formatDate = date => moment(date).format('LL')
// # /**
// Parse the sex and return a user-friendly string * Parse the sex and return a user-friendly string
// @param sex {string} 'male' | 'female' * @param sex {string} 'male' | 'female'
// # */
$scope.formatSex = function (sex) { $scope.formatSex = function (sex) {
if (sex === 'male') { if (sex === 'male') {
return _t('man') return _t('man')
@ -222,10 +222,10 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
} }
} }
// # /**
// Retrieve the label for the given subtype in the current type * Retrieve the label for the given subtype in the current type
// @param key {string} statistic subtype key * @param key {string} statistic subtype key
// # */
$scope.formatSubtype = function (key) { $scope.formatSubtype = function (key) {
let label = '' let label = ''
angular.forEach($scope.type.active.subtypes, function (subtype) { angular.forEach($scope.type.active.subtypes, function (subtype) {
@ -236,10 +236,10 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
return label return label
} }
// # /**
// Helper usable in ng-switch to determine the input type to display for custom filter value * Helper usable in ng-switch to determine the input type to display for custom filter value
// @param filter {Object} custom filter criterion * @param filter {Object} custom filter criterion
// # */
$scope.getCustomValueInputType = function (filter) { $scope.getCustomValueInputType = function (filter) {
if (filter && filter.values) { if (filter && filter.values) {
if (typeof (filter.values[0]) === 'string') { if (typeof (filter.values[0]) === 'string') {
@ -252,10 +252,10 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
} }
} }
// # /**
// Change the sorting order and refresh the results to match the new order * Change the sorting order and refresh the results to match the new order
// @param filter {Object} any filter * @param filter {Object} any filter
// # */
$scope.toggleSorting = function (filter) { $scope.toggleSorting = function (filter) {
switch ($scope.sorting[filter]) { switch ($scope.sorting[filter]) {
case 'none': $scope.sorting[filter] = 'asc'; break case 'none': $scope.sorting[filter] = 'asc'; break
@ -265,19 +265,19 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
return refreshStats() return refreshStats()
} }
// # /**
// Return the user's name from his given ID * Return the user's name from his given ID
// @param id {number} user ID * @param id {number} user ID
// # */
$scope.getUserNameFromId = function (id) { $scope.getUserNameFromId = function (id) {
const name = $scope.members[id] const name = $scope.members[id]
return (name || `ID ${id}`) return (name || `ID ${id}`)
} }
// # /**
// Run a scroll query to elasticsearch to append the next packet of results to those displayed. * Run a scroll query to elasticsearch to append the next packet of results to those displayed.
// If the ES search context has expired when the user ask for more results, we re-run the whole query. * If the ES search context has expired when the user ask for more results, we re-run the whole query.
// # */
$scope.showMoreResults = function () { $scope.showMoreResults = function () {
// if all results were retrieved, do nothing // if all results were retrieved, do nothing
if ($scope.data.length >= $scope.totalHits) { if ($scope.data.length >= $scope.totalHits) {
@ -303,9 +303,9 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
} }
} }
// # /**
// Open a modal dialog asking the user for details about exporting the statistics tables to an excel file * Open a modal dialog asking the user for details about exporting the statistics tables to an excel file
// # */
$scope.exportToExcel = function () { $scope.exportToExcel = function () {
const options = { const options = {
templateUrl: '<%= asset_path "admin/statistics/export.html" %>', templateUrl: '<%= asset_path "admin/statistics/export.html" %>',
@ -337,9 +337,9 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = () => const initialize = () =>
// workaround for angular-bootstrap::tabs behavior: on tab deletion, another tab will be selected // workaround for angular-bootstrap::tabs behavior: on tab deletion, another tab will be selected
// which will cause every tabs to reload, one by one, when the view is closed // which will cause every tabs to reload, one by one, when the view is closed
@ -349,20 +349,20 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
} }
}) })
// # /**
// Generic function to toggle a bootstrap datePicker * Generic function to toggle a bootstrap datePicker
// @param $event {Object} jQuery event object * @param $event {Object} jQuery event object
// @param datePicker {Object} settings object of the concerned datepicker. Must have an 'opened' property * @param datePicker {Object} settings object of the concerned datepicker. Must have an 'opened' property
// # */
var toggleDatePicker = function ($event, datePicker) { var toggleDatePicker = function ($event, datePicker) {
$event.preventDefault() $event.preventDefault()
$event.stopPropagation() $event.stopPropagation()
return datePicker.opened = !datePicker.opened return datePicker.opened = !datePicker.opened
} }
// # /**
// Force update the statistics table, querying elasticSearch according to the current config values * Force update the statistics table, querying elasticSearch according to the current config values
// # */
var refreshStats = function () { var refreshStats = function () {
if ($scope.selectedIndex && !$scope.preventRefresh) { if ($scope.selectedIndex && !$scope.preventRefresh) {
$scope.data = [] $scope.data = []
@ -395,14 +395,14 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
} }
} }
// # /**
// Run the elasticSearch query to retreive the /stats/type aggregations * Run the elasticSearch query to retreive the /stats/type aggregations
// @param index {String} elasticSearch document type (account|event|machine|project|subscription|training) * @param index {String} elasticSearch document type (account|event|machine|project|subscription|training)
// @param type {String} statistics type (month|year|booking|hour|user|project) * @param type {String} statistics type (month|year|booking|hour|user|project)
// @param custom {{key:{string}, value:{string}}|null} custom filter property or null to disable this filter * @param custom {{key:{string}, value:{string}}|null} custom filter property or null to disable this filter
// @param callback {function} function be to run after results were retrieved, it will receive * @param callback {function} function be to run after results were retrieved, it will receive
// two parameters : results {Object}, error {String} (if any) * two parameters : results {Object}, error {String} (if any)
// # */
var queryElasticStats = function (index, type, custom, callback) { var queryElasticStats = function (index, type, custom, callback) {
// handle invalid callback // handle invalid callback
if (typeof (callback) !== 'function') { if (typeof (callback) !== 'function') {
@ -431,17 +431,17 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
}) })
} }
// # /**
// Build an object representing the content of the REST-JSON query to elasticSearch, * Build an object representing the content of the REST-JSON query to elasticSearch,
// based on the provided parameters for row data recovering. * based on the provided parameters for row data recovering.
// @param type {String} statistics type (month|year|booking|hour|user|project) * @param type {String} statistics type (month|year|booking|hour|user|project)
// @param custom {{key:{string}, value:{string}}|null} custom filter property or null to disable this filter * @param custom {{key:{string}, value:{string}}|null} custom filter property or null to disable this filter
// @param ageMin {Number|null} filter by age: range lower value OR null to do not filter * @param ageMin {Number|null} filter by age: range lower value OR null to do not filter
// @param ageMax {Number|null} filter by age: range higher value OR null to do not filter * @param ageMax {Number|null} filter by age: range higher value OR null to do not filter
// @param intervalBegin {moment} statitics interval beginning (moment.js type) * @param intervalBegin {moment} statitics interval beginning (moment.js type)
// @param intervalEnd {moment} statitics interval ending (moment.js type) * @param intervalEnd {moment} statitics interval ending (moment.js type)
// @param sortings {Array|null} elasticSearch criteria for sorting the results * @param sortings {Array|null} elasticSearch criteria for sorting the results
// # */
var buildElasticDataQuery = function (type, custom, ageMin, ageMax, intervalBegin, intervalEnd, sortings) { var buildElasticDataQuery = function (type, custom, ageMin, ageMax, intervalBegin, intervalEnd, sortings) {
const q = { const q = {
'query': { 'query': {
@ -512,11 +512,11 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
return q return q
} }
// # /**
// Build the elasticSearch query DSL to match the selected cutom filter * Build the elasticSearch query DSL to match the selected cutom filter
// @param custom {Object} if custom is empty or undefined, an empty string will be returned * @param custom {Object} if custom is empty or undefined, an empty string will be returned
// @returns {{match:{*}}|string} * @returns {{match:{*}}|string}
// # */
var buildElasticCustomCriterion = function (custom) { var buildElasticCustomCriterion = function (custom) {
if (custom) { if (custom) {
const criterion = { const criterion = {
@ -534,10 +534,10 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
} }
} }
// # /**
// Parse the provided criteria array and return the corresponding elasticSearch syntax * Parse the provided criteria array and return the corresponding elasticSearch syntax
// @param criteria {Array} array of {key_to_sort:order} * @param criteria {Array} array of {key_to_sort:order}
// # */
var buildElasticSortCriteria = function (criteria) { var buildElasticSortCriteria = function (criteria) {
const crits = [] const crits = []
angular.forEach(criteria, function (value, key) { angular.forEach(criteria, function (value, key) {
@ -550,10 +550,10 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
return crits return crits
} }
// # /**
// Fullfil the list of available options in the custom filter panel. The list will be based on common * Fullfil the list of available options in the custom filter panel. The list will be based on common
// properties and on index-specific properties (additional_fields) * properties and on index-specific properties (additional_fields)
// # */
var buildCustomFiltersList = function () { var buildCustomFiltersList = function () {
$scope.filters = [] $scope.filters = []
@ -587,10 +587,10 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
}) })
} }
// # /**
// Build and return an object according to the custom filter set by the user, used to request elasticsearch * Build and return an object according to the custom filter set by the user, used to request elasticsearch
// @return {Object|null} * @return {Object|null}
// # */
var buildCustomFilterQuery = function () { var buildCustomFilterQuery = function () {
let custom = null let custom = null
if (!angular.isUndefinedOrNull($scope.customFilter.criterion) && if (!angular.isUndefinedOrNull($scope.customFilter.criterion) &&
@ -612,32 +612,32 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
Application.Controllers.controller('ExportStatisticsController', [ '$scope', '$uibModalInstance', 'Export', 'dates', 'query', 'index', 'type', 'CSRF', 'growl', '_t', Application.Controllers.controller('ExportStatisticsController', [ '$scope', '$uibModalInstance', 'Export', 'dates', 'query', 'index', 'type', 'CSRF', 'growl', '_t',
function ($scope, $uibModalInstance, Export, dates, query, index, type, CSRF, growl, _t) { function ($scope, $uibModalInstance, Export, dates, query, index, type, CSRF, growl, _t) {
// # Retrieve Anti-CSRF tokens from cookies // Retrieve Anti-CSRF tokens from cookies
CSRF.setMetaTags() CSRF.setMetaTags()
// # Bindings for date range // Bindings for date range
$scope.dates = dates $scope.dates = dates
// # Body of the query to export // Body of the query to export
$scope.query = JSON.stringify(query) $scope.query = JSON.stringify(query)
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = `/stats/${index.key}/export` $scope.actionUrl = `/stats/${index.key}/export`
// # Key of the current search' statistic type // Key of the current search' statistic type
$scope.typeKey = type.key $scope.typeKey = type.key
// # Form action on the above URL // Form action on the above URL
$scope.method = 'post' $scope.method = 'post'
// # Anti-CSRF token to inject into the download form // Anti-CSRF token to inject into the download form
$scope.csrfToken = angular.element('meta[name="csrf-token"]')[0].content $scope.csrfToken = angular.element('meta[name="csrf-token"]')[0].content
// # Binding of the export type (global / current) // Binding of the export type (global / current)
$scope.export = $scope.export =
{ type: 'current' } { type: 'current' }
// # datePicker parameters for interval beginning // datePicker parameters for interval beginning
$scope.exportStart = { $scope.exportStart = {
format: Fablab.uibDateFormat, format: Fablab.uibDateFormat,
opened: false, // default: datePicker is not shown opened: false, // default: datePicker is not shown
@ -648,7 +648,7 @@ Application.Controllers.controller('ExportStatisticsController', [ '$scope', '$u
} }
} }
// # datePicker parameters for interval ending // datePicker parameters for interval ending
$scope.exportEnd = { $scope.exportEnd = {
format: Fablab.uibDateFormat, format: Fablab.uibDateFormat,
opened: false, // default: datePicker is not shown opened: false, // default: datePicker is not shown
@ -659,22 +659,22 @@ Application.Controllers.controller('ExportStatisticsController', [ '$scope', '$u
} }
} }
// # /**
// Callback to open the datepicker (interval start) * Callback to open the datepicker (interval start)
// @param $event {Object} jQuery event object * @param $event {Object} jQuery event object
// # */
$scope.toggleStartDatePicker = $event => $scope.exportStart.opened = !$scope.exportStart.opened $scope.toggleStartDatePicker = $event => $scope.exportStart.opened = !$scope.exportStart.opened
// # /**
// Callback to open the datepicker (interval end) * Callback to open the datepicker (interval end)
// @param $event {Object} jQuery event object * @param $event {Object} jQuery event object
// # */
$scope.toggleEndDatePicker = $event => $scope.exportEnd.opened = !$scope.exportEnd.opened $scope.toggleEndDatePicker = $event => $scope.exportEnd.opened = !$scope.exportEnd.opened
// # /**
// Callback when exchanging the export type between 'global' and 'current view' * Callback when exchanging the export type between 'global' and 'current view'
// Adjust the query and the requesting url according to this type. * Adjust the query and the requesting url according to this type.
// # */
$scope.setRequest = function () { $scope.setRequest = function () {
if ($scope.export.type === 'global') { if ($scope.export.type === 'global') {
$scope.actionUrl = '/stats/global/export' $scope.actionUrl = '/stats/global/export'
@ -700,9 +700,9 @@ Application.Controllers.controller('ExportStatisticsController', [ '$scope', '$u
} }
} }
// # /**
// Callback to close the modal, telling the caller what is exported * Callback to close the modal, telling the caller what is exported
// # */
$scope.exportData = function () { $scope.exportData = function () {
const statusQry = { category: 'statistics', type: $scope.export.type, query: $scope.query } const statusQry = { category: 'statistics', type: $scope.export.type, query: $scope.query }
if ($scope.export.type !== 'global') { if ($scope.export.type !== 'global') {
@ -719,9 +719,9 @@ Application.Controllers.controller('ExportStatisticsController', [ '$scope', '$u
return $uibModalInstance.close(statusQry) return $uibModalInstance.close(statusQry)
} }
// # /**
// Callback to cancel the export and close the modal * Callback to cancel the export and close the modal
// # */
return $scope.cancel = () => $uibModalInstance.dismiss('cancel') return $scope.cancel = () => $uibModalInstance.dismiss('cancel')
} }
]) ])

View File

@ -16,27 +16,27 @@
/* COMMON CODE */ /* COMMON CODE */
// # /**
// Provides a set of common callback methods to the $scope parameter. These methods are used * Provides a set of common callback methods to the $scope parameter. These methods are used
// in the various trainings' admin controllers. * in the various trainings' admin controllers.
// *
// Provides : * Provides :
// - $scope.submited(content) * - $scope.submited(content)
// - $scope.fileinputClass(v) * - $scope.fileinputClass(v)
// - $scope.onDisableToggled * - $scope.onDisableToggled
// *
// Requires : * Requires :
// - $state (Ui-Router) [ 'app.admin.trainings' ] * - $state (Ui-Router) [ 'app.admin.trainings' ]
// - $scope.training * - $scope.training
// # /*
class TrainingsController { class TrainingsController {
constructor ($scope, $state) { constructor ($scope, $state) {
// # /*
// For use with ngUpload (https://github.com/twilson63/ngUpload). * 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 * 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. * $scope.alerts array. If everything goes fine, the user is redirected to the trainings list.
// @param content {Object} JSON - The upload's result * @param content {Object} JSON - The upload's result
// # */
$scope.submited = function (content) { $scope.submited = function (content) {
if ((content.id == null)) { if ((content.id == null)) {
$scope.alerts = [] $scope.alerts = []
@ -53,21 +53,21 @@ class TrainingsController {
} }
} }
// # /**
// Changes the current user's view, redirecting him to the machines list * Changes the current user's view, redirecting him to the machines list
// # */
$scope.cancel = () => $state.go('app.admin.trainings') $scope.cancel = () => $state.go('app.admin.trainings')
// # /**
// Force the 'public_page' attribute to false when the current training is disabled * Force the 'public_page' attribute to false when the current training is disabled
// # */
$scope.onDisableToggled = () => $scope.training.public_page = !$scope.training.disabled $scope.onDisableToggled = () => $scope.training.public_page = !$scope.training.disabled
// # /**
// For use with 'ng-class', returns the CSS class name for the uploads previews. * 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. * 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) * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)
// # */
$scope.fileinputClass = function (v) { $scope.fileinputClass = function (v) {
if (v) { if (v) {
return 'fileinput-exists' return 'fileinput-exists'
@ -78,117 +78,117 @@ class TrainingsController {
} }
} }
// # /**
// Controller used in the training creation page (admin) * Controller used in the training creation page (admin)
// # */
Application.Controllers.controller('NewTrainingController', [ '$scope', '$state', 'machinesPromise', 'CSRF', Application.Controllers.controller('NewTrainingController', [ '$scope', '$state', 'machinesPromise', 'CSRF',
function ($scope, $state, machinesPromise, CSRF) { function ($scope, $state, machinesPromise, CSRF) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # Form action on the following URL // Form action on the following URL
$scope.method = 'post' $scope.method = 'post'
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = '/api/trainings/' $scope.actionUrl = '/api/trainings/'
// # list of machines // list of machines
$scope.machines = machinesPromise $scope.machines = machinesPromise
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
CSRF.setMetaTags() CSRF.setMetaTags()
// # Using the TrainingsController // Using the TrainingsController
return new TrainingsController($scope, $state) return new TrainingsController($scope, $state)
} }
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])
// # /**
// Controller used in the training edition page (admin) * Controller used in the training edition page (admin)
// # */
Application.Controllers.controller('EditTrainingController', [ '$scope', '$state', '$stateParams', 'trainingPromise', 'machinesPromise', 'CSRF', Application.Controllers.controller('EditTrainingController', [ '$scope', '$state', '$stateParams', 'trainingPromise', 'machinesPromise', 'CSRF',
function ($scope, $state, $stateParams, trainingPromise, machinesPromise, CSRF) { function ($scope, $state, $stateParams, trainingPromise, machinesPromise, CSRF) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # Form action on the following URL // Form action on the following URL
$scope.method = 'patch' $scope.method = 'patch'
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = `/api/trainings/${$stateParams.id}` $scope.actionUrl = `/api/trainings/${$stateParams.id}`
// # Details of the training to edit (id in URL) // Details of the training to edit (id in URL)
$scope.training = trainingPromise $scope.training = trainingPromise
// # list of machines // list of machines
$scope.machines = machinesPromise $scope.machines = machinesPromise
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
CSRF.setMetaTags() CSRF.setMetaTags()
// # Using the TrainingsController // Using the TrainingsController
return new TrainingsController($scope, $state) return new TrainingsController($scope, $state)
} }
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])
// # /**
// Controller used in the trainings management page, allowing admins users to see and manage the list of trainings and reservations. * 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', Application.Controllers.controller('TrainingsAdminController', ['$scope', '$state', '$uibModal', 'Training', 'trainingsPromise', 'machinesPromise', '_t', 'growl', 'dialogs',
function ($scope, $state, $uibModal, Training, trainingsPromise, machinesPromise, _t, growl, dialogs) { function ($scope, $state, $uibModal, Training, trainingsPromise, machinesPromise, _t, growl, dialogs) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # list of trainings // list of trainings
let groupAvailabilities let groupAvailabilities
$scope.trainings = trainingsPromise $scope.trainings = trainingsPromise
// # simplified list of machines // simplified list of machines
$scope.machines = machinesPromise $scope.machines = machinesPromise
// # Training to monitor, binded with drop-down selection // Training to monitor, binded with drop-down selection
$scope.monitoring = $scope.monitoring =
{ training: null } { training: null }
// # list of training availabilies, grouped by date // list of training availabilies, grouped by date
$scope.groupedAvailabilities = {} $scope.groupedAvailabilities = {}
// # default: accordions are not open // default: accordions are not open
$scope.accordions = {} $scope.accordions = {}
// # Binding for the parseInt function // Binding for the parseInt function
$scope.parseInt = parseInt $scope.parseInt = parseInt
// # Default: we show only enabled trainings // Default: we show only enabled trainings
$scope.trainingFiltering = 'enabled' $scope.trainingFiltering = 'enabled'
// # Available options for filtering trainings by status // Available options for filtering trainings by status
$scope.filterDisabled = [ $scope.filterDisabled = [
'enabled', 'enabled',
'disabled', 'disabled',
'all' 'all'
] ]
// # /**
// In the trainings listing tab, return the stringified list of machines associated with the provided training * In the trainings listing tab, return the stringified list of machines associated with the provided training
// @param training {Object} Training object, inherited from $resource * @param training {Object} Training object, inherited from $resource
// @returns {string} * @returns {string}
// # */
$scope.showMachines = function (training) { $scope.showMachines = function (training) {
const selected = [] const selected = []
angular.forEach($scope.machines, function (m) { angular.forEach($scope.machines, function (m) {
@ -199,11 +199,11 @@ Application.Controllers.controller('TrainingsAdminController', ['$scope', '$stat
if (selected.length) { return selected.join(', ') } else { return _t('none') } if (selected.length) { return selected.join(', ') } else { return _t('none') }
} }
// # /**
// 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/
// @param index {number} training index in the $scope.trainings array * @param index {number} training index in the $scope.trainings array
// # */
$scope.cancelTraining = function (rowform, index) { $scope.cancelTraining = function (rowform, index) {
if ($scope.trainings[index].id != null) { if ($scope.trainings[index].id != null) {
return rowform.$cancel() return rowform.$cancel()
@ -212,13 +212,13 @@ Application.Controllers.controller('TrainingsAdminController', ['$scope', '$stat
} }
} }
// # /**
// In the trainings monitoring tab, callback to open a modal window displaying the current bookings for the * 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 * provided training slot. The admin will be then able to validate the training for the users that followed
// the training. * the training.
// @param training {Object} Training object, inherited from $resource * @param training {Object} Training object, inherited from $resource
// @param availability {Object} time slot when the training occurs * @param availability {Object} time slot when the training occurs
// # */
$scope.showReservations = (training, availability) => $scope.showReservations = (training, availability) =>
$uibModal.open({ $uibModal.open({
templateUrl: '<%= asset_path "admin/trainings/validTrainingModal.html" %>', templateUrl: '<%= asset_path "admin/trainings/validTrainingModal.html" %>',
@ -227,10 +227,10 @@ Application.Controllers.controller('TrainingsAdminController', ['$scope', '$stat
$scope.usersToValid = [] $scope.usersToValid = []
// # /**
// Mark/unmark the provided user for training validation * Mark/unmark the provided user for training validation
// @param user {Object} from the availability.reservation_users list * @param user {Object} from the availability.reservation_users list
// # */
$scope.toggleSelection = function (user) { $scope.toggleSelection = function (user) {
const index = $scope.usersToValid.indexOf(user) const index = $scope.usersToValid.indexOf(user)
if (index > -1) { if (index > -1) {
@ -240,9 +240,9 @@ Application.Controllers.controller('TrainingsAdminController', ['$scope', '$stat
} }
} }
// # /**
// Validates the modifications (training validations) and save them to the server * Validates the modifications (training validations) and save them to the server
// # */
$scope.ok = function () { $scope.ok = function () {
const users = $scope.usersToValid.map(u => u.id) const users = $scope.usersToValid.map(u => u.id)
return Training.update({ id: training.id }, { return Training.update({ id: training.id }, {
@ -257,18 +257,18 @@ Application.Controllers.controller('TrainingsAdminController', ['$scope', '$stat
}) })
} }
// # /**
// Cancel the modifications and close the modal window * Cancel the modifications and close the modal window
// # */
return $scope.cancel = () => $uibModalInstance.dismiss('cancel') return $scope.cancel = () => $uibModalInstance.dismiss('cancel')
} }
] }) ] })
// # /**
// Delete the provided training and, in case of sucess, remove it from the trainings list afterwards * 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 index {number} index of the provided training in $scope.trainings
// @param training {Object} training to delete * @param training {Object} training to delete
// # */
$scope.removeTraining = (index, training) => $scope.removeTraining = (index, training) =>
dialogs.confirm({ dialogs.confirm({
resolve: { resolve: {
@ -288,23 +288,23 @@ Application.Controllers.controller('TrainingsAdminController', ['$scope', '$stat
, error => growl.warning(_t('unable_to_delete_the_training_because_some_users_alredy_booked_it'))) , 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 * Takes a month number and return its localized literal name
// @param {Number} from 0 to 11 * @param {Number} from 0 to 11
// @returns {String} eg. 'janvier' * @returns {String} eg. 'janvier'
// # */
$scope.formatMonth = function (number) { $scope.formatMonth = function (number) {
number = parseInt(number) number = parseInt(number)
return moment().month(number).format('MMMM') return moment().month(number).format('MMMM')
} }
// # /**
// Given a day, month and year, return a localized literal name for the day * Given a day, month and year, return a localized literal name for the day
// @param day {Number} from 1 to 31 * @param day {Number} from 1 to 31
// @param month {Number} from 0 to 11 * @param month {Number} from 0 to 11
// @param year {Number} Gregorian's year number * @param year {Number} Gregorian's year number
// @returns {String} eg. 'mercredi 12' * @returns {String} eg. 'mercredi 12'
// # */
$scope.formatDay = function (day, month, year) { $scope.formatDay = function (day, month, year) {
day = parseInt(day) day = parseInt(day)
month = parseInt(month) month = parseInt(month)
@ -313,10 +313,10 @@ Application.Controllers.controller('TrainingsAdminController', ['$scope', '$stat
return moment({ year, month, day }).format('dddd D') return moment({ year, month, day }).format('dddd D')
} }
// # /**
// Callback when the drop-down selection is changed. * Callback when the drop-down selection is changed.
// The selected training details will be loaded from the API and rendered into the accordions. * The selected training details will be loaded from the API and rendered into the accordions.
// # */
$scope.selectTrainingToMonitor = () => $scope.selectTrainingToMonitor = () =>
Training.availabilities({ id: $scope.monitoring.training.id }, function (training) { Training.availabilities({ id: $scope.monitoring.training.id }, function (training) {
$scope.groupedAvailabilities = groupAvailabilities([training]) $scope.groupedAvailabilities = groupAvailabilities([training])
@ -331,11 +331,11 @@ Application.Controllers.controller('TrainingsAdminController', ['$scope', '$stat
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Group the trainings availabilites by trainings and by dates and return the resulting tree * Group the trainings availabilites by trainings and by dates and return the resulting tree
// @param trainings {Array} $scope.trainings is expected here * @param trainings {Array} $scope.trainings is expected here
// @returns {Object} Tree constructed as /training_name/year/month/day/[availabilities] * @returns {Object} Tree constructed as /training_name/year/month/day/[availabilities]
// # */
return groupAvailabilities = function (trainings) { return groupAvailabilities = function (trainings) {
const tree = {} const tree = {}
for (let training of Array.from(trainings)) { for (let training of Array.from(trainings)) {

View File

@ -465,7 +465,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
} }
} }
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])

View File

@ -166,11 +166,11 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
// Message displayed to the end user about rules that applies to events reservations // Message displayed to the end user about rules that applies to events reservations
$scope.eventExplicationsAlert = settingsPromise.event_explications_alert $scope.eventExplicationsAlert = settingsPromise.event_explications_alert
// # /**
// Callback to delete the provided event (admins only) * Callback to delete the provided event (admins only)
// @param event {$resource} angular's Event $resource * @param event {$resource} angular's Event $resource
// # */
$scope.deleteEvent = function(event) { $scope.deleteEvent = event =>
dialogs.confirm({ dialogs.confirm({
resolve: { resolve: {
object () { object () {
@ -192,9 +192,9 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
) )
} }
// # /**
// Callback to call when the number of tickets to book changes in the current booking * Callback to call when the number of tickets to book changes in the current booking
// # */
$scope.changeNbPlaces = function () { $scope.changeNbPlaces = function () {
// compute the total remaning places // compute the total remaning places
let remain = $scope.event.nb_free_places - $scope.reserve.nbReservePlaces let remain = $scope.event.nb_free_places - $scope.reserve.nbReservePlaces
@ -220,18 +220,18 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
return $scope.computeEventAmount() return $scope.computeEventAmount()
} }
// # /**
// Callback to reset the current reservation parameters * Callback to reset the current reservation parameters
// @param e {Object} see https://docs.angularjs.org/guide/expression#-event- * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
$scope.cancelReserve = function (e) { $scope.cancelReserve = function (e) {
e.preventDefault() e.preventDefault()
return resetEventReserve() return resetEventReserve()
} }
// # /**
// Callback to allow the user to set the details for his reservation * Callback to allow the user to set the details for his reservation
// # */
$scope.reserveEvent = function () { $scope.reserveEvent = function () {
if ($scope.event.nb_total_places > 0) { if ($scope.event.nb_total_places > 0) {
$scope.reserveSuccess = false $scope.reserveSuccess = false
@ -248,10 +248,10 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
} }
} }
// # /**
// Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's * Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's
// reservations. (admins only) * reservations. (admins only)
// # */
$scope.updateMember = function () { $scope.updateMember = function () {
resetEventReserve() resetEventReserve()
$scope.reserveSuccess = false $scope.reserveSuccess = false
@ -263,9 +263,9 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
} }
} }
// # /**
// Callback to trigger the payment process of the current reservation * Callback to trigger the payment process of the current reservation
// # */
$scope.payEvent = function () { $scope.payEvent = function () {
// first, we check that a user was selected // first, we check that a user was selected
if (Object.keys($scope.ctrl.member).length > 0) { if (Object.keys($scope.ctrl.member).length > 0) {
@ -287,9 +287,9 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
} }
} }
// # /**
// Callback to validate the booking of a free event * Callback to validate the booking of a free event
// # */
$scope.validReserveEvent = function () { $scope.validReserveEvent = function () {
const reservation = { const reservation = {
user_id: $scope.ctrl.member.id, user_id: $scope.ctrl.member.id,
@ -333,12 +333,12 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
}) })
} }
// # /**
// Callback to alter an already booked reservation date. A modal window will be opened to allow the user to choose * Callback to alter an already booked reservation date. A modal window will be opened to allow the user to choose
// a new date for his reservation (if any available) * a new date for his reservation (if any available)
// @param reservation {{id:number, reservable_id:number, nb_reserve_places:number}} * @param reservation {{id:number, reservable_id:number, nb_reserve_places:number}}
// @param e {Object} see https://docs.angularjs.org/guide/expression#-event- * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
$scope.modifyReservation = function (reservation, e) { $scope.modifyReservation = function (reservation, e) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
@ -409,10 +409,10 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
}) })
} }
// # /**
// Checks if the provided reservation is able to be moved (date change) * Checks if the provided reservation is able to be moved (date change)
// @param reservation {{total_booked_seats:number}} * @param reservation {{total_booked_seats:number}}
// # */
$scope.reservationCanModify = function (reservation) { $scope.reservationCanModify = function (reservation) {
const slotStart = moment(reservation.slots[0].start_at) const slotStart = moment(reservation.slots[0].start_at)
const now = moment() const now = moment()
@ -424,10 +424,10 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
return (isAble && $scope.enableBookingMove && (slotStart.diff(now, 'hours') >= $scope.moveBookingDelay)) return (isAble && $scope.enableBookingMove && (slotStart.diff(now, 'hours') >= $scope.moveBookingDelay))
} }
// # /**
// Compute the total amount for the current reservation according to the previously set parameters * Compute the total amount for the current reservation according to the previously set parameters
// and assign the result in $scope.reserve.amountTotal * and assign the result in $scope.reserve.amountTotal
// # */
$scope.computeEventAmount = function () { $scope.computeEventAmount = function () {
// first we check that a user was selected // first we check that a user was selected
if (Object.keys($scope.ctrl.member).length > 0) { if (Object.keys($scope.ctrl.member).length > 0) {
@ -441,24 +441,20 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
} }
} }
// # /**
// Return the URL allowing to share the current project on the Facebook social network * Return the URL allowing to share the current project on the Facebook social network
// # */
$scope.shareOnFacebook = function() { $scope.shareOnFacebook = () => `https://www.facebook.com/share.php?u=${$state.href('app.public.events_show', { id: $scope.event.id }, { absolute: true }).replace('#', '%23')}`
return `https://www.facebook.com/share.php?u=${$state.href('app.public.events_show', { id: $scope.event.id }, { absolute: true }).replace('#', '%23')}`;
}
// # /**
// Return the URL allowing to share the current project on the Twitter social network * Return the URL allowing to share the current project on the Twitter social network
// # */
$scope.shareOnTwitter = function() { $scope.shareOnTwitter = () => `https://twitter.com/intent/tweet?url=${encodeURIComponent($state.href('app.public.events_show', { id: $scope.event.id }, { absolute: true }))}&text=${encodeURIComponent($scope.event.title)}`
return `https://twitter.com/intent/tweet?url=${encodeURIComponent($state.href('app.public.events_show', { id: $scope.event.id }, { absolute: true }))}&text=${encodeURIComponent($scope.event.title)}`;
}
// # /**
// Return the textual description of the conditions applyable to the given price's category * Return the textual description of the conditions applyable to the given price's category
// @param category_id {number} ID of the price's category * @param category_id {number} ID of the price's category
// # */
$scope.getPriceCategoryConditions = function (category_id) { $scope.getPriceCategoryConditions = function (category_id) {
for (let cat of Array.from($scope.priceCategories)) { for (let cat of Array.from($scope.priceCategories)) {
if (cat.id === category_id) { if (cat.id === category_id) {
@ -469,9 +465,9 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
// set the controlled user as the current user if the current user is not an admin // set the controlled user as the current user if the current user is not an admin
if ($scope.currentUser) { if ($scope.currentUser) {
@ -496,27 +492,22 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
}) })
} }
// # /**
// Retrieve the reservations for the couple event / user * Retrieve the reservations for the couple event / user
// @param reservable_id {number} the current event id * @param reservable_id {number} the current event id
// @param reservable_type {string} 'Event' * @param reservable_type {string} 'Event'
// @param user_id {number} the user's id (current or managed) * @param user_id {number} the user's id (current or managed)
// # */
const getReservations = function(reservable_id, reservable_type, user_id) { var getReservations = (reservable_id, reservable_type, user_id) =>
Reservation.query({ Reservation.query({ reservable_id, reservable_type, user_id }).$promise.then(reservations => $scope.reservations = reservations)
reservable_id,
reservable_type,
user_id
}).$promise.then(function(reservations) { $scope.reservations = reservations; })
}
// # /**
// Create an hash map implementing the Reservation specs * Create an hash map implementing the Reservation specs
// @param member {Object} User as retrieved from the API: current user / selected user if current is admin * @param member {Object} User as retreived from the API: current user / selected user if current is admin
// @param reserve {Object} Reservation parameters (places...) * @param reserve {Object} Reservation parameters (places...)
// @param event {Object} Current event * @param event {Object} Current event
// @return {{user_id:number, reservable_id:number, reservable_type:string, slots_attributes:Array<Object>, nb_reserve_places:number}} * @return {{user_id:number, reservable_id:number, reservable_type:string, slots_attributes:Array<Object>, nb_reserve_places:number}}
// # */
var mkReservation = function (member, reserve, event) { var mkReservation = function (member, reserve, event) {
const reservation = { const reservation = {
user_id: member.id, user_id: member.id,
@ -547,12 +538,12 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
return reservation return reservation
} }
// # /**
// Format the parameters expected by /api/prices/compute or /api/reservations and return the resulting object * Format the parameters expected by /api/prices/compute or /api/reservations and return the resulting object
// @param reservation {Object} as returned by mkReservation() * @param reservation {Object} as returned by mkReservation()
// @param coupon {Object} Coupon as returned from the API * @param coupon {Object} Coupon as returned from the API
// @return {{reservation:Object, coupon_code:string}} * @return {{reservation:Object, coupon_code:string}}
// # */
var mkRequestParams = function (reservation, coupon) { var mkRequestParams = function (reservation, coupon) {
const params = { const params = {
reservation, reservation,
@ -562,9 +553,9 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
return params return params
} }
// # /**
// Set the current reservation to the default values. This implies to reservation form to be hidden. * Set the current reservation to the default values. This implies to reservation form to be hidden.
// # */
var resetEventReserve = function () { var resetEventReserve = function () {
if ($scope.event) { if ($scope.event) {
$scope.reserve = { $scope.reserve = {
@ -587,11 +578,11 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
} }
} }
// # /**
// Open a modal window which trigger the stripe payment process * Open a modal window which trigger the stripe payment process
// @param reservation {Object} to book * @param reservation {Object} to book
// # */
const payByStripe = function(reservation) { var payByStripe = reservation =>
$uibModal.open({ $uibModal.open({
templateUrl: '<%= asset_path "stripe/payment_modal.html" %>', templateUrl: '<%= asset_path "stripe/payment_modal.html" %>',
size: 'md', size: 'md',
@ -659,11 +650,11 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
}).result['finally'](null).then(function(reservation) { afterPayment(reservation); }) }).result['finally'](null).then(function(reservation) { afterPayment(reservation); })
}; };
// # /**
// Open a modal window which trigger the local payment process * Open a modal window which trigger the local payment process
// @param reservation {Object} to book * @param reservation {Object} to book
// # */
const payOnSite = function(reservation) { var payOnSite = reservation =>
$uibModal.open({ $uibModal.open({
templateUrl: '<%= asset_path "shared/valid_reservation_modal.html" %>', templateUrl: '<%= asset_path "shared/valid_reservation_modal.html" %>',
size: 'sm', size: 'sm',
@ -737,10 +728,10 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
.result['finally'](null).then(function(reservation) { afterPayment(reservation) }) .result['finally'](null).then(function(reservation) { afterPayment(reservation) })
} }
// # /**
// What to do after the payment was successful * What to do after the payment was successful
// @param reservation {Object} booked reservation * @param resveration {Object} booked reservation
// # */
var afterPayment = function (reservation) { var afterPayment = function (reservation) {
$scope.event.nb_free_places = $scope.event.nb_free_places - reservation.total_booked_seats $scope.event.nb_free_places = $scope.event.nb_free_places - reservation.total_booked_seats
resetEventReserve() resetEventReserve()
@ -752,7 +743,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
} }
} }
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])

View File

@ -16,29 +16,29 @@
/* COMMON CODE */ /* COMMON CODE */
// # /**
// Provides a set of common callback methods to the $scope parameter. These methods are used * Provides a set of common callback methods to the $scope parameter. These methods are used
// in the various machines' admin controllers. * in the various machines' admin controllers.
// *
// Provides : * Provides :
// - $scope.submited(content) * - $scope.submited(content)
// - $scope.cancel() * - $scope.cancel()
// - $scope.fileinputClass(v) * - $scope.fileinputClass(v)
// - $scope.addFile() * - $scope.addFile()
// - $scope.deleteFile(file) * - $scope.deleteFile(file)
// *
// Requires : * Requires :
// - $scope.machine.machine_files_attributes = [] * - $scope.machine.machine_files_attributes = []
// - $state (Ui-Router) [ 'app.public.machines_list' ] * - $state (Ui-Router) [ 'app.public.machines_list' ]
// # /*
class MachinesController { class MachinesController {
constructor ($scope, $state) { constructor ($scope, $state) {
// # /*
// For use with ngUpload (https://github.com/twilson63/ngUpload). * 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 * 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 machines list. * $scope.alerts array. If everything goes fine, the user is redirected to the machines list.
// @param content {Object} JSON - The upload's result * @param content {Object} JSON - The upload's result
// # */
$scope.submited = function (content) { $scope.submited = function (content) {
if ((content.id == null)) { if ((content.id == null)) {
$scope.alerts = [] $scope.alerts = []
@ -55,16 +55,16 @@ class MachinesController {
} }
} }
// # /**
// Changes the current user's view, redirecting him to the machines list * Changes the current user's view, redirecting him to the machines list
// # */
$scope.cancel = () => $state.go('app.public.machines_list') $scope.cancel = () => $state.go('app.public.machines_list')
// # /**
// For use with 'ng-class', returns the CSS class name for the uploads previews. * 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. * 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) * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)
// # */
$scope.fileinputClass = function (v) { $scope.fileinputClass = function (v) {
if (v) { if (v) {
return 'fileinput-exists' return 'fileinput-exists'
@ -73,17 +73,17 @@ class MachinesController {
} }
} }
// # /**
// This will create a single new empty entry into the machine attachements list. * This will create a single new empty entry into the machine attachements list.
// # */
$scope.addFile = () => $scope.machine.machine_files_attributes.push({}) $scope.addFile = () => $scope.machine.machine_files_attributes.push({})
// # /**
// This will remove the given file from the machine attachements list. If the file was previously uploaded * This will remove the given file from the machine attachements list. If the file was previously uploaded
// to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from * to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from
// the attachements array. * the attachements array.
// @param file {Object} the file to delete * @param file {Object} the file to delete
// # */
$scope.deleteFile = function (file) { $scope.deleteFile = function (file) {
const index = $scope.machine.machine_files_attributes.indexOf(file) const index = $scope.machine.machine_files_attributes.indexOf(file)
if (file.id != null) { if (file.id != null) {
@ -95,14 +95,14 @@ class MachinesController {
} }
} }
// # /**
// Manages the transition when a user clicks on the reservation button. * Manages the transition when a user clicks on the reservation button.
// According to the status of user currently logged into the system, redirect him to the reservation page, * According to the status of user currently logged into the system, redirect him to the reservation page,
// or display a modal window asking him to complete a training before he can book a machine reservation. * or display a modal window asking him to complete a training before he can book a machine reservation.
// @param machine {{id:number}} An object containg the id of the machine to book, * @param machine {{id:number}} An object containg the id of the machine to book,
// the object will be completed before the fonction returns. * the object will be completed before the fonction returns.
// @param e {Object} see https://docs.angularjs.org/guide/expression#-event- * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
const _reserveMachine = function (machine, e) { const _reserveMachine = function (machine, e) {
const _this = this const _this = this
e.preventDefault() e.preventDefault()
@ -177,21 +177,21 @@ const _reserveMachine = function (machine, e) {
}) })
} }
// # /**
// Controller used in the public listing page, allowing everyone to see the list of machines * Controller used in the public listing page, allowing everyone to see the list of machines
// # */
Application.Controllers.controller('MachinesController', ['$scope', '$state', '_t', 'Machine', '$uibModal', 'machinesPromise', function ($scope, $state, _t, Machine, $uibModal, machinesPromise) { Application.Controllers.controller('MachinesController', ['$scope', '$state', '_t', 'Machine', '$uibModal', 'machinesPromise', function ($scope, $state, _t, Machine, $uibModal, machinesPromise) {
// # Retrieve the list of machines // Retrieve the list of machines
$scope.machines = machinesPromise $scope.machines = machinesPromise
// # /**
// Redirect the user to the machine details page * Redirect the user to the machine details page
// # */
$scope.showMachine = machine => $state.go('app.public.machines_show', { id: machine.slug }) $scope.showMachine = machine => $state.go('app.public.machines_show', { id: machine.slug })
// # /**
// Callback to book a reservation for the current machine * Callback to book a reservation for the current machine
// # */
$scope.reserveMachine = _reserveMachine.bind({ $scope.reserveMachine = _reserveMachine.bind({
$scope, $scope,
$state, $state,
@ -200,10 +200,10 @@ Application.Controllers.controller('MachinesController', ['$scope', '$state', '_
Machine Machine
}) })
// # Default: we show only enabled machines // Default: we show only enabled machines
$scope.machineFiltering = 'enabled' $scope.machineFiltering = 'enabled'
// # Available options for filtering machines by status // Available options for filtering machines by status
return $scope.filterDisabled = [ return $scope.filterDisabled = [
'enabled', 'enabled',
'disabled', 'disabled',
@ -212,70 +212,70 @@ Application.Controllers.controller('MachinesController', ['$scope', '$state', '_
} }
]) ])
// # /**
// Controller used in the machine creation page (admin) * Controller used in the machine creation page (admin)
// # */
Application.Controllers.controller('NewMachineController', ['$scope', '$state', 'CSRF', function ($scope, $state, CSRF) { Application.Controllers.controller('NewMachineController', ['$scope', '$state', 'CSRF', function ($scope, $state, CSRF) {
CSRF.setMetaTags() CSRF.setMetaTags()
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = '/api/machines/' $scope.actionUrl = '/api/machines/'
// # Form action on the above URL // Form action on the above URL
$scope.method = 'post' $scope.method = 'post'
// # default machine parameters // default machine parameters
$scope.machine = $scope.machine =
{ machine_files_attributes: [] } { machine_files_attributes: [] }
// # Using the MachinesController // Using the MachinesController
return new MachinesController($scope, $state) return new MachinesController($scope, $state)
} }
]) ])
// # /**
// Controller used in the machine edition page (admin) * Controller used in the machine edition page (admin)
// # */
Application.Controllers.controller('EditMachineController', ['$scope', '$state', '$stateParams', 'machinePromise', 'CSRF', function ($scope, $state, $stateParams, machinePromise, CSRF) { Application.Controllers.controller('EditMachineController', ['$scope', '$state', '$stateParams', 'machinePromise', 'CSRF', function ($scope, $state, $stateParams, machinePromise, CSRF) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = `/api/machines/${$stateParams.id}` $scope.actionUrl = `/api/machines/${$stateParams.id}`
// # Form action on the above URL // Form action on the above URL
$scope.method = 'put' $scope.method = 'put'
// # Retrieve the details for the machine id in the URL, if an error occurs redirect the user to the machines list // Retrieve the details for the machine id in the URL, if an error occurs redirect the user to the machines list
$scope.machine = machinePromise $scope.machine = machinePromise
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
CSRF.setMetaTags() CSRF.setMetaTags()
// # Using the MachinesController // Using the MachinesController
return new MachinesController($scope, $state) return new MachinesController($scope, $state)
} }
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])
// # /**
// Controller used in the machine details page (public) * Controller used in the machine details page (public)
// # */
Application.Controllers.controller('ShowMachineController', ['$scope', '$state', '$uibModal', '$stateParams', '_t', 'Machine', 'growl', 'machinePromise', 'dialogs', Application.Controllers.controller('ShowMachineController', ['$scope', '$state', '$uibModal', '$stateParams', '_t', 'Machine', 'growl', 'machinePromise', 'dialogs',
function ($scope, $state, $uibModal, $stateParams, _t, Machine, growl, machinePromise, dialogs) { function ($scope, $state, $uibModal, $stateParams, _t, Machine, growl, machinePromise, dialogs) {
// # Retrieve the details for the machine id in the URL, if an error occurs redirect the user to the machines list // Retrieve the details for the machine id in the URL, if an error occurs redirect the user to the machines list
$scope.machine = machinePromise $scope.machine = machinePromise
// # /**
// Callback to delete the current machine (admins only) * Callback to delete the current machine (admins only)
// # */
$scope.delete = function (machine) { $scope.delete = function (machine) {
// check the permissions // check the permissions
if ($scope.currentUser.role !== 'admin') { if ($scope.currentUser.role !== 'admin') {
@ -299,9 +299,9 @@ Application.Controllers.controller('ShowMachineController', ['$scope', '$state',
} }
} }
// # /**
// Callback to book a reservation for the current machine * Callback to book a reservation for the current machine
// # */
return $scope.reserveMachine = _reserveMachine.bind({ return $scope.reserveMachine = _reserveMachine.bind({
$scope, $scope,
$state, $state,
@ -312,10 +312,10 @@ Application.Controllers.controller('ShowMachineController', ['$scope', '$state',
} }
]) ])
// # /**
// Controller used in the machine reservation page (for logged users who have completed the training and admins). * Controller used in the machine reservation page (for logged users who have completed the training and admins).
// This controller workflow is pretty similar to the trainings reservation controller. * This controller workflow is pretty similar to the trainings reservation controller.
// # */
Application.Controllers.controller('ReserveMachineController', ['$scope', '$stateParams', '_t', 'moment', 'Auth', '$timeout', 'Member', 'Availability', 'plansPromise', 'groupsPromise', 'machinePromise', 'settingsPromise', 'uiCalendarConfig', 'CalendarConfig', Application.Controllers.controller('ReserveMachineController', ['$scope', '$stateParams', '_t', 'moment', 'Auth', '$timeout', 'Member', 'Availability', 'plansPromise', 'groupsPromise', 'machinePromise', 'settingsPromise', 'uiCalendarConfig', 'CalendarConfig',
function ($scope, $stateParams, _t, moment, Auth, $timeout, Member, Availability, plansPromise, groupsPromise, machinePromise, settingsPromise, uiCalendarConfig, CalendarConfig) { function ($scope, $stateParams, _t, moment, Auth, $timeout, Member, Availability, plansPromise, groupsPromise, machinePromise, settingsPromise, uiCalendarConfig, CalendarConfig) {
@ -332,19 +332,19 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # bind the machine availabilities with full-Calendar events // bind the machine availabilities with full-Calendar events
$scope.eventSources = [] $scope.eventSources = []
// # indicates the state of the current view : calendar or plans information // indicates the state of the current view : calendar or plans information
$scope.plansAreShown = false $scope.plansAreShown = false
// # will store the user's plan if he choosed to buy one // will store the user's plan if he choosed to buy one
$scope.selectedPlan = null $scope.selectedPlan = null
// # the moment when the plan selection changed for the last time, used to trigger changes in the cart // the moment when the plan selection changed for the last time, used to trigger changes in the cart
$scope.planSelectionTime = null $scope.planSelectionTime = null
// # mapping of fullCalendar events. // mapping of fullCalendar events.
$scope.events = { $scope.events = {
reserved: [], // Slots that the user wants to book reserved: [], // Slots that the user wants to book
modifiable: null, // Slot that the user wants to change modifiable: null, // Slot that the user wants to change
@ -353,16 +353,16 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
moved: null // Slots that were just moved by the user (change done) -> {newSlot:* oldSlot: *} moved: null // Slots that were just moved by the user (change done) -> {newSlot:* oldSlot: *}
} }
// # the moment when the slot selection changed for the last time, used to trigger changes in the cart // the moment when the slot selection changed for the last time, used to trigger changes in the cart
$scope.selectionTime = null $scope.selectionTime = null
// # the last clicked event in the calender // the last clicked event in the calender
$scope.selectedEvent = null $scope.selectedEvent = null
// # the application global settings // the application global settings
$scope.settings = settingsPromise $scope.settings = settingsPromise
// # list of plans, classified by group // list of plans, classified by group
$scope.plansClassifiedByGroup = [] $scope.plansClassifiedByGroup = []
for (let group of Array.from(groupsPromise)) { for (let group of Array.from(groupsPromise)) {
const groupObj = { id: group.id, name: group.name, plans: [] } const groupObj = { id: group.id, name: group.name, plans: [] }
@ -372,14 +372,14 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
$scope.plansClassifiedByGroup.push(groupObj) $scope.plansClassifiedByGroup.push(groupObj)
} }
// # the user to deal with, ie. the current user for non-admins // the user to deal with, ie. the current user for non-admins
$scope.ctrl = $scope.ctrl =
{ member: {} } { member: {} }
// # current machine to reserve // current machine to reserve
$scope.machine = machinePromise $scope.machine = machinePromise
// # fullCalendar (v2) configuration // fullCalendar (v2) configuration
$scope.calendarConfig = CalendarConfig({ $scope.calendarConfig = CalendarConfig({
minTime: moment.duration(moment(settingsPromise.booking_window_start).format('HH:mm:ss')), minTime: moment.duration(moment(settingsPromise.booking_window_start).format('HH:mm:ss')),
maxTime: moment.duration(moment(settingsPromise.booking_window_end).format('HH:mm:ss')), maxTime: moment.duration(moment(settingsPromise.booking_window_end).format('HH:mm:ss')),
@ -391,24 +391,24 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
} }
}) })
// # Global config: message to the end user concerning the subscriptions rules // Global config: message to the end user concerning the subscriptions rules
$scope.subscriptionExplicationsAlert = settingsPromise.subscription_explications_alert $scope.subscriptionExplicationsAlert = settingsPromise.subscription_explications_alert
// # Global config: message to the end user concerning the machine bookings // Global config: message to the end user concerning the machine bookings
$scope.machineExplicationsAlert = settingsPromise.machine_explications_alert $scope.machineExplicationsAlert = settingsPromise.machine_explications_alert
// # /**
// Change the last selected slot's appearence to looks like 'added to cart' * Change the last selected slot's appearence to looks like 'added to cart'
// # */
$scope.markSlotAsAdded = function () { $scope.markSlotAsAdded = function () {
$scope.selectedEvent.backgroundColor = FREE_SLOT_BORDER_COLOR $scope.selectedEvent.backgroundColor = FREE_SLOT_BORDER_COLOR
$scope.selectedEvent.title = _t('i_reserve') $scope.selectedEvent.title = _t('i_reserve')
return updateCalendar() return updateCalendar()
} }
// # /**
// Change the last selected slot's appearence to looks like 'never added to cart' * Change the last selected slot's appearence to looks like 'never added to cart'
// # */
$scope.markSlotAsRemoved = function (slot) { $scope.markSlotAsRemoved = function (slot) {
slot.backgroundColor = 'white' slot.backgroundColor = 'white'
slot.borderColor = FREE_SLOT_BORDER_COLOR slot.borderColor = FREE_SLOT_BORDER_COLOR
@ -421,23 +421,23 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
return updateCalendar() return updateCalendar()
} }
// # /**
// Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book' * Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book'
// # */
$scope.slotCancelled = () => $scope.markSlotAsRemoved($scope.selectedEvent) $scope.slotCancelled = () => $scope.markSlotAsRemoved($scope.selectedEvent)
// # /**
// Change the last selected slot's appearence to looks like 'currently looking for a new destination to exchange' * Change the last selected slot's appearence to looks like 'currently looking for a new destination to exchange'
// # */
$scope.markSlotAsModifying = function () { $scope.markSlotAsModifying = function () {
$scope.selectedEvent.backgroundColor = '#eee' $scope.selectedEvent.backgroundColor = '#eee'
$scope.selectedEvent.title = _t('i_change') $scope.selectedEvent.title = _t('i_change')
return updateCalendar() return updateCalendar()
} }
// # /**
// Change the last selected slot's appearence to looks like 'the slot being exchanged will take this place' * Change the last selected slot's appearence to looks like 'the slot being exchanged will take this place'
// # */
$scope.changeModifyMachineSlot = function () { $scope.changeModifyMachineSlot = function () {
if ($scope.events.placable) { if ($scope.events.placable) {
$scope.events.placable.backgroundColor = 'white' $scope.events.placable.backgroundColor = 'white'
@ -450,9 +450,9 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
return updateCalendar() return updateCalendar()
} }
// # /**
// When modifying an already booked reservation, callback when the modification was successfully done. * When modifying an already booked reservation, callback when the modification was successfully done.
// # */
$scope.modifyMachineSlot = function () { $scope.modifyMachineSlot = function () {
$scope.events.placable.title = $scope.currentUser.role !== 'admin' ? _t('i_ve_reserved') : _t('not_available') $scope.events.placable.title = $scope.currentUser.role !== 'admin' ? _t('i_ve_reserved') : _t('not_available')
$scope.events.placable.backgroundColor = 'white' $scope.events.placable.backgroundColor = 'white'
@ -471,9 +471,9 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
return updateCalendar() return updateCalendar()
} }
// # /**
// Cancel the current booking modification, reseting the whole process * Cancel the current booking modification, reseting the whole process
// # */
$scope.cancelModifyMachineSlot = function () { $scope.cancelModifyMachineSlot = function () {
if ($scope.events.placable) { if ($scope.events.placable) {
$scope.events.placable.backgroundColor = 'white' $scope.events.placable.backgroundColor = 'white'
@ -485,20 +485,20 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
return updateCalendar() return updateCalendar()
} }
// # /**
// Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's * Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's
// reservations. (admins only) * reservations. (admins only)
// # */
$scope.updateMember = function () { $scope.updateMember = function () {
$scope.plansAreShown = false $scope.plansAreShown = false
$scope.selectedPlan = null $scope.selectedPlan = null
return Member.get({ id: $scope.ctrl.member.id }, member => $scope.ctrl.member = member) return Member.get({ id: $scope.ctrl.member.id }, member => $scope.ctrl.member = member)
} }
// # /**
// Changes the user current view from the plan subsription screen to the machine reservation agenda * Changes the user current view from the plan subsription screen to the machine reservation agenda
// @param e {Object} see https://docs.angularjs.org/guide/expression#-event- * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
$scope.doNotSubscribePlan = function (e) { $scope.doNotSubscribePlan = function (e) {
e.preventDefault() e.preventDefault()
$scope.plansAreShown = false $scope.plansAreShown = false
@ -506,15 +506,15 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
return $scope.planSelectionTime = new Date() return $scope.planSelectionTime = new Date()
} }
// # /**
// Switch the user's view from the reservation agenda to the plan subscription * Switch the user's view from the reservation agenda to the plan subscription
// # */
$scope.showPlans = () => $scope.plansAreShown = true $scope.showPlans = () => $scope.plansAreShown = true
// # /**
// Add the provided plan to the current shopping cart * Add the provided plan to the current shopping cart
// @param plan {Object} the plan to subscribe * @param plan {Object} the plan to subscribe
// # */
$scope.selectPlan = function (plan) { $scope.selectPlan = function (plan) {
// toggle selected plan // toggle selected plan
if ($scope.selectedPlan !== plan) { if ($scope.selectedPlan !== plan) {
@ -525,11 +525,11 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
return $scope.planSelectionTime = new Date() return $scope.planSelectionTime = new Date()
} }
// # /**
// Once the reservation is booked (payment process successfully completed), change the event style * Once the reservation is booked (payment process successfully completed), change the event style
// in fullCalendar, update the user's subscription and free-credits if needed * in fullCalendar, update the user's subscription and free-credits if needed
// @param reservation {Object} * @param reservation {Object}
// # */
$scope.afterPayment = function (reservation) { $scope.afterPayment = function (reservation) {
angular.forEach($scope.events.reserved, function (machineSlot, key) { angular.forEach($scope.events.reserved, function (machineSlot, key) {
machineSlot.is_reserved = true machineSlot.is_reserved = true
@ -556,16 +556,16 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
return refetchCalendar() return refetchCalendar()
} }
// # /**
// To use as callback in Array.prototype.filter to get only enabled plans * To use as callback in Array.prototype.filter to get only enabled plans
// # */
$scope.filterDisabledPlans = plan => !plan.disabled $scope.filterDisabledPlans = plan => !plan.disabled
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
Availability.machine({ machineId: $stateParams.id }, availabilities => Availability.machine({ machineId: $stateParams.id }, availabilities =>
$scope.eventSources.push({ $scope.eventSources.push({
@ -579,22 +579,22 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
} }
} }
// # /**
// Triggered when the user click on a reservation slot in the agenda. * Triggered when the user click on a reservation slot in the agenda.
// Defines the behavior to adopt depending on the slot status (already booked, free, ready to be reserved ...), * Defines the behavior to adopt depending on the slot status (already booked, free, ready to be reserved ...),
// the user's subscription (current or about to be took) and the time (the user cannot modify a booked reservation * the user's subscription (current or about to be took) and the time (the user cannot modify a booked reservation
// if it's too late). * if it's too late).
// # */
var calendarEventClickCb = function (event, jsEvent, view) { var calendarEventClickCb = function (event, jsEvent, view) {
$scope.selectedEvent = event $scope.selectedEvent = event
return $scope.selectionTime = new Date() return $scope.selectionTime = new Date()
} }
// # /**
// Triggered when fullCalendar tries to graphicaly render an event block. * Triggered when fullCalendar tries to graphicaly render an event block.
// Append the event tag into the block, just after the event title. * Append the event tag into the block, just after the event title.
// @see http://fullcalendar.io/docs/event_rendering/eventRender/ * @see http://fullcalendar.io/docs/event_rendering/eventRender/
// # */
var eventRenderCb = function (event, element) { var eventRenderCb = function (event, element) {
if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) { if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) {
let html = '' let html = ''
@ -605,14 +605,14 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
} }
} }
// # /**
// After payment, update the id of the newly reserved slot with the id returned by the server. * After payment, update the id of the newly reserved slot with the id returned by the server.
// This will allow the user to modify the reservation he just booked. The associated user will also be registered * This will allow the user to modify the reservation he just booked. The associated user will also be registered
// with the slot. * with the slot.
// @param slot {Object} * @param slot {Object}
// @param reservation {Object} * @param reservation {Object}
// @param user {Object} user associated with the slot * @param user {Object} user associated with the slot
// # */
var updateMachineSlot = (slot, reservation, user) => var updateMachineSlot = (slot, reservation, user) =>
angular.forEach(reservation.slots, function (s) { angular.forEach(reservation.slots, function (s) {
if (slot.start.isSame(s.start_at)) { if (slot.start.isSame(s.start_at)) {
@ -621,21 +621,21 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
} }
}) })
// # /**
// Update the calendar's display to render the new attributes of the events * Update the calendar's display to render the new attributes of the events
// # */
var updateCalendar = () => uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents') var updateCalendar = () => uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents')
// # /**
// Asynchronously fetch the events from the API and refresh the calendar's view with these new events * Asynchronously fetch the events from the API and refresh the calendar's view with these new events
// # */
var refetchCalendar = () => var refetchCalendar = () =>
$timeout(function () { $timeout(function () {
uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents') uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents')
return uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents') return uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents')
}) })
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])

View File

@ -16,18 +16,18 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
function ($scope, $rootScope, $state, $uibModal, Auth, dialogs, growl, plansPromise, groupsPromise, Subscription, Member, subscriptionExplicationsPromise, _t, Wallet, helpers) { function ($scope, $rootScope, $state, $uibModal, Auth, dialogs, growl, plansPromise, groupsPromise, Subscription, Member, subscriptionExplicationsPromise, _t, Wallet, helpers) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # list of groups // list of groups
let plan let plan
$scope.groups = groupsPromise.filter(g => (g.slug !== 'admins') & !g.disabled) $scope.groups = groupsPromise.filter(g => (g.slug !== 'admins') & !g.disabled)
// # default : do not show the group changing form // default : do not show the group changing form
// # group ID of the current/selected user // group ID of the current/selected user
$scope.group = { $scope.group = {
change: false, change: false,
id: null id: null
} }
// # list of plans, classified by group // list of plans, classified by group
$scope.plansClassifiedByGroup = [] $scope.plansClassifiedByGroup = []
for (var group of Array.from($scope.groups)) { for (var group of Array.from($scope.groups)) {
const groupObj = { id: group.id, name: group.name, plans: [] } const groupObj = { id: group.id, name: group.name, plans: [] }
@ -37,34 +37,34 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
$scope.plansClassifiedByGroup.push(groupObj) $scope.plansClassifiedByGroup.push(groupObj)
} }
// # user to deal with // user to deal with
$scope.ctrl = { $scope.ctrl = {
member: null, member: null,
member_id: null member_id: null
} }
// # already subscribed plan of the current user // already subscribed plan of the current user
$scope.paid = $scope.paid =
{ plan: null } { plan: null }
// # plan to subscribe (shopping cart) // plan to subscribe (shopping cart)
$scope.selectedPlan = null $scope.selectedPlan = null
// # Discount coupon to apply to the basket, if any // Discount coupon to apply to the basket, if any
$scope.coupon = $scope.coupon =
{ applied: null } { applied: null }
// # Storage for the total price (plan price + coupon, if any) // Storage for the total price (plan price + coupon, if any)
$scope.cart = $scope.cart =
{ total: null } { total: null }
// # text that appears in the bottom-right box of the page (subscriptions rules details) // text that appears in the bottom-right box of the page (subscriptions rules details)
$scope.subscriptionExplicationsAlert = subscriptionExplicationsPromise.setting.value $scope.subscriptionExplicationsAlert = subscriptionExplicationsPromise.setting.value
// # /**
// Callback to deal with the subscription of the user selected in the dropdown list instead of the current user's * Callback to deal with the subscription of the user selected in the dropdown list instead of the current user's
// subscription. (admins only) * subscription. (admins only)
// # */
$scope.updateMember = function () { $scope.updateMember = function () {
$scope.selectedPlan = null $scope.selectedPlan = null
$scope.paid.plan = null $scope.paid.plan = null
@ -75,10 +75,10 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
}) })
} }
// # /**
// Add the provided plan to the shopping basket * Add the provided plan to the shopping basket
// @param plan {Object} The plan to subscribe to * @param plan {Object} The plan to subscribe to
// # */
$scope.selectPlan = function (plan) { $scope.selectPlan = function (plan) {
if ($scope.isAuthenticated()) { if ($scope.isAuthenticated()) {
if ($scope.selectedPlan !== plan) { if ($scope.selectedPlan !== plan) {
@ -92,9 +92,9 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
} }
} }
// # /**
// Callback to trigger the payment process of the subscription * Callback to trigger the payment process of the subscription
// # */
$scope.openSubscribePlanModal = () => $scope.openSubscribePlanModal = () =>
Wallet.getWalletByUser({ user_id: $scope.ctrl.member.id }, function (wallet) { Wallet.getWalletByUser({ user_id: $scope.ctrl.member.id }, function (wallet) {
const amountToPay = helpers.getAmountToPay($scope.cart.total, wallet.amount) const amountToPay = helpers.getAmountToPay($scope.cart.total, wallet.amount)
@ -107,9 +107,9 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
} }
}) })
// # /**
// Return the group object, identified by the ID set in $scope.group.id * Return the group object, identified by the ID set in $scope.group.id
// # */
$scope.getUserGroup = function () { $scope.getUserGroup = function () {
for (group of Array.from($scope.groups)) { for (group of Array.from($scope.groups)) {
if (group.id === $scope.group.id) { if (group.id === $scope.group.id) {
@ -118,9 +118,9 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
} }
} }
// # /**
// Change the group of the current/selected user to the one set in $scope.group.id * Change the group of the current/selected user to the one set in $scope.group.id
// # */
$scope.selectGroup = () => $scope.selectGroup = () =>
Member.update({ id: $scope.ctrl.member.id }, { user: { group_id: $scope.group.id } }, function (user) { Member.update({ id: $scope.ctrl.member.id }, { user: { group_id: $scope.group.id } }, function (user) {
$scope.ctrl.member = user $scope.ctrl.member = user
@ -142,22 +142,22 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
return console.error(err) return console.error(err)
}) })
// # /**
// Return an enumerable meaninful string for the gender of the provider user * Return an enumerable meaninful string for the gender of the provider user
// @param user {Object} Database user record * @param user {Object} Database user record
// @return {string} 'male' or 'female' * @return {string} 'male' or 'female'
// # */
$scope.getGender = function (user) { $scope.getGender = function (user) {
if (user && user.profile) { if (user && user.profile) {
if (user.profile.gender === 'true') { return 'male' } else { return 'female' } if (user.profile.gender === 'true') { return 'male' } else { return 'female' }
} else { return 'other' } } else { return 'other' }
} }
// # /**
// Test if the provided date is in the future * Test if the provided date is in the future
// @param dateTime {Date} * @param dateTime {Date}
// @return {boolean} * @return {boolean}
// # */
$scope.isInFuture = function (dateTime) { $scope.isInFuture = function (dateTime) {
if (moment().diff(moment(dateTime)) < 0) { if (moment().diff(moment(dateTime)) < 0) {
return true return true
@ -166,16 +166,16 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
} }
} }
// # /**
// To use as callback in Array.prototype.filter to get only enabled plans * To use as callback in Array.prototype.filter to get only enabled plans
// # */
$scope.filterDisabledPlans = plan => !plan.disabled $scope.filterDisabledPlans = plan => !plan.disabled
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
if ($scope.currentUser) { if ($scope.currentUser) {
if ($scope.currentUser.role !== 'admin') { if ($scope.currentUser.role !== 'admin') {
@ -195,10 +195,10 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
}) })
} }
// # /**
// Compute the total amount for the current reservation according to the previously set parameters * Compute the total amount for the current reservation according to the previously set parameters
// and assign the result in $scope.reserve.amountTotal * and assign the result in $scope.reserve.amountTotal
// # */
var updateCartPrice = function () { var updateCartPrice = function () {
// first we check that a user was selected // first we check that a user was selected
if (Object.keys($scope.ctrl.member).length > 0) { if (Object.keys($scope.ctrl.member).length > 0) {
@ -218,9 +218,9 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
} }
} }
// # /**
// Open a modal window which trigger the stripe payment process * Open a modal window which trigger the stripe payment process
// # */
var payByStripe = () => var payByStripe = () =>
$uibModal.open({ $uibModal.open({
templateUrl: '<%= asset_path "stripe/payment_modal.html" %>', templateUrl: '<%= asset_path "stripe/payment_modal.html" %>',
@ -251,11 +251,11 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
// retrieve the CGV // retrieve the CGV
CustomAsset.get({ name: 'cgv-file' }, cgv => $scope.cgv = cgv.custom_asset) CustomAsset.get({ name: 'cgv-file' }, cgv => $scope.cgv = cgv.custom_asset)
// # /**
// Callback for click on the 'proceed' button. * Callback for click on the 'proceed' button.
// Handle the stripe's card tokenization process response and save the subscription to the API with the * Handle the stripe's card tokenization process response and save the subscription to the API with the
// card token just created. * card token just created.
// # */
return $scope.payment = function (status, response) { return $scope.payment = function (status, response) {
if (response.error) { if (response.error) {
return growl.error(response.error.message) return growl.error(response.error.message)
@ -289,9 +289,9 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
return $scope.coupon.applied = null return $scope.coupon.applied = null
}) })
// # /**
// Open a modal window which trigger the local payment process * Open a modal window which trigger the local payment process
// # */
var payOnSite = () => var payOnSite = () =>
$uibModal.open({ $uibModal.open({
templateUrl: '<%= asset_path "plans/payment_modal.html" %>', templateUrl: '<%= asset_path "plans/payment_modal.html" %>',
@ -336,10 +336,10 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
} }
} }
// # /**
// Callback for the 'proceed' button. * Callback for the 'proceed' button.
// Save the subscription to the API * Save the subscription to the API
// # */
$scope.ok = function () { $scope.ok = function () {
$scope.attempting = true $scope.attempting = true
return Subscription.save({ return Subscription.save({
@ -359,10 +359,10 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
}) })
} }
// # /**
// Callback for the 'cancel' button. * Callback for the 'cancel' button.
// Close the modal box. * Close the modal box.
// # */
return $scope.cancel = () => $uibModalInstance.dismiss('cancel') return $scope.cancel = () => $uibModalInstance.dismiss('cancel')
} }
] }) ] })
@ -375,7 +375,7 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
return $scope.coupon.applied = null return $scope.coupon.applied = null
}) })
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])

View File

@ -17,37 +17,37 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
function ($scope, $rootScope, $state, $window, _t, growl, CSRF, Auth, Member, settingsPromise, activeProviderPromise, groupsPromise, cguFile, memberPromise, Session, dialogs, AuthProvider) { function ($scope, $rootScope, $state, $window, _t, growl, CSRF, Auth, Member, settingsPromise, activeProviderPromise, groupsPromise, cguFile, memberPromise, Session, dialogs, AuthProvider) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = `/api/members/${memberPromise.id}` $scope.actionUrl = `/api/members/${memberPromise.id}`
// # Form action on the above URL // Form action on the above URL
$scope.method = 'patch' $scope.method = 'patch'
// # genre of the application name (eg. "_le_ Fablab" or "_la_ Fabrique") // genre of the application name (eg. "_le_ Fablab" or "_la_ Fabrique")
$scope.nameGenre = settingsPromise.name_genre $scope.nameGenre = settingsPromise.name_genre
// # name of the current fablab application (eg. "Fablab de la Casemate") // name of the current fablab application (eg. "Fablab de la Casemate")
$scope.fablabName = settingsPromise.fablab_name $scope.fablabName = settingsPromise.fablab_name
// # information from the current SSO provider // information from the current SSO provider
$scope.activeProvider = activeProviderPromise $scope.activeProvider = activeProviderPromise
// # list of user's groups (student/standard/...) // list of user's groups (student/standard/...)
$scope.groups = groupsPromise $scope.groups = groupsPromise
// # current user, contains information retrieved from the SSO // current user, contains information retrieved from the SSO
$scope.user = memberPromise $scope.user = memberPromise
// # disallow the user to change his password as he connect from SSO // disallow the user to change his password as he connect from SSO
$scope.preventPassword = true $scope.preventPassword = true
// # mapping of fields to disable // mapping of fields to disable
$scope.preventField = {} $scope.preventField = {}
// # CGU // CGU
$scope.cgu = cguFile.custom_asset $scope.cgu = cguFile.custom_asset
// # Angular-Bootstrap datepicker configuration for birthday // Angular-Bootstrap datepicker configuration for birthday
$scope.datePicker = { $scope.datePicker = {
format: Fablab.uibDateFormat, format: Fablab.uibDateFormat,
opened: false, // default: datePicker is not shown opened: false, // default: datePicker is not shown
@ -56,23 +56,23 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
} }
} }
// # /**
// Callback to diplay the datepicker as a dropdown when clicking on the input field * Callback to diplay the datepicker as a dropdown when clicking on the input field
// @param $event {Object} jQuery event object * @param $event {Object} jQuery event object
// # */
$scope.openDatePicker = function ($event) { $scope.openDatePicker = function ($event) {
$event.preventDefault() $event.preventDefault()
$event.stopPropagation() $event.stopPropagation()
return $scope.datePicker.opened = true return $scope.datePicker.opened = true
} }
// # /**
// For use with ngUpload (https://github.com/twilson63/ngUpload). * 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 * 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's profile is updated and the user is * $scope.alerts array. If everything goes fine, the user's profile is updated and the user is
// redirected to the home page * redirected to the home page
// @param content {Object} JSON - The upload's result * @param content {Object} JSON - The upload's result
// # */
$scope.submited = function (content) { $scope.submited = function (content) {
if ((content.id == null)) { if ((content.id == null)) {
$scope.alerts = [] $scope.alerts = []
@ -96,11 +96,11 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
} }
} }
// # /**
// For use with 'ng-class', returns the CSS class name for the uploads previews. * 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. * 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) * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)
// # */
$scope.fileinputClass = function (v) { $scope.fileinputClass = function (v) {
if (v) { if (v) {
return 'fileinput-exists' return 'fileinput-exists'
@ -109,9 +109,9 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
} }
} }
// # /**
// Merge the current user into the account with the given auth_token * Merge the current user into the account with the given auth_token
// # */
$scope.registerAuthToken = () => $scope.registerAuthToken = () =>
Member.merge({ id: $rootScope.currentUser.id }, { user: { auth_token: $scope.user.auth_token } }, function (user) { Member.merge({ id: $rootScope.currentUser.id }, { user: { auth_token: $scope.user.auth_token } }, function (user) {
$scope.user = user $scope.user = user
@ -128,10 +128,10 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
} }
}) })
// # /**
// Return the email given by the SSO provider, parsed if needed * Return the email given by the SSO provider, parsed if needed
// @return {String} E-mail of the current user * @return {String} E-mail of the current user
// # */
$scope.ssoEmail = function () { $scope.ssoEmail = function () {
const { email } = memberPromise const { email } = memberPromise
if (email) { if (email) {
@ -143,10 +143,10 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
return email return email
} }
// # /**
// Test if the user's mail is marked as duplicate * Test if the user's mail is marked as duplicate
// @return {boolean} * @return {boolean}
// # */
$scope.hasDuplicate = function () { $scope.hasDuplicate = function () {
const { email } = memberPromise const { email } = memberPromise
if (email) { if (email) {
@ -154,10 +154,10 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
} }
} }
// # /**
// Ask for email confirmation and send the SSO merging token again * Ask for email confirmation and send the SSO merging token again
// @param $event {Object} jQuery event object * @param $event {Object} jQuery event object
// # */
$scope.resendCode = function (event) { $scope.resendCode = function (event) {
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
@ -176,9 +176,9 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
) )
} }
// # /**
// Disconnect and re-connect the user to the SSO to force the synchronisation of the profile's data * Disconnect and re-connect the user to the SSO to force the synchronisation of the profile's data
// # */
$scope.syncProfile = () => $scope.syncProfile = () =>
Auth.logout().then(function (oldUser) { Auth.logout().then(function (oldUser) {
Session.destroy() Session.destroy()
@ -193,9 +193,9 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
CSRF.setMetaTags() CSRF.setMetaTags()
@ -206,7 +206,7 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
return angular.forEach(activeProviderPromise.mapping, map => $scope.preventField[map] = true) return angular.forEach(activeProviderPromise.mapping, map => $scope.preventField[map] = true)
} }
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }

View File

@ -17,33 +17,33 @@
/* COMMON CODE */ /* COMMON CODE */
// # /**
// Provides a set of common properties and methods to the $scope parameter. They are used * Provides a set of common properties and methods to the $scope parameter. They are used
// in the various projects' admin controllers. * in the various projects' admin controllers.
// *
// Provides : * Provides :
// - $scope.totalSteps * - $scope.totalSteps
// - $scope.machines = [{Machine}] * - $scope.machines = [{Machine}]
// - $scope.components = [{Component}] * - $scope.components = [{Component}]
// - $scope.themes = [{Theme}] * - $scope.themes = [{Theme}]
// - $scope.licences = [{Licence}] * - $scope.licences = [{Licence}]
// - $scope.allowedExtensions = [{String}] * - $scope.allowedExtensions = [{String}]
// - $scope.submited(content) * - $scope.submited(content)
// - $scope.cancel() * - $scope.cancel()
// - $scope.addFile() * - $scope.addFile()
// - $scope.deleteFile(file) * - $scope.deleteFile(file)
// - $scope.addStep() * - $scope.addStep()
// - $scope.deleteStep(step) * - $scope.deleteStep(step)
// - $scope.changeStepIndex(step, newIdx) * - $scope.changeStepIndex(step, newIdx)
// *
// Requires : * Requires :
// - $scope.project.project_caos_attributes = [] * - $scope.project.project_caos_attributes = []
// - $scope.project.project_steps_attributes = [] * - $scope.project.project_steps_attributes = []
// - $state (Ui-Router) [ 'app.public.projects_show', 'app.public.projects_list' ] * - $state (Ui-Router) [ 'app.public.projects_show', 'app.public.projects_list' ]
// # */
class ProjectsController { class ProjectsController {
constructor ($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t) { constructor ($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t) {
// # Retrieve the list of machines from the server // Retrieve the list of machines from the server
Machine.query().$promise.then(data => Machine.query().$promise.then(data =>
$scope.machines = data.map(d => $scope.machines = data.map(d =>
({ ({
@ -53,7 +53,7 @@ class ProjectsController {
) )
) )
// # Retrieve the list of components from the server // Retrieve the list of components from the server
Component.query().$promise.then(data => Component.query().$promise.then(data =>
$scope.components = data.map(d => $scope.components = data.map(d =>
({ ({
@ -63,7 +63,7 @@ class ProjectsController {
) )
) )
// # Retrieve the list of themes from the server // Retrieve the list of themes from the server
Theme.query().$promise.then(data => Theme.query().$promise.then(data =>
$scope.themes = data.map(d => $scope.themes = data.map(d =>
({ ({
@ -73,7 +73,7 @@ class ProjectsController {
) )
) )
// # Retrieve the list of licences from the server // Retrieve the list of licences from the server
Licence.query().$promise.then(data => Licence.query().$promise.then(data =>
$scope.licences = data.map(d => $scope.licences = data.map(d =>
({ ({
@ -83,18 +83,18 @@ class ProjectsController {
) )
) )
// # Total number of documentation steps for the current project // Total number of documentation steps for the current project
$scope.totalSteps = $scope.project.project_steps_attributes.length $scope.totalSteps = $scope.project.project_steps_attributes.length
// # List of extensions allowed for CAD attachements upload // List of extensions allowed for CAD attachements upload
$scope.allowedExtensions = allowedExtensions $scope.allowedExtensions = allowedExtensions
// # /**
// For use with ngUpload (https://github.com/twilson63/ngUpload). * For use with ngUpload (https://github.com/twilson63/ngUpload).
// Intended to be the callback when an upload is done: any raised error will be stacked in the * Intended to be the callback when an upload is done: any raised error will be stacked in the
// $scope.alerts array. If everything goes fine, the user is redirected to the project page. * $scope.alerts array. If everything goes fine, the user is redirected to the project page.
// @param content {Object} JSON - The upload's result * @param content {Object} JSON - The upload's result
// # */
$scope.submited = function (content) { $scope.submited = function (content) {
if ((content.id == null)) { if ((content.id == null)) {
$scope.alerts = [] $scope.alerts = []
@ -113,11 +113,11 @@ class ProjectsController {
} }
} }
// # /**
// For use with 'ng-class', returns the CSS class name for the uploads previews. * 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. * 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) * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)
// # */
$scope.fileinputClass = function (v) { $scope.fileinputClass = function (v) {
if (v) { if (v) {
return 'fileinput-exists' return 'fileinput-exists'
@ -126,17 +126,17 @@ class ProjectsController {
} }
} }
// # /**
// This will create a single new empty entry into the project's CAO attachements list. * This will create a single new empty entry into the project's CAO attachements list.
// # */
$scope.addFile = () => $scope.project.project_caos_attributes.push({}) $scope.addFile = () => $scope.project.project_caos_attributes.push({})
// # /**
// This will remove the given file from the project's CAO attachements list. If the file was previously uploaded * This will remove the given file from the project's CAO attachements list. If the file was previously uploaded
// to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from * to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from
// the CAO attachements array. * the CAO attachements array.
// @param file {Object} the file to delete * @param file {Object} the file to delete
// # */
$scope.deleteFile = function (file) { $scope.deleteFile = function (file) {
const index = $scope.project.project_caos_attributes.indexOf(file) const index = $scope.project.project_caos_attributes.indexOf(file)
if (file.id != null) { if (file.id != null) {
@ -146,20 +146,20 @@ class ProjectsController {
} }
} }
// # /**
// This will create a single new empty entry into the project's steps list. * This will create a single new empty entry into the project's steps list.
// # */
$scope.addStep = function () { $scope.addStep = function () {
$scope.totalSteps += 1 $scope.totalSteps += 1
return $scope.project.project_steps_attributes.push({ step_nb: $scope.totalSteps, project_step_images_attributes: [] }) return $scope.project.project_steps_attributes.push({ step_nb: $scope.totalSteps, project_step_images_attributes: [] })
} }
// # /**
// This will remove the given step from the project's steps list. If the step was previously saved * This will remove the given step from the project's steps list. If the step was previously saved
// on the server, it will be marked for deletion for the next saving. Otherwise, it will be simply truncated from * on the server, it will be marked for deletion for the next saving. Otherwise, it will be simply truncated from
// the steps array. * the steps array.
// @param file {Object} the file to delete * @param file {Object} the file to delete
// # */
$scope.deleteStep = step => $scope.deleteStep = step =>
dialogs.confirm({ dialogs.confirm({
resolve: { resolve: {
@ -195,13 +195,13 @@ class ProjectsController {
})() })()
}) })
// # /**
// Change the step_nb property of the given step to the new value provided. The step that was previously at this * Change the step_nb property of the given step to the new value provided. The step that was previously at this
// index will be assigned to the old position of the provided step. * index will be assigned to the old position of the provided step.
// @param event {Object} see https://docs.angularjs.org/guide/expression#-event- * @param event {Object} see https://docs.angularjs.org/guide/expression#-event-
// @param step {Object} the project's step to reindex * @param step {Object} the project's step to reindex
// @param newIdx {number} the new index to assign to the step * @param newIdx {number} the new index to assign to the step
// # */
$scope.changeStepIndex = function (event, step, newIdx) { $scope.changeStepIndex = function (event, step, newIdx) {
if (event) { event.preventDefault() } if (event) { event.preventDefault() }
for (let s of Array.from($scope.project.project_steps_attributes)) { for (let s of Array.from($scope.project.project_steps_attributes)) {
@ -224,16 +224,16 @@ class ProjectsController {
, error => console.error(error)) , error => console.error(error))
} }
// # /**
// This will create a single new empty entry into the project's step image list. * This will create a single new empty entry into the project's step image list.
// # */
$scope.addProjectStepImage = step => step.project_step_images_attributes.push({}) $scope.addProjectStepImage = step => step.project_step_images_attributes.push({})
// # /**
// This will remove the given image from the project's step image list. * This will remove the given image from the project's step image list.
// @param step {Object} the project step has images * @param step {Object} the project step has images
// @param image {Object} the image to delete * @param image {Object} the image to delete
// # */
$scope.deleteProjectStepImage = function (step, image) { $scope.deleteProjectStepImage = function (step, image) {
const index = step.project_step_images_attributes.indexOf(image) const index = step.project_step_images_attributes.indexOf(image)
if (image.id != null) { if (image.id != null) {
@ -245,9 +245,9 @@ class ProjectsController {
} }
} }
// # /**
// Controller used on projects listing page * Controller used on projects listing page
// # */
Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'Project', 'machinesPromise', 'themesPromise', 'componentsPromise', 'paginationService', 'OpenlabProject', '$window', 'growl', '_t', '$location', '$timeout', Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'Project', 'machinesPromise', 'themesPromise', 'componentsPromise', 'paginationService', 'OpenlabProject', '$window', 'growl', '_t', '$location', '$timeout',
function ($scope, $state, Project, machinesPromise, themesPromise, componentsPromise, paginationService, OpenlabProject, $window, growl, _t, $location, $timeout) { function ($scope, $state, Project, machinesPromise, themesPromise, componentsPromise, paginationService, OpenlabProject, $window, growl, _t, $location, $timeout) {
/* PRIVATE STATIC CONSTANTS */ /* PRIVATE STATIC CONSTANTS */
@ -257,16 +257,16 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # Fab-manager's instance ID in the openLab network // Fab-manager's instance ID in the openLab network
$scope.openlabAppId = Fablab.openlabAppId $scope.openlabAppId = Fablab.openlabAppId
// # Is openLab enabled on the instance? // Is openLab enabled on the instance?
$scope.openlab = { $scope.openlab = {
projectsActive: Fablab.openlabProjectsActive, projectsActive: Fablab.openlabProjectsActive,
searchOverWholeNetwork: false searchOverWholeNetwork: false
} }
// # default search parameters // default search parameters
$scope.search = { $scope.search = {
q: ($location.$$search.q || ''), q: ($location.$$search.q || ''),
from: ($location.$$search.from || undefined), from: ($location.$$search.from || undefined),
@ -275,16 +275,16 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
theme_id: (parseInt($location.$$search.theme_id) || undefined) theme_id: (parseInt($location.$$search.theme_id) || undefined)
} }
// # list of projects to display // list of projects to display
$scope.projects = [] $scope.projects = []
// # list of machines / used for filtering // list of machines / used for filtering
$scope.machines = machinesPromise $scope.machines = machinesPromise
// # list of themes / used for filtering // list of themes / used for filtering
$scope.themes = themesPromise $scope.themes = themesPromise
// # list of components / used for filtering // list of components / used for filtering
$scope.components = componentsPromise $scope.components = componentsPromise
$scope.searchOverWholeNetworkChanged = () => $scope.searchOverWholeNetworkChanged = () =>
@ -334,10 +334,10 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
} }
} }
// # /**
// Callback to switch the user's view to the detailled project page * Callback to switch the user's view to the detailled project page
// @param project {{slug:string}} The project to display * @param project {{slug:string}} The project to display
// # */
$scope.showProject = function (project) { $scope.showProject = function (project) {
if (($scope.openlab.searchOverWholeNetwork === true) && (project.app_id !== Fablab.openlabAppId)) { if (($scope.openlab.searchOverWholeNetwork === true) && (project.app_id !== Fablab.openlabAppId)) {
$window.open(project.project_url, '_blank') $window.open(project.project_url, '_blank')
@ -347,9 +347,9 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
} }
} }
// # /**
// function to set all url query search parameters from search object * function to set all url query search parameters from search object
// # */
$scope.setUrlQueryParams = function (search) { $scope.setUrlQueryParams = function (search) {
updateUrlParam('page', 1) updateUrlParam('page', 1)
updateUrlParam('q', search.q) updateUrlParam('q', search.q)
@ -361,9 +361,9 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
if ($location.$$search.whole_network === 'f') { if ($location.$$search.whole_network === 'f') {
$scope.openlab.searchOverWholeNetwork = false $scope.openlab.searchOverWholeNetwork = false
@ -373,10 +373,10 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
return $scope.triggerSearch() return $scope.triggerSearch()
} }
// # /**
// function to update url query param, little hack to turn off reloadOnSearch and re-enable it after setting the params * function to update url query param, little hack to turn off reloadOnSearch and re-enable it after setting the params
// params example: 'q' , 'presse-purée' * params example: 'q' , 'presse-purée'
// # */
var updateUrlParam = function (name, value) { var updateUrlParam = function (name, value) {
$state.current.reloadOnSearch = false $state.current.reloadOnSearch = false
$location.search(name, value) $location.search(name, value)
@ -399,25 +399,25 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
return project return project
}) })
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }
]) ])
// # /**
// Controller used in the project creation page * Controller used in the project creation page
// # */
Application.Controllers.controller('NewProjectController', ['$scope', '$state', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'Diacritics', 'dialogs', 'allowedExtensions', '_t', Application.Controllers.controller('NewProjectController', ['$scope', '$state', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'Diacritics', 'dialogs', 'allowedExtensions', '_t',
function ($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, Diacritics, dialogs, allowedExtensions, _t) { function ($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, Diacritics, dialogs, allowedExtensions, _t) {
CSRF.setMetaTags() CSRF.setMetaTags()
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = '/api/projects/' $scope.actionUrl = '/api/projects/'
// # Form action on the above URL // Form action on the above URL
$scope.method = 'post' $scope.method = 'post'
// # Default project parameters // Default project parameters
$scope.project = { $scope.project = {
project_steps_attributes: [], project_steps_attributes: [],
project_caos_attributes: [] project_caos_attributes: []
@ -425,25 +425,25 @@ Application.Controllers.controller('NewProjectController', ['$scope', '$state',
$scope.matchingMembers = [] $scope.matchingMembers = []
// # Using the ProjectsController // Using the ProjectsController
return new ProjectsController($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t) return new ProjectsController($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t)
} }
]) ])
// # /**
// Controller used in the project edition page * Controller used in the project edition page
// # */
Application.Controllers.controller('EditProjectController', ['$scope', '$state', '$stateParams', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'projectPromise', 'Diacritics', 'dialogs', 'allowedExtensions', '_t', Application.Controllers.controller('EditProjectController', ['$scope', '$state', '$stateParams', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'projectPromise', 'Diacritics', 'dialogs', 'allowedExtensions', '_t',
function ($scope, $state, $stateParams, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, projectPromise, Diacritics, dialogs, allowedExtensions, _t) { function ($scope, $state, $stateParams, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, projectPromise, Diacritics, dialogs, allowedExtensions, _t) {
CSRF.setMetaTags() CSRF.setMetaTags()
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = `/api/projects/${$stateParams.id}` $scope.actionUrl = `/api/projects/${$stateParams.id}`
// # Form action on the above URL // Form action on the above URL
$scope.method = 'put' $scope.method = 'put'
// # Retrieve the project's details, if an error occured, redirect the user to the projects list page // Retrieve the project's details, if an error occured, redirect the user to the projects list page
$scope.project = projectPromise $scope.project = projectPromise
$scope.matchingMembers = $scope.project.project_users.map(u => $scope.matchingMembers = $scope.project.project_users.map(u =>
@ -453,28 +453,28 @@ Application.Controllers.controller('EditProjectController', ['$scope', '$state',
}) })
) )
// # Using the ProjectsController // Using the ProjectsController
return new ProjectsController($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t) return new ProjectsController($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t)
} }
]) ])
// # /**
// Controller used in the public project's details page * Controller used in the public project's details page
// # */
Application.Controllers.controller('ShowProjectController', ['$scope', '$state', 'projectPromise', '$location', '$uibModal', 'dialogs', '_t', Application.Controllers.controller('ShowProjectController', ['$scope', '$state', 'projectPromise', '$location', '$uibModal', 'dialogs', '_t',
function ($scope, $state, projectPromise, $location, $uibModal, dialogs, _t) { function ($scope, $state, projectPromise, $location, $uibModal, dialogs, _t) {
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # Store the project's details // Store the project's details
$scope.project = projectPromise $scope.project = projectPromise
$scope.projectUrl = $location.absUrl() $scope.projectUrl = $location.absUrl()
$scope.disqusShortname = Fablab.disqusShortname $scope.disqusShortname = Fablab.disqusShortname
// # /**
// Test if the provided user has the edition rights on the current project * Test if the provided user has the edition rights on the current project
// @param [user] {{id:number}} (optional) the user to check rights * @param [user] {{id:number}} (optional) the user to check rights
// @returns boolean * @returns boolean
// # */
$scope.projectEditableBy = function (user) { $scope.projectEditableBy = function (user) {
if ((user == null)) { return false } if ((user == null)) { return false }
if ($scope.project.author_id === user.id) { return true } if ($scope.project.author_id === user.id) { return true }
@ -485,20 +485,20 @@ Application.Controllers.controller('ShowProjectController', ['$scope', '$state',
return canEdit return canEdit
} }
// # /**
// Test if the provided user has the deletion rights on the current project * Test if the provided user has the deletion rights on the current project
// @param [user] {{id:number}} (optional) the user to check rights * @param [user] {{id:number}} (optional) the user to check rights
// @returns boolean * @returns boolean
// # */
$scope.projectDeletableBy = function (user) { $scope.projectDeletableBy = function (user) {
if ((user == null)) { return false } if ((user == null)) { return false }
if ($scope.project.author_id === user.id) { return true } if ($scope.project.author_id === user.id) { return true }
} }
// # /**
// Callback to delete the current project. Then, the user is redirected to the projects list page, * Callback to delete the current project. Then, the user is redirected to the projects list page,
// which is refreshed. Admins and project owner only are allowed to delete a project * which is refreshed. Admins and project owner only are allowed to delete a project
// # */
$scope.deleteProject = function () { $scope.deleteProject = function () {
// check the permissions // check the permissions
if (($scope.currentUser.role === 'admin') || $scope.projectDeletableBy($scope.currentUser)) { if (($scope.currentUser.role === 'admin') || $scope.projectDeletableBy($scope.currentUser)) {
@ -521,10 +521,10 @@ Application.Controllers.controller('ShowProjectController', ['$scope', '$state',
} }
} }
// # /**
// Open a modal box containg a form that allow the end-user to signal an abusive content * Open a modal box containg a form that allow the end-user to signal an abusive content
// @param e {Object} jQuery event * @param e {Object} jQuery event
// # */
$scope.signalAbuse = function (e) { $scope.signalAbuse = function (e) {
if (e) { e.preventDefault() } if (e) { e.preventDefault() }
@ -559,14 +559,14 @@ Application.Controllers.controller('ShowProjectController', ['$scope', '$state',
] }) ] })
} }
// # /**
// Return the URL allowing to share the current project on the Facebook social network * Return the URL allowing to share the current project on the Facebook social network
// # */
$scope.shareOnFacebook = () => `https://www.facebook.com/share.php?u=${$state.href('app.public.projects_show', { id: $scope.project.slug }, { absolute: true }).replace('#', '%23')}` $scope.shareOnFacebook = () => `https://www.facebook.com/share.php?u=${$state.href('app.public.projects_show', { id: $scope.project.slug }, { absolute: true }).replace('#', '%23')}`
// # /**
// Return the URL allowing to share the current project on the Twitter social network * Return the URL allowing to share the current project on the Twitter social network
// # */
return $scope.shareOnTwitter = () => `https://twitter.com/intent/tweet?url=${encodeURIComponent($state.href('app.public.projects_show', { id: $scope.project.slug }, { absolute: true }))}&text=${encodeURIComponent($scope.project.name)}` return $scope.shareOnTwitter = () => `https://twitter.com/intent/tweet?url=${encodeURIComponent($state.href('app.public.projects_show', { id: $scope.project.slug }, { absolute: true }))}&text=${encodeURIComponent($scope.project.name)}`
} }
]) ])

View File

@ -16,29 +16,29 @@
/* COMMON CODE */ /* COMMON CODE */
// # /**
// Provides a set of common callback methods to the $scope parameter. These methods are used * Provides a set of common callback methods to the $scope parameter. These methods are used
// in the various spaces' admin controllers. * in the various spaces' admin controllers.
// *
// Provides : * Provides :
// - $scope.submited(content) * - $scope.submited(content)
// - $scope.cancel() * - $scope.cancel()
// - $scope.fileinputClass(v) * - $scope.fileinputClass(v)
// - $scope.addFile() * - $scope.addFile()
// - $scope.deleteFile(file) * - $scope.deleteFile(file)
// *
// Requires : * Requires :
// - $scope.space.space_files_attributes = [] * - $scope.space.space_files_attributes = []
// - $state (Ui-Router) [ 'app.public.spaces_list' ] * - $state (Ui-Router) [ 'app.public.spaces_list' ]
// # /*
class SpacesController { class SpacesController {
constructor ($scope, $state) { constructor ($scope, $state) {
// # /*
// For use with ngUpload (https://github.com/twilson63/ngUpload). * 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 * 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 spaces list. * $scope.alerts array. If everything goes fine, the user is redirected to the spaces list.
// @param content {Object} JSON - The upload's result * @param content {Object} JSON - The upload's result
// # */
$scope.submited = function (content) { $scope.submited = function (content) {
if ((content.id == null)) { if ((content.id == null)) {
$scope.alerts = [] $scope.alerts = []
@ -55,16 +55,16 @@ class SpacesController {
} }
} }
// # /**
// Changes the current user's view, redirecting him to the spaces list * Changes the current user's view, redirecting him to the spaces list
// # */
$scope.cancel = () => $state.go('app.public.spaces_list') $scope.cancel = () => $state.go('app.public.spaces_list')
// # /**
// For use with 'ng-class', returns the CSS class name for the uploads previews. * 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. * 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) * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)
// # */
$scope.fileinputClass = function (v) { $scope.fileinputClass = function (v) {
if (v) { if (v) {
return 'fileinput-exists' return 'fileinput-exists'
@ -73,17 +73,17 @@ class SpacesController {
} }
} }
// # /**
// This will create a single new empty entry into the space attachements list. * This will create a single new empty entry into the space attachements list.
// # */
$scope.addFile = () => $scope.space.space_files_attributes.push({}) $scope.addFile = () => $scope.space.space_files_attributes.push({})
// # /**
// This will remove the given file from the space attachements list. If the file was previously uploaded * This will remove the given file from the space attachements list. If the file was previously uploaded
// to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from * to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from
// the attachements array. * the attachements array.
// @param file {Object} the file to delete * @param file {Object} the file to delete
// # */
$scope.deleteFile = function (file) { $scope.deleteFile = function (file) {
const index = $scope.space.space_files_attributes.indexOf(file) const index = $scope.space.space_files_attributes.indexOf(file)
if (file.id != null) { if (file.id != null) {
@ -95,27 +95,27 @@ class SpacesController {
} }
} }
// # /**
// Controller used in the public listing page, allowing everyone to see the list of spaces * Controller used in the public listing page, allowing everyone to see the list of spaces
// # */
Application.Controllers.controller('SpacesController', ['$scope', '$state', 'spacesPromise', function ($scope, $state, spacesPromise) { Application.Controllers.controller('SpacesController', ['$scope', '$state', 'spacesPromise', function ($scope, $state, spacesPromise) {
// # Retrieve the list of spaces // Retrieve the list of spaces
$scope.spaces = spacesPromise $scope.spaces = spacesPromise
// # /**
// Redirect the user to the space details page * Redirect the user to the space details page
// # */
$scope.showSpace = space => $state.go('app.public.space_show', { id: space.slug }) $scope.showSpace = space => $state.go('app.public.space_show', { id: space.slug })
// # /**
// Callback to book a reservation for the current space * Callback to book a reservation for the current space
// # */
$scope.reserveSpace = space => $state.go('app.logged.space_reserve', { id: space.slug }) $scope.reserveSpace = space => $state.go('app.logged.space_reserve', { id: space.slug })
// # Default: we show only enabled spaces // Default: we show only enabled spaces
$scope.spaceFiltering = 'enabled' $scope.spaceFiltering = 'enabled'
// # Available options for filtering spaces by status // Available options for filtering spaces by status
return $scope.filterDisabled = [ return $scope.filterDisabled = [
'enabled', 'enabled',
'disabled', 'disabled',
@ -124,64 +124,64 @@ Application.Controllers.controller('SpacesController', ['$scope', '$state', 'spa
} }
]) ])
// # /**
// Controller used in the space creation page (admin) * Controller used in the space creation page (admin)
// # */
Application.Controllers.controller('NewSpaceController', ['$scope', '$state', 'CSRF', function ($scope, $state, CSRF) { Application.Controllers.controller('NewSpaceController', ['$scope', '$state', 'CSRF', function ($scope, $state, CSRF) {
CSRF.setMetaTags() CSRF.setMetaTags()
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = '/api/spaces/' $scope.actionUrl = '/api/spaces/'
// # Form action on the above URL // Form action on the above URL
$scope.method = 'post' $scope.method = 'post'
// # default space parameters // default space parameters
$scope.space = $scope.space =
{ space_files_attributes: [] } { space_files_attributes: [] }
// # Using the SpacesController // Using the SpacesController
return new SpacesController($scope, $state) return new SpacesController($scope, $state)
} }
]) ])
// # /**
// Controller used in the space edition page (admin) * Controller used in the space edition page (admin)
// # */
Application.Controllers.controller('EditSpaceController', ['$scope', '$state', '$stateParams', 'spacePromise', 'CSRF', function ($scope, $state, $stateParams, spacePromise, CSRF) { Application.Controllers.controller('EditSpaceController', ['$scope', '$state', '$stateParams', 'spacePromise', 'CSRF', function ($scope, $state, $stateParams, spacePromise, CSRF) {
CSRF.setMetaTags() CSRF.setMetaTags()
// # API URL where the form will be posted // API URL where the form will be posted
$scope.actionUrl = `/api/spaces/${$stateParams.id}` $scope.actionUrl = `/api/spaces/${$stateParams.id}`
// # Form action on the above URL // Form action on the above URL
$scope.method = 'put' $scope.method = 'put'
// # space to modify // space to modify
$scope.space = spacePromise $scope.space = spacePromise
// # Using the SpacesController // Using the SpacesController
return new SpacesController($scope, $state) return new SpacesController($scope, $state)
} }
]) ])
Application.Controllers.controller('ShowSpaceController', ['$scope', '$state', 'spacePromise', '_t', 'dialogs', 'growl', function ($scope, $state, spacePromise, _t, dialogs, growl) { Application.Controllers.controller('ShowSpaceController', ['$scope', '$state', 'spacePromise', '_t', 'dialogs', 'growl', function ($scope, $state, spacePromise, _t, dialogs, growl) {
// # Details of the space witch id/slug is provided in the URL // Details of the space witch id/slug is provided in the URL
$scope.space = spacePromise $scope.space = spacePromise
// # /**
// Callback to book a reservation for the current space * Callback to book a reservation for the current space
// @param event {Object} see https://docs.angularjs.org/guide/expression#-event- * @param event {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
$scope.reserveSpace = function (event) { $scope.reserveSpace = function (event) {
event.preventDefault() event.preventDefault()
return $state.go('app.logged.space_reserve', { id: $scope.space.slug }) return $state.go('app.logged.space_reserve', { id: $scope.space.slug })
} }
// # /**
// Callback to book a reservation for the current space * Callback to book a reservation for the current space
// @param event {Object} see https://docs.angularjs.org/guide/expression#-event- * @param event {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
return $scope.deleteSpace = function (event) { return $scope.deleteSpace = function (event) {
event.preventDefault() event.preventDefault()
// check the permissions // check the permissions
@ -208,11 +208,11 @@ Application.Controllers.controller('ShowSpaceController', ['$scope', '$state', '
} }
]) ])
// # /**
// Controller used in the spaces reservation agenda page. * Controller used in the spaces reservation agenda page.
// This controller is very similar to the machine reservation controller with one major difference: here, there is many places * This controller is very similar to the machine reservation controller with one major difference: here, there is many places
// per slots. * per slots.
// # */
Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateParams', 'Auth', '$timeout', 'Availability', 'Member', 'availabilitySpacesPromise', 'plansPromise', 'groupsPromise', 'settingsPromise', 'spacePromise', '_t', 'uiCalendarConfig', 'CalendarConfig', Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateParams', 'Auth', '$timeout', 'Availability', 'Member', 'availabilitySpacesPromise', 'plansPromise', 'groupsPromise', 'settingsPromise', 'spacePromise', '_t', 'uiCalendarConfig', 'CalendarConfig',
function ($scope, $stateParams, Auth, $timeout, Availability, Member, availabilitySpacesPromise, plansPromise, groupsPromise, settingsPromise, spacePromise, _t, uiCalendarConfig, CalendarConfig) { function ($scope, $stateParams, Auth, $timeout, Availability, Member, availabilitySpacesPromise, plansPromise, groupsPromise, settingsPromise, spacePromise, _t, uiCalendarConfig, CalendarConfig) {
@ -229,14 +229,14 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # bind the spaces availabilities with full-Calendar events // bind the spaces availabilities with full-Calendar events
$scope.eventSources = [ { events: availabilitySpacesPromise, textColor: 'black' } ] $scope.eventSources = [ { events: availabilitySpacesPromise, textColor: 'black' } ]
// # the user to deal with, ie. the current user for non-admins // the user to deal with, ie. the current user for non-admins
$scope.ctrl = $scope.ctrl =
{ member: {} } { member: {} }
// # list of plans, classified by group // list of plans, classified by group
$scope.plansClassifiedByGroup = [] $scope.plansClassifiedByGroup = []
for (let group of Array.from(groupsPromise)) { for (let group of Array.from(groupsPromise)) {
const groupObj = { id: group.id, name: group.name, plans: [] } const groupObj = { id: group.id, name: group.name, plans: [] }
@ -246,7 +246,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
$scope.plansClassifiedByGroup.push(groupObj) $scope.plansClassifiedByGroup.push(groupObj)
} }
// # mapping of fullCalendar events. // mapping of fullCalendar events.
$scope.events = { $scope.events = {
reserved: [], // Slots that the user wants to book reserved: [], // Slots that the user wants to book
modifiable: null, // Slot that the user wants to change modifiable: null, // Slot that the user wants to change
@ -255,25 +255,25 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
moved: null // Slots that were just moved by the user (change done) -> {newSlot:* oldSlot: *} moved: null // Slots that were just moved by the user (change done) -> {newSlot:* oldSlot: *}
} }
// # the moment when the slot selection changed for the last time, used to trigger changes in the cart // the moment when the slot selection changed for the last time, used to trigger changes in the cart
$scope.selectionTime = null $scope.selectionTime = null
// # the last clicked event in the calender // the last clicked event in the calender
$scope.selectedEvent = null $scope.selectedEvent = null
// # indicates the state of the current view : calendar or plans information // indicates the state of the current view : calendar or plans information
$scope.plansAreShown = false $scope.plansAreShown = false
// # will store the user's plan if he choosed to buy one // will store the user's plan if he choosed to buy one
$scope.selectedPlan = null $scope.selectedPlan = null
// # the moment when the plan selection changed for the last time, used to trigger changes in the cart // the moment when the plan selection changed for the last time, used to trigger changes in the cart
$scope.planSelectionTime = null $scope.planSelectionTime = null
// # Selected space // Selected space
$scope.space = spacePromise $scope.space = spacePromise
// # fullCalendar (v2) configuration // fullCalendar (v2) configuration
$scope.calendarConfig = CalendarConfig({ $scope.calendarConfig = CalendarConfig({
minTime: moment.duration(moment(settingsPromise.booking_window_start).format('HH:mm:ss')), minTime: moment.duration(moment(settingsPromise.booking_window_start).format('HH:mm:ss')),
maxTime: moment.duration(moment(settingsPromise.booking_window_end).format('HH:mm:ss')), maxTime: moment.duration(moment(settingsPromise.booking_window_end).format('HH:mm:ss')),
@ -285,26 +285,26 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
} }
}) })
// # Application global settings // Application global settings
$scope.settings = settingsPromise $scope.settings = settingsPromise
// # Global config: message to the end user concerning the subscriptions rules // Global config: message to the end user concerning the subscriptions rules
$scope.subscriptionExplicationsAlert = settingsPromise.subscription_explications_alert $scope.subscriptionExplicationsAlert = settingsPromise.subscription_explications_alert
// # Global config: message to the end user concerning the space reservation // Global config: message to the end user concerning the space reservation
$scope.spaceExplicationsAlert = settingsPromise.space_explications_alert $scope.spaceExplicationsAlert = settingsPromise.space_explications_alert
// # /**
// Change the last selected slot's appearence to looks like 'added to cart' * Change the last selected slot's appearence to looks like 'added to cart'
// # */
$scope.markSlotAsAdded = function () { $scope.markSlotAsAdded = function () {
$scope.selectedEvent.backgroundColor = SELECTED_EVENT_BG_COLOR $scope.selectedEvent.backgroundColor = SELECTED_EVENT_BG_COLOR
return updateCalendar() return updateCalendar()
} }
// # /**
// Change the last selected slot's appearence to looks like 'never added to cart' * Change the last selected slot's appearence to looks like 'never added to cart'
// # */
$scope.markSlotAsRemoved = function (slot) { $scope.markSlotAsRemoved = function (slot) {
slot.backgroundColor = 'white' slot.backgroundColor = 'white'
slot.title = '' slot.title = ''
@ -318,23 +318,23 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
return updateCalendar() return updateCalendar()
} }
// # /**
// Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book' * Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book'
// # */
$scope.slotCancelled = () => $scope.markSlotAsRemoved($scope.selectedEvent) $scope.slotCancelled = () => $scope.markSlotAsRemoved($scope.selectedEvent)
// # /**
// Change the last selected slot's appearence to looks like 'currently looking for a new destination to exchange' * Change the last selected slot's appearence to looks like 'currently looking for a new destination to exchange'
// # */
$scope.markSlotAsModifying = function () { $scope.markSlotAsModifying = function () {
$scope.selectedEvent.backgroundColor = '#eee' $scope.selectedEvent.backgroundColor = '#eee'
$scope.selectedEvent.title = _t('space_reserve.i_change') $scope.selectedEvent.title = _t('space_reserve.i_change')
return updateCalendar() return updateCalendar()
} }
// # /**
// Change the last selected slot's appearence to looks like 'the slot being exchanged will take this place' * Change the last selected slot's appearence to looks like 'the slot being exchanged will take this place'
// # */
$scope.changeModifyTrainingSlot = function () { $scope.changeModifyTrainingSlot = function () {
if ($scope.events.placable) { if ($scope.events.placable) {
$scope.events.placable.backgroundColor = 'white' $scope.events.placable.backgroundColor = 'white'
@ -347,9 +347,9 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
return updateCalendar() return updateCalendar()
} }
// # /**
// When modifying an already booked reservation, callback when the modification was successfully done. * When modifying an already booked reservation, callback when the modification was successfully done.
// # */
$scope.modifyTrainingSlot = function () { $scope.modifyTrainingSlot = function () {
$scope.events.placable.title = _t('space_reserve.i_ve_reserved') $scope.events.placable.title = _t('space_reserve.i_ve_reserved')
$scope.events.placable.backgroundColor = 'white' $scope.events.placable.backgroundColor = 'white'
@ -369,9 +369,9 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
return updateCalendar() return updateCalendar()
} }
// # /**
// Cancel the current booking modification, reseting the whole process * Cancel the current booking modification, reseting the whole process
// # */
$scope.cancelModifyTrainingSlot = function () { $scope.cancelModifyTrainingSlot = function () {
if ($scope.events.placable) { if ($scope.events.placable) {
$scope.events.placable.backgroundColor = 'white' $scope.events.placable.backgroundColor = 'white'
@ -383,10 +383,10 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
return updateCalendar() return updateCalendar()
} }
// # /**
// Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's * Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's
// reservations. (admins only) * reservations. (admins only)
// # */
$scope.updateMember = function () { $scope.updateMember = function () {
if ($scope.ctrl.member) { if ($scope.ctrl.member) {
Member.get({ id: $scope.ctrl.member.id }, function (member) { Member.get({ id: $scope.ctrl.member.id }, function (member) {
@ -407,10 +407,10 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
return $scope.plansAreShown = false return $scope.plansAreShown = false
} }
// # /**
// Add the provided plan to the current shopping cart * Add the provided plan to the current shopping cart
// @param plan {Object} the plan to subscribe * @param plan {Object} the plan to subscribe
// # */
$scope.selectPlan = function (plan) { $scope.selectPlan = function (plan) {
// toggle selected plan // toggle selected plan
if ($scope.selectedPlan !== plan) { if ($scope.selectedPlan !== plan) {
@ -421,10 +421,10 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
return $scope.planSelectionTime = new Date() return $scope.planSelectionTime = new Date()
} }
// # /**
// Changes the user current view from the plan subsription screen to the machine reservation agenda * Changes the user current view from the plan subsription screen to the machine reservation agenda
// @param e {Object} see https://docs.angularjs.org/guide/expression#-event- * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
$scope.doNotSubscribePlan = function (e) { $scope.doNotSubscribePlan = function (e) {
e.preventDefault() e.preventDefault()
$scope.plansAreShown = false $scope.plansAreShown = false
@ -432,16 +432,16 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
return $scope.planSelectionTime = new Date() return $scope.planSelectionTime = new Date()
} }
// # /**
// Switch the user's view from the reservation agenda to the plan subscription * Switch the user's view from the reservation agenda to the plan subscription
// # */
$scope.showPlans = () => $scope.plansAreShown = true $scope.showPlans = () => $scope.plansAreShown = true
// # /**
// Once the reservation is booked (payment process successfully completed), change the event style * Once the reservation is booked (payment process successfully completed), change the event style
// in fullCalendar, update the user's subscription and free-credits if needed * in fullCalendar, update the user's subscription and free-credits if needed
// @param reservation {Object} * @param reservation {Object}
// # */
$scope.afterPayment = function (reservation) { $scope.afterPayment = function (reservation) {
angular.forEach($scope.events.paid, function (spaceSlot, key) { angular.forEach($scope.events.paid, function (spaceSlot, key) {
spaceSlot.is_reserved = true spaceSlot.is_reserved = true
@ -466,29 +466,29 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
return refetchCalendar() return refetchCalendar()
} }
// # /**
// To use as callback in Array.prototype.filter to get only enabled plans * To use as callback in Array.prototype.filter to get only enabled plans
// # */
$scope.filterDisabledPlans = plan => !plan.disabled $scope.filterDisabledPlans = plan => !plan.disabled
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
if ($scope.currentUser.role !== 'admin') { if ($scope.currentUser.role !== 'admin') {
return Member.get({ id: $scope.currentUser.id }, member => $scope.ctrl.member = member) return Member.get({ id: $scope.currentUser.id }, member => $scope.ctrl.member = member)
} }
} }
// # /**
// Triggered when the user clicks on a reservation slot in the agenda. * Triggered when the user clicks on a reservation slot in the agenda.
// Defines the behavior to adopt depending on the slot status (already booked, free, ready to be reserved ...), * Defines the behavior to adopt depending on the slot status (already booked, free, ready to be reserved ...),
// the user's subscription (current or about to be took) and the time (the user cannot modify a booked reservation * the user's subscription (current or about to be took) and the time (the user cannot modify a booked reservation
// if it's too late). * if it's too late).
// @see http://fullcalendar.io/docs/mouse/eventClick/ * @see http://fullcalendar.io/docs/mouse/eventClick/
// # */
var calendarEventClickCb = function (event, jsEvent, view) { var calendarEventClickCb = function (event, jsEvent, view) {
$scope.selectedEvent = event $scope.selectedEvent = event
if ($stateParams.id === 'all') { if ($stateParams.id === 'all') {
@ -497,11 +497,11 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
return $scope.selectionTime = new Date() return $scope.selectionTime = new Date()
} }
// # /**
// Triggered when fullCalendar tries to graphicaly render an event block. * Triggered when fullCalendar tries to graphicaly render an event block.
// Append the event tag into the block, just after the event title. * Append the event tag into the block, just after the event title.
// @see http://fullcalendar.io/docs/event_rendering/eventRender/ * @see http://fullcalendar.io/docs/event_rendering/eventRender/
// # */
var eventRenderCb = function (event, element, view) { var eventRenderCb = function (event, element, view) {
if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) { if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) {
let html = '' let html = ''
@ -512,12 +512,12 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
} }
} }
// # /**
// After payment, update the id of the newly reserved slot with the id returned by the server. * After payment, update the id of the newly reserved slot with the id returned by the server.
// This will allow the user to modify the reservation he just booked. * This will allow the user to modify the reservation he just booked.
// @param slot {Object} * @param slot {Object}
// @param reservation {Object} * @param reservation {Object}
// # */
var updateSpaceSlotId = (slot, reservation) => var updateSpaceSlotId = (slot, reservation) =>
angular.forEach(reservation.slots, function (s) { angular.forEach(reservation.slots, function (s) {
if (slot.start_at === slot.start_at) { if (slot.start_at === slot.start_at) {
@ -525,21 +525,21 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
} }
}) })
// # /**
// Update the calendar's display to render the new attributes of the events * Update the calendar's display to render the new attributes of the events
// # */
var updateCalendar = () => uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents') var updateCalendar = () => uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents')
// # /**
// Asynchronously fetch the events from the API and refresh the calendar's view with these new events * Asynchronously fetch the events from the API and refresh the calendar's view with these new events
// # */
var refetchCalendar = () => var refetchCalendar = () =>
$timeout(function () { $timeout(function () {
uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents') uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents')
return uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents') return uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents')
}) })
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }

View File

@ -14,35 +14,35 @@
*/ */
'use strict' 'use strict'
// # /**
// Public listing of the trainings * Public listing of the trainings
// # */
Application.Controllers.controller('TrainingsController', ['$scope', '$state', 'trainingsPromise', function ($scope, $state, trainingsPromise) { Application.Controllers.controller('TrainingsController', ['$scope', '$state', 'trainingsPromise', function ($scope, $state, trainingsPromise) {
// # List of trainings // List of trainings
$scope.trainings = trainingsPromise $scope.trainings = trainingsPromise
// # /**
// Callback for the 'reserve' button * Callback for the 'reserve' button
// # */
$scope.reserveTraining = (training, event) => $state.go('app.logged.trainings_reserve', { id: training.slug }) $scope.reserveTraining = (training, event) => $state.go('app.logged.trainings_reserve', { id: training.slug })
// # /**
// Callback for the 'show' button * Callback for the 'show' button
// # */
return $scope.showTraining = training => $state.go('app.public.training_show', { id: training.slug }) return $scope.showTraining = training => $state.go('app.public.training_show', { id: training.slug })
} }
]) ])
// # /**
// Public view of a specific training * Public view of a specific training
// # */
Application.Controllers.controller('ShowTrainingController', ['$scope', '$state', 'trainingPromise', 'growl', '_t', 'dialogs', function ($scope, $state, trainingPromise, growl, _t, dialogs) { Application.Controllers.controller('ShowTrainingController', ['$scope', '$state', 'trainingPromise', 'growl', '_t', 'dialogs', function ($scope, $state, trainingPromise, growl, _t, dialogs) {
// # Current training // Current training
$scope.training = trainingPromise $scope.training = trainingPromise
// # /**
// Callback to delete the current training (admins only) * Callback to delete the current training (admins only)
// # */
$scope.delete = function (training) { $scope.delete = function (training) {
// check the permissions // check the permissions
if ($scope.currentUser.role !== 'admin') { if ($scope.currentUser.role !== 'admin') {
@ -66,23 +66,23 @@ Application.Controllers.controller('ShowTrainingController', ['$scope', '$state'
} }
} }
// # /**
// Callback for the 'reserve' button * Callback for the 'reserve' button
// # */
$scope.reserveTraining = (training, event) => $state.go('app.logged.trainings_reserve', { id: training.id }) $scope.reserveTraining = (training, event) => $state.go('app.logged.trainings_reserve', { id: training.id })
// # /**
// Revert view to the full list of trainings ("<-" button) * Revert view to the full list of trainings ("<-" button)
// # */
return $scope.cancel = event => $state.go('app.public.trainings_list') return $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', '$stateParams', 'Auth', '$timeout', 'Availability', 'Member', 'availabilityTrainingsPromise', 'plansPromise', 'groupsPromise', 'settingsPromise', 'trainingPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', Application.Controllers.controller('ReserveTrainingController', ['$scope', '$stateParams', 'Auth', '$timeout', 'Availability', 'Member', 'availabilityTrainingsPromise', 'plansPromise', 'groupsPromise', 'settingsPromise', 'trainingPromise', '_t', 'uiCalendarConfig', 'CalendarConfig',
function ($scope, $stateParams, Auth, $timeout, Availability, Member, availabilityTrainingsPromise, plansPromise, groupsPromise, settingsPromise, trainingPromise, _t, uiCalendarConfig, CalendarConfig) { function ($scope, $stateParams, Auth, $timeout, Availability, Member, availabilityTrainingsPromise, plansPromise, groupsPromise, settingsPromise, trainingPromise, _t, uiCalendarConfig, CalendarConfig) {
@ -96,14 +96,14 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
/* PUBLIC SCOPE */ /* PUBLIC SCOPE */
// # bind the trainings availabilities with full-Calendar events // bind the trainings availabilities with full-Calendar events
$scope.eventSources = [ { events: availabilityTrainingsPromise, textColor: 'black' } ] $scope.eventSources = [ { events: availabilityTrainingsPromise, textColor: 'black' } ]
// # the user to deal with, ie. the current user for non-admins // the user to deal with, ie. the current user for non-admins
$scope.ctrl = $scope.ctrl =
{ member: {} } { member: {} }
// # list of plans, classified by group // list of plans, classified by group
$scope.plansClassifiedByGroup = [] $scope.plansClassifiedByGroup = []
for (let group of Array.from(groupsPromise)) { for (let group of Array.from(groupsPromise)) {
const groupObj = { id: group.id, name: group.name, plans: [] } const groupObj = { id: group.id, name: group.name, plans: [] }
@ -113,7 +113,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
$scope.plansClassifiedByGroup.push(groupObj) $scope.plansClassifiedByGroup.push(groupObj)
} }
// # mapping of fullCalendar events. // mapping of fullCalendar events.
$scope.events = { $scope.events = {
reserved: [], // Slots that the user wants to book reserved: [], // Slots that the user wants to book
modifiable: null, // Slot that the user wants to change modifiable: null, // Slot that the user wants to change
@ -122,28 +122,28 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
moved: null // Slots that were just moved by the user (change done) -> {newSlot:* oldSlot: *} moved: null // Slots that were just moved by the user (change done) -> {newSlot:* oldSlot: *}
} }
// # the moment when the slot selection changed for the last time, used to trigger changes in the cart // the moment when the slot selection changed for the last time, used to trigger changes in the cart
$scope.selectionTime = null $scope.selectionTime = null
// # the last clicked event in the calender // the last clicked event in the calender
$scope.selectedEvent = null $scope.selectedEvent = null
// # indicates the state of the current view : calendar or plans information // indicates the state of the current view : calendar or plans information
$scope.plansAreShown = false $scope.plansAreShown = false
// # will store the user's plan if he choosed to buy one // will store the user's plan if he choosed to buy one
$scope.selectedPlan = null $scope.selectedPlan = null
// # the moment when the plan selection changed for the last time, used to trigger changes in the cart // the moment when the plan selection changed for the last time, used to trigger changes in the cart
$scope.planSelectionTime = null $scope.planSelectionTime = null
// # Selected training // Selected training
$scope.training = trainingPromise $scope.training = trainingPromise
// # 'all' OR training's slug // 'all' OR training's slug
$scope.mode = $stateParams.id $scope.mode = $stateParams.id
// # fullCalendar (v2) configuration // fullCalendar (v2) configuration
$scope.calendarConfig = CalendarConfig({ $scope.calendarConfig = CalendarConfig({
minTime: moment.duration(moment(settingsPromise.booking_window_start).format('HH:mm:ss')), minTime: moment.duration(moment(settingsPromise.booking_window_start).format('HH:mm:ss')),
maxTime: moment.duration(moment(settingsPromise.booking_window_end).format('HH:mm:ss')), maxTime: moment.duration(moment(settingsPromise.booking_window_end).format('HH:mm:ss')),
@ -155,29 +155,29 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
} }
}) })
// # Application global settings // Application global settings
$scope.settings = settingsPromise $scope.settings = settingsPromise
// # Global config: message to the end user concerning the subscriptions rules // Global config: message to the end user concerning the subscriptions rules
$scope.subscriptionExplicationsAlert = settingsPromise.subscription_explications_alert $scope.subscriptionExplicationsAlert = settingsPromise.subscription_explications_alert
// # Global config: message to the end user concerning the training reservation // Global config: message to the end user concerning the training reservation
$scope.trainingExplicationsAlert = settingsPromise.training_explications_alert $scope.trainingExplicationsAlert = settingsPromise.training_explications_alert
// # Global config: message to the end user giving advice about the training reservation // Global config: message to the end user giving advice about the training reservation
$scope.trainingInformationMessage = settingsPromise.training_information_message $scope.trainingInformationMessage = settingsPromise.training_information_message
// # /**
// Change the last selected slot's appearence to looks like 'added to cart' * Change the last selected slot's appearence to looks like 'added to cart'
// # */
$scope.markSlotAsAdded = function () { $scope.markSlotAsAdded = function () {
$scope.selectedEvent.backgroundColor = SELECTED_EVENT_BG_COLOR $scope.selectedEvent.backgroundColor = SELECTED_EVENT_BG_COLOR
return updateCalendar() return updateCalendar()
} }
// # /**
// Change the last selected slot's appearence to looks like 'never added to cart' * Change the last selected slot's appearence to looks like 'never added to cart'
// # */
$scope.markSlotAsRemoved = function (slot) { $scope.markSlotAsRemoved = function (slot) {
slot.backgroundColor = 'white' slot.backgroundColor = 'white'
slot.title = slot.training.name slot.title = slot.training.name
@ -191,23 +191,23 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
return updateCalendar() return updateCalendar()
} }
// # /**
// Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book' * Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book'
// # */
$scope.slotCancelled = () => $scope.markSlotAsRemoved($scope.selectedEvent) $scope.slotCancelled = () => $scope.markSlotAsRemoved($scope.selectedEvent)
// # /**
// Change the last selected slot's appearence to looks like 'currently looking for a new destination to exchange' * Change the last selected slot's appearence to looks like 'currently looking for a new destination to exchange'
// # */
$scope.markSlotAsModifying = function () { $scope.markSlotAsModifying = function () {
$scope.selectedEvent.backgroundColor = '#eee' $scope.selectedEvent.backgroundColor = '#eee'
$scope.selectedEvent.title = $scope.selectedEvent.training.name + ' - ' + _t('i_change') $scope.selectedEvent.title = $scope.selectedEvent.training.name + ' - ' + _t('i_change')
return updateCalendar() return updateCalendar()
} }
// # /**
// Change the last selected slot's appearence to looks like 'the slot being exchanged will take this place' * Change the last selected slot's appearence to looks like 'the slot being exchanged will take this place'
// # */
$scope.changeModifyTrainingSlot = function () { $scope.changeModifyTrainingSlot = function () {
if ($scope.events.placable) { if ($scope.events.placable) {
$scope.events.placable.backgroundColor = 'white' $scope.events.placable.backgroundColor = 'white'
@ -220,9 +220,9 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
return updateCalendar() return updateCalendar()
} }
// # /**
// When modifying an already booked reservation, callback when the modification was successfully done. * When modifying an already booked reservation, callback when the modification was successfully done.
// # */
$scope.modifyTrainingSlot = function () { $scope.modifyTrainingSlot = function () {
$scope.events.placable.title = $scope.currentUser.role !== 'admin' ? $scope.events.placable.training.name + ' - ' + _t('i_ve_reserved') : $scope.events.placable.training.name $scope.events.placable.title = $scope.currentUser.role !== 'admin' ? $scope.events.placable.training.name + ' - ' + _t('i_ve_reserved') : $scope.events.placable.training.name
$scope.events.placable.backgroundColor = 'white' $scope.events.placable.backgroundColor = 'white'
@ -242,9 +242,9 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
return updateCalendar() return updateCalendar()
} }
// # /**
// Cancel the current booking modification, reseting the whole process * Cancel the current booking modification, reseting the whole process
// # */
$scope.cancelModifyTrainingSlot = function () { $scope.cancelModifyTrainingSlot = function () {
if ($scope.events.placable) { if ($scope.events.placable) {
$scope.events.placable.backgroundColor = 'white' $scope.events.placable.backgroundColor = 'white'
@ -256,10 +256,10 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
return updateCalendar() return updateCalendar()
} }
// # /**
// Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's * Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's
// reservations. (admins only) * reservations. (admins only)
// # */
$scope.updateMember = function () { $scope.updateMember = function () {
if ($scope.ctrl.member) { if ($scope.ctrl.member) {
Member.get({ id: $scope.ctrl.member.id }, function (member) { Member.get({ id: $scope.ctrl.member.id }, function (member) {
@ -281,10 +281,10 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
return $scope.plansAreShown = false return $scope.plansAreShown = false
} }
// # /**
// Add the provided plan to the current shopping cart * Add the provided plan to the current shopping cart
// @param plan {Object} the plan to subscribe * @param plan {Object} the plan to subscribe
// # */
$scope.selectPlan = function (plan) { $scope.selectPlan = function (plan) {
// toggle selected plan // toggle selected plan
if ($scope.selectedPlan !== plan) { if ($scope.selectedPlan !== plan) {
@ -295,10 +295,10 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
return $scope.planSelectionTime = new Date() return $scope.planSelectionTime = new Date()
} }
// # /**
// Changes the user current view from the plan subsription screen to the machine reservation agenda * Changes the user current view from the plan subsription screen to the machine reservation agenda
// @param e {Object} see https://docs.angularjs.org/guide/expression#-event- * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
$scope.doNotSubscribePlan = function (e) { $scope.doNotSubscribePlan = function (e) {
e.preventDefault() e.preventDefault()
$scope.plansAreShown = false $scope.plansAreShown = false
@ -306,16 +306,16 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
return $scope.planSelectionTime = new Date() return $scope.planSelectionTime = new Date()
} }
// # /**
// Switch the user's view from the reservation agenda to the plan subscription * Switch the user's view from the reservation agenda to the plan subscription
// # */
$scope.showPlans = () => $scope.plansAreShown = true $scope.showPlans = () => $scope.plansAreShown = true
// # /**
// Once the reservation is booked (payment process successfully completed), change the event style * Once the reservation is booked (payment process successfully completed), change the event style
// in fullCalendar, update the user's subscription and free-credits if needed * in fullCalendar, update the user's subscription and free-credits if needed
// @param reservation {Object} * @param reservation {Object}
// # */
$scope.afterPayment = function (reservation) { $scope.afterPayment = function (reservation) {
$scope.events.paid[0].backgroundColor = 'white' $scope.events.paid[0].backgroundColor = 'white'
$scope.events.paid[0].is_reserved = true $scope.events.paid[0].is_reserved = true
@ -338,29 +338,29 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
return refetchCalendar() return refetchCalendar()
} }
// # /**
// To use as callback in Array.prototype.filter to get only enabled plans * To use as callback in Array.prototype.filter to get only enabled plans
// # */
$scope.filterDisabledPlans = plan => !plan.disabled $scope.filterDisabledPlans = plan => !plan.disabled
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the controller is loaded * Kind of constructor: these actions will be realized first when the controller is loaded
// # */
const initialize = function () { const initialize = function () {
if ($scope.currentUser.role !== 'admin') { if ($scope.currentUser.role !== 'admin') {
return Member.get({ id: $scope.currentUser.id }, member => $scope.ctrl.member = member) return Member.get({ id: $scope.currentUser.id }, member => $scope.ctrl.member = member)
} }
} }
// # /**
// Triggered when the user clicks on a reservation slot in the agenda. * Triggered when the user clicks on a reservation slot in the agenda.
// Defines the behavior to adopt depending on the slot status (already booked, free, ready to be reserved ...), * Defines the behavior to adopt depending on the slot status (already booked, free, ready to be reserved ...),
// the user's subscription (current or about to be took) and the time (the user cannot modify a booked reservation * the user's subscription (current or about to be took) and the time (the user cannot modify a booked reservation
// if it's too late). * if it's too late).
// @see http://fullcalendar.io/docs/mouse/eventClick/ * @see http://fullcalendar.io/docs/mouse/eventClick/
// # */
var calendarEventClickCb = function (event, jsEvent, view) { var calendarEventClickCb = function (event, jsEvent, view) {
$scope.selectedEvent = event $scope.selectedEvent = event
if ($stateParams.id === 'all') { if ($stateParams.id === 'all') {
@ -369,11 +369,11 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
return $scope.selectionTime = new Date() return $scope.selectionTime = new Date()
} }
// # /**
// Triggered when fullCalendar tries to graphicaly render an event block. * Triggered when fullCalendar tries to graphicaly render an event block.
// Append the event tag into the block, just after the event title. * Append the event tag into the block, just after the event title.
// @see http://fullcalendar.io/docs/event_rendering/eventRender/ * @see http://fullcalendar.io/docs/event_rendering/eventRender/
// # */
var eventRenderCb = function (event, element, view) { var eventRenderCb = function (event, element, view) {
if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) { if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) {
let html = '' let html = ''
@ -384,12 +384,12 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
} }
} }
// # /**
// After payment, update the id of the newly reserved slot with the id returned by the server. * After payment, update the id of the newly reserved slot with the id returned by the server.
// This will allow the user to modify the reservation he just booked. * This will allow the user to modify the reservation he just booked.
// @param slot {Object} * @param slot {Object}
// @param reservation {Object} * @param reservation {Object}
// # */
var updateTrainingSlotId = (slot, reservation) => var updateTrainingSlotId = (slot, reservation) =>
angular.forEach(reservation.slots, function (s) { angular.forEach(reservation.slots, function (s) {
if (slot.start_at === slot.start_at) { if (slot.start_at === slot.start_at) {
@ -397,21 +397,21 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
} }
}) })
// # /**
// Update the calendar's display to render the new attributes of the events * Update the calendar's display to render the new attributes of the events
// # */
var updateCalendar = () => uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents') var updateCalendar = () => uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents')
// # /**
// Asynchronously fetch the events from the API and refresh the calendar's view with these new events * Asynchronously fetch the events from the API and refresh the calendar's view with these new events
// # */
var refetchCalendar = () => var refetchCalendar = () =>
$timeout(function () { $timeout(function () {
uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents') uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents')
return uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents') return uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents')
}) })
// # !!! MUST BE CALLED AT THE END of the controller // !!! MUST BE CALLED AT THE END of the controller
return initialize() return initialize()
} }

View File

@ -39,48 +39,48 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
}, },
templateUrl: '<%= asset_path "shared/_cart.html" %>', templateUrl: '<%= asset_path "shared/_cart.html" %>',
link ($scope, element, attributes) { link ($scope, element, attributes) {
// # will store the user's plan if he choosed to buy one // will store the user's plan if he choosed to buy one
$scope.selectedPlan = null $scope.selectedPlan = null
// # total amount of the bill to pay // total amount of the bill to pay
$scope.amountTotal = 0 $scope.amountTotal = 0
// # total amount of the elements in the cart, without considering any coupon // total amount of the elements in the cart, without considering any coupon
$scope.totalNoCoupon = 0 $scope.totalNoCoupon = 0
// # Discount coupon to apply to the basket, if any // Discount coupon to apply to the basket, if any
$scope.coupon = $scope.coupon =
{ applied: null } { applied: null }
// # Global config: is the user authorized to change his bookings slots? // Global config: is the user authorized to change his bookings slots?
$scope.enableBookingMove = ($scope.settings.booking_move_enable === 'true') $scope.enableBookingMove = ($scope.settings.booking_move_enable === 'true')
// # Global config: delay in hours before a booking while changing the booking slot is forbidden // Global config: delay in hours before a booking while changing the booking slot is forbidden
$scope.moveBookingDelay = parseInt($scope.settings.booking_move_delay) $scope.moveBookingDelay = parseInt($scope.settings.booking_move_delay)
// # Global config: is the user authorized to cancel his bookings? // Global config: is the user authorized to cancel his bookings?
$scope.enableBookingCancel = ($scope.settings.booking_cancel_enable === 'true') $scope.enableBookingCancel = ($scope.settings.booking_cancel_enable === 'true')
// # Global config: delay in hours before a booking while the cancellation is forbidden // Global config: delay in hours before a booking while the cancellation is forbidden
$scope.cancelBookingDelay = parseInt($scope.settings.booking_cancel_delay) $scope.cancelBookingDelay = parseInt($scope.settings.booking_cancel_delay)
// # /**
// Add the provided slot to the shopping cart (state transition from free to 'about to be reserved') * Add the provided slot to the shopping cart (state transition from free to 'about to be reserved')
// and increment the total amount of the cart if needed. * and increment the total amount of the cart if needed.
// @param slot {Object} fullCalendar event object * @param slot {Object} fullCalendar event object
// # */
$scope.validateSlot = function (slot) { $scope.validateSlot = function (slot) {
slot.isValid = true slot.isValid = true
return updateCartPrice() return updateCartPrice()
} }
// # /**
// Remove the provided slot from the shopping cart (state transition from 'about to be reserved' to free) * Remove the provided slot from the shopping cart (state transition from 'about to be reserved' to free)
// and decrement the total amount of the cart if needed. * and decrement the total amount of the cart if needed.
// @param slot {Object} fullCalendar event object * @param slot {Object} fullCalendar event object
// @param index {number} index of the slot in the reservation array * @param index {number} index of the slot in the reservation array
// @param [event] {Object} see https://docs.angularjs.org/guide/expression#-event- * @param [event] {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
$scope.removeSlot = function (slot, index, event) { $scope.removeSlot = function (slot, index, event) {
if (event) { event.preventDefault() } if (event) { event.preventDefault() }
$scope.events.reserved.splice(index, 1) $scope.events.reserved.splice(index, 1)
@ -94,10 +94,10 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
return updateCartPrice() return updateCartPrice()
} }
// # /**
// Checks that every selected slots were added to the shopping cart. Ie. will return false if * Checks that every selected slots were added to the shopping cart. Ie. will return false if
// any checked slot was not validated by the user. * any checked slot was not validated by the user.
// # */
$scope.isSlotsValid = function () { $scope.isSlotsValid = function () {
let isValid = true let isValid = true
angular.forEach($scope.events.reserved, function (m) { angular.forEach($scope.events.reserved, function (m) {
@ -106,9 +106,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
return isValid return isValid
} }
// # /**
// Switch the user's view from the reservation agenda to the plan subscription * Switch the user's view from the reservation agenda to the plan subscription
// # */
$scope.showPlans = function () { $scope.showPlans = function () {
// first, we ensure that a user was selected (admin) or logged (member) // first, we ensure that a user was selected (admin) or logged (member)
if (Object.keys($scope.user).length > 0) { if (Object.keys($scope.user).length > 0) {
@ -119,9 +119,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
} }
} }
// # /**
// Validates the shopping chart and redirect the user to the payment step * Validates the shopping chart and redirect the user to the payment step
// # */
$scope.payCart = function () { $scope.payCart = function () {
// first, we check that a user was selected // first, we check that a user was selected
if (Object.keys($scope.user).length > 0) { if (Object.keys($scope.user).length > 0) {
@ -143,9 +143,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
} }
} }
// # /**
// When modifying an already booked reservation, confirm the modification. * When modifying an already booked reservation, confirm the modification.
// # */
$scope.modifySlot = () => $scope.modifySlot = () =>
Slot.update({ id: $scope.events.modifiable.id }, { Slot.update({ id: $scope.events.modifiable.id }, {
slot: { slot: {
@ -171,10 +171,10 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
return console.error(err) return console.error(err)
}) })
// # /**
// Cancel the current booking modification, reseting the whole process * Cancel the current booking modification, reseting the whole process
// @param event {Object} see https://docs.angularjs.org/guide/expression#-event- * @param event {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
$scope.cancelModifySlot = function (event) { $scope.cancelModifySlot = function (event) {
if (event) { event.preventDefault() } if (event) { event.preventDefault() }
if (typeof $scope.onSlotModifyCancel === 'function') { $scope.onSlotModifyCancel() } if (typeof $scope.onSlotModifyCancel === 'function') { $scope.onSlotModifyCancel() }
@ -182,20 +182,20 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
return $scope.events.modifiable = null return $scope.events.modifiable = null
} }
// # /**
// When modifying an already booked reservation, cancel the choice of the new slot * When modifying an already booked reservation, cancel the choice of the new slot
// @param e {Object} see https://docs.angularjs.org/guide/expression#-event- * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
// # */
$scope.removeSlotToPlace = function (e) { $scope.removeSlotToPlace = function (e) {
e.preventDefault() e.preventDefault()
if (typeof $scope.onSlotModifyUnselect === 'function') { $scope.onSlotModifyUnselect() } if (typeof $scope.onSlotModifyUnselect === 'function') { $scope.onSlotModifyUnselect() }
return $scope.events.placable = null return $scope.events.placable = null
} }
// # /**
// Checks if $scope.events.modifiable and $scope.events.placable have tag incompatibilities * Checks if $scope.events.modifiable and $scope.events.placable have tag incompatibilities
// @returns {boolean} true in case of incompatibility * @returns {boolean} true in case of incompatibility
// # */
$scope.tagMissmatch = function () { $scope.tagMissmatch = function () {
if ($scope.events.placable.tag_ids.length === 0) { return false } if ($scope.events.placable.tag_ids.length === 0) { return false }
for (let tag of Array.from($scope.events.modifiable.tags)) { for (let tag of Array.from($scope.events.modifiable.tags)) {
@ -206,17 +206,17 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
return false return false
} }
// # /**
// Check if the currently logged user has teh 'admin' role? * Check if the currently logged user has teh 'admin' role?
// @returns {boolean} * @returns {boolean}
// # */
$scope.isAdmin = () => $rootScope.currentUser && ($rootScope.currentUser.role === 'admin') $scope.isAdmin = () => $rootScope.currentUser && ($rootScope.currentUser.role === 'admin')
/* PRIVATE SCOPE */ /* PRIVATE SCOPE */
// # /**
// Kind of constructor: these actions will be realized first when the directive is loaded * Kind of constructor: these actions will be realized first when the directive is loaded
// # */
const initialize = function () { const initialize = function () {
// What the binded slot // What the binded slot
$scope.$watch('slotSelectionTime', function (newValue, oldValue) { $scope.$watch('slotSelectionTime', function (newValue, oldValue) {
@ -243,9 +243,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
}) })
} }
// # /**
// Callback triggered when the selected slot changed * Callback triggered when the selected slot changed
// # */
var slotSelectionChanged = function () { var slotSelectionChanged = function () {
if ($scope.slot) { if ($scope.slot) {
if (!$scope.slot.is_reserved && !$scope.events.modifiable && !$scope.slot.is_completed) { if (!$scope.slot.is_reserved && !$scope.events.modifiable && !$scope.slot.is_completed) {
@ -328,9 +328,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
} }
} }
// # /**
// Reset the parameters that may lead to a wrong price but leave the content (events added to cart) * Reset the parameters that may lead to a wrong price but leave the content (events added to cart)
// # */
var resetCartState = function () { var resetCartState = function () {
$scope.selectedPlan = null $scope.selectedPlan = null
$scope.coupon.applied = null $scope.coupon.applied = null
@ -340,10 +340,10 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
return $scope.events.placable = null return $scope.events.placable = null
} }
// # /**
// Determines if the provided booked slot is able to be modified by the user. * Determines if the provided booked slot is able to be modified by the user.
// @param slot {Object} fullCalendar event object * @param slot {Object} fullCalendar event object
// # */
var slotCanBeModified = function (slot) { var slotCanBeModified = function (slot) {
if ($scope.isAdmin()) { return true } if ($scope.isAdmin()) { return true }
const slotStart = moment(slot.start) const slotStart = moment(slot.start)
@ -355,10 +355,10 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
} }
} }
// # /**
// Determines if the provided booked slot is able to be canceled by the user. * Determines if the provided booked slot is able to be canceled by the user.
// @param slot {Object} fullCalendar event object * @param slot {Object} fullCalendar event object
// # */
var slotCanBeCanceled = function (slot) { var slotCanBeCanceled = function (slot) {
if ($scope.isAdmin()) { return true } if ($scope.isAdmin()) { return true }
const slotStart = moment(slot.start) const slotStart = moment(slot.start)
@ -370,9 +370,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
} }
} }
// # /**
// Callback triggered when the selected slot changed * Callback triggered when the selected slot changed
// # */
var planSelectionChanged = function () { var planSelectionChanged = function () {
if (Auth.isAuthenticated()) { if (Auth.isAuthenticated()) {
if ($scope.selectedPlan !== $scope.plan) { if ($scope.selectedPlan !== $scope.plan) {
@ -389,9 +389,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
} }
} }
// # /**
// Update the total price of the current selection/reservation * Update the total price of the current selection/reservation
// # */
var updateCartPrice = function () { var updateCartPrice = function () {
if (Object.keys($scope.user).length > 0) { if (Object.keys($scope.user).length > 0) {
const r = mkReservation($scope.user, $scope.events.reserved, $scope.selectedPlan) const r = mkReservation($scope.user, $scope.events.reserved, $scope.selectedPlan)
@ -417,12 +417,12 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
}) })
) )
// # /**
// Format the parameters expected by /api/prices/compute or /api/reservations and return the resulting object * Format the parameters expected by /api/prices/compute or /api/reservations and return the resulting object
// @param reservation {Object} as returned by mkReservation() * @param reservation {Object} as returned by mkReservation()
// @param coupon {Object} Coupon as returned from the API * @param coupon {Object} Coupon as returned from the API
// @return {{reservation:Object, coupon_code:string}} * @return {{reservation:Object, coupon_code:string}}
// # */
var mkRequestParams = function (reservation, coupon) { var mkRequestParams = function (reservation, coupon) {
const params = { const params = {
reservation, reservation,
@ -432,13 +432,13 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
return params return params
} }
// # /**
// Create an hash map implementing the Reservation specs * Create an hash map implementing the Reservation specs
// @param member {Object} User as retreived from the API: current user / selected user if current is admin * @param member {Object} User as retreived from the API: current user / selected user if current is admin
// @param slots {Array<Object>} Array of fullCalendar events: slots selected on the calendar * @param slots {Array<Object>} Array of fullCalendar events: slots selected on the calendar
// @param [plan] {Object} Plan as retrived from the API: plan to buy with the current reservation * @param [plan] {Object} Plan as retrived from the API: plan to buy with the current reservation
// @return {{user_id:Number, reservable_id:Number, reservable_type:String, slots_attributes:Array<Object>, plan_id:Number|null}} * @return {{user_id:Number, reservable_id:Number, reservable_type:String, slots_attributes:Array<Object>, plan_id:Number|null}}
// # */
var mkReservation = function (member, slots, plan = null) { var mkReservation = function (member, slots, plan = null) {
const reservation = { const reservation = {
user_id: member.id, user_id: member.id,
@ -459,9 +459,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
return reservation return reservation
} }
// # /**
// Open a modal window that allows the user to process a credit card payment for his current shopping cart. * Open a modal window that allows the user to process a credit card payment for his current shopping cart.
// # */
var payByStripe = reservation => var payByStripe = reservation =>
$uibModal.open({ $uibModal.open({
templateUrl: '<%= asset_path "stripe/payment_modal.html" %>', templateUrl: '<%= asset_path "stripe/payment_modal.html" %>',
@ -500,9 +500,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
// Used in wallet info template to interpolate some translations // Used in wallet info template to interpolate some translations
$scope.numberFilter = $filter('number') $scope.numberFilter = $filter('number')
// # /**
// Callback to process the payment with Stripe, triggered on button click * Callback to process the payment with Stripe, triggered on button click
// # */
return $scope.payment = function (status, response) { return $scope.payment = function (status, response) {
if (response.error) { if (response.error) {
return growl.error(response.error.message) return growl.error(response.error.message)
@ -538,9 +538,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
] }) ] })
.result['finally'](null).then(reservation => afterPayment(reservation)) .result['finally'](null).then(reservation => afterPayment(reservation))
// # /**
// Open a modal window that allows the user to process a local payment for his current shopping cart (admin only). * Open a modal window that allows the user to process a local payment for his current shopping cart (admin only).
// # */
var payOnSite = reservation => var payOnSite = reservation =>
$uibModal.open({ $uibModal.open({
templateUrl: '<%= asset_path "shared/valid_reservation_modal.html" %>', templateUrl: '<%= asset_path "shared/valid_reservation_modal.html" %>',
@ -587,9 +587,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
} }
} }
// # /**
// Callback to process the local payment, triggered on button click * Callback to process the local payment, triggered on button click
// # */
$scope.ok = function () { $scope.ok = function () {
$scope.attempting = true $scope.attempting = true
return Reservation.save(mkRequestParams($scope.reservation, coupon), function (reservation) { return Reservation.save(mkRequestParams($scope.reservation, coupon), function (reservation) {
@ -607,9 +607,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
] }) ] })
.result['finally'](null).then(reservation => afterPayment(reservation)) .result['finally'](null).then(reservation => afterPayment(reservation))
// # /**
// Actions to run after the payment was successfull * Actions to run after the payment was successfull
// # */
var afterPayment = function (reservation) { var afterPayment = function (reservation) {
// we set the cart content as 'paid' to display a summary of the transaction // we set the cart content as 'paid' to display a summary of the transaction
$scope.events.paid = $scope.events.reserved $scope.events.paid = $scope.events.reserved
@ -622,7 +622,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
return $scope.selectedPlan = null return $scope.selectedPlan = null
} }
// # !!! MUST BE CALLED AT THE END of the directive // !!! MUST BE CALLED AT THE END of the directive
return initialize() return initialize()
} }
}) })

View File

@ -40,9 +40,9 @@ Application.Directives.directive('coupon', [ '$rootScope', 'Coupon', '_t', ($roo
} }
}) })
// # /**
// Callback to validate the code * Callback to validate the code
// # */
$scope.validateCode = function () { $scope.validateCode = function () {
$scope.messages = [] $scope.messages = []
if ($scope.couponCode === '') { if ($scope.couponCode === '') {
@ -66,9 +66,9 @@ Application.Directives.directive('coupon', [ '$rootScope', 'Coupon', '_t', ($roo
} }
} }
// # /**
// Callback to remove the message at provided index from the displayed list * Callback to remove the message at provided index from the displayed list
// # */
return $scope.closeMessage = index => $scope.messages.splice(index, 1) return $scope.closeMessage = index => $scope.messages.splice(index, 1)
} }
}) })

View File

@ -11,14 +11,14 @@
*/ */
'use strict' 'use strict'
// # /**
// This directive will allow to select a member. * This directive will allow to select a member.
// Please surround it with a ng-if directive to prevent it from being used by a non-admin user. * Please surround it with a ng-if directive to prevent it from being used by a non-admin user.
// The resulting member will be set into the parent $scope (=> $scope.ctrl.member). * The resulting member will be set into the parent $scope (=> $scope.ctrl.member).
// The directive takes an optional parameter "subscription" as a "boolean string" that will filter the user * The directive takes an optional parameter "subscription" as a "boolean string" that will filter the user
// which have a valid running subscription or not. * which have a valid running subscription or not.
// Usage: <select-member [subscription="false|true"]></select-member> * Usage: <select-member [subscription="false|true"]></select-member>
// # */
Application.Directives.directive('selectMember', [ 'Diacritics', 'Member', (Diacritics, Member) => Application.Directives.directive('selectMember', [ 'Diacritics', 'Member', (Diacritics, Member) =>
({ ({
restrict: 'E', restrict: 'E',

View File

@ -38,7 +38,7 @@ angular.module('application.router', ['ui.router'])
] ]
}, },
onEnter: ['$rootScope', 'logoFile', 'logoBlackFile', function ($rootScope, logoFile, logoBlackFile) { onEnter: ['$rootScope', 'logoFile', 'logoBlackFile', function ($rootScope, logoFile, logoBlackFile) {
// # Application logo // Application logo
$rootScope.logo = logoFile.custom_asset $rootScope.logo = logoFile.custom_asset
return $rootScope.logoBlack = logoBlackFile.custom_asset return $rootScope.logoBlack = logoBlackFile.custom_asset
} }