diff --git a/.eslintrc b/.eslintrc index 109c20198..8753c7e69 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,6 +2,11 @@ "extends": "standard", "rules": { "semi": ["error", "always"] + }, + "globals": { + "Application": true, + "angular": true, + "Fablab": true } } diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 000000000..59b273ced --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,2 @@ +Metrics/LineLength: + Max: 120 diff --git a/app/assets/javascripts/app.js.erb b/app/assets/javascripts/app.js similarity index 53% rename from app/assets/javascripts/app.js.erb rename to app/assets/javascripts/app.js index bb05f35c7..b4fbe1d4b 100644 --- a/app/assets/javascripts/app.js.erb +++ b/app/assets/javascripts/app.js @@ -5,6 +5,7 @@ * creating namespaces and moduled for controllers, filters, services, and directives. */ +// eslint-disable-next-line no-use-before-define var Application = Application || {}; Application.Constants = angular.module('application.constants', []); @@ -13,58 +14,49 @@ Application.Controllers = angular.module('application.controllers', []); Application.Filters = angular.module('application.filters', []); Application.Directives = angular.module('application.directives', []); - angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ngCookies', 'ui.router', 'ui.bootstrap', - 'ngUpload', 'duScroll', 'application.filters','application.services', 'application.directives', - 'frapontillo.bootstrap-switch', 'application.constants', 'application.controllers', 'application.router', - 'ui.select', 'ui.calendar', 'angularMoment', 'Devise', 'DeviseModal', 'angular-growl', 'xeditable', - 'checklist-model', 'unsavedChanges', 'angular-loading-bar', 'ngTouch', 'angular-google-analytics', - 'angularUtils.directives.dirDisqus', 'summernote', 'elasticsearch', 'angular-medium-editor', 'naif.base64', - 'minicolors', 'pascalprecht.translate', 'ngFitText', 'ngAside', 'ngCapsLock']). -config(['$httpProvider', 'AuthProvider', "growlProvider", "unsavedWarningsConfigProvider", "AnalyticsProvider", "uibDatepickerPopupConfig", "$provide", "$translateProvider", - function($httpProvider, AuthProvider, growlProvider, unsavedWarningsConfigProvider, AnalyticsProvider, uibDatepickerPopupConfig, $provide, $translateProvider) { - - + 'ngUpload', 'duScroll', 'application.filters', 'application.services', 'application.directives', + 'frapontillo.bootstrap-switch', 'application.constants', 'application.controllers', 'application.router', + 'ui.select', 'ui.calendar', 'angularMoment', 'Devise', 'DeviseModal', 'angular-growl', 'xeditable', + 'checklist-model', 'unsavedChanges', 'angular-loading-bar', 'ngTouch', 'angular-google-analytics', + 'angularUtils.directives.dirDisqus', 'summernote', 'elasticsearch', 'angular-medium-editor', 'naif.base64', + 'minicolors', 'pascalprecht.translate', 'ngFitText', 'ngAside', 'ngCapsLock']) + .config(['$httpProvider', 'AuthProvider', 'growlProvider', 'unsavedWarningsConfigProvider', 'AnalyticsProvider', 'uibDatepickerPopupConfig', '$provide', '$translateProvider', + function ($httpProvider, AuthProvider, growlProvider, unsavedWarningsConfigProvider, AnalyticsProvider, uibDatepickerPopupConfig, $provide, $translateProvider) { // Google analytics - <% #if Rails.env.production? %> AnalyticsProvider.setAccount(Fablab.gaId); // track all routes (or not) AnalyticsProvider.trackPages(true); AnalyticsProvider.setDomainName(Fablab.defaultHost); AnalyticsProvider.useAnalytics(true); AnalyticsProvider.setPageEvent('$stateChangeSuccess'); - <% #else %> - //AnalyticsProvider.setAccount('DISABLED'); - <% #end %> - // Custom messages for the date-picker widget - uibDatepickerPopupConfig.closeText = Fablab.translations.app.shared.buttons.close; - uibDatepickerPopupConfig.clearText = Fablab.translations.app.shared.buttons.clear; - uibDatepickerPopupConfig.currentText = Fablab.translations.app.shared.buttons.today; + // Custom messages for the date-picker widget + uibDatepickerPopupConfig.closeText = Fablab.translations.app.shared.buttons.close; + uibDatepickerPopupConfig.clearText = Fablab.translations.app.shared.buttons.clear; + uibDatepickerPopupConfig.currentText = Fablab.translations.app.shared.buttons.today; - // Custom messages for angular-unsavedChanges - unsavedWarningsConfigProvider.navigateMessage = Fablab.translations.app.shared.messages.you_will_lose_any_unsaved_modification_if_you_quit_this_page; - unsavedWarningsConfigProvider.reloadMessage = Fablab.translations.app.shared.messages.you_will_lose_any_unsaved_modification_if_you_reload_this_page; + // Custom messages for angular-unsavedChanges + unsavedWarningsConfigProvider.navigateMessage = Fablab.translations.app.shared.messages.you_will_lose_any_unsaved_modification_if_you_quit_this_page; + unsavedWarningsConfigProvider.reloadMessage = Fablab.translations.app.shared.messages.you_will_lose_any_unsaved_modification_if_you_reload_this_page; - // Set how long the popup messages (growl) will remain - growlProvider.globalTimeToLive(5000); - - // Configure the i18n module to load the partial translations from the given API URL - $translateProvider.useLoader('$translatePartialLoader', { - urlTemplate: '/api/translations/{lang}/{part}' - }); - // Enable the cache to speed-up the loading times on already seen pages - $translateProvider.useLoaderCache(true); - // Secure i18n module against XSS attacks by escaping the output - $translateProvider.useSanitizeValueStrategy('escapeParameters'); - // Enable the MessageFormat interpolation (used for pluralization) - $translateProvider.addInterpolation('$translateMessageFormatInterpolation'); - // Set the langage of the instance (from ruby configuration) - $translateProvider.preferredLanguage(Fablab.locale); - - }]).run(["$rootScope", "$log", "AuthService", "Auth", "amMoment", "$state", "editableOptions", 'Analytics', - function($rootScope, $log, AuthService, Auth, amMoment, $state, editableOptions, Analytics) { + // Set how long the popup messages (growl) will remain + growlProvider.globalTimeToLive(5000); + // Configure the i18n module to load the partial translations from the given API URL + $translateProvider.useLoader('$translatePartialLoader', { + urlTemplate: '/api/translations/{lang}/{part}' + }); + // Enable the cache to speed-up the loading times on already seen pages + $translateProvider.useLoaderCache(true); + // Secure i18n module against XSS attacks by escaping the output + $translateProvider.useSanitizeValueStrategy('escapeParameters'); + // Enable the MessageFormat interpolation (used for pluralization) + $translateProvider.addInterpolation('$translateMessageFormatInterpolation'); + // Set the langage of the instance (from ruby configuration) + $translateProvider.preferredLanguage(Fablab.locale); + }]).run(['$rootScope', '$log', 'AuthService', 'Auth', 'amMoment', '$state', 'editableOptions', 'Analytics', + function ($rootScope, $log, AuthService, Auth, amMoment, $state, editableOptions, Analytics) { // Angular-moment (date-time manipulations library) amMoment.changeLocale(Fablab.moment_locale); @@ -73,7 +65,7 @@ config(['$httpProvider', 'AuthProvider', "growlProvider", "unsavedWarningsConfig // Alter the UI-Router's $state, registering into some information concerning the previous $state. // This is used to allow the user to navigate to the previous state - $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ + $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) { $state.prevState = fromState; $state.prevParams = fromParams; }); @@ -85,11 +77,11 @@ config(['$httpProvider', 'AuthProvider', "growlProvider", "unsavedWarningsConfig // Global function to allow the user to navigate to the previous screen (ie. $state). // If no previous $state were recorded, navigate to the home page - $rootScope.backPrevLocation = function(event){ + $rootScope.backPrevLocation = function (event) { event.preventDefault(); event.stopPropagation(); - if($state.prevState.name == ""){ - $state.prevState = "app.public.home"; + if ($state.prevState.name === '') { + $state.prevState = 'app.public.home'; } $state.go($state.prevState, $state.prevParams); }; @@ -116,8 +108,8 @@ config(['$httpProvider', 'AuthProvider', "growlProvider", "unsavedWarningsConfig // Prevent the usage of the application for members with incomplete profiles: they will be redirected to // the 'profile completion' page. This is especially useful for user's accounts imported through SSO. $rootScope.$on('$stateChangeStart', function (event, toState) { - Auth.currentUser().then(function(currentUser) { - if (currentUser.need_completion && toState.name != 'app.logged.profileCompletion') { + Auth.currentUser().then(function (currentUser) { + if (currentUser.need_completion && toState.name !== 'app.logged.profileCompletion') { $state.go('app.logged.profileCompletion'); } }); @@ -127,7 +119,6 @@ config(['$httpProvider', 'AuthProvider', "growlProvider", "unsavedWarningsConfig // see https://github.com/revolunet/angular-google-analytics#automatic-page-view-tracking Analytics.pageView(); - /** * This helper method builds and return an array contaning every integers between * the provided start and end. @@ -135,16 +126,15 @@ config(['$httpProvider', 'AuthProvider', "growlProvider", "unsavedWarningsConfig * @param end {number} * @return {Array} [start .. end] */ - $rootScope.intArray = function(start, end) { + $rootScope.intArray = function (start, end) { var arr = []; for (var i = start; i < end; i++) { arr.push(i); } return arr; }; - - }]).constant('angularMomentConfig', { + }]).constant('angularMomentConfig', { timezone: Fablab.timezone }); -angular.isUndefinedOrNull = function(val) { - return angular.isUndefined(val) || val === null +angular.isUndefinedOrNull = function (val) { + return angular.isUndefined(val) || val === null; }; diff --git a/app/assets/javascripts/controllers/application.js.erb b/app/assets/javascripts/controllers/application.js.erb index c5a003e0c..9b7b698ad 100644 --- a/app/assets/javascripts/controllers/application.js.erb +++ b/app/assets/javascripts/controllers/application.js.erb @@ -14,20 +14,19 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$scope', '$window', '$locale', 'Session', 'AuthService', 'Auth', '$uibModal', '$state', 'growl', 'Notification', '$interval', 'Setting', '_t', 'Version', function ($rootScope, $scope, $window, $locale, Session, AuthService, Auth, $uibModal, $state, growl, Notification, $interval, Setting, _t, Version) { - /* PRIVATE STATIC CONSTANTS */ // User's notifications will get refreshed every 30s - const NOTIFICATIONS_CHECK_PERIOD = 30000 + const NOTIFICATIONS_CHECK_PERIOD = 30000; - /* PUBLIC SCOPE */ + /* PUBLIC SCOPE */ // Fab-manager's version $scope.version = - { version: '' } + { version: '' }; // currency symbol for the current locale (cf. angular-i18n) - $rootScope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM + $rootScope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM; /** * Set the current user to the provided value and initialize the session @@ -35,17 +34,17 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco */ $scope.setCurrentUser = function (user) { if (!angular.isUndefinedOrNull(user)) { - $rootScope.currentUser = user - Session.create(user) - getNotifications() + $rootScope.currentUser = user; + Session.create(user); + getNotifications(); // fab-manager's app-version if (user.role === 'admin') { - return $scope.version = Version.get() + return $scope.version = Version.get(); } else { - return $scope.version = { version: '' } + return $scope.version = { version: '' }; } } - } + }; /** * Login callback @@ -53,36 +52,36 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco * @param callback {function} */ $scope.login = function (e, callback) { - if (e) { e.preventDefault() } - return openLoginModal(null, null, callback) - } + if (e) { e.preventDefault(); } + return openLoginModal(null, null, callback); + }; /** * Logout callback * @param e {Object} see https://docs.angularjs.org/guide/expression#-event- */ $scope.logout = function (e) { - e.preventDefault() + e.preventDefault(); return Auth.logout().then(function () { - Session.destroy() - $rootScope.currentUser = null - $rootScope.toCheckNotifications = false + Session.destroy(); + $rootScope.currentUser = null; + $rootScope.toCheckNotifications = false; $scope.notifications = { total: 0, unread: 0 - } - return $state.go('app.public.home') + }; + return $state.go('app.public.home'); }, function (error) { - console.error(`An error occurred logging out: ${error}`); - }) - } + console.error(`An error occurred logging out: ${error}`); + }); + }; /** * Open the modal window allowing the user to create an account. * @param e {Object} see https://docs.angularjs.org/guide/expression#-event- */ $scope.signup = function (e) { - if (e) { e.preventDefault() } + if (e) { e.preventDefault(); } return $uibModal.open({ templateUrl: '<%= asset_path "shared/signupModal.html" %>', @@ -95,33 +94,33 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco options: { startingDay: Fablab.weekStartingDay } - } + }; // callback to open the date picker (account creation modal) $scope.openDatePicker = function ($event) { - $event.preventDefault() - $event.stopPropagation() - return $scope.datePicker.opened = true - } + $event.preventDefault(); + $event.stopPropagation(); + return $scope.datePicker.opened = true; + }; // retrieve the groups (standard, student ...) - Group.query(function(groups) { + Group.query(function (groups) { $scope.groups = groups; - }) + }); // retrieve the CGU - CustomAsset.get({ name: 'cgu-file' }, function(cgu) { + CustomAsset.get({ name: 'cgu-file' }, function (cgu) { $scope.cgu = cgu.custom_asset; - }) + }); // default user's parameters $scope.user = { is_allow_contact: true, is_allow_newsletter: false - } + }; // Errors display - $scope.alerts = [] + $scope.alerts = []; $scope.closeAlert = function (index) { $scope.alerts.splice(index, 1); }; @@ -134,15 +133,15 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco const orga = $scope.user.organization; delete $scope.user.organization; // register on server - return Auth.register($scope.user).then(function(user) { + return Auth.register($scope.user).then(function (user) { // creation successful - $uibModalInstance.close(user) + $uibModalInstance.close(user); }, function (error) { // creation failed... // restore organization param - $scope.user.organization = orga + $scope.user.organization = orga; // display errors - angular.forEach(error.data.errors, function(v, k) { + angular.forEach(error.data.errors, function (v, k) { angular.forEach(function (v, err) { $scope.alerts.push({ msg: k + ': ' + err, @@ -150,20 +149,20 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco }); }); }); - }) + }); }; }] - }).result['finally'](null).then(function(user) { + }).result['finally'](null).then(function (user) { // when the account was created successfully, set the session to the newly created account - $scope.setCurrentUser(user) - }) - } + $scope.setCurrentUser(user); + }); + }; /** * Open the modal window allowing the user to change his password. * @param token {string} security token for password changing. The user should have recieved it by mail */ - $scope.editPassword = function(token) { + $scope.editPassword = function (token) { $uibModal.open({ templateUrl: '<%= asset_path "shared/passwordEditModal.html" %>', size: 'md', @@ -171,32 +170,32 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco $scope.user = { reset_password_token: token }; $scope.alerts = []; $scope.closeAlert = function (index) { - $scope.alerts.splice(index, 1) + $scope.alerts.splice(index, 1); }; return $scope.changePassword = function () { - $scope.alerts = [] - return $http.put('/users/password.json', { user: $scope.user }).success(function () { $uibModalInstance.close() }).error(function (data) { - angular.forEach(data.errors, function(v, k) { - angular.forEach(function(v, err) { + $scope.alerts = []; + return $http.put('/users/password.json', { user: $scope.user }).success(function () { $uibModalInstance.close(); }).error(function (data) { + angular.forEach(data.errors, function (v, k) { + angular.forEach(function (v, err) { $scope.alerts.push({ msg: k + ': ' + err, type: 'danger' }); }); }); - }) - } + }); + }; }] }).result['finally'](null).then(function () { - growl.success(_t('your_password_was_successfully_changed')) - return Auth.login().then(function(user) { - $scope.setCurrentUser(user) + growl.success(_t('your_password_was_successfully_changed')); + return Auth.login().then(function (user) { + $scope.setCurrentUser(user); }, function (error) { console.error(`Authentication failed: ${error}`); } - ) - }) + ); + }); }; /** @@ -204,25 +203,25 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco * @param event {Object} see https://docs.angularjs.org/guide/expression#-event- */ $scope.toggleNavSize = function (event) { - let $classes, $targets + let $classes, $targets; if (typeof event === 'undefined') { - console.error('[ApplicationController::toggleNavSize] Missing event parameter') - return + console.error('[ApplicationController::toggleNavSize] Missing event parameter'); + return; } - let toggler = $(event.target) - if (!toggler.data('toggle')) { toggler = toggler.closest('[data-toggle^="class"]') } + let toggler = $(event.target); + if (!toggler.data('toggle')) { toggler = toggler.closest('[data-toggle^="class"]'); } - const $class = toggler.data()['toggle'] - const $target = toggler.data('target') || toggler.attr('data-link') + const $class = toggler.data()['toggle']; + const $target = toggler.data('target') || toggler.attr('data-link'); if ($class) { - const $tmp = $class.split(':')[1] - if ($tmp) { $classes = $tmp.split(',') } + const $tmp = $class.split(':')[1]; + if ($tmp) { $classes = $tmp.split(','); } } if ($target) { - $targets = $target.split(',') + $targets = $target.split(','); } if ($classes && $classes.length) { @@ -230,93 +229,92 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco if ($classes[index].indexOf('*') !== -1) { const patt = new RegExp('\\s', +$classes[index].replace(/\*/g, '[A-Za-z0-9-_]+').split(' ').join('\\s|\\s'), - +'\\s', 'g') + +'\\s', 'g'); $(toggler).each(function (i, it) { - let cn = ` ${it.className} ` + let cn = ` ${it.className} `; while (patt.test(cn)) { - cn = cn.replace(patt, ' ') + cn = cn.replace(patt, ' '); } - return it.className = $.trim(cn) - }) + return it.className = $.trim(cn); + }); } - return (($targets[index] !== '#') && $($targets[index]).toggleClass($classes[index])) || toggler.toggleClass($classes[index]) - }) + return (($targets[index] !== '#') && $($targets[index]).toggleClass($classes[index])) || toggler.toggleClass($classes[index]); + }); } - toggler.toggleClass('active') - } + toggler.toggleClass('active'); + }; - /* PRIVATE SCOPE */ + /* PRIVATE SCOPE */ /** * Kind of constructor: these actions will be realized first when the controller is loaded */ const initialize = function () { // try to retrieve any currently logged user Auth.login().then(function (user) { - $scope.setCurrentUser(user) + $scope.setCurrentUser(user); // force users to complete their profile if they are not if (user.need_completion) { - return $state.transitionTo('app.logged.profileCompletion') + return $state.transitionTo('app.logged.profileCompletion'); } - }, function(error) { + }, function (error) { console.error(`Authentication failed: ${error}`); - $rootScope.toCheckNotifications = false - }) + $rootScope.toCheckNotifications = false; + }); // bind to the $stateChangeStart event (AngularJS/UI-Router) $rootScope.$on('$stateChangeStart', function (event, toState, toParams) { - if (!toState.data) { return } + if (!toState.data) { return; } - const { authorizedRoles } = toState.data + const { authorizedRoles } = toState.data; if (!AuthService.isAuthorized(authorizedRoles)) { - event.preventDefault() + event.preventDefault(); if (AuthService.isAuthenticated()) { // user is not allowed - console.error('[ApplicationController::initialize] user is not allowed') + console.error('[ApplicationController::initialize] user is not allowed'); } else { // user is not logged in - openLoginModal(toState, toParams) + openLoginModal(toState, toParams); } } - }) + }); // we stop polling notifications when the page is not in foreground - onPageVisible(function(state) { $rootScope.toCheckNotifications = (state === 'visible') }) + onPageVisible(function (state) { $rootScope.toCheckNotifications = (state === 'visible'); }); - Setting.get({ name: 'fablab_name' }, function(data) { $scope.fablabName = data.setting.value }) - Setting.get({ name: 'name_genre' }, function(data) { $scope.nameGenre = data.setting.value }) + Setting.get({ name: 'fablab_name' }, function (data) { $scope.fablabName = data.setting.value; }); + Setting.get({ name: 'name_genre' }, function (data) { $scope.nameGenre = data.setting.value; }); // shorthands - $scope.isAuthenticated = Auth.isAuthenticated - $scope.isAuthorized = AuthService.isAuthorized - return $rootScope.login = $scope.login - } + $scope.isAuthenticated = Auth.isAuthenticated; + $scope.isAuthorized = AuthService.isAuthorized; + return $rootScope.login = $scope.login; + }; /** * Retreive once the notifications from the server and display a message popup for each new one. * Then, periodically check for new notifications. */ var getNotifications = function () { - $rootScope.toCheckNotifications = true + $rootScope.toCheckNotifications = true; if (!$rootScope.checkNotificationsIsInit && !!$rootScope.currentUser) { - setTimeout(function() { + setTimeout(function () { // we request the most recent notifications Notification.last_unread(function (notifications) { - $rootScope.lastCheck = new Date() - $scope.notifications = notifications.totals + $rootScope.lastCheck = new Date(); + $scope.notifications = notifications.totals; const toDisplay = []; - angular.forEach(notifications.notifications, function(n) { toDisplay.push(n) }); + angular.forEach(notifications.notifications, function (n) { toDisplay.push(n); }); if (toDisplay.length < notifications.totals.unread) { toDisplay.push({ message: { description: _t('and_NUMBER_other_notifications', { NUMBER: notifications.totals.unread - toDisplay.length }, 'messageformat') } }); } - angular.forEach(toDisplay, function(notification) { growl.info(notification.message.description); }) - }) - - }, 2000) + angular.forEach(toDisplay, function (notification) { growl.info(notification.message.description); }); + }); + }, 2000); const checkNotifications = function () { if ($rootScope.toCheckNotifications) { @@ -324,15 +322,15 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco $rootScope.lastCheck = new Date(); $scope.notifications = data.totals; - angular.forEach(data.notifications, function(notification) { growl.info(notification.message.description) }); - }) + angular.forEach(data.notifications, function (notification) { growl.info(notification.message.description); }); + }); } }; $interval(checkNotifications, NOTIFICATIONS_CHECK_PERIOD); $rootScope.checkNotificationsIsInit = true; } - } + }; /** * Open the modal window allowing the user to log in. @@ -340,19 +338,19 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco var openLoginModal = function (toState, toParams, callback) { <% active_provider = AuthProvider.active %> <% if active_provider.providable_type != DatabaseProvider.name %> - $window.location.href = '<%=user_omniauth_authorize_path(AuthProvider.active.strategy_name.to_sym)%>' + $window.location.href = '<%=user_omniauth_authorize_path(AuthProvider.active.strategy_name.to_sym)%>'; <% else %> return $uibModal.open({ templateUrl: '<%= asset_path "shared/deviseModal.html" %>', size: 'sm', controller: ['$scope', '$uibModalInstance', '_t', function ($scope, $uibModalInstance, _t) { - const user = ($scope.user = {}) - $scope.login = function() { + const user = ($scope.user = {}); + $scope.login = function () { Auth.login(user).then(function (user) { // Authentication succeeded ... - $uibModalInstance.close(user) + $uibModalInstance.close(user); if (callback && (typeof callback === 'function')) { - return callback(user) + return callback(user); } } , function (error) { @@ -361,57 +359,57 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco return $scope.alerts.push({ msg: _t('wrong_email_or_password'), type: 'danger' - }) - }) - } + }); + }); + }; // handle modal behaviors. The provided reason will be used to define the following actions - $scope.dismiss = function() { $uibModalInstance.dismiss('cancel') } + $scope.dismiss = function () { $uibModalInstance.dismiss('cancel'); }; $scope.openSignup = function (e) { - e.preventDefault() - return $uibModalInstance.dismiss('signup') - } + e.preventDefault(); + return $uibModalInstance.dismiss('signup'); + }; return $scope.openResetPassword = function (e) { - e.preventDefault() - return $uibModalInstance.dismiss('resetPassword') - } + e.preventDefault(); + return $uibModalInstance.dismiss('resetPassword'); + }; }] }).result['finally'](null).then(function (user) { - // what to do when the modal is closed + // what to do when the modal is closed - // authentication succeeded, set the session, gather the notifications and redirect - $scope.setCurrentUser(user); + // authentication succeeded, set the session, gather the notifications and redirect + $scope.setCurrentUser(user); - if ((toState !== null) && (toParams !== null)) { - return $state.go(toState, toParams) - } - }, function (reason) { - // authentication did not ended successfully - if (reason === 'signup') { - // open signup modal - $scope.signup(); - } else if (reason === 'resetPassword') { - // open the 'reset password' modal - return $uibModal.open({ - templateUrl: '<%= asset_path "shared/passwordNewModal.html" %>', - size: 'sm', - controller: ['$scope', '$uibModalInstance', '$http', function ($scope, $uibModalInstance, $http) { - $scope.user = { email: '' } - return $scope.sendReset = function () { - $scope.alerts = [] - return $http.post('/users/password.json', { user: $scope.user }).success(function() { $uibModalInstance.close() }).error(function() { - $scope.alerts.push({ - msg: _t('your_email_address_is_unknown'), - type: 'danger' - }); - }) - } - }] - }).result['finally'](null).then(function() { growl.info(_t('you_will_receive_in_a_moment_an_email_with_instructions_to_reset_your_password')) }) - } - }) - } + if ((toState !== null) && (toParams !== null)) { + return $state.go(toState, toParams); + } + }, function (reason) { + // authentication did not ended successfully + if (reason === 'signup') { + // open signup modal + $scope.signup(); + } else if (reason === 'resetPassword') { + // open the 'reset password' modal + return $uibModal.open({ + templateUrl: '<%= asset_path "shared/passwordNewModal.html" %>', + size: 'sm', + controller: ['$scope', '$uibModalInstance', '$http', function ($scope, $uibModalInstance, $http) { + $scope.user = { email: '' }; + return $scope.sendReset = function () { + $scope.alerts = []; + return $http.post('/users/password.json', { user: $scope.user }).success(function () { $uibModalInstance.close(); }).error(function () { + $scope.alerts.push({ + msg: _t('your_email_address_is_unknown'), + type: 'danger' + }); + }); + }; + }] + }).result['finally'](null).then(function () { growl.info(_t('you_will_receive_in_a_moment_an_email_with_instructions_to_reset_your_password')); }); + } + }); + }; // otherwise the user just closed the modal <% end %> @@ -422,11 +420,11 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco * Inspired by http://stackoverflow.com/questions/1060008/is-there-a-way-to-detect-if-a-browser-window-is-not-currently-active#answer-1060034 */ var onPageVisible = function (callback) { - let hidden = 'hidden' + let hidden = 'hidden'; const onchange = function (evt) { - const v = 'visible' - const h = 'hidden' + const v = 'visible'; + const h = 'hidden'; const evtMap = { focus: v, focusin: v, @@ -434,38 +432,38 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco blur: h, focusout: h, pagehide: h - } - evt = evt || window.event + }; + evt = evt || window.event; if (evt.type in evtMap) { - if (typeof callback === 'function') { callback(evtMap[evt.type]) } + if (typeof callback === 'function') { callback(evtMap[evt.type]); } } else { - if (typeof callback === 'function') { callback(this[hidden] ? 'hidden' : 'visible') } + if (typeof callback === 'function') { callback(this[hidden] ? 'hidden' : 'visible'); } } - } + }; // Standards: if (hidden in document) { - document.addEventListener('visibilitychange', onchange) + document.addEventListener('visibilitychange', onchange); } else if ((hidden = 'mozHidden') in document) { - document.addEventListener('mozvisibilitychange', onchange) + document.addEventListener('mozvisibilitychange', onchange); } else if ((hidden = 'webkitHidden') in document) { - document.addEventListener('webkitvisibilitychange', onchange) + document.addEventListener('webkitvisibilitychange', onchange); } else if ((hidden = 'msHidden') in document) { - document.addEventListener('msvisibilitychange', onchange) + document.addEventListener('msvisibilitychange', onchange); // IE 9 and lower } else if ('onfocusin' in document) { - document.onfocusin = (document.onfocusout = onchange) + document.onfocusin = (document.onfocusout = onchange); // All others } else { - window.onpageshow = (window.onpagehide = (window.onfocus = (window.onblur = onchange))) + window.onpageshow = (window.onpagehide = (window.onfocus = (window.onblur = onchange))); } // set the initial state (but only if browser supports the Page Visibility API) if (document[hidden] !== undefined) { - return onchange({ type: document[hidden] ? 'blur' : 'focus' }) + return onchange({ type: document[hidden] ? 'blur' : 'focus' }); } - } + }; // !!! MUST BE CALLED AT THE END of the controller - return initialize() + return initialize(); } -]) +]); diff --git a/app/assets/javascripts/controllers/events.js.erb b/app/assets/javascripts/controllers/events.js.erb index 0067358e6..dc43d3e2a 100644 --- a/app/assets/javascripts/controllers/events.js.erb +++ b/app/assets/javascripts/controllers/events.js.erb @@ -18,88 +18,88 @@ Application.Controllers.controller('EventsController', ['$scope', '$state', 'Eve /* PUBLIC SCOPE */ // The events displayed on the page - $scope.events = [] + $scope.events = []; // The currently displayed page number - $scope.page = 1 + $scope.page = 1; // List of categories for the events - $scope.categories = categoriesPromise + $scope.categories = categoriesPromise; // List of events themes - $scope.themes = themesPromise + $scope.themes = themesPromise; // List of age ranges - $scope.ageRanges = ageRangesPromise + $scope.ageRanges = ageRangesPromise; // Hide or show the 'load more' button - $scope.noMoreResults = false + $scope.noMoreResults = false; // Active filters for the events list $scope.filters = { category_id: null, theme_id: null, age_range_id: null - } + }; - $scope.monthNames = [<%= t('date.month_names')[1..-1].map { |m| "\"#{m}\"" }.join(', ') %>] + $scope.monthNames = [<%= t('date.month_names')[1..-1].map { |m| "\"#{m}\"" }.join(', ') %>]; /** * Adds a resultset of events to the bottom of the page, grouped by month */ $scope.loadMoreEvents = function () { - $scope.page += 1 + $scope.page += 1; return Event.query(Object.assign({ page: $scope.page }, $scope.filters), function (data) { - $scope.events = $scope.events.concat(data) - groupEvents($scope.events) + $scope.events = $scope.events.concat(data); + groupEvents($scope.events); if (!data[0] || (data[0].nb_total_events <= $scope.events.length)) { - return $scope.noMoreResults = true + return $scope.noMoreResults = true; } - }) - } + }); + }; /** * Callback to redirect the user to the specified event page * @param event {{id:number}} */ - $scope.showEvent = function(event) { $state.go('app.public.events_show', { id: event.id }); }; + $scope.showEvent = function (event) { $state.go('app.public.events_show', { id: event.id }); }; /** * Callback to refresh the events list according to the filters set */ $scope.filterEvents = function () { // reinitialize results datasets - $scope.page = 1 - $scope.eventsGroupByMonth = {} - $scope.events = [] - $scope.monthOrder = [] - $scope.noMoreResults = false + $scope.page = 1; + $scope.eventsGroupByMonth = {}; + $scope.events = []; + $scope.monthOrder = []; + $scope.noMoreResults = false; // run a search query return Event.query(Object.assign({ page: $scope.page }, $scope.filters), function (data) { - $scope.events = data - groupEvents(data) + $scope.events = data; + groupEvents(data); if (!data[0] || (data[0].nb_total_events <= $scope.events.length)) { - return $scope.noMoreResults = true + return $scope.noMoreResults = true; } - }) - } + }); + }; /** * Test if the provided event occurs on a single day or on many days * @param event {{start_date:Date, end_date:Date}} Event object as retreived from the API * @return {boolean} false if the event occurs on many days */ - $scope.onSingleDay = function(event) { moment(event.start_date).isSame(event.end_date, 'day'); }; + $scope.onSingleDay = function (event) { moment(event.start_date).isSame(event.end_date, 'day'); }; - /* PRIVATE SCOPE */ + /* PRIVATE SCOPE */ /** * Kind of constructor: these actions will be realized first when the controller is loaded */ - const initialize = function() { + const initialize = function () { $scope.filterEvents(); }; @@ -111,31 +111,31 @@ Application.Controllers.controller('EventsController', ['$scope', '$state', 'Eve */ const groupEvents = function (events) { if (events.length > 0) { - const eventsGroupedByMonth = _.groupBy(events, function(obj) { - return _.map(['month_id', 'year'], function(key) { + const eventsGroupedByMonth = _.groupBy(events, function (obj) { + return _.map(['month_id', 'year'], function (key) { return obj[key]; }); - }) - $scope.eventsGroupByMonth = Object.assign($scope.eventsGroupByMonth, eventsGroupedByMonth) - return $scope.monthOrder = Object.keys($scope.eventsGroupByMonth) + }); + $scope.eventsGroupByMonth = Object.assign($scope.eventsGroupByMonth, eventsGroupedByMonth); + return $scope.monthOrder = Object.keys($scope.eventsGroupByMonth); } - } + }; // # !!! MUST BE CALLED AT THE END of the controller - initialize() + initialize(); } -]) +]); Application.Controllers.controller('ShowEventController', ['$scope', '$state', '$stateParams', 'Event', '$uibModal', 'Member', 'Reservation', 'Price', 'CustomAsset', 'eventPromise', 'growl', '_t', 'Wallet', 'helpers', 'dialogs', 'priceCategoriesPromise', 'settingsPromise', function ($scope, $state, $stateParams, Event, $uibModal, Member, Reservation, Price, CustomAsset, eventPromise, growl, _t, Wallet, helpers, dialogs, priceCategoriesPromise, settingsPromise) { /* PUBLIC SCOPE */ // reservations for the currently shown event - $scope.reservations = [] + $scope.reservations = []; // user to deal with $scope.ctrl = - { member: {} } + { member: {} }; // parameters for a new reservation $scope.reserve = { @@ -148,26 +148,26 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' amountTotal: 0, totalNoCoupon: 0, totalSeats: 0 - } + }; // Discount coupon to apply to the basket, if any $scope.coupon = - { applied: null } + { applied: null }; // Get the details for the current event (event's id is recovered from the current URL) - $scope.event = eventPromise + $scope.event = eventPromise; // List of price categories for the events - $scope.priceCategories = priceCategoriesPromise + $scope.priceCategories = priceCategoriesPromise; // Global config: is the user authorized to change his bookings slots? - $scope.enableBookingMove = (settingsPromise.booking_move_enable === 'true') + $scope.enableBookingMove = (settingsPromise.booking_move_enable === 'true'); // Global config: delay in hours before a booking while changing the booking slot is forbidden - $scope.moveBookingDelay = parseInt(settingsPromise.booking_move_delay) + $scope.moveBookingDelay = parseInt(settingsPromise.booking_move_delay); // 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) @@ -180,91 +180,92 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' return { title: _t('confirmation_required'), msg: _t('do_you_really_want_to_delete_this_event') - } + }; } } - }, function() { + }, function () { // the admin has confirmed, delete - event.$delete(function() { - $state.go('app.public.events_list') - return growl.info(_t('event_successfully_deleted')) - }, function(error) { + event.$delete(function () { + $state.go('app.public.events_list'); + return growl.info(_t('event_successfully_deleted')); + }, function (error) { console.error(error); growl.error(_t('unable_to_delete_the_event_because_some_users_alredy_booked_it')); - })} - ) - } + }); + } + ); + }; /** * Callback to call when the number of tickets to book changes in the current booking */ $scope.changeNbPlaces = function () { // 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; for (let ticket in $scope.reserve.tickets) { - remain -= $scope.reserve.tickets[ticket] + remain -= $scope.reserve.tickets[ticket]; } // we store the total number of seats booked, this is used to know if the 'pay' button must be shown - $scope.reserve.totalSeats = $scope.event.nb_free_places - remain + $scope.reserve.totalSeats = $scope.event.nb_free_places - remain; // update the available seats for full price tickets - const fullPriceRemains = $scope.reserve.nbReservePlaces + remain - $scope.reserve.nbPlaces.normal = __range__(0, fullPriceRemains, true) + const fullPriceRemains = $scope.reserve.nbReservePlaces + remain; + $scope.reserve.nbPlaces.normal = __range__(0, fullPriceRemains, true); // update the available seats for other prices tickets for (let key in $scope.reserve.nbPlaces) { if (key !== 'normal') { - const priceRemain = $scope.reserve.tickets[key] + remain - $scope.reserve.nbPlaces[key] = __range__(0, priceRemain, true) + const priceRemain = $scope.reserve.tickets[key] + remain; + $scope.reserve.nbPlaces[key] = __range__(0, priceRemain, true); } } // recompute the total price - return $scope.computeEventAmount() - } + return $scope.computeEventAmount(); + }; /** * Callback to reset the current reservation parameters * @param e {Object} see https://docs.angularjs.org/guide/expression#-event- */ $scope.cancelReserve = function (e) { - e.preventDefault() - return resetEventReserve() - } + e.preventDefault(); + return resetEventReserve(); + }; /** * Callback to allow the user to set the details for his reservation */ $scope.reserveEvent = function () { if ($scope.event.nb_total_places > 0) { - $scope.reserveSuccess = false + $scope.reserveSuccess = false; if (!$scope.isAuthenticated()) { return $scope.login(null, function (user) { - $scope.reserve.toReserve = !$scope.reserve.toReserve + $scope.reserve.toReserve = !$scope.reserve.toReserve; if (user.role !== 'admin') { - return $scope.ctrl.member = user + return $scope.ctrl.member = user; } - }) + }); } else { - return $scope.reserve.toReserve = !$scope.reserve.toReserve + return $scope.reserve.toReserve = !$scope.reserve.toReserve; } } - } + }; /** * Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's * reservations. (admins only) */ $scope.updateMember = function () { - resetEventReserve() - $scope.reserveSuccess = false + resetEventReserve(); + $scope.reserveSuccess = false; if ($scope.ctrl.member) { return Member.get({ id: $scope.ctrl.member.id }, function (member) { - $scope.ctrl.member = member - return getReservations($scope.event.id, 'Event', $scope.ctrl.member.id) - }) + $scope.ctrl.member = member; + return getReservations($scope.event.id, 'Event', $scope.ctrl.member.id); + }); } - } + }; /** * Callback to trigger the payment process of the current reservation @@ -272,23 +273,23 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' $scope.payEvent = function () { // first, we check that a user was selected if (Object.keys($scope.ctrl.member).length > 0) { - const reservation = mkReservation($scope.ctrl.member, $scope.reserve, $scope.event) + const reservation = mkReservation($scope.ctrl.member, $scope.reserve, $scope.event); return Wallet.getWalletByUser({ user_id: $scope.ctrl.member.id }, function (wallet) { - const amountToPay = helpers.getAmountToPay($scope.reserve.amountTotal, wallet.amount) + const amountToPay = helpers.getAmountToPay($scope.reserve.amountTotal, wallet.amount); if (($scope.currentUser.role !== 'admin') && (amountToPay > 0)) { - return payByStripe(reservation) + return payByStripe(reservation); } else { if (($scope.currentUser.role === 'admin') || (amountToPay === 0)) { - return payOnSite(reservation) + return payOnSite(reservation); } } - }) + }); } else { // otherwise we alert, this error musn't occur when the current user is not admin - return growl.error(_t('please_select_a_member_first')) + return growl.error(_t('please_select_a_member_first')); } - } + }; /** * Callback to validate the booking of a free event @@ -301,40 +302,40 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' slots_attributes: [], nb_reserve_places: $scope.reserve.nbReservePlaces, tickets_attributes: [] - } + }; // a single slot is used for events reservation.slots_attributes.push({ start_at: $scope.event.start_date, end_at: $scope.event.end_date, availability_id: $scope.event.availability.id - }) + }); // iterate over reservations per prices for (let price_id in $scope.reserve.tickets) { - const seats = $scope.reserve.tickets[price_id] + const seats = $scope.reserve.tickets[price_id]; reservation.tickets_attributes.push({ event_price_category_id: price_id, booked: seats - }) + }); } // set the attempting marker - $scope.attempting = true + $scope.attempting = true; // save the reservation to the API return Reservation.save({ reservation }, function (reservation) { // reservation successfull - afterPayment(reservation) - return $scope.attempting = false + afterPayment(reservation); + return $scope.attempting = false; } , function (response) { // reservation failed - $scope.alerts = [] + $scope.alerts = []; $scope.alerts.push({ msg: response.data.card[0], type: 'danger' - }) + }); // unset the attempting marker - return $scope.attempting = false - }) - } + return $scope.attempting = false; + }); + }; /** * Callback to alter an already booked reservation date. A modal window will be opened to allow the user to choose @@ -343,89 +344,89 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' * @param e {Object} see https://docs.angularjs.org/guide/expression#-event- */ $scope.modifyReservation = function (reservation, e) { - e.preventDefault() - e.stopPropagation() + e.preventDefault(); + e.stopPropagation(); - const index = $scope.reservations.indexOf(reservation) + const index = $scope.reservations.indexOf(reservation); return $uibModal.open({ templateUrl: '<%= asset_path "events/modify_event_reservation_modal.html" %>', resolve: { - event () { return $scope.event }, - reservation () { return reservation } + event () { return $scope.event; }, + reservation () { return reservation; } }, controller: ['$scope', '$uibModalInstance', 'event', 'reservation', 'Reservation', function ($scope, $uibModalInstance, event, reservation, Reservation) { // we copy the controller's resolved parameters into the scope - $scope.event = event - $scope.reservation = angular.copy(reservation) + $scope.event = event; + $scope.reservation = angular.copy(reservation); // set the reservable_id to the first available event for (e of Array.from(event.recurrence_events)) { if (e.nb_free_places > reservation.total_booked_seats) { - $scope.reservation.reservable_id = e.id - break + $scope.reservation.reservable_id = e.id; + break; } } // Callback to validate the new reservation's date $scope.ok = function () { - let eventToPlace = null + let eventToPlace = null; angular.forEach(event.recurrence_events, function (e) { if (e.id === parseInt($scope.reservation.reservable_id, 10)) { - return eventToPlace = e + return eventToPlace = e; } - }) - $scope.reservation.slots[0].start_at = eventToPlace.start_date - $scope.reservation.slots[0].end_at = eventToPlace.end_date - $scope.reservation.slots[0].availability_id = eventToPlace.availability_id - $scope.reservation.slots_attributes = $scope.reservation.slots - $scope.attempting = true + }); + $scope.reservation.slots[0].start_at = eventToPlace.start_date; + $scope.reservation.slots[0].end_at = eventToPlace.end_date; + $scope.reservation.slots[0].availability_id = eventToPlace.availability_id; + $scope.reservation.slots_attributes = $scope.reservation.slots; + $scope.attempting = true; Reservation.update({ id: reservation.id }, { reservation: $scope.reservation }, function (reservation) { - $uibModalInstance.close(reservation) - $scope.attempting = true + $uibModalInstance.close(reservation); + $scope.attempting = true; } , function (response) { - $scope.alerts = [] - angular.forEach(response, function(v, k) { - angular.forEach(v, function(err) { - $scope.alerts.push({ msg: k + ': ' + err, type: 'danger' }) ; - }) - }) + $scope.alerts = []; + angular.forEach(response, function (v, k) { + angular.forEach(v, function (err) { + $scope.alerts.push({ msg: k + ': ' + err, type: 'danger' }); + }); + }); $scope.attempting = false; - }) - } + }); + }; // Callback to cancel the modification - $scope.cancel = function() { $uibModalInstance.dismiss('cancel') } + $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); }; } ] }) .result['finally'](null).then(function (reservation) { // remove the reservation from the user's reservations list for this event (occurrence) - $scope.reservations.splice(index, 1) + $scope.reservations.splice(index, 1); // add the number of places transfered (to the new date) to the total of free places for this event - $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; // remove the number of places transfered from the total of free places of the receiving occurrance angular.forEach($scope.event.recurrence_events, function (e) { if (e.id === parseInt(reservation.reservable.id, 10)) { - return e.nb_free_places = e.nb_free_places - reservation.total_booked_seats + return e.nb_free_places = e.nb_free_places - reservation.total_booked_seats; } - }) - }) - } + }); + }); + }; /** * Checks if the provided reservation is able to be moved (date change) * @param reservation {{total_booked_seats:number}} */ $scope.reservationCanModify = function (reservation) { - const slotStart = moment(reservation.slots[0].start_at) - const now = moment() + const slotStart = moment(reservation.slots[0].start_at); + const now = moment(); - let isAble = false + let isAble = false; angular.forEach($scope.event.recurrence_events, function (e) { - if (e.nb_free_places >= reservation.total_booked_seats) { return isAble = true } - }) - return (isAble && $scope.enableBookingMove && (slotStart.diff(now, 'hours') >= $scope.moveBookingDelay)) - } + if (e.nb_free_places >= reservation.total_booked_seats) { return isAble = true; } + }); + return (isAble && $scope.enableBookingMove && (slotStart.diff(now, 'hours') >= $scope.moveBookingDelay)); + }; /** * Compute the total amount for the current reservation according to the previously set parameters @@ -434,25 +435,25 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' $scope.computeEventAmount = function () { // first we check that a user was selected if (Object.keys($scope.ctrl.member).length > 0) { - const r = mkReservation($scope.ctrl.member, $scope.reserve, $scope.event) + const r = mkReservation($scope.ctrl.member, $scope.reserve, $scope.event); return Price.compute(mkRequestParams(r, $scope.coupon.applied), function (res) { - $scope.reserve.amountTotal = res.price - return $scope.reserve.totalNoCoupon = res.price_without_coupon - }) + $scope.reserve.amountTotal = res.price; + return $scope.reserve.totalNoCoupon = res.price_without_coupon; + }); } else { - return $scope.reserve.amountTotal = null + return $scope.reserve.amountTotal = null; } - } + }; /** * Return the URL allowing to share the current project on the Facebook social network */ - $scope.shareOnFacebook = function () { return `https://www.facebook.com/share.php?u=${$state.href('app.public.events_show', { id: $scope.event.id }, { absolute: true }).replace('#', '%23')}`; } + $scope.shareOnFacebook = function () { 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 */ - $scope.shareOnTwitter = function () { 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)}`; } + $scope.shareOnTwitter = function () { 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 @@ -461,12 +462,12 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' $scope.getPriceCategoryConditions = function (category_id) { for (let cat of Array.from($scope.priceCategories)) { if (cat.id === category_id) { - return cat.conditions + return cat.conditions; } } - } + }; - /* PRIVATE SCOPE */ + /* PRIVATE SCOPE */ /** * Kind of constructor: these actions will be realized first when the controller is loaded @@ -475,25 +476,25 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' // set the controlled user as the current user if the current user is not an admin if ($scope.currentUser) { if ($scope.currentUser.role !== 'admin') { - $scope.ctrl.member = $scope.currentUser + $scope.ctrl.member = $scope.currentUser; } } // initialize the "reserve" object with the event's data - resetEventReserve() + resetEventReserve(); // if non-admin, get the current user's reservations into $scope.reservations if ($scope.currentUser) { - getReservations($scope.event.id, 'Event', $scope.currentUser.id) + getReservations($scope.event.id, 'Event', $scope.currentUser.id); } // watch when a coupon is applied to re-compute the total price return $scope.$watch('coupon.applied', function (newValue, oldValue) { if ((newValue !== null) || (oldValue !== null)) { - return $scope.computeEventAmount() + return $scope.computeEventAmount(); } - }) - } + }); + }; /** * Retrieve the reservations for the couple event / user @@ -506,7 +507,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' reservable_id, reservable_type, user_id - }).$promise.then(function (reservations) { $scope.reservations = reservations }) + }).$promise.then(function (reservations) { $scope.reservations = reservations; }); }; /** @@ -524,27 +525,27 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' slots_attributes: [], nb_reserve_places: reserve.nbReservePlaces, tickets_attributes: [] - } + }; reservation.slots_attributes.push({ start_at: event.start_date, end_at: event.end_date, availability_id: event.availability.id, offered: event.offered || false - }) + }); for (let evt_px_cat of Array.from(event.prices)) { - const booked = reserve.tickets[evt_px_cat.id] + const booked = reserve.tickets[evt_px_cat.id]; if (booked > 0) { reservation.tickets_attributes.push({ event_price_category_id: evt_px_cat.id, booked - }) + }); } } - return reservation - } + return reservation; + }; /** * Format the parameters expected by /api/prices/compute or /api/reservations and return the resulting object @@ -556,10 +557,10 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' const params = { reservation, coupon_code: ((coupon ? coupon.code : undefined)) - } + }; - return params - } + return params; + }; /** * Set the current reservation to the default values. This implies to reservation form to be hidden. @@ -575,16 +576,16 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' toReserve: false, amountTotal: 0, totalSeats: 0 - } + }; for (let evt_px_cat of Array.from($scope.event.prices)) { - $scope.reserve.nbPlaces[evt_px_cat.id] = __range__(0, $scope.event.nb_free_places, true) - $scope.reserve.tickets[evt_px_cat.id] = 0 + $scope.reserve.nbPlaces[evt_px_cat.id] = __range__(0, $scope.event.nb_free_places, true); + $scope.reserve.tickets[evt_px_cat.id] = 0; } - return $scope.event.offered = false + return $scope.event.offered = false; } - } + }; /** * Open a modal window which trigger the stripe payment process @@ -596,66 +597,66 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' size: 'md', resolve: { reservation () { - return reservation + return reservation; }, price () { - return Price.compute(mkRequestParams(reservation, $scope.coupon.applied)).$promise + return Price.compute(mkRequestParams(reservation, $scope.coupon.applied)).$promise; }, wallet () { - return Wallet.getWalletByUser({ user_id: reservation.user_id }).$promise + return Wallet.getWalletByUser({ user_id: reservation.user_id }).$promise; }, cgv () { - return CustomAsset.get({ name: 'cgv-file' }).$promise + return CustomAsset.get({ name: 'cgv-file' }).$promise; }, objectToPay () { return { eventToReserve: $scope.event, reserve: $scope.reserve, member: $scope.ctrl.member - } + }; }, coupon () { - return $scope.coupon.applied + return $scope.coupon.applied; } }, controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', 'growl', 'wallet', 'helpers', '$filter', 'coupon', function ($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation, growl, wallet, helpers, $filter, coupon) { // User's wallet amount - $scope.walletAmount = wallet.amount + $scope.walletAmount = wallet.amount; // Price - $scope.amount = helpers.getAmountToPay(price.price, wallet.amount) + $scope.amount = helpers.getAmountToPay(price.price, wallet.amount); // CGV - $scope.cgv = cgv.custom_asset + $scope.cgv = cgv.custom_asset; // Reservation - $scope.reservation = reservation + $scope.reservation = reservation; // Used in wallet info template to interpolate some translations - $scope.numberFilter = $filter('number') + $scope.numberFilter = $filter('number'); // Callback for the stripe payment authorization return $scope.payment = function (status, response) { if (response.error) { - return growl.error(response.error.message) + return growl.error(response.error.message); } else { - $scope.attempting = true - $scope.reservation.card_token = response.id - Reservation.save(mkRequestParams($scope.reservation, coupon), function(reservation) { $uibModalInstance.close(reservation); } + $scope.attempting = true; + $scope.reservation.card_token = response.id; + Reservation.save(mkRequestParams($scope.reservation, coupon), function (reservation) { $uibModalInstance.close(reservation); } , function (response) { - $scope.alerts = [] + $scope.alerts = []; $scope.alerts.push({ msg: response.data.card[0], type: 'danger' - }) - return $scope.attempting = false - }) + }); + return $scope.attempting = false; + }); } - } + }; } ] - }).result['finally'](null).then(function(reservation) { afterPayment(reservation); }) + }).result['finally'](null).then(function (reservation) { afterPayment(reservation); }); }; /** @@ -668,100 +669,100 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' size: 'sm', resolve: { reservation () { - return reservation + return reservation; }, price () { - return Price.compute(mkRequestParams(reservation, $scope.coupon.applied)).$promise + return Price.compute(mkRequestParams(reservation, $scope.coupon.applied)).$promise; }, wallet () { - return Wallet.getWalletByUser({ user_id: reservation.user_id }).$promise + return Wallet.getWalletByUser({ user_id: reservation.user_id }).$promise; }, coupon () { - return $scope.coupon.applied + return $scope.coupon.applied; } }, controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', 'wallet', 'helpers', '$filter', 'coupon', function ($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation, wallet, helpers, $filter, coupon) { // User's wallet amount - $scope.walletAmount = wallet.amount + $scope.walletAmount = wallet.amount; // Price - $scope.price = price.price + $scope.price = price.price; // price to pay - $scope.amount = helpers.getAmountToPay(price.price, wallet.amount) + $scope.amount = helpers.getAmountToPay(price.price, wallet.amount); // Reservation - $scope.reservation = reservation + $scope.reservation = reservation; // Used in wallet info template to interpolate some translations - $scope.numberFilter = $filter('number') + $scope.numberFilter = $filter('number'); // Button label if ($scope.amount > 0) { - $scope.validButtonName = _t('confirm_payment_of_html', { ROLE: $scope.currentUser.role, AMOUNT: $filter('currency')($scope.amount) }, 'messageformat') + $scope.validButtonName = _t('confirm_payment_of_html', { ROLE: $scope.currentUser.role, AMOUNT: $filter('currency')($scope.amount) }, 'messageformat'); } else { if ((price.price > 0) && ($scope.walletAmount === 0)) { - $scope.validButtonName = _t('confirm_payment_of_html', { ROLE: $scope.currentUser.role, AMOUNT: $filter('currency')(price.price) }, 'messageformat') + $scope.validButtonName = _t('confirm_payment_of_html', { ROLE: $scope.currentUser.role, AMOUNT: $filter('currency')(price.price) }, 'messageformat'); } else { - $scope.validButtonName = _t('confirm') + $scope.validButtonName = _t('confirm'); } } // Callback to validate the payment $scope.ok = function () { - $scope.attempting = true + $scope.attempting = true; return Reservation.save(mkRequestParams($scope.reservation, coupon), function (reservation) { - $uibModalInstance.close(reservation) - return $scope.attempting = true + $uibModalInstance.close(reservation); + return $scope.attempting = true; } , function (response) { - $scope.alerts = [] - angular.forEach(response, function(v, k) { - angular.forEach(v, function(err) { + $scope.alerts = []; + angular.forEach(response, function (v, k) { + angular.forEach(v, function (err) { $scope.alerts.push({ msg: k + ': ' + err, type: 'danger' - }) - }) - }) - return $scope.attempting = false - }) - } + }); + }); + }); + return $scope.attempting = false; + }); + }; // Callback to cancel the payment - return $scope.cancel = function() { $uibModalInstance.dismiss('cancel'); } + return $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); }; } ] }) - .result['finally'](null).then(function(reservation) { afterPayment(reservation) }) - } + .result['finally'](null).then(function (reservation) { afterPayment(reservation); }); + }; /** * What to do after the payment was successful * @param resveration {Object} booked reservation */ var afterPayment = function (reservation) { - $scope.event.nb_free_places = $scope.event.nb_free_places - reservation.total_booked_seats - resetEventReserve() - $scope.reserveSuccess = true - $scope.coupon.applied = null - $scope.reservations.push(reservation) + $scope.event.nb_free_places = $scope.event.nb_free_places - reservation.total_booked_seats; + resetEventReserve(); + $scope.reserveSuccess = true; + $scope.coupon.applied = null; + $scope.reservations.push(reservation); if ($scope.currentUser.role === 'admin') { - return $scope.ctrl.member = null + return $scope.ctrl.member = null; } - } + }; // !!! MUST BE CALLED AT THE END of the controller - return initialize() + return initialize(); } -]) +]); function __range__ (left, right, inclusive) { - let range = [] - let ascending = left < right - let end = !inclusive ? right : ascending ? right + 1 : right - 1 + let range = []; + let ascending = left < right; + let end = !inclusive ? right : ascending ? right + 1 : right - 1; for (let i = left; ascending ? i < end : i > end; ascending ? i++ : i--) { - range.push(i) + range.push(i); } - return range + return range; } diff --git a/app/assets/javascripts/controllers/notifications.js b/app/assets/javascripts/controllers/notifications.js index 0ca61d34e..0e979b031 100644 --- a/app/assets/javascripts/controllers/notifications.js +++ b/app/assets/javascripts/controllers/notifications.js @@ -17,11 +17,6 @@ * inherits $scope.$parent.notifications (global notifications state) from ApplicationController */ Application.Controllers.controller('NotificationsController', ['$scope', 'Notification', function ($scope, Notification) { - /* PRIVATE STATIC CONSTANTS */ - - // Number of notifications added to the page when the user clicks on 'load next notifications' - const NOTIFICATIONS_PER_PAGE = 15; - /* PUBLIC SCOPE */ // Array containg the archived notifications (already read) diff --git a/app/assets/javascripts/router.js.erb b/app/assets/javascripts/router.js.erb index 3f178be58..d0a256845 100644 --- a/app/assets/javascripts/router.js.erb +++ b/app/assets/javascripts/router.js.erb @@ -32,7 +32,7 @@ angular.module('application.router', ['ui.router']) resolve: { logoFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-file' }).$promise; }], logoBlackFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-black-file' }).$promise; }], - commonTranslations: [ 'Translations', function (Translations) { return Translations.query(['app.public.common', 'app.shared.buttons', 'app.shared.elements']).$promise; }] + commonTranslations: ['Translations', function (Translations) { return Translations.query(['app.public.common', 'app.shared.buttons', 'app.shared.elements']).$promise; }] }, onEnter: ['$rootScope', 'logoFile', 'logoBlackFile', function ($rootScope, logoFile, logoBlackFile) { // Application logo @@ -78,7 +78,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query('app.public.about').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.public.about').$promise; }] } }) .state('app.public.home', { @@ -95,7 +95,7 @@ angular.module('application.router', ['ui.router']) upcomingEventsPromise: ['Event', function (Event) { return Event.upcoming({ limit: 3 }).$promise; }], homeBlogpostPromise: ['Setting', function (Setting) { return Setting.get({ name: 'home_blogpost' }).$promise; }], twitterNamePromise: ['Setting', function (Setting) { return Setting.get({ name: 'twitter_name' }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.public.home').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.public.home').$promise; }] } }) @@ -114,7 +114,7 @@ angular.module('application.router', ['ui.router']) groupsPromise: ['Group', function (Group) { return Group.query().$promise; }], cguFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'cgu-file' }).$promise; }], memberPromise: ['Member', 'currentUser', function (Member, currentUser) { return Member.get({ id: currentUser.id }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.logged.profileCompletion', 'app.shared.user']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.logged.profileCompletion', 'app.shared.user']).$promise; }] } }) @@ -135,7 +135,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query(['app.logged.dashboard.profile', 'app.shared.public_profile']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.logged.dashboard.profile', 'app.shared.public_profile']).$promise; }] } }) .state('app.logged.dashboard.settings', { @@ -149,7 +149,7 @@ angular.module('application.router', ['ui.router']) resolve: { groups: ['Group', function (Group) { return Group.query().$promise; }], activeProviderPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.active().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.logged.dashboard.settings', 'app.shared.user']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.logged.dashboard.settings', 'app.shared.user']).$promise; }] } }) .state('app.logged.dashboard.projects', { @@ -161,7 +161,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query('app.logged.dashboard.projects').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.logged.dashboard.projects').$promise; }] } }) .state('app.logged.dashboard.trainings', { @@ -173,7 +173,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query('app.logged.dashboard.trainings').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.logged.dashboard.trainings').$promise; }] } }) .state('app.logged.dashboard.events', { @@ -185,7 +185,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query('app.logged.dashboard.events').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.logged.dashboard.events').$promise; }] } }) .state('app.logged.dashboard.invoices', { @@ -197,7 +197,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query('app.logged.dashboard.invoices').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.logged.dashboard.invoices').$promise; }] } }) .state('app.logged.dashboard.wallet', { @@ -211,7 +211,7 @@ angular.module('application.router', ['ui.router']) resolve: { walletPromise: ['Wallet', 'currentUser', function (Wallet, currentUser) { return Wallet.getWalletByUser({ user_id: currentUser.id }).$promise; }], transactionsPromise: ['Wallet', 'walletPromise', function (Wallet, walletPromise) { return Wallet.transactions({ id: walletPromise.id }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.shared.wallet']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.shared.wallet']).$promise; }] } }) @@ -226,7 +226,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { memberPromise: ['$stateParams', 'Member', function ($stateParams, Member) { return Member.get({ id: $stateParams.id }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.logged.members_show', 'app.shared.public_profile']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.logged.members_show', 'app.shared.public_profile']).$promise; }] } }) .state('app.logged.members', { @@ -239,7 +239,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { membersPromise: ['Member', function (Member) { return Member.query({ requested_attributes: '[profile]', page: 1, size: 10 }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.logged.members').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.logged.members').$promise; }] } }) @@ -256,7 +256,7 @@ angular.module('application.router', ['ui.router']) themesPromise: ['Theme', function (Theme) { return Theme.query().$promise; }], componentsPromise: ['Component', function (Component) { return Component.query().$promise; }], machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.public.projects_list').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.public.projects_list').$promise; }] } }) .state('app.logged.projects_new', { @@ -269,7 +269,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { allowedExtensions: ['Project', function (Project) { return Project.allowedExtensions().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.logged.projects_new', 'app.shared.project']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.logged.projects_new', 'app.shared.project']).$promise; }] } }) .state('app.public.projects_show', { @@ -282,7 +282,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { projectPromise: ['$stateParams', 'Project', function ($stateParams, Project) { return Project.get({ id: $stateParams.id }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.public.projects_show').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.public.projects_show').$promise; }] } }) .state('app.logged.projects_edit', { @@ -296,7 +296,7 @@ angular.module('application.router', ['ui.router']) resolve: { projectPromise: ['$stateParams', 'Project', function ($stateParams, Project) { return Project.get({ id: $stateParams.id }).$promise; }], allowedExtensions: ['Project', function (Project) { return Project.allowedExtensions().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.logged.projects_edit', 'app.shared.project']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.logged.projects_edit', 'app.shared.project']).$promise; }] } }) @@ -311,7 +311,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.public.machines_list', 'app.shared.training_reservation_modal', 'app.shared.request_training_modal']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.public.machines_list', 'app.shared.training_reservation_modal', 'app.shared.request_training_modal']).$promise; }] } }) .state('app.admin.machines_new', { @@ -323,7 +323,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.machines_new', 'app.shared.machine']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.machines_new', 'app.shared.machine']).$promise; }] } }) .state('app.public.machines_show', { @@ -336,7 +336,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { machinePromise: ['Machine', '$stateParams', function (Machine, $stateParams) { return Machine.get({ id: $stateParams.id }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.public.machines_show', 'app.shared.training_reservation_modal', 'app.shared.request_training_modal']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.public.machines_show', 'app.shared.training_reservation_modal', 'app.shared.request_training_modal']).$promise; }] } }) .state('app.logged.machines_reserve', { @@ -363,7 +363,7 @@ angular.module('application.router', ['ui.router']) 'subscription_explications_alert']` }).$promise; }], - translations: [ 'Translations', function (Translations) { + translations: ['Translations', function (Translations) { return Translations.query(['app.logged.machines_reserve', 'app.shared.plan_subscribe', 'app.shared.member_select', 'app.shared.stripe', 'app.shared.valid_reservation_modal', 'app.shared.confirm_modify_slot_modal', 'app.shared.wallet', 'app.shared.coupon_input', 'app.shared.cart']).$promise; @@ -380,7 +380,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { machinePromise: ['Machine', '$stateParams', function (Machine, $stateParams) { return Machine.get({ id: $stateParams.id }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.machines_edit', 'app.shared.machine']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.machines_edit', 'app.shared.machine']).$promise; }] } }) @@ -396,7 +396,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { spacesPromise: ['Space', function (Space) { return Space.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.public.spaces_list']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.public.spaces_list']).$promise; }] } }) .state('app.admin.space_new', { @@ -409,7 +409,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.space_new', 'app.shared.space']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.space_new', 'app.shared.space']).$promise; }] } }) .state('app.public.space_show', { @@ -423,7 +423,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { spacePromise: ['Space', '$stateParams', function (Space, $stateParams) { return Space.get({ id: $stateParams.id }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.public.space_show']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.public.space_show']).$promise; }] } }) .state('app.admin.space_edit', { @@ -437,7 +437,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { spacePromise: ['Space', '$stateParams', function (Space, $stateParams) { return Space.get({ id: $stateParams.id }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.space_edit', 'app.shared.space']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.space_edit', 'app.shared.space']).$promise; }] } }) .state('app.logged.space_reserve', { @@ -465,7 +465,7 @@ angular.module('application.router', ['ui.router']) 'subscription_explications_alert', \ 'space_explications_alert']` }).$promise; }], - translations: [ 'Translations', function (Translations) { + translations: ['Translations', function (Translations) { return Translations.query(['app.logged.space_reserve', 'app.shared.plan_subscribe', 'app.shared.member_select', 'app.shared.stripe', 'app.shared.valid_reservation_modal', 'app.shared.confirm_modify_slot_modal', 'app.shared.wallet', 'app.shared.coupon_input', 'app.shared.cart']).$promise; @@ -484,7 +484,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { trainingsPromise: ['Training', function (Training) { return Training.query({ public_page: true }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.public.trainings_list']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.public.trainings_list']).$promise; }] } }) .state('app.public.training_show', { @@ -497,7 +497,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { trainingPromise: ['Training', '$stateParams', function (Training, $stateParams) { return Training.get({ id: $stateParams.id }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.public.training_show']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.public.training_show']).$promise; }] } }) .state('app.logged.trainings_reserve', { @@ -528,7 +528,7 @@ angular.module('application.router', ['ui.router']) 'training_explications_alert', \ 'training_information_message']` }).$promise; }], - translations: [ 'Translations', function (Translations) { + translations: ['Translations', function (Translations) { return Translations.query(['app.logged.trainings_reserve', 'app.shared.plan_subscribe', 'app.shared.member_select', 'app.shared.stripe', 'app.shared.valid_reservation_modal', 'app.shared.confirm_modify_slot_modal', 'app.shared.wallet', 'app.shared.coupon_input', 'app.shared.cart']).$promise; @@ -545,7 +545,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query('app.logged.notifications').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.logged.notifications').$promise; }] } }) @@ -563,7 +563,7 @@ angular.module('application.router', ['ui.router']) subscriptionExplicationsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'subscription_explications_alert' }).$promise; }], plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }], groupsPromise: ['Group', function (Group) { return Group.query().$promise; }], - translations: [ 'Translations', function (Translations) { + translations: ['Translations', function (Translations) { return Translations.query(['app.public.plans', 'app.shared.member_select', 'app.shared.stripe', 'app.shared.wallet', 'app.shared.coupon_input']).$promise; }] @@ -583,7 +583,7 @@ angular.module('application.router', ['ui.router']) categoriesPromise: ['Category', function (Category) { return Category.query().$promise; }], themesPromise: ['EventTheme', function (EventTheme) { return EventTheme.query().$promise; }], ageRangesPromise: ['AgeRange', function (AgeRange) { return AgeRange.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.public.events_list').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.public.events_list').$promise; }] } }) .state('app.public.events_show', { @@ -598,7 +598,7 @@ angular.module('application.router', ['ui.router']) eventPromise: ['Event', '$stateParams', function (Event, $stateParams) { return Event.get({ id: $stateParams.id }).$promise; }], priceCategoriesPromise: ['PriceCategory', function (PriceCategory) { return PriceCategory.query().$promise; }], settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['booking_move_enable', 'booking_move_delay', 'event_explications_alert']" }).$promise; }], - translations: [ 'Translations', function (Translations) { + translations: ['Translations', function (Translations) { return Translations.query(['app.public.events_show', 'app.shared.member_select', 'app.shared.stripe', 'app.shared.valid_reservation_modal', 'app.shared.wallet', 'app.shared.coupon_input']).$promise; }] @@ -620,7 +620,7 @@ angular.module('application.router', ['ui.router']) trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }], machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }], spacesPromise: ['Space', function (Space) { return Space.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.public.calendar']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.public.calendar']).$promise; }] } }) @@ -638,7 +638,7 @@ angular.module('application.router', ['ui.router']) bookingWindowStart: ['Setting', function (Setting) { return Setting.get({ name: 'booking_window_start' }).$promise; }], bookingWindowEnd: ['Setting', function (Setting) { return Setting.get({ name: 'booking_window_end' }).$promise; }], machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.admin.calendar').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.admin.calendar').$promise; }] } }) @@ -655,7 +655,7 @@ angular.module('application.router', ['ui.router']) componentsPromise: ['Component', function (Component) { return Component.query().$promise; }], licencesPromise: ['Licence', function (Licence) { return Licence.query().$promise; }], themesPromise: ['Theme', function (Theme) { return Theme.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.admin.project_elements').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.admin.project_elements').$promise; }] } }) @@ -671,7 +671,7 @@ angular.module('application.router', ['ui.router']) resolve: { trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }], machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.trainings', 'app.shared.trainings']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.trainings', 'app.shared.trainings']).$promise; }] } }) .state('app.admin.trainings_new', { @@ -684,7 +684,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.trainings_new', 'app.shared.trainings']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.trainings_new', 'app.shared.trainings']).$promise; }] } }) .state('app.admin.trainings_edit', { @@ -698,7 +698,7 @@ angular.module('application.router', ['ui.router']) resolve: { trainingPromise: ['Training', '$stateParams', function (Training, $stateParams) { return Training.get({ id: $stateParams.id }).$promise; }], machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.shared.trainings').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.shared.trainings').$promise; }] } }) // events @@ -716,7 +716,7 @@ angular.module('application.router', ['ui.router']) themesPromise: ['EventTheme', function (EventTheme) { return EventTheme.query().$promise; }], ageRangesPromise: ['AgeRange', function (AgeRange) { return AgeRange.query().$promise; }], priceCategoriesPromise: ['PriceCategory', function (PriceCategory) { return PriceCategory.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.admin.events').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.admin.events').$promise; }] } }) .state('app.admin.events_new', { @@ -732,7 +732,7 @@ angular.module('application.router', ['ui.router']) themesPromise: ['EventTheme', function (EventTheme) { return EventTheme.query().$promise; }], ageRangesPromise: ['AgeRange', function (AgeRange) { return AgeRange.query().$promise; }], priceCategoriesPromise: ['PriceCategory', function (PriceCategory) { return PriceCategory.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.events_new', 'app.shared.event']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.events_new', 'app.shared.event']).$promise; }] } }) .state('app.admin.events_edit', { @@ -749,7 +749,7 @@ angular.module('application.router', ['ui.router']) themesPromise: ['EventTheme', function (EventTheme) { return EventTheme.query().$promise; }], ageRangesPromise: ['AgeRange', function (AgeRange) { return AgeRange.query().$promise; }], priceCategoriesPromise: ['PriceCategory', function (PriceCategory) { return PriceCategory.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.events_edit', 'app.shared.event']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.events_edit', 'app.shared.event']).$promise; }] } }) .state('app.admin.event_reservations', { @@ -763,7 +763,7 @@ angular.module('application.router', ['ui.router']) resolve: { eventPromise: ['Event', '$stateParams', function (Event, $stateParams) { return Event.get({ id: $stateParams.id }).$promise; }], reservationsPromise: ['Reservation', '$stateParams', function (Reservation, $stateParams) { return Reservation.query({ reservable_id: $stateParams.id, reservable_type: 'Event' }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.admin.event_reservations').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.admin.event_reservations').$promise; }] } }) @@ -781,7 +781,7 @@ angular.module('application.router', ['ui.router']) groups: ['Group', function (Group) { return Group.query().$promise; }], machinesPricesPromise: ['Price', function (Price) { return Price.query({ priceable_type: 'Machine', plan_id: 'null' }).$promise; }], trainingsPricingsPromise: ['TrainingsPricing', function (TrainingsPricing) { return TrainingsPricing.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.pricing', 'app.shared.member_select', 'app.shared.coupon']).$promise; }], + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.pricing', 'app.shared.member_select', 'app.shared.coupon']).$promise; }], trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }], machineCreditsPromise: ['Credit', function (Credit) { return Credit.query({ creditable_type: 'Machine' }).$promise; }], machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }], @@ -811,7 +811,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.plans.new', 'app.shared.plan']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.plans.new', 'app.shared.plan']).$promise; }] } }) .state('app.admin.plans.edit', { @@ -827,7 +827,7 @@ angular.module('application.router', ['ui.router']) machines: ['Machine', function (Machine) { return Machine.query().$promise; }], plans: ['Plan', function (Plan) { return Plan.query().$promise; }], planPromise: ['Plan', '$stateParams', function (Plan, $stateParams) { return Plan.get({ id: $stateParams.id }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.plans.edit', 'app.shared.plan']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.plans.edit', 'app.shared.plan']).$promise; }] } }) @@ -841,7 +841,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.coupons_new', 'app.shared.coupon']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.coupons_new', 'app.shared.coupon']).$promise; }] } }) .state('app.admin.coupons_edit', { @@ -854,7 +854,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { couponPromise: ['Coupon', '$stateParams', function (Coupon, $stateParams) { return Coupon.get({ id: $stateParams.id }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.coupons_edit', 'app.shared.coupon']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.coupons_edit', 'app.shared.coupon']).$promise; }] } }) @@ -885,7 +885,7 @@ angular.module('application.router', ['ui.router']) query: { number: '', customer: '', date: null, order_by: '-reference', page: 1, size: 20 } }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.admin.invoices').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.admin.invoices').$promise; }] } }) @@ -916,7 +916,7 @@ angular.module('application.router', ['ui.router']) groupsPromise: ['Group', function (Group) { return Group.query().$promise; }], tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }], authProvidersPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.admin.members').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.admin.members').$promise; }] } }) .state('app.admin.members_new', { @@ -928,7 +928,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.members_new', 'app.shared.user', 'app.shared.user_admin']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.members_new', 'app.shared.user', 'app.shared.user_admin']).$promise; }] } }) .state('app.admin.members_edit', { @@ -945,7 +945,7 @@ angular.module('application.router', ['ui.router']) walletPromise: ['Wallet', '$stateParams', function (Wallet, $stateParams) { return Wallet.getWalletByUser({ user_id: $stateParams.id }).$promise; }], transactionsPromise: ['Wallet', 'walletPromise', function (Wallet, walletPromise) { return Wallet.transactions({ id: walletPromise.id }).$promise; }], tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.members_edit', 'app.shared.user', 'app.shared.user_admin', 'app.shared.wallet']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.members_edit', 'app.shared.user', 'app.shared.user_admin', 'app.shared.wallet']).$promise; }] } }) .state('app.admin.admins_new', { @@ -957,7 +957,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query('app.admin.admins_new').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.admin.admins_new').$promise; }] } }) @@ -973,7 +973,7 @@ angular.module('application.router', ['ui.router']) resolve: { mappingFieldsPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.mapping_fields().$promise; }], authProvidersPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.authentication_new', 'app.shared.authentication', 'app.shared.oauth2']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.authentication_new', 'app.shared.authentication', 'app.shared.oauth2']).$promise; }] } }) .state('app.admin.authentication_edit', { @@ -987,7 +987,7 @@ angular.module('application.router', ['ui.router']) resolve: { providerPromise: ['AuthProvider', '$stateParams', function (AuthProvider, $stateParams) { return AuthProvider.get({ id: $stateParams.id }).$promise; }], mappingFieldsPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.mapping_fields().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query(['app.admin.authentication_edit', 'app.shared.authentication', 'app.shared.oauth2']).$promise; }] + translations: ['Translations', function (Translations) { return Translations.query(['app.admin.authentication_edit', 'app.shared.authentication', 'app.shared.oauth2']).$promise; }] } }) @@ -1003,7 +1003,7 @@ angular.module('application.router', ['ui.router']) resolve: { membersPromise: ['Member', function (Member) { return Member.mapping().$promise; }], statisticsPromise: ['Statistics', function (Statistics) { return Statistics.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.admin.statistics').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.admin.statistics').$promise; }] } }) .state('app.admin.stats_graphs', { @@ -1015,7 +1015,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - translations: [ 'Translations', function (Translations) { return Translations.query('app.admin.stats_graphs').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.admin.stats_graphs').$promise; }] } }) @@ -1063,7 +1063,7 @@ angular.module('application.router', ['ui.router']) cgvFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'cgv-file' }).$promise; }], faviconFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'favicon-file' }).$promise; }], profileImageFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'profile-image-file' }).$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.admin.settings').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.admin.settings').$promise; }] } }) @@ -1078,7 +1078,7 @@ angular.module('application.router', ['ui.router']) }, resolve: { clientsPromise: ['OpenAPIClient', function (OpenAPIClient) { return OpenAPIClient.query().$promise; }], - translations: [ 'Translations', function (Translations) { return Translations.query('app.admin.open_api_clients').$promise; }] + translations: ['Translations', function (Translations) { return Translations.query('app.admin.open_api_clients').$promise; }] } }); } diff --git a/app/assets/javascripts/services/diacritics.js b/app/assets/javascripts/services/diacritics.js index 8dba61b01..0361bf3c0 100755 --- a/app/assets/javascripts/services/diacritics.js +++ b/app/assets/javascripts/services/diacritics.js @@ -111,6 +111,7 @@ Application.Services.service('Diacritics', [ } } + // eslint-disable-next-line no-control-regex return str.replace(/[^\u0000-\u007E]/g, function (a) { return diacriticsMap[a] || a; }); diff --git a/app/controllers/api/notifications_controller.rb b/app/controllers/api/notifications_controller.rb index 02fb14ccf..c4e4bf30b 100644 --- a/app/controllers/api/notifications_controller.rb +++ b/app/controllers/api/notifications_controller.rb @@ -2,9 +2,12 @@ class API::NotificationsController < API::ApiController include NotifyWith::NotificationsApi before_action :authenticate_user! + # Number of notifications added to the page when the user clicks on 'load next notifications' + NOTIFICATIONS_PER_PAGE = 15 + def index loop do - @notifications = current_user.notifications.page(params[:page]).per(15).order('created_at DESC') + @notifications = current_user.notifications.page(params[:page]).per(NOTIFICATIONS_PER_PAGE).order('created_at DESC') # we delete obsolete notifications on first access break unless delete_obsoletes(@notifications) end @@ -38,6 +41,7 @@ class API::NotificationsController < API::ApiController end private + def delete_obsoletes(notifications) cleaned = false notifications.each do |n|