Merge branch 'dev' for release 4.6.0
1
.browserslistrc
Normal file
@ -0,0 +1 @@
|
||||
defaults
|
@ -16,6 +16,7 @@ redis
|
||||
# Ignore public assets
|
||||
public/uploads
|
||||
public/assets
|
||||
public/packs
|
||||
|
||||
# Ignore all logfiles and tempfiles.
|
||||
log
|
||||
@ -35,6 +36,9 @@ exports
|
||||
# CSV imports
|
||||
imports
|
||||
|
||||
# accounting archives
|
||||
accounting
|
||||
|
||||
.DS_Store
|
||||
|
||||
# Development files
|
||||
|
8
.gitignore
vendored
@ -18,6 +18,8 @@
|
||||
/coverage
|
||||
|
||||
/public/uploads
|
||||
/public/packs
|
||||
/public/packs-test
|
||||
/public/assets
|
||||
/public/api
|
||||
|
||||
@ -38,7 +40,7 @@
|
||||
# CSV imports
|
||||
/imports/*
|
||||
|
||||
# Archives of cLosed accounting periods
|
||||
# Archives of closed accounting periods
|
||||
/accounting/*
|
||||
|
||||
.DS_Store
|
||||
@ -56,3 +58,7 @@
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
/yarn-error.log
|
||||
yarn-debug.log*
|
||||
.yarn-integrity
|
||||
|
@ -1,34 +0,0 @@
|
||||
|
||||
Fab-manager uses some external components, which are licenced under the
|
||||
terms of the following licences:
|
||||
|
||||
- [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0):
|
||||
- [jasny-bootstrap](https://github.com/jasny/bootstrap/)
|
||||
- [elasticsearch](https://github.com/elasticsearch/bower-elasticsearch-js)
|
||||
- [nvd3](https://github.com/novus/nvd3)
|
||||
- [angular-bootstrap-switch](https://github.com/frapontillo/angular-bootstrap-switch)
|
||||
- [elasticsearch-rails](https://github.com/elastic/elasticsearch-rails)
|
||||
- [elasticsearch-model](https://github.com/elastic/elasticsearch-rails/tree/master/elasticsearch-model)
|
||||
- [elasticsearch-persistence](https://github.com/elastic/elasticsearch-rails/tree/master/elasticsearch-persistence)
|
||||
- font [Open Sans](http://www.fontsquirrel.com/fonts/open-sans)
|
||||
|
||||
- [General Public License version 2](http://www.gnu.org/licenses/old-licenses/gpl-2.0-faq.en.html):
|
||||
- [railroady](https://github.com/preston/railroady)
|
||||
- [unicorn](https://github.com/defunkt/unicorn)
|
||||
- [prawn](https://github.com/prawnpdf/prawn)
|
||||
- [prawn-table](https://github.com/prawnpdf/prawn-table)
|
||||
|
||||
- [BSD-2-Clause](https://opensource.org/licenses/BSD-2-Clause)
|
||||
- [ruby](https://www.ruby-lang.org)
|
||||
- [rubyzip](https://github.com/rubyzip/rubyzip)
|
||||
- [byebug](https://github.com/deivid-rodriguez/byebug)
|
||||
|
||||
- [MIT Licence](https://opensource.org/licenses/MIT)
|
||||
- Errors and omissions excepted, all the other external libraries used
|
||||
in this project.
|
||||
|
||||
Please refer to the libraries documentation for more information about
|
||||
their licences.
|
||||
|
||||
Complete lists of used libraries are available in `package.json` for the
|
||||
JS/EcmaScript libraries and in `Gemfile` for Ruby libraries.
|
19
CHANGELOG.md
@ -1,5 +1,24 @@
|
||||
# Changelog Fab-manager
|
||||
|
||||
## v4.6.0 2020 October 20
|
||||
|
||||
- Migrated the assets build pipeline from Sprockets to Webpack
|
||||
- Version check during the upgrade
|
||||
- Fix a bug: changing the date of a training session does not prevent the selection of a different type of training
|
||||
- Fix a bug: unable to change the date formats using the setup script
|
||||
- Fix a bug: missing translation for projets drafts in public profile
|
||||
- Fix a bug: email notification after reservation update have wrong previous date (#234)
|
||||
- Fix a bug: unable to rename a group containing users
|
||||
- Updated contribution guidelines
|
||||
- Updated summernote to 0.8.18
|
||||
- Updated angular-summernote to 0.8.1
|
||||
- Updated FontAwesome from v4 to v5
|
||||
- Updated jquery-minicolors to 2.3.5
|
||||
- Updated angular-bootstrap-switch to 0.5.2
|
||||
- Updated bootstrap-switch to 3.4.0
|
||||
- Updated fullCalendar to 3.10.2
|
||||
- [TODO DEPLOY] `\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/scripts/mount-webpack.sh | bash`
|
||||
|
||||
## v4.5.9 2020 September 29
|
||||
|
||||
- Ability to configure until when the events are shown on the home page
|
||||
|
@ -56,7 +56,7 @@ Example:
|
||||
> 2. This is the second step
|
||||
> 3. Further steps, etc.
|
||||
>
|
||||
> `<url>` - a link to the reduced test case
|
||||
> `<url>` - a link to your instance, demonstrating the problem
|
||||
>
|
||||
> Any other information you want to share that is relevant to the issue being reported. This might include the lines of
|
||||
> code that you have identified as causing the bug, and potential solutions (and your opinions on their merits).
|
||||
@ -69,8 +69,8 @@ Feature requests are welcome. But take a moment to find out whether your idea fi
|
||||
project. It's up to *you* to make a strong case to convince the project's developers of the merits of this feature.
|
||||
Please provide as much detail and context as possible.
|
||||
|
||||
Please note also that [the forum](https://forum.fab-manager.com) is probably a better place for discussing about feature
|
||||
requests.
|
||||
Please note also that [the feedback tool](https://feedback.fab-manager.com) is probably a better place for discussing
|
||||
about feature requests.
|
||||
|
||||
|
||||
<a name="pull-requests"></a>
|
||||
@ -132,3 +132,20 @@ Adhering to the following process is the best way to get your work included in t
|
||||
|
||||
**IMPORTANT**: By submitting a patch, you agree to allow the project owners to license your work under the terms of
|
||||
the [GNU Affero General Public License](LICENSE.md).
|
||||
|
||||
<a name="translations"></a>
|
||||
## Translations
|
||||
|
||||
Event without any technical skills, you can contribute to translate Fab-manager to your local language.
|
||||
This is possible using a [Translation Management System](https://en.wikipedia.org/wiki/Translation_management_system)
|
||||
known as [Crowdin](https://crowdin.com/). This tool helps the community to contribute to the translation of Fab-Manager
|
||||
into their favorite local languages.
|
||||
|
||||
You can access it at [translate.fab-manager.com](https://translate.fab-manager.com/) and start translating.
|
||||
If you want to translate Fab-Manager to a new unlisted language, just post a comment [on the forum](https://forum.fab-manager.com/)
|
||||
or [create an issue on GitHub](https://github.com/sleede/fab-manager/issues) and we'll be happy to add it
|
||||
to the list of supported languages.
|
||||
|
||||
If you know where an untranslated sentence is located and you can't find it on Crowdin, you can use
|
||||
the "in-context translation": [in-context.translate.fab-manager.com](https://in-context.translate.fab-manager.com/).
|
||||
From there, you'll be able to browse the application interface and select in one click the sentences you want to translate.
|
||||
|
@ -44,7 +44,7 @@ RUN bundle install --binstubs --without development test doc
|
||||
WORKDIR /usr/src/app
|
||||
COPY package.json /usr/src/app/package.json
|
||||
COPY yarn.lock /usr/src/app/yarn.lock
|
||||
RUN yarn install --production
|
||||
RUN yarn install
|
||||
|
||||
# Clean up build deps, cached packages and temp files
|
||||
RUN apk del .build-deps && \
|
||||
@ -62,7 +62,7 @@ RUN mkdir -p /usr/src/app && \
|
||||
mkdir -p /usr/src/app/imports && \
|
||||
mkdir -p /usr/src/app/log && \
|
||||
mkdir -p /usr/src/app/public/uploads && \
|
||||
mkdir -p /usr/src/app/public/assets && \
|
||||
mkdir -p /usr/src/app/public/packs && \
|
||||
mkdir -p /usr/src/app/accounting && \
|
||||
mkdir -p /usr/src/app/tmp/sockets && \
|
||||
mkdir -p /usr/src/app/tmp/pids
|
||||
@ -76,7 +76,7 @@ VOLUME /usr/src/app/exports
|
||||
VOLUME /usr/src/app/imports
|
||||
VOLUME /usr/src/app/public
|
||||
VOLUME /usr/src/app/public/uploads
|
||||
VOLUME /usr/src/app/public/assets
|
||||
VOLUME /usr/src/app/public/packs
|
||||
VOLUME /usr/src/app/accounting
|
||||
VOLUME /var/log/supervisor
|
||||
|
||||
|
20
Gemfile
@ -2,29 +2,18 @@
|
||||
|
||||
source 'https://rubygems.org'
|
||||
|
||||
git 'https://github.com/judynjagi/compass.git', branch: 'stable' do
|
||||
gem 'compass-core'
|
||||
end
|
||||
|
||||
gem 'compass-rails', '3.1.0'
|
||||
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
||||
gem 'rails', '~> 5.2.4'
|
||||
# Used by rails 5.2 to reduce the app boot time by over 50%
|
||||
gem 'bootsnap'
|
||||
# Use Puma as web server
|
||||
gem 'puma', '3.12.6'
|
||||
# Use SCSS for stylesheets
|
||||
gem 'sass-rails', '~> 5.0', '>= 5.0.6'
|
||||
gem 'webpacker', '~> 5.x'
|
||||
|
||||
# Use Uglifier as compressor for JavaScript assets
|
||||
gem 'uglifier', '>= 4.1.20'
|
||||
|
||||
# Use jquery as the JavaScript library
|
||||
gem 'jquery-rails'
|
||||
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
|
||||
gem 'jbuilder', '~> 2.5'
|
||||
gem 'jbuilder_cache_multi'
|
||||
gem "json", ">= 2.3.0"
|
||||
gem 'json', '>= 2.3.0'
|
||||
|
||||
gem 'forgery'
|
||||
gem 'responders', '~> 2.0'
|
||||
@ -72,6 +61,7 @@ gem 'seed_dump'
|
||||
gem 'pg'
|
||||
gem 'pg_search'
|
||||
|
||||
# authentication
|
||||
gem 'devise', '>= 4.6.0'
|
||||
|
||||
gem 'omniauth', '~> 1.9.0'
|
||||
@ -80,11 +70,9 @@ gem 'omniauth-rails_csrf_protection', '~> 0.1'
|
||||
|
||||
gem 'rolify'
|
||||
|
||||
# pagination
|
||||
gem 'kaminari'
|
||||
|
||||
gem 'bootstrap-sass', '>= 3.4.1'
|
||||
gem 'font-awesome-rails'
|
||||
|
||||
# Image processing ruby wrapper for ImageMagick
|
||||
gem 'mini_magick'
|
||||
# upload files
|
||||
|
65
Gemfile.lock
@ -1,21 +1,3 @@
|
||||
GIT
|
||||
remote: https://github.com/judynjagi/compass.git
|
||||
revision: 1692c0a7fd8ada392ad5f524bef756ab74e300d0
|
||||
branch: stable
|
||||
specs:
|
||||
compass (1.0.3)
|
||||
chunky_png (~> 1.2)
|
||||
compass-core (~> 1.0.2)
|
||||
compass-import-once (~> 1.0.5)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
sass (>= 3.3.13, < 3.5)
|
||||
compass-core (1.0.2)
|
||||
multi_json (~> 1.0)
|
||||
sass (>= 3.3.0, < 3.5)
|
||||
compass-import-once (1.0.5)
|
||||
sass (>= 3.2, < 3.5)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
@ -75,8 +57,6 @@ GEM
|
||||
rails (>= 4.1)
|
||||
arel (9.0.0)
|
||||
ast (2.4.0)
|
||||
autoprefixer-rails (9.7.4)
|
||||
execjs
|
||||
awesome_print (1.8.0)
|
||||
axiom-types (0.1.1)
|
||||
descendants_tracker (~> 0.0.4)
|
||||
@ -86,9 +66,6 @@ GEM
|
||||
bindex (0.8.1)
|
||||
bootsnap (1.4.6)
|
||||
msgpack (~> 1.0)
|
||||
bootstrap-sass (3.4.1)
|
||||
autoprefixer-rails (>= 5.2.1)
|
||||
sassc (>= 2.0.0)
|
||||
builder (3.2.4)
|
||||
camertron-eprun (1.1.1)
|
||||
carrierwave (2.1.0)
|
||||
@ -107,15 +84,10 @@ GEM
|
||||
actionpack (>= 3.1)
|
||||
caxlsx (>= 3.0)
|
||||
chroma (0.2.0)
|
||||
chunky_png (1.3.11)
|
||||
cldr-plurals-runtime-rb (1.0.1)
|
||||
coercible (1.0.0)
|
||||
descendants_tracker (~> 0.0.1)
|
||||
compass-rails (3.1.0)
|
||||
compass (~> 1.0.0)
|
||||
sass-rails (< 5.1)
|
||||
sprockets (< 4.0)
|
||||
concurrent-ruby (1.1.7)
|
||||
concurrent-ruby (1.1.6)
|
||||
connection_pool (2.2.3)
|
||||
coveralls_reborn (0.18.0)
|
||||
simplecov (>= 0.18.1, < 0.20.0)
|
||||
@ -163,14 +135,11 @@ GEM
|
||||
erubi (1.9.0)
|
||||
et-orbi (1.2.1)
|
||||
tzinfo
|
||||
execjs (2.7.0)
|
||||
faker (2.10.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
faraday (0.17.3)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffi (1.12.2)
|
||||
font-awesome-rails (4.7.0.5)
|
||||
railties (>= 3.2, < 6.1)
|
||||
foreman (0.87.0)
|
||||
forgery (0.7.0)
|
||||
friendly_id (5.1.0)
|
||||
@ -201,10 +170,6 @@ GEM
|
||||
activesupport (>= 5.0.0)
|
||||
jbuilder_cache_multi (0.1.0)
|
||||
jbuilder (>= 1.5.0, < 3)
|
||||
jquery-rails (4.3.5)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (2.3.1)
|
||||
jwt (2.2.1)
|
||||
kaminari (1.2.1)
|
||||
@ -303,6 +268,8 @@ GEM
|
||||
rack (2.2.3)
|
||||
rack-protection (2.0.8.1)
|
||||
rack
|
||||
rack-proxy (0.6.5)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
railroady (1.5.3)
|
||||
@ -369,18 +336,10 @@ GEM
|
||||
rubyzip (>= 1.3.0)
|
||||
rubyzip (1.3.0)
|
||||
safe_yaml (1.0.5)
|
||||
sass (3.4.25)
|
||||
sass-rails (5.0.7)
|
||||
railties (>= 4.0.0, < 6)
|
||||
sass (~> 3.1)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
tilt (>= 1.1, < 3)
|
||||
sassc (2.2.1)
|
||||
ffi (~> 1.9)
|
||||
seed_dump (3.3.1)
|
||||
activerecord (>= 4)
|
||||
activesupport (>= 4)
|
||||
semantic_range (2.3.0)
|
||||
sha3 (1.0.1)
|
||||
sidekiq (6.0.7)
|
||||
connection_pool (>= 2.2.2)
|
||||
@ -418,7 +377,6 @@ GEM
|
||||
tins (~> 1.0)
|
||||
thor (0.20.3)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.10)
|
||||
tins (1.25.0)
|
||||
sync
|
||||
ttfunk (1.5.1)
|
||||
@ -428,8 +386,6 @@ GEM
|
||||
tzinfo
|
||||
tzinfo (1.2.7)
|
||||
thread_safe (~> 0.1)
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unicode-display_width (1.4.1)
|
||||
vcr (3.0.1)
|
||||
virtus (1.0.5)
|
||||
@ -448,6 +404,11 @@ GEM
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
webpacker (5.2.1)
|
||||
activesupport (>= 5.2)
|
||||
rack-proxy (>= 0.6.1)
|
||||
railties (>= 5.2)
|
||||
semantic_range (>= 2.3.0)
|
||||
websocket-driver (0.7.3)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
@ -463,13 +424,10 @@ DEPENDENCIES
|
||||
apipie-rails
|
||||
awesome_print
|
||||
bootsnap
|
||||
bootstrap-sass (>= 3.4.1)
|
||||
carrierwave
|
||||
caxlsx
|
||||
caxlsx_rails
|
||||
chroma
|
||||
compass-core!
|
||||
compass-rails (= 3.1.0)
|
||||
coveralls_reborn (~> 0.18.0)
|
||||
database_cleaner
|
||||
devise (>= 4.6.0)
|
||||
@ -479,14 +437,12 @@ DEPENDENCIES
|
||||
elasticsearch-rails (~> 5)
|
||||
faker
|
||||
faraday (~> 0.17)
|
||||
font-awesome-rails
|
||||
foreman
|
||||
forgery
|
||||
friendly_id (~> 5.1.0)
|
||||
icalendar
|
||||
jbuilder (~> 2.5)
|
||||
jbuilder_cache_multi
|
||||
jquery-rails
|
||||
json (>= 2.3.0)
|
||||
kaminari
|
||||
listen (~> 3.0.5)
|
||||
@ -518,7 +474,6 @@ DEPENDENCIES
|
||||
rubocop (~> 0.61.1)
|
||||
rubyXL
|
||||
rubyzip (>= 1.3.0)
|
||||
sass-rails (~> 5.0, >= 5.0.6)
|
||||
seed_dump
|
||||
sha3
|
||||
sidekiq (>= 6.0.7)
|
||||
@ -528,10 +483,10 @@ DEPENDENCIES
|
||||
spring-watcher-listen (~> 2.0.0)
|
||||
stripe (= 5.1.1)
|
||||
sys-filesystem
|
||||
uglifier (>= 4.1.20)
|
||||
vcr (= 3.0.1)
|
||||
web-console (>= 3.3.0)
|
||||
webmock
|
||||
webpacker (~> 5.x)
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.4
|
||||
|
@ -1,4 +1,4 @@
|
||||
Copyright (C) 2019 Sleede
|
||||
Copyright (C) 2020 Sleede
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
|
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 20 KiB |
@ -1,87 +0,0 @@
|
||||
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
||||
// listed below.
|
||||
//
|
||||
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
||||
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
||||
//
|
||||
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||
// compiled file.
|
||||
//
|
||||
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
||||
// about supported directives.
|
||||
//
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require bootstrap
|
||||
//= require polyfill
|
||||
//= require angular
|
||||
//= require angular-cookies
|
||||
//= require angular-resource
|
||||
//= require angular-sanitize
|
||||
//= require angular-cookies
|
||||
//= require angular-touch
|
||||
//= require @uirouter/angularjs/release/angular-ui-router
|
||||
//= require angular-ui-bootstrap/dist/ui-bootstrap-tpls
|
||||
//= require ui-select/dist/select
|
||||
//= require moment/moment
|
||||
//= require moment-timezone/builds/moment-timezone-with-data-2012-2022
|
||||
//= require angular-ui-calendar/src/calendar
|
||||
//= require fullcalendar/dist/fullcalendar
|
||||
//= require angular-moment/angular-moment
|
||||
//= require ngUpload/ng-upload
|
||||
//= require jasny-bootstrap/js/fileinput
|
||||
//= require holderjs/holder
|
||||
//= require AngularDevise/lib/devise
|
||||
//= require devise-modal
|
||||
//= require angular-growl-v2/build/angular-growl
|
||||
//= require angular-xeditable/dist/js/xeditable
|
||||
//= require checklist-model/checklist-model
|
||||
//= require angular-unsavedchanges/lib/unsavedChanges
|
||||
//= require angular-loading-bar/src/loading-bar
|
||||
//= require angular-scroll/angular-scroll
|
||||
//= require angular-google-analytics/dist/angular-google-analytics
|
||||
//= require dirDisqus
|
||||
//= require humanize
|
||||
//= require underscore/underscore
|
||||
//= require elasticsearch-browser/elasticsearch.angular
|
||||
//= require d3/d3
|
||||
//= require nvd3/build/nv.d3.js
|
||||
//= require twitter-fetcher
|
||||
//= require app
|
||||
//= require router
|
||||
//= require medium-editor/dist/js/medium-editor
|
||||
//= require angular-medium-editor/dist/angular-medium-editor
|
||||
//= require bootstrap-switch/dist/js/bootstrap-switch.min
|
||||
//= require angular-bootstrap-switch/dist/angular-bootstrap-switch.min
|
||||
//= require angular-base64-upload/dist/angular-base64-upload.min
|
||||
//= require summernote/dist/summernote
|
||||
//= require angular-summernote/dist/angular-summernote
|
||||
//= require summernote-ext-nugget
|
||||
//= require jquery-minicolors/jquery.minicolors.js
|
||||
//= require angular-minicolors/angular-minicolors.js
|
||||
//= require angular-translate/dist/angular-translate
|
||||
//= require angular-translate-loader-partial/angular-translate-loader-partial
|
||||
//= require messageformat/messageformat
|
||||
//= require angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat
|
||||
//= require ng-fittext/dist/ng-FitText.min
|
||||
//= require angular-aside/dist/js/angular-aside
|
||||
//= require ng-caps-lock/ng-caps-lock
|
||||
//= require angular-recaptcha
|
||||
//= require codemirror/lib/codemirror
|
||||
//= require codemirror/addon/edit/matchbrackets
|
||||
//= require codemirror/mode/css/css
|
||||
//= require codemirror/mode/sass/sass
|
||||
//= require angular-ui-codemirror/src/ui-codemirror
|
||||
//= require angular-hotkeys/build/hotkeys
|
||||
//= require hone/dist/hone
|
||||
//= require tether/dist/js/tether
|
||||
//= require angular-bind-html-compile/angular-bind-html-compile
|
||||
//= require angular-ui-tour/dist/angular-ui-tour
|
||||
//= require_tree ./controllers
|
||||
//= require_tree ./services
|
||||
//= require_tree ./directives
|
||||
//= require_tree ./filters
|
||||
|
||||
<%
|
||||
PluginRegistry.javascripts.each { |js| require_asset(js) }
|
||||
%>
|
@ -1,122 +0,0 @@
|
||||
/**
|
||||
* Created by sylvain on 20/08/14.
|
||||
*
|
||||
* Based on http://jsperf.com/diacritics/12
|
||||
*/
|
||||
Application.Services.service('Diacritics', [
|
||||
'$resource', function ($resource) {
|
||||
return {
|
||||
|
||||
/**
|
||||
* Fast diacritics removing function, works on the provided string.
|
||||
* Eg. "éêè çä bönjoür" will become "eee ca bonjour"
|
||||
* @param str {string} to ascii-fy
|
||||
* @returns {string} without diacritics
|
||||
*/
|
||||
remove: function (str) {
|
||||
var defaultDiacriticsRemovalap = [
|
||||
{ 'base': 'A', 'letters': '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F' },
|
||||
{ 'base': 'AA', 'letters': '\uA732' },
|
||||
{ 'base': 'AE', 'letters': '\u00C6\u01FC\u01E2' },
|
||||
{ 'base': 'AO', 'letters': '\uA734' },
|
||||
{ 'base': 'AU', 'letters': '\uA736' },
|
||||
{ 'base': 'AV', 'letters': '\uA738\uA73A' },
|
||||
{ 'base': 'AY', 'letters': '\uA73C' },
|
||||
{ 'base': 'B', 'letters': '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181' },
|
||||
{ 'base': 'C', 'letters': '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E' },
|
||||
{ 'base': 'D', 'letters': '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779' },
|
||||
{ 'base': 'DZ', 'letters': '\u01F1\u01C4' },
|
||||
{ 'base': 'Dz', 'letters': '\u01F2\u01C5' },
|
||||
{ 'base': 'E', 'letters': '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E' },
|
||||
{ 'base': 'F', 'letters': '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' },
|
||||
{ 'base': 'G', 'letters': '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E' },
|
||||
{ 'base': 'H', 'letters': '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D' },
|
||||
{ 'base': 'I', 'letters': '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197' },
|
||||
{ 'base': 'J', 'letters': '\u004A\u24BF\uFF2A\u0134\u0248' },
|
||||
{ 'base': 'K', 'letters': '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2' },
|
||||
{ 'base': 'L', 'letters': '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780' },
|
||||
{ 'base': 'LJ', 'letters': '\u01C7' },
|
||||
{ 'base': 'Lj', 'letters': '\u01C8' },
|
||||
{ 'base': 'M', 'letters': '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' },
|
||||
{ 'base': 'N', 'letters': '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4' },
|
||||
{ 'base': 'NJ', 'letters': '\u01CA' },
|
||||
{ 'base': 'Nj', 'letters': '\u01CB' },
|
||||
{ 'base': 'O', 'letters': '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C' },
|
||||
{ 'base': 'OI', 'letters': '\u01A2' },
|
||||
{ 'base': 'OO', 'letters': '\uA74E' },
|
||||
{ 'base': 'OU', 'letters': '\u0222' },
|
||||
{ 'base': 'OE', 'letters': '\u008C\u0152' },
|
||||
{ 'base': 'oe', 'letters': '\u009C\u0153' },
|
||||
{ 'base': 'P', 'letters': '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754' },
|
||||
{ 'base': 'Q', 'letters': '\u0051\u24C6\uFF31\uA756\uA758\u024A' },
|
||||
{ 'base': 'R', 'letters': '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782' },
|
||||
{ 'base': 'S', 'letters': '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784' },
|
||||
{ 'base': 'T', 'letters': '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786' },
|
||||
{ 'base': 'TZ', 'letters': '\uA728' },
|
||||
{ 'base': 'U', 'letters': '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244' },
|
||||
{ 'base': 'V', 'letters': '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' },
|
||||
{ 'base': 'VY', 'letters': '\uA760' },
|
||||
{ 'base': 'W', 'letters': '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72' },
|
||||
{ 'base': 'X', 'letters': '\u0058\u24CD\uFF38\u1E8A\u1E8C' },
|
||||
{ 'base': 'Y', 'letters': '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE' },
|
||||
{ 'base': 'Z', 'letters': '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762' },
|
||||
{ 'base': 'a', 'letters': '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250' },
|
||||
{ 'base': 'aa', 'letters': '\uA733' },
|
||||
{ 'base': 'ae', 'letters': '\u00E6\u01FD\u01E3' },
|
||||
{ 'base': 'ao', 'letters': '\uA735' },
|
||||
{ 'base': 'au', 'letters': '\uA737' },
|
||||
{ 'base': 'av', 'letters': '\uA739\uA73B' },
|
||||
{ 'base': 'ay', 'letters': '\uA73D' },
|
||||
{ 'base': 'b', 'letters': '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253' },
|
||||
{ 'base': 'c', 'letters': '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184' },
|
||||
{ 'base': 'd', 'letters': '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A' },
|
||||
{ 'base': 'dz', 'letters': '\u01F3\u01C6' },
|
||||
{ 'base': 'e', 'letters': '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD' },
|
||||
{ 'base': 'f', 'letters': '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' },
|
||||
{ 'base': 'g', 'letters': '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F' },
|
||||
{ 'base': 'h', 'letters': '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265' },
|
||||
{ 'base': 'hv', 'letters': '\u0195' },
|
||||
{ 'base': 'i', 'letters': '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131' },
|
||||
{ 'base': 'j', 'letters': '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' },
|
||||
{ 'base': 'k', 'letters': '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3' },
|
||||
{ 'base': 'l', 'letters': '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747' },
|
||||
{ 'base': 'lj', 'letters': '\u01C9' },
|
||||
{ 'base': 'm', 'letters': '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' },
|
||||
{ 'base': 'n', 'letters': '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5' },
|
||||
{ 'base': 'nj', 'letters': '\u01CC' },
|
||||
{ 'base': 'o', 'letters': '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275' },
|
||||
{ 'base': 'oi', 'letters': '\u01A3' },
|
||||
{ 'base': 'ou', 'letters': '\u0223' },
|
||||
{ 'base': 'oo', 'letters': '\uA74F' },
|
||||
{ 'base': 'p', 'letters': '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755' },
|
||||
{ 'base': 'q', 'letters': '\u0071\u24E0\uFF51\u024B\uA757\uA759' },
|
||||
{ 'base': 'r', 'letters': '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783' },
|
||||
{ 'base': 's', 'letters': '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B' },
|
||||
{ 'base': 't', 'letters': '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787' },
|
||||
{ 'base': 'tz', 'letters': '\uA729' },
|
||||
{ 'base': 'u', 'letters': '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289' },
|
||||
{ 'base': 'v', 'letters': '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' },
|
||||
{ 'base': 'vy', 'letters': '\uA761' },
|
||||
{ 'base': 'w', 'letters': '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73' },
|
||||
{ 'base': 'x', 'letters': '\u0078\u24E7\uFF58\u1E8B\u1E8D' },
|
||||
{ 'base': 'y', 'letters': '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF' },
|
||||
{ 'base': 'z', 'letters': '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763' }
|
||||
];
|
||||
|
||||
var diacriticsMap = {};
|
||||
for (var i = 0; i < defaultDiacriticsRemovalap.length; i++) {
|
||||
var letters = defaultDiacriticsRemovalap[i].letters.split('');
|
||||
for (var j = 0; j < letters.length; j++) {
|
||||
diacriticsMap[letters[j]] = defaultDiacriticsRemovalap[i].base;
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-control-regex
|
||||
return str.replace(/[^\u0000-\u007E]/g, function (a) {
|
||||
return diacriticsMap[a] || a;
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
]);
|
@ -1,3 +0,0 @@
|
||||
Application.Services.service('es', function (esFactory) {
|
||||
return esFactory({ host: window.location.origin });
|
||||
});
|
@ -1,59 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
Application.Services.factory('Help', ['$rootScope', '$uibModal', '$state', 'AuthService',
|
||||
function ($rootScope, $uibModal, $state, AuthService) {
|
||||
const TOURS = {
|
||||
'app.public.home': 'welcome',
|
||||
'app.public.machines_list': 'machines',
|
||||
'app.public.spaces_list': 'spaces',
|
||||
'app.admin.trainings': 'trainings',
|
||||
'app.admin.calendar': 'calendar',
|
||||
'app.admin.members': 'members',
|
||||
'app.admin.invoices': 'invoices',
|
||||
'app.admin.pricing': 'pricing',
|
||||
'app.admin.events': 'events',
|
||||
'app.admin.projects': 'projects',
|
||||
'app.admin.statistics': 'statistics',
|
||||
'app.admin.settings': 'settings',
|
||||
'app.admin.open_api_clients': 'open-api'
|
||||
};
|
||||
|
||||
|
||||
return function (e) {
|
||||
if (!AuthService.isAuthorized(['admin', 'manager'])) return;
|
||||
|
||||
if (e.key === 'F1') {
|
||||
e.preventDefault();
|
||||
// retrieve the tour name, based on the current location
|
||||
const tourName = TOURS[$state.current.name];
|
||||
|
||||
// if no tour, just open the guide
|
||||
if (tourName === undefined) {
|
||||
return window.open('https://github.com/sleede/fab-manager/raw/master/doc/fr/guide_utilisation_fab_manager_v4.5.pdf', '_blank');
|
||||
}
|
||||
|
||||
$uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "shared/help_modal.html" %>',
|
||||
resolve: {
|
||||
tourName: function () { return tourName; }
|
||||
},
|
||||
controller: ['$scope', '$uibModalInstance', 'uiTourService', 'tourName', function ($scope, $uibModalInstance, uiTourService, tourName) {
|
||||
// start the tour and hide the modal
|
||||
$scope.onTour = function () {
|
||||
const tour = uiTourService.getTourByName(tourName);
|
||||
if (tour) { tour.start(); }
|
||||
|
||||
$uibModalInstance.close('tour');
|
||||
};
|
||||
|
||||
// open the user's guide and hide the modal
|
||||
$scope.onGuide = function () {
|
||||
$uibModalInstance.close('guide');
|
||||
};
|
||||
}]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}]);
|
@ -1,6 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
// list the social networks supported in the user's profiles
|
||||
Application.Services.factory('SocialNetworks', [function () {
|
||||
return ['facebook', 'twitter', 'google_plus', 'viadeo', 'linkedin', 'instagram', 'youtube', 'vimeo', 'dailymotion', 'github', 'echosciences', 'website', 'pinterest', 'lastfm', 'flickr'];
|
||||
}]);
|
@ -1,3 +0,0 @@
|
||||
/*
|
||||
*= require fullcalendar/dist/fullcalendar.print
|
||||
*/
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
*= require_self
|
||||
*= require ui-select/dist/select
|
||||
*= require fullcalendar/dist/fullcalendar
|
||||
*= require jasny-bootstrap/dist/css/jasny-bootstrap
|
||||
*= require angular-growl-v2/build/angular-growl
|
||||
*= require angular-xeditable/dist/css/xeditable
|
||||
*= require angular-loading-bar/build/loading-bar
|
||||
*= require nvd3/build/nv.d3
|
||||
*= require font-awesome
|
||||
*= require medium-editor/dist/css/medium-editor
|
||||
*= require medium-editor/dist/css/themes/default
|
||||
*= require bootstrap-switch/dist/css/bootstrap3/bootstrap-switch
|
||||
*= require summernote/dist/summernote
|
||||
*= require jquery-minicolors/jquery.minicolors.css
|
||||
*= require angular-aside/dist/css/angular-aside
|
||||
*= require codemirror/lib/codemirror
|
||||
*/
|
||||
|
||||
@import "app.functions";
|
||||
@import "bootstrap-compass";
|
||||
@import "bootstrap-sprockets";
|
||||
@import "compass";
|
||||
@import "bootstrap_and_overrides";
|
||||
|
||||
@import "app.utilities";
|
||||
@import "app.colors";
|
||||
|
||||
@import "app.base";
|
||||
@import "app.layout";
|
||||
@import "app.nav";
|
||||
|
||||
@import "app.buttons";
|
||||
@import "app.components";
|
||||
@import "app.plugins";
|
||||
@import "modules/*";
|
||||
|
||||
@import "app.responsive";
|
||||
|
||||
<% PluginRegistry.stylesheets.each do |stylesheet| %>
|
||||
<% basename = File.basename(stylesheet,'.scss') %>
|
||||
<%= "@import '#{basename}';" %>
|
||||
<% end %>
|
@ -1,339 +0,0 @@
|
||||
<div class="alert alert-warning p-md m-t" role="alert" ng-hide="modules.invoicing">
|
||||
<i class="fa fa-warning m-r"></i>
|
||||
<span translate>{{ 'app.admin.invoices.warning_invoices_disabled' }}</span>
|
||||
</div>
|
||||
<form class="invoice-placeholder">
|
||||
<div class="invoice-logo">
|
||||
<img src="data:image/png;base64," data-src="holder.js/100%x100%/text:/font:FontAwesome/icon" bs-holder ng-if="!invoice.logo" class="img-responsive">
|
||||
<img base-sixty-four-image="invoice.logo" ng-if="invoice.logo && invoice.logo.base64">
|
||||
<div class="tools-box">
|
||||
<div class="btn-group">
|
||||
<div class="btn btn-default btn-file">
|
||||
<i class="fa fa-edit"></i> {{ 'app.admin.invoices.change_logo' | translate }}
|
||||
<input type="file" accept="image/png,image/jpeg,image/x-png,image/pjpeg" name="invoice[logo][attachment]" ng-model="invoice.logo" base-sixty-four-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="invoice-buyer-infos">
|
||||
<strong translate>{{ 'app.admin.invoices.john_smith' }}</strong>
|
||||
<div translate>{{ 'app.admin.invoices.john_smith_at_example_com' }}</div>
|
||||
</div>
|
||||
<div class="invoice-reference invoice-editable" ng-click="openEditReference()">{{ 'app.admin.invoices.invoice_reference_' | translate }} {{mkReference()}}</div>
|
||||
<div class="invoice-code invoice-editable" ng-show="invoice.code.active" ng-click="openEditCode()">{{ 'app.admin.invoices.code_' | translate }} {{invoice.code.model}}</div>
|
||||
<div class="invoice-code invoice-activable" ng-show="!invoice.code.active" ng-click="openEditCode()" translate>{{ 'app.admin.invoices.code_disabled' }}</div>
|
||||
<div class="invoice-order invoice-editable" ng-click="openEditInvoiceNb()"> {{ 'app.admin.invoices.order_num' | translate }} {{mkNumber()}}</div>
|
||||
<div class="invoice-date">{{ 'app.admin.invoices.invoice_issued_on_DATE_at_TIME' | translate:{DATE:(today | amDateFormat:'L'), TIME:(today | amDateFormat:'LT')} }}</div>
|
||||
<div class="invoice-object">
|
||||
{{ 'app.admin.invoices.object_reservation_of_john_smith_on_DATE_at_TIME' | translate:{DATE:(inOneWeek | amDateFormat:'L'), TIME:(inOneWeek | amDateFormat:'LT')} }}
|
||||
</div>
|
||||
<div class="invoice-data">
|
||||
{{ 'app.admin.invoices.order_summary' | translate }}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th translate>{{ 'app.admin.invoices.details' }}</th>
|
||||
<th class="right" translate>{{ 'app.admin.invoices.amount' }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ 'app.admin.invoices.machine_booking-3D_printer' | translate }} {{inOneWeek | amDateFormat:'LLL'}} - {{inOneWeekAndOneHour | amDateFormat:'LT'}}</td>
|
||||
<td class="right">{{30.0 | currency}}</td>
|
||||
</tr>
|
||||
|
||||
<tr class="invoice-total" ng-class="{'bold vat-line':invoice.VAT.active}">
|
||||
<td ng-show="!invoice.VAT.active" translate>{{ 'app.admin.invoices.total_amount' }}</td>
|
||||
<td ng-show="invoice.VAT.active" translate>{{ 'app.admin.invoices.total_including_all_taxes' }}</td>
|
||||
<td class="right">{{30.0 | currency}}</td>
|
||||
</tr>
|
||||
|
||||
<tr class="invoice-vat invoice-activable" ng-click="openEditVAT()" ng-show="!invoice.VAT.active">
|
||||
<td translate>{{ 'app.admin.invoices.VAT_disabled' }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr class="invoice-vat invoice-editable vat-line italic" ng-click="openEditVAT()" ng-show="invoice.VAT.active">
|
||||
<td>{{ 'app.admin.invoices.including_VAT' | translate }} {{invoice.VAT.rate}} %</td>
|
||||
<td>{{30-(30/(invoice.VAT.rate/100+1)) | currency}}</td>
|
||||
</tr>
|
||||
<tr class="invoice-ht vat-line italic" ng-show="invoice.VAT.active">
|
||||
<td translate>{{ 'app.admin.invoices.including_total_excluding_taxes' }}</td>
|
||||
<td>{{30/(invoice.VAT.rate/100+1) | currency}}</td>
|
||||
</tr>
|
||||
<tr class="invoice-payed vat-line bold" ng-show="invoice.VAT.active">
|
||||
<td translate>{{ 'app.admin.invoices.including_amount_payed_on_ordering' }}</td>
|
||||
<td>{{30.0 | currency}}</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="invoice-payment" translate translate-values="{DATE:(today | amDateFormat:'L'), TIME:(today | amDateFormat:'LT'), AMOUNT:(30.0 | currency)}">
|
||||
{{ 'app.admin.invoices.settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT' }}
|
||||
</p>
|
||||
</div>
|
||||
<div medium-editor class="invoice-text invoice-editable" ng-model="invoice.text.content"
|
||||
options='{
|
||||
"placeholder": "{{ "app.admin.invoices.important_notes" | translate }}",
|
||||
"buttons": ["underline"]
|
||||
}'
|
||||
ng-blur="textEditEnd($event)">
|
||||
</div>
|
||||
<div medium-editor class="invoice-legals invoice-editable" ng-model="invoice.legals.content"
|
||||
options='{
|
||||
"placeholder": "{{ "app.admin.invoices.address_and_legal_information" | translate }}",
|
||||
"buttons": ["bold", "underline"]
|
||||
}'
|
||||
ng-blur="legalsEditEnd($event)">
|
||||
</div>
|
||||
</form>
|
||||
<div class="invoice-file">
|
||||
<h3 class="m-l" translate>{{ 'app.admin.invoices.filename' }}</h3>
|
||||
<i class="fa fa-file-pdf-o" aria-hidden="true"></i>
|
||||
<span class="filename"><span class="prefix" ng-click="openEditPrefix()">{{file.prefix}}</span>-{{file.nextId}}_{{file.date}}.pdf</span>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/ng-template" id="editReference.html">
|
||||
<div class="custom-invoice">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ 'app.admin.invoices.invoice_reference' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body row">
|
||||
<div class="elements col-md-4">
|
||||
<h4>Éléments</h4>
|
||||
<ul>
|
||||
<li ng-click="invoice.reference.help = 'addYear.html'">{{ 'app.admin.invoices.year' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addMonth.html'">{{ 'app.admin.invoices.month' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addDay.html'">{{ 'app.admin.invoices.day' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addInvoiceNumber.html'">{{ 'app.admin.invoices.num_of_invoice' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addOnlineInfo.html'">{{ 'app.admin.invoices.online_sales' | translate }}</li>
|
||||
<%# <li ng-click="invoice.reference.help = 'addWalletInfo.html'">{{ 'app.admin.invoices.wallet' | translate }}</li> %>
|
||||
<li ng-click="invoice.reference.help = 'addRefundInfo.html'">{{ 'app.admin.invoices.refund' | translate }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="model">
|
||||
<h4 translate>{{ 'app.admin.invoices.model' }}</h4>
|
||||
<input type="text" class="form-control" ng-model="model">
|
||||
</div>
|
||||
<div class="help">
|
||||
<h4 translate>{{ 'app.admin.invoices.documentation' }}</h4>
|
||||
<ng-include src="invoice.reference.help" autoscroll="true">
|
||||
</ng-include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" ng-click="ok()" translate>{{ 'app.shared.buttons.confirm' }}</button>
|
||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addYear.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>YY</strong></td><td translate>{{ 'app.admin.invoices.2_digits_year' }}</td></tr>
|
||||
<tr><td><strong>YYYY</strong></td><td translate>{{ 'app.admin.invoices.4_digits_year' }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addMonth.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>M</strong></td><td translate>{{ 'app.admin.invoices.month_number' }}</td></tr>
|
||||
<tr><td><strong>MM</strong></td><td translate>{{ 'app.admin.invoices.2_digits_month_number' }}</td></tr>
|
||||
<tr><td><strong>MMM</strong></td><td translate>{{ 'app.admin.invoices.3_characters_month_name' }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addDay.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>D</strong></td><td translate>{{ 'app.admin.invoices.day_in_the_month' }}</td></tr>
|
||||
<tr><td><strong>DD</strong></td><td translate>{{ 'app.admin.invoices.2_digits_day_in_the_month' }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addInvoiceNumber.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>dd...dd</strong></td><td translate>{{ 'app.admin.invoices.n_digits_daily_count_of_invoices' }}</td></tr>
|
||||
<tr><td><strong>mm...mm</strong></td><td translate>{{ 'app.admin.invoices.n_digits_monthly_count_of_invoices' }}</td></tr>
|
||||
<tr><td><strong>yy...yy</strong></td><td translate>{{ 'app.admin.invoices.n_digits_annual_amount_of_invoices' }}</td></tr>
|
||||
</table>
|
||||
<span class="bottom-notes" translate>{{ 'app.admin.invoices.beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left' }}</span>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addOrderNumber.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>nn...nn</strong></td><td translate>{{ 'app.admin.invoices.n_digits_count_of_orders' }}</td></tr>
|
||||
<tr><td><strong>dd...dd</strong></td><td translate>{{ 'app.admin.invoices.n_digits_daily_count_of_orders' }}</td></tr>
|
||||
<tr><td><strong>mm...mm</strong></td><td translate>{{ 'app.admin.invoices.n_digits_monthly_count_of_orders' }}</td></tr>
|
||||
<tr><td><strong>yy...yy</strong></td><td translate>{{ 'app.admin.invoices.n_digits_annual_amount_of_orders' }}</td></tr>
|
||||
</table>
|
||||
<span class="bottom-notes" translate>{{ 'app.admin.invoices.beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left' }}</span>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addOnlineInfo.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>X[texte]</strong></td><td>{{ 'app.admin.invoices.add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned' | translate }} <mark translate>{{ 'app.admin.invoices.this_will_never_be_added_when_a_refund_notice_is_present' }}</mark> {{ 'app.admin.invoices.eg_XVL_will_add_VL_to_the_invoices_settled_with_stripe' | translate }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addWalletInfo.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>W[texte]</strong></td><td>{{ 'app.admin.invoices.add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned' | translate }} <mark translate>{{ 'app.admin.invoices.this_will_never_be_added_when_a_refund_notice_is_present' }}</mark> {{ 'app.admin.invoices.eg_WPM_will_add_PM_to_the_invoices_settled_with_wallet' | translate }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addRefundInfo.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>R[texte]</strong></td><td>{{ 'app.admin.invoices.add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned' | translate }}<mark translate>{{ 'app.admin.invoices.this_will_never_be_added_when_an_online_sales_notice_is_present' }}</mark> {{ 'app.admin.invoices.eg_RA_will_add_A_to_the_refund_invoices' | translate }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="editCode.html">
|
||||
<div class="custom-invoice">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ 'app.admin.invoices.code' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="enableCode" class="control-label" translate>{{ 'app.admin.invoices.enable_the_code' }}</label>
|
||||
<input bs-switch
|
||||
ng-model="isSelected"
|
||||
id="enableCode"
|
||||
type="checkbox"
|
||||
class="form-control m-l-sm"
|
||||
switch-on-text="{{ 'app.admin.invoices.enabled' | translate }}"
|
||||
switch-off-text="{{ 'app.admin.invoices.disabled' | translate }}"
|
||||
switch-animate="true"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-show="isSelected">
|
||||
<label for="codeModel" class="control-label" translate>{{ 'app.admin.invoices.code' }}</label>
|
||||
<input id="codeModel" type="text" ng-model="codeModel" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" ng-click="ok()" translate>{{ 'app.shared.buttons.confirm' }}</button>
|
||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<script type="text/ng-template" id="editNumber.html">
|
||||
<div class="custom-invoice">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ 'app.admin.invoices.order_number' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body row">
|
||||
<div class="elements col-md-4">
|
||||
<h4 translate>{{ 'app.admin.invoices.elements' }}</h4>
|
||||
<ul>
|
||||
<li ng-click="invoice.number.help = 'addYear.html'">{{ 'app.admin.invoices.year' | translate }}</li>
|
||||
<li ng-click="invoice.number.help = 'addMonth.html'">{{ 'app.admin.invoices.month' | translate }}</li>
|
||||
<li ng-click="invoice.number.help = 'addDay.html'">{{ 'app.admin.invoices.day' | translate }}</li>
|
||||
<li ng-click="invoice.number.help = 'addOrderNumber.html'">{{ 'app.admin.invoices.order_num' | translate }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="model">
|
||||
<h4 translate>{{ 'app.admin.invoices.model' }}</h4>
|
||||
<input type="text" class="form-control" ng-model="model">
|
||||
</div>
|
||||
<div class="help">
|
||||
<h4 translate>{{ 'app.admin.invoices.documentation' }}</h4>
|
||||
<ng-include src="invoice.number.help" autoscroll="true">
|
||||
</ng-include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" ng-click="ok()" translate>{{ 'app.shared.buttons.confirm' }}</button>
|
||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/ng-template" id="editVAT.html">
|
||||
<div class="custom-invoice">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ 'app.admin.invoices.VAT' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="enableVAT" class="control-label" translate>{{ 'app.admin.invoices.enable_VAT' }}</label>
|
||||
<input bs-switch
|
||||
ng-model="isSelected"
|
||||
id="enableVAT"
|
||||
type="checkbox"
|
||||
class="form-control m-l-sm"
|
||||
switch-on-text="{{ 'app.admin.invoices.enabled' | translate }}"
|
||||
switch-off-text="{{ 'app.admin.invoices.disabled' | translate }}"
|
||||
switch-animate="true"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-show="isSelected">
|
||||
<label for="vatRate" class="control-label" translate>{{ 'app.admin.invoices.VAT_rate' }}</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">% </span>
|
||||
<input id="vatRate" type="number" ng-model="rate" class="form-control" min="0" max="100"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m-t-lg">
|
||||
<h4 translate>{{ 'app.admin.invoices.VAT_history' }}</h4>
|
||||
<table class="table scrollable-3-cols">
|
||||
<thead>
|
||||
<tr>
|
||||
<th translate>{{ 'app.admin.invoices.VAT_rate' }}</th>
|
||||
<th translate>{{ 'app.admin.invoices.changed_at' }}</th>
|
||||
<th translate>{{ 'app.admin.invoices.changed_by' }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="value in history | orderBy:'-date'">
|
||||
<td>
|
||||
<span class="no-user-label" ng-show="value.enabled === false" translate>{{'app.admin.invoices.VAT_disabled'}}</span>
|
||||
<span class="no-user-label" ng-show="value.enabled === true" translate>{{'app.admin.invoices.VAT_enabled'}}</span>
|
||||
<span ng-show="value.rate">{{value.rate}}</span>
|
||||
</td>
|
||||
<td>{{value.date | amDateFormat:'L LT'}}</td>
|
||||
<td>{{value.user.name}}<span class="no-user-label" ng-hide="value.user" translate>{{ 'app.admin.invoices.deleted_user' }}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" ng-click="ok()" translate>{{ 'app.shared.buttons.confirm' }}</button>
|
||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/ng-template" id="editPrefix.html">
|
||||
<div class="custom-invoice">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ 'app.admin.invoices.filename' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="alert alert-info m-h-md" translate>
|
||||
{{ 'app.admin.invoices.prefix_info' }}
|
||||
</p>
|
||||
<div>
|
||||
<div class="model">
|
||||
<label for="prefix" translate>{{ 'app.admin.invoices.prefix' }}</label>
|
||||
<input type="text" id="prefix" class="form-control" ng-model="model">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" ng-click="ok()" translate>{{ 'app.shared.buttons.confirm' }}</button>
|
||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
@ -1,35 +0,0 @@
|
||||
<form class="{{classes}}" name="settingSelectMultipleForm">
|
||||
<div class="form-group">
|
||||
<label for="setting-{{setting.name}}" class="control-label m-r" translate>{{ label }}</label>
|
||||
<select class="form-control"
|
||||
id="setting-{{setting.name}}"
|
||||
ng-model="selection"
|
||||
ng-required="required"
|
||||
ng-options="opt for opt in options"
|
||||
multiple>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<button ng-click="removeItem()" class="btn btn-default"><i class="fa fa-trash"></i></button>
|
||||
<button ng-click="addItem()" class="btn btn-default"><i class="fa fa-plus"></i></button>
|
||||
</div>
|
||||
<button name="button" class="btn btn-warning m-t" ng-click="save(setting)" ng-disabled="settingSelectMultipleForm.$invalid" translate>{{ 'app.shared.buttons.save' }}</button>
|
||||
</form>
|
||||
|
||||
<script type="text/ng-template" id="newSelectOption.html">
|
||||
<div>
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ titleNew }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="alert alert-info" ng-show="descriptionNew" ng-bind-html="descriptionNew | translate"></p>
|
||||
<form class="row m-md" name="newSelectOptionForm">
|
||||
<input type="text" class="form-control" ng-model="value" required>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" ng-disabled="newSelectOptionForm.$invalid" ng-click="ok()" translate>{{ 'app.shared.buttons.confirm' }}</button>
|
||||
<button class="btn btn-default" ng-click="dismiss()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
@ -1,18 +0,0 @@
|
||||
<div>
|
||||
<section class="heading">
|
||||
<div class="row no-gutter">
|
||||
<ng-include src="'<%= asset_path "dashboard/nav.html" %>'"></ng-include>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<div class="row no-gutter">
|
||||
<div class="col-md-12 m m-t-lg">
|
||||
<ng-include src="'<%= asset_path "wallet/show.html" %>'"></ng-include>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 m m-t-lg">
|
||||
<ng-include src="'<%= asset_path "wallet/transactions.html" %>'"></ng-include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
app/frontend/images/fabmanager-logo.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 619 B After Width: | Height: | Size: 619 B |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 1015 B After Width: | Height: | Size: 1015 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
87
app/frontend/packs/application.js.erb
Normal file
@ -0,0 +1,87 @@
|
||||
import 'core-js/stable';
|
||||
import 'regenerator-runtime/runtime';
|
||||
|
||||
import 'jquery';
|
||||
import {} from 'jquery-ujs';
|
||||
import 'bootstrap-sass';
|
||||
import '../src/javascript/lib/polyfill';
|
||||
import 'angular';
|
||||
import 'angular-i18n/angular-locale_<%= Rails.application.secrets.angular_locale %>.js';
|
||||
import 'angular-cookies';
|
||||
import 'angular-resource';
|
||||
import 'angular-sanitize';
|
||||
import 'angular-touch';
|
||||
import '@uirouter/angularjs';
|
||||
import 'angular-ui-bootstrap';
|
||||
import 'ui-select';
|
||||
import 'moment';
|
||||
import 'moment/locale/<%= Rails.application.secrets.moment_locale %>.js';
|
||||
import 'moment-timezone';
|
||||
import 'angular-ui-calendar';
|
||||
import 'fullcalendar';
|
||||
import 'fullcalendar/dist/locale/<%= Rails.application.secrets.fullcalendar_locale %>.js';
|
||||
import 'angular-moment';
|
||||
import 'ngUpload';
|
||||
import 'jasny-bootstrap/js/fileinput';
|
||||
import 'holderjs';
|
||||
import 'AngularDevise';
|
||||
import '../src/javascript/lib/devise-modal';
|
||||
import 'angular-growl-v2';
|
||||
import 'angular-xeditable';
|
||||
import 'checklist-model/checklist-model';
|
||||
import 'angular-unsavedchanges/lib/unsavedChanges';
|
||||
import 'angular-loading-bar/src/loading-bar';
|
||||
import 'angular-scroll/angular-scroll';
|
||||
import 'angular-google-analytics/dist/angular-google-analytics';
|
||||
import '../src/javascript/lib/dirDisqus';
|
||||
import '../src/javascript/lib/humanize';
|
||||
import 'underscore/underscore';
|
||||
import 'elasticsearch-browser/elasticsearch.angular';
|
||||
import 'd3/d3';
|
||||
import 'nvd3/build/nv.d3.js';
|
||||
import 'twitter-fetcher';
|
||||
import 'medium-editor/dist/js/medium-editor';
|
||||
import 'angular-medium-editor/dist/angular-medium-editor';
|
||||
import 'bootstrap-switch/dist/js/bootstrap-switch';
|
||||
import 'angular-bootstrap-switch/dist/angular-bootstrap-switch';
|
||||
import 'angular-base64-upload/dist/angular-base64-upload.min';
|
||||
import 'summernote';
|
||||
import 'summernote/lang/summernote-<%= Rails.application.secrets.summernote_locale %>.js';
|
||||
import 'angular-summernote/dist/angular-summernote';
|
||||
import '../src/javascript/lib/summernote-ext-nugget';
|
||||
import '@claviska/jquery-minicolors/jquery.minicolors.js';
|
||||
import 'angular-minicolors/angular-minicolors.js';
|
||||
import 'angular-translate/dist/angular-translate';
|
||||
import 'angular-translate-loader-partial/angular-translate-loader-partial';
|
||||
import 'messageformat/messageformat';
|
||||
import 'angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat';
|
||||
import 'ng-fittext/dist/ng-FitText.min';
|
||||
import 'angular-aside/dist/js/angular-aside';
|
||||
import 'ng-caps-lock/ng-caps-lock';
|
||||
import 'angular-recaptcha';
|
||||
import 'codemirror/lib/codemirror';
|
||||
import 'codemirror/addon/edit/matchbrackets';
|
||||
import 'codemirror/mode/css/css';
|
||||
import 'codemirror/mode/sass/sass';
|
||||
import 'angular-ui-codemirror/src/ui-codemirror';
|
||||
import 'angular-hotkeys/build/hotkeys';
|
||||
import 'hone/dist/hone';
|
||||
import 'tether/dist/js/tether';
|
||||
import 'angular-bind-html-compile/angular-bind-html-compile';
|
||||
import 'angular-ui-tour/app/angular-ui-tour';
|
||||
import '@fortawesome/fontawesome-free';
|
||||
import '@fortawesome/fontawesome-free/js/v4-shims';
|
||||
|
||||
require('../src/javascript/app.js');
|
||||
require('../src/javascript/router.js');
|
||||
require('../src/javascript/plugins.js.erb');
|
||||
|
||||
function importAll (r) { r.keys().forEach(r); }
|
||||
|
||||
importAll(require.context('../src/javascript/controllers/', true, /.*/));
|
||||
importAll(require.context('../src/javascript/services/', true, /.*/));
|
||||
importAll(require.context('../src/javascript/directives/', true, /.*/));
|
||||
importAll(require.context('../src/javascript/filters/', true, /.*/));
|
||||
|
||||
importAll(require.context('../images', true));
|
||||
importAll(require.context('../templates', true));
|
18
app/frontend/packs/application.scss
Normal file
@ -0,0 +1,18 @@
|
||||
@import '~ui-select/dist/select';
|
||||
@import '~fullcalendar/dist/fullcalendar';
|
||||
@import '~jasny-bootstrap/dist/css/jasny-bootstrap';
|
||||
@import '~angular-growl-v2/build/angular-growl';
|
||||
@import '~angular-xeditable/dist/css/xeditable';
|
||||
@import '~angular-loading-bar/build/loading-bar';
|
||||
@import '~nvd3/build/nv.d3';
|
||||
@import '~@fortawesome/fontawesome-free/css/all';
|
||||
@import '~@fortawesome/fontawesome-free/css/v4-shims';
|
||||
@import '~medium-editor/dist/css/medium-editor';
|
||||
@import '~medium-editor/dist/css/themes/default';
|
||||
@import '~bootstrap-switch/dist/css/bootstrap3/bootstrap-switch';
|
||||
@import '~summernote/src/styles/summernote-bs3';
|
||||
@import '~@claviska/jquery-minicolors/jquery.minicolors';
|
||||
@import '~angular-aside/dist/css/angular-aside';
|
||||
@import '~codemirror/lib/codemirror';
|
||||
|
||||
@import '../src/stylesheets/application.scss';
|
4
app/frontend/packs/plugins.scss.erb
Normal file
@ -0,0 +1,4 @@
|
||||
<% PluginRegistry.stylesheets.each do |stylesheet| %>
|
||||
<% basename = File.basename(stylesheet,'.scss') %>
|
||||
<%= "@import '#{basename}';" %>
|
||||
<% end %>
|
2
app/frontend/packs/printer.scss
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
@import '../src/stylesheets/app.printer';
|
@ -8,7 +8,6 @@
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
var Application = Application || {};
|
||||
|
||||
Application.Constants = angular.module('application.constants', []);
|
||||
Application.Services = angular.module('application.services', []);
|
||||
Application.Controllers = angular.module('application.controllers', []);
|
||||
Application.Filters = angular.module('application.filters', []);
|
||||
@ -16,7 +15,7 @@ Application.Directives = angular.module('application.directives', []);
|
||||
|
||||
angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.router', 'ui.bootstrap',
|
||||
'ngUpload', 'duScroll', 'application.filters', 'application.services', 'application.directives',
|
||||
'frapontillo.bootstrap-switch', 'application.constants', 'application.controllers', 'application.router',
|
||||
'frapontillo.bootstrap-switch', 'application.controllers', 'application.router',
|
||||
'ui.select', 'ui.calendar', 'angularMoment', 'Devise', 'angular-growl', 'xeditable',
|
||||
'checklist-model', 'unsavedChanges', 'angular-loading-bar', 'ngTouch', 'angular-google-analytics',
|
||||
'angularUtils.directives.dirDisqus', 'summernote', 'elasticsearch', 'angular-medium-editor', 'naif.base64',
|
||||
@ -66,8 +65,8 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
|
||||
$translateProvider.preferredLanguage(Fablab.locale);
|
||||
// End the tour when the user clicks the forward or back buttons of the browser
|
||||
TourConfigProvider.enableNavigationInterceptors();
|
||||
}]).run(['$rootScope', '$log', 'AuthService', 'Auth', 'amMoment', '$state', 'editableOptions', 'Analytics',
|
||||
function ($rootScope, $log, AuthService, Auth, amMoment, $state, editableOptions, Analytics) {
|
||||
}]).run(['$rootScope', '$log', 'Auth', 'amMoment', '$state', 'editableOptions', 'Analytics',
|
||||
function ($rootScope, $log, Auth, amMoment, $state, editableOptions, Analytics) {
|
||||
// Angular-moment (date-time manipulations library)
|
||||
amMoment.changeLocale(Fablab.moment_locale);
|
||||
|
||||
@ -141,8 +140,10 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
|
||||
};
|
||||
}]).constant('angularMomentConfig', {
|
||||
timezone: Fablab.timezone
|
||||
});
|
||||
}).constant('moment', require('moment-timezone'));
|
||||
|
||||
angular.isUndefinedOrNull = function (val) {
|
||||
return angular.isUndefined(val) || val === null;
|
||||
};
|
||||
|
||||
module.exports = { Application };
|
@ -87,7 +87,7 @@ class AuthenticationController {
|
||||
*/
|
||||
$scope.defineDataMapping = function (mapping) {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/authentications/_data_mapping.html" %>',
|
||||
templateUrl: '/admin/authentications/_data_mapping.html',
|
||||
size: 'md',
|
||||
resolve: {
|
||||
field () { return mapping; },
|
@ -46,18 +46,17 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
$scope.eventsInCalendar = (settingsPromise.events_in_calendar === 'true');
|
||||
|
||||
// bind the availabilities slots with full-Calendar events
|
||||
$scope.eventSources = [];
|
||||
$scope.eventSources.push({
|
||||
$scope.eventSources = [{
|
||||
url: '/api/availabilities',
|
||||
textColor: 'black'
|
||||
});
|
||||
}];
|
||||
|
||||
// fullCalendar (v2) configuration
|
||||
$scope.calendarConfig = CalendarConfig({
|
||||
slotDuration: BASE_SLOT,
|
||||
snapDuration: BOOKING_SNAP,
|
||||
selectable: true,
|
||||
selecHelper: true,
|
||||
selectHelper: true,
|
||||
minTime: moment.duration(moment(bookingWindowStart.setting.value).format('HH:mm:ss')),
|
||||
maxTime: moment.duration(moment(bookingWindowEnd.setting.value).format('HH:mm:ss')),
|
||||
select (start, end, jsEvent, view) {
|
||||
@ -69,7 +68,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
eventRender (event, element, view) {
|
||||
return eventRenderCb(event, element, view);
|
||||
},
|
||||
viewRender(view, element) {
|
||||
viewRender (view, element) {
|
||||
return viewRenderCb(view, element);
|
||||
},
|
||||
loading (isLoading, view) {
|
||||
@ -101,7 +100,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
{ id: slot.slot_id },
|
||||
function (data, status) { // success
|
||||
// update the canceled_at attribute
|
||||
for (let resa of Array.from($scope.reservations)) {
|
||||
for (const resa of Array.from($scope.reservations)) {
|
||||
if (resa.slot_id === data.id) {
|
||||
resa.canceled_at = data.canceled_at;
|
||||
break;
|
||||
@ -185,9 +184,9 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
},
|
||||
function () {
|
||||
// the admin has confirmed, remove the plan
|
||||
const plans = _.drop($scope.availability.plan_ids, plan.id);
|
||||
_.drop($scope.availability.plan_ids, plan.id);
|
||||
|
||||
return Availability.update({ id: $scope.availability.id }, { availability: { plans_attributes: [{ id: plan.id, _destroy: true }] } }
|
||||
Availability.update({ id: $scope.availability.id }, { availability: { plans_attributes: [{ id: plan.id, _destroy: true }] } }
|
||||
, function (data, status) { // success
|
||||
// update the plan_ids attribute
|
||||
$scope.availability.plan_ids = data.plan_ids;
|
||||
@ -273,7 +272,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
// open a confirmation dialog
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "admin/calendar/deleteRecurrent.html" %>',
|
||||
templateUrl: '/admin/calendar/deleteRecurrent.html',
|
||||
size: 'md',
|
||||
controller: 'DeleteRecurrentAvailabilityController',
|
||||
resolve: {
|
||||
@ -282,7 +281,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
});
|
||||
// once the dialog was closed, do things depending on the result
|
||||
modalInstance.result.then(function (res) {
|
||||
if (res.status == 'success') {
|
||||
if (res.status === 'success') {
|
||||
$scope.availability = null;
|
||||
}
|
||||
for (const availability of res.availabilities) {
|
||||
@ -355,7 +354,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile.tours.indexOf('calendar') < 0) {
|
||||
uitour.start();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
@ -380,12 +379,12 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
*
|
||||
* @returns {array}
|
||||
*/
|
||||
var availabilityPlans = function() {
|
||||
const availabilityPlans = function () {
|
||||
const plansClassifiedByGroup = [];
|
||||
const _plans = _.filter(plansPromise, function (p) { return _.include($scope.availability.plan_ids, p.id) });
|
||||
for (let group of Array.from(groupsPromise)) {
|
||||
const _plans = _.filter(plansPromise, function (p) { return _.includes($scope.availability.plan_ids, p.id); });
|
||||
for (const group of Array.from(groupsPromise)) {
|
||||
const groupObj = { id: group.id, name: group.name, plans: [] };
|
||||
for (let plan of Array.from(_plans)) {
|
||||
for (const plan of Array.from(_plans)) {
|
||||
if (plan.group_id === group.id) { groupObj.plans.push(plan); }
|
||||
}
|
||||
if (groupObj.plans.length > 0) {
|
||||
@ -419,14 +418,14 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
|
||||
// then we open a modal window to let the admin specify the slot type
|
||||
const modalInstance = $uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/calendar/eventModal.html" %>',
|
||||
templateUrl: '/admin/calendar/eventModal.html',
|
||||
controller: 'CreateEventModalController',
|
||||
backdrop: 'static',
|
||||
keyboard: false,
|
||||
resolve: {
|
||||
start() { return start; },
|
||||
end() { return end; },
|
||||
slots() { return Math.ceil(slots); },
|
||||
start () { return start; },
|
||||
end () { return end; },
|
||||
slots () { return Math.ceil(slots); },
|
||||
machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],
|
||||
trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }],
|
||||
spacesPromise: ['Space', function (Space) { return Space.query().$promise; }],
|
||||
@ -434,7 +433,8 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],
|
||||
groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],
|
||||
slotDurationPromise: ['Setting', function (Setting) { return Setting.get({ name: 'slot_duration' }).$promise; }]
|
||||
} });
|
||||
}
|
||||
});
|
||||
// when the modal is closed, we send the slot to the server for saving
|
||||
modalInstance.result.then(
|
||||
function (availability) {
|
||||
@ -472,10 +472,10 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
$scope.availability.plans = availabilityPlans();
|
||||
|
||||
if ($scope.availabilityDom) {
|
||||
$scope.availabilityDom.classList.remove("fc-selected")
|
||||
$scope.availabilityDom.classList.remove('fc-selected');
|
||||
}
|
||||
$scope.availabilityDom = jsEvent.target.closest('.fc-event');
|
||||
$scope.availabilityDom.classList.add("fc-selected")
|
||||
$scope.availabilityDom.classList.add('fc-selected');
|
||||
|
||||
// if the user has clicked on the delete event button, delete the event
|
||||
if ($(jsEvent.target).hasClass('remove-event')) {
|
||||
@ -495,14 +495,13 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
if (event.available_type !== 'event') {
|
||||
element.find('.fc-content').prepend('<span class="remove-event">x </span>');
|
||||
}
|
||||
if (event.tags.length > 0) {
|
||||
if (event.tags && event.tags.length > 0) {
|
||||
let html = '';
|
||||
for (let tag of Array.from(event.tags)) {
|
||||
for (const tag of Array.from(event.tags)) {
|
||||
html += `<span class='label label-success text-white'>${tag.name}</span> `;
|
||||
}
|
||||
element.find('.fc-title').append(`<br/>${html}`);
|
||||
}
|
||||
// force return to prevent coffee-script auto-return to return random value (possiblity falsy)
|
||||
};
|
||||
|
||||
/**
|
||||
@ -510,10 +509,9 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
* @see https://fullcalendar.io/docs/resource_data/loading/
|
||||
*/
|
||||
const loadingCb = function (isLoading, view) {
|
||||
if (isLoading) {
|
||||
if (isLoading && uiCalendarConfig.calendars.calendar) {
|
||||
// we remove existing events when fetching starts to prevent duplicates
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@ -521,7 +519,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
* Triggered when the view is changed
|
||||
* @see https://fullcalendar.io/docs/v3/viewRender#v2
|
||||
*/
|
||||
const viewRenderCb = function(view, element) {
|
||||
const viewRenderCb = function (view, element) {
|
||||
// we unselect the current event to keep consistency
|
||||
$scope.availability = null;
|
||||
$scope.availabilityDom = null;
|
||||
@ -634,7 +632,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
/**
|
||||
* Select/unselect all the machines
|
||||
*/
|
||||
$scope.toggleAll = function() {
|
||||
$scope.toggleAll = function () {
|
||||
const count = $scope.selectedMachines.length;
|
||||
$scope.selectedMachines = [];
|
||||
$scope.selectedMachinesBinding = {};
|
||||
@ -642,9 +640,9 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
$scope.machines.forEach(function (machine) {
|
||||
$scope.selectedMachines.push(machine);
|
||||
$scope.selectedMachinesBinding[machine.id] = true;
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds or removes the provided plan from the current slot
|
||||
@ -662,7 +660,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
/**
|
||||
* Select/unselect all the plans
|
||||
*/
|
||||
$scope.toggleAllPlans = function() {
|
||||
$scope.toggleAllPlans = function () {
|
||||
const count = $scope.selectedPlans.length;
|
||||
$scope.selectedPlans = [];
|
||||
$scope.selectedPlansBinding = {};
|
||||
@ -670,7 +668,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
plansPromise.forEach(function (plan) {
|
||||
$scope.selectedPlans.push(plan);
|
||||
$scope.selectedPlansBinding[plan.id] = true;
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -739,7 +737,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
*/
|
||||
$scope.isTypeDivided = function () {
|
||||
return isTypeDivided($scope.availability.available_type);
|
||||
}
|
||||
};
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
@ -755,7 +753,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
}
|
||||
|
||||
// when disable is only subscriptions option, reset all selected plans
|
||||
$scope.$watch('isOnlySubscriptions', function(value) {
|
||||
$scope.$watch('isOnlySubscriptions', function (value) {
|
||||
if (!value) {
|
||||
$scope.selectedPlans = [];
|
||||
$scope.selectedPlansBinding = {};
|
||||
@ -763,14 +761,14 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
});
|
||||
|
||||
// group plans by Group
|
||||
for (let group of groupsPromise.filter(g => !g.disabled)) {
|
||||
const groupObj = { id: group.id, name: group.name, plans: [] };
|
||||
for (let plan of plansPromise.filter(g => !g.disabled)) {
|
||||
if (plan.group_id === group.id) { groupObj.plans.push(plan); }
|
||||
}
|
||||
if (groupObj.plans.length > 0) {
|
||||
$scope.plansClassifiedByGroup.push(groupObj);
|
||||
}
|
||||
for (const group of groupsPromise.filter(g => !g.disabled)) {
|
||||
const groupObj = { id: group.id, name: group.name, plans: [] };
|
||||
for (const plan of plansPromise.filter(g => !g.disabled)) {
|
||||
if (plan.group_id === group.id) { groupObj.plans.push(plan); }
|
||||
}
|
||||
if (groupObj.plans.length > 0) {
|
||||
$scope.plansClassifiedByGroup.push(groupObj);
|
||||
}
|
||||
}
|
||||
|
||||
// When the slot duration changes, we increment the availability to match the value
|
||||
@ -784,9 +782,9 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
|
||||
// When the number of slot changes, we increment the availability to match the value
|
||||
$scope.$watch('slots_nb', function (newValue, oldValue, scope) {
|
||||
start = moment($scope.start);
|
||||
start.add($scope.availability.slot_duration * newValue, 'minutes');
|
||||
$scope.end = start.toDate();
|
||||
start = moment($scope.start);
|
||||
start.add($scope.availability.slot_duration * newValue, 'minutes');
|
||||
$scope.end = start.toDate();
|
||||
});
|
||||
|
||||
// When we configure a machine/space availability, do not let the user change the end time, as the total
|
||||
@ -803,7 +801,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
$scope.end = moment($scope.start).add(upper, 'minutes').toDate();
|
||||
$scope.slots_nb = upperSlots;
|
||||
} else {
|
||||
$scope.slots_nb = slotsCurrentRange;
|
||||
$scope.slots_nb = slotsCurrentRange;
|
||||
}
|
||||
$scope.availability.end_at = $scope.end;
|
||||
} else {
|
||||
@ -844,8 +842,8 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
* Test if the provided availability type is divided in slots
|
||||
*/
|
||||
const isTypeDivided = function (type) {
|
||||
return ((type === 'machines') || (type === 'space'));
|
||||
}
|
||||
return ((type === 'machines') || (type === 'space'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates that a machine or more was/were selected before continuing to step 3 (adjust time + tags)
|
||||
@ -891,7 +889,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
$scope.availability.slot_duration = parseInt(slotDurationPromise.setting.value, 10);
|
||||
}
|
||||
$scope.step++;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute the various occurrences of the availability, according to the recurrence settings
|
||||
@ -923,7 +921,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
$scope.reservableName = '';
|
||||
switch ($scope.availability.available_type) {
|
||||
case 'machines':
|
||||
$scope.reservableName = localizedList($scope.selectedMachines)
|
||||
$scope.reservableName = localizedList($scope.selectedMachines);
|
||||
break;
|
||||
case 'training':
|
||||
$scope.reservableName = `<strong>${$scope.selectedTraining.name}</strong>`;
|
||||
@ -932,25 +930,25 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
$scope.reservableName = `<strong>${$scope.selectedSpace.name}</strong>`;
|
||||
break;
|
||||
default:
|
||||
$scope.reservableName = `<span class="warning">${_t("app.admin.calendar.none")}</span>`;
|
||||
$scope.reservableName = `<span class="warning">${_t('app.admin.calendar.none')}</span>`;
|
||||
}
|
||||
const tags = $scope.tags.filter(function (t) {
|
||||
return $scope.availability.tag_ids.indexOf(t.id) > -1;
|
||||
})
|
||||
});
|
||||
$scope.tagsName = localizedList(tags);
|
||||
if ($scope.isOnlySubscriptions && $scope.selectedPlans.length > 0) {
|
||||
$scope.plansName = localizedList($scope.selectedPlans);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const localizedList = function (items) {
|
||||
if (items.length === 0) return `<span class="text-gray text-italic">${_t("app.admin.calendar.none")}</span>`;
|
||||
if (items.length === 0) return `<span class="text-gray text-italic">${_t('app.admin.calendar.none')}</span>`;
|
||||
|
||||
const names = items.map(function (i) { return $sce.trustAsHtml(`<strong>${i.name}</strong>`); });
|
||||
if (items.length > 1) return names.slice(0, -1).join(', ') + ` ${_t('app.admin.calendar.and')} ` + names[names.length - 1];
|
||||
|
||||
return names[0];
|
||||
}
|
||||
};
|
||||
|
||||
// !!! MUST BE CALLED AT THE END of the controller
|
||||
return initialize();
|
||||
@ -962,7 +960,6 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
||||
*/
|
||||
Application.Controllers.controller('DeleteRecurrentAvailabilityController', ['$scope', '$uibModalInstance', 'Availability', 'availabilityPromise', 'growl', '_t',
|
||||
function ($scope, $uibModalInstance, Availability, availabilityPromise, growl, _t) {
|
||||
|
||||
// is the current slot (to be deleted) recurrent?
|
||||
$scope.isRecurrent = availabilityPromise.is_recurrent;
|
||||
|
||||
@ -982,17 +979,17 @@ Application.Controllers.controller('DeleteRecurrentAvailabilityController', ['$s
|
||||
if (res.deleted > 1) {
|
||||
growl.success(_t(
|
||||
'app.admin.calendar.slots_deleted',
|
||||
{START: moment(start_at).format('LL LT'), COUNT: res.deleted - 1}
|
||||
{ START: moment(start_at).format('LL LT'), COUNT: res.deleted - 1 }
|
||||
));
|
||||
} else {
|
||||
growl.success(_t(
|
||||
'app.admin.calendar.slot_successfully_deleted',
|
||||
{START: moment(start_at).format('LL LT'), END: moment(end_at).format('LT')}
|
||||
{ START: moment(start_at).format('LL LT'), END: moment(end_at).format('LT') }
|
||||
));
|
||||
}
|
||||
$uibModalInstance.close({
|
||||
status: 'success',
|
||||
availabilities: res.details.map(function (d) { return d.availability.id })
|
||||
availabilities: res.details.map(function (d) { return d.availability.id; })
|
||||
});
|
||||
},
|
||||
function (res) {
|
||||
@ -1001,32 +998,30 @@ Application.Controllers.controller('DeleteRecurrentAvailabilityController', ['$s
|
||||
if (data.total > 1) {
|
||||
growl.warning(_t(
|
||||
'app.admin.calendar.slots_not_deleted',
|
||||
{TOTAL: data.total, COUNT: data.total - data.deleted}
|
||||
{ TOTAL: data.total, COUNT: data.total - data.deleted }
|
||||
));
|
||||
} else {
|
||||
growl.error(_t(
|
||||
'app.admin.calendar.unable_to_delete_the_slot',
|
||||
{START: moment(start_at).format('LL LT'), END: moment(end_at).format('LT')}
|
||||
{ START: moment(start_at).format('LL LT'), END: moment(end_at).format('LT') }
|
||||
));
|
||||
}
|
||||
$uibModalInstance.close({
|
||||
status: 'failed',
|
||||
availabilities: data.details.filter(function (d) { return d.status }).map(function (d) { return d.availability.id })
|
||||
availabilities: data.details.filter(function (d) { return d.status; }).map(function (d) { return d.availability.id; })
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancellation callback
|
||||
*/
|
||||
$scope.cancel = function () {
|
||||
$uibModalInstance.dismiss('cancel');
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Controller used in the iCalendar (ICS) imports management page
|
||||
*/
|
||||
@ -1061,8 +1056,8 @@ Application.Controllers.controller('AdminICalendarController', ['$scope', 'iCale
|
||||
// failed
|
||||
growl.error(_t('app.admin.icalendar.create_error'));
|
||||
console.error(error);
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a CSS-like style of the given calendar configuration
|
||||
@ -1071,11 +1066,11 @@ Application.Controllers.controller('AdminICalendarController', ['$scope', 'iCale
|
||||
$scope.calendarStyle = function (calendar) {
|
||||
return {
|
||||
'border-color': calendar.color,
|
||||
'color': calendar.text_color,
|
||||
'width': calendar.text_hidden ? '50px' : 'auto',
|
||||
'height': calendar.text_hidden ? '21px' : 'auto'
|
||||
color: calendar.text_color,
|
||||
width: calendar.text_hidden ? '50px' : 'auto',
|
||||
height: calendar.text_hidden ? '21px' : 'auto'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete the given calendar from the database
|
||||
@ -1108,8 +1103,8 @@ Application.Controllers.controller('AdminICalendarController', ['$scope', 'iCale
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronously re-fetches the events from the given calendar
|
||||
@ -1126,7 +1121,7 @@ Application.Controllers.controller('AdminICalendarController', ['$scope', 'iCale
|
||||
growl.error(_t('app.admin.icalendar.sync_failed'));
|
||||
console.error(error);
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
]);
|
@ -279,7 +279,7 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
|
||||
*/
|
||||
$scope.newPriceCategory = function () {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/events/price_form.html" %>',
|
||||
templateUrl: '/admin/events/price_form.html',
|
||||
size: 'md',
|
||||
resolve: {
|
||||
category () { return {}; }
|
||||
@ -307,7 +307,7 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
|
||||
return growl.error(_t('app.admin.events.unexpected_error_occurred_please_refresh'));
|
||||
} else {
|
||||
return $uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/events/price_form.html" %>',
|
||||
templateUrl: '/admin/events/price_form.html',
|
||||
size: 'md',
|
||||
resolve: {
|
||||
category () { return $scope.priceCategories[index]; }
|
||||
@ -645,7 +645,7 @@ Application.Controllers.controller('EditEventController', ['$scope', '$state', '
|
||||
// open a choice edit-mode dialog
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "events/editRecurrent.html" %>',
|
||||
templateUrl: '/events/editRecurrent.html',
|
||||
size: 'md',
|
||||
controller: 'EditRecurrentEventController',
|
||||
resolve: {
|
@ -58,8 +58,8 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
prefix: settings.invoice_prefix,
|
||||
nextId: 40,
|
||||
date: moment().format('DDMMYYYY'),
|
||||
templateUrl: 'editPrefix.html'
|
||||
}
|
||||
templateUrl: '/admin/invoices/settings/editPrefix.html'
|
||||
};
|
||||
|
||||
// Invoices parameters
|
||||
$scope.invoice = {
|
||||
@ -67,22 +67,22 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
reference: {
|
||||
model: '',
|
||||
help: null,
|
||||
templateUrl: 'editReference.html'
|
||||
templateUrl: '/admin/invoices/settings/editReference.html'
|
||||
},
|
||||
code: {
|
||||
model: '',
|
||||
active: true,
|
||||
templateUrl: 'editCode.html'
|
||||
templateUrl: '/admin/invoices/settings/editCode.html'
|
||||
},
|
||||
number: {
|
||||
model: '',
|
||||
help: null,
|
||||
templateUrl: 'editNumber.html'
|
||||
templateUrl: '/admin/invoices/settings/editNumber.html'
|
||||
},
|
||||
VAT: {
|
||||
rate: 19.6,
|
||||
active: false,
|
||||
templateUrl: 'editVAT.html'
|
||||
templateUrl: '/admin/invoices/settings/editVAT.html'
|
||||
},
|
||||
text: {
|
||||
content: ''
|
||||
@ -96,87 +96,87 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
$scope.settings = {
|
||||
journalCode: {
|
||||
name: 'accounting_journal_code',
|
||||
value: settings['accounting_journal_code']
|
||||
value: settings.accounting_journal_code
|
||||
},
|
||||
cardClientCode: {
|
||||
name: 'accounting_card_client_code',
|
||||
value: settings['accounting_card_client_code']
|
||||
value: settings.accounting_card_client_code
|
||||
},
|
||||
cardClientLabel: {
|
||||
name: 'accounting_card_client_label',
|
||||
value: settings['accounting_card_client_label']
|
||||
value: settings.accounting_card_client_label
|
||||
},
|
||||
walletClientCode: {
|
||||
name: 'accounting_wallet_client_code',
|
||||
value: settings['accounting_wallet_client_code']
|
||||
value: settings.accounting_wallet_client_code
|
||||
},
|
||||
walletClientLabel: {
|
||||
name: 'accounting_wallet_client_label',
|
||||
value: settings['accounting_wallet_client_label']
|
||||
value: settings.accounting_wallet_client_label
|
||||
},
|
||||
otherClientCode: {
|
||||
name: 'accounting_other_client_code',
|
||||
value: settings['accounting_other_client_code']
|
||||
value: settings.accounting_other_client_code
|
||||
},
|
||||
otherClientLabel: {
|
||||
name: 'accounting_other_client_label',
|
||||
value: settings['accounting_other_client_label']
|
||||
value: settings.accounting_other_client_label
|
||||
},
|
||||
walletCode: {
|
||||
name: 'accounting_wallet_code',
|
||||
value: settings['accounting_wallet_code']
|
||||
value: settings.accounting_wallet_code
|
||||
},
|
||||
walletLabel: {
|
||||
name: 'accounting_wallet_label',
|
||||
value: settings['accounting_wallet_label']
|
||||
value: settings.accounting_wallet_label
|
||||
},
|
||||
vatCode: {
|
||||
name: 'accounting_VAT_code',
|
||||
value: settings['accounting_VAT_code']
|
||||
value: settings.accounting_VAT_code
|
||||
},
|
||||
vatLabel: {
|
||||
name: 'accounting_VAT_label',
|
||||
value: settings['accounting_VAT_label']
|
||||
value: settings.accounting_VAT_label
|
||||
},
|
||||
subscriptionCode: {
|
||||
name: 'accounting_subscription_code',
|
||||
value: settings['accounting_subscription_code']
|
||||
value: settings.accounting_subscription_code
|
||||
},
|
||||
subscriptionLabel: {
|
||||
name: 'accounting_subscription_label',
|
||||
value: settings['accounting_subscription_label']
|
||||
value: settings.accounting_subscription_label
|
||||
},
|
||||
machineCode: {
|
||||
name: 'accounting_Machine_code',
|
||||
value: settings['accounting_Machine_code']
|
||||
value: settings.accounting_Machine_code
|
||||
},
|
||||
machineLabel: {
|
||||
name: 'accounting_Machine_label',
|
||||
value: settings['accounting_Machine_label']
|
||||
value: settings.accounting_Machine_label
|
||||
},
|
||||
trainingCode: {
|
||||
name: 'accounting_Training_code',
|
||||
value: settings['accounting_Training_code']
|
||||
value: settings.accounting_Training_code
|
||||
},
|
||||
trainingLabel: {
|
||||
name: 'accounting_Training_label',
|
||||
value: settings['accounting_Training_label']
|
||||
value: settings.accounting_Training_label
|
||||
},
|
||||
eventCode: {
|
||||
name: 'accounting_Event_code',
|
||||
value: settings['accounting_Event_code']
|
||||
value: settings.accounting_Event_code
|
||||
},
|
||||
eventLabel: {
|
||||
name: 'accounting_Event_label',
|
||||
value: settings['accounting_Event_label']
|
||||
value: settings.accounting_Event_label
|
||||
},
|
||||
spaceCode: {
|
||||
name: 'accounting_Space_code',
|
||||
value: settings['accounting_Space_code']
|
||||
value: settings.accounting_Space_code
|
||||
},
|
||||
spaceLabel: {
|
||||
name: 'accounting_Space_label',
|
||||
value: settings['accounting_Space_label']
|
||||
value: settings.accounting_Space_label
|
||||
}
|
||||
};
|
||||
|
||||
@ -220,12 +220,12 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
$scope.generateAvoirForInvoice = function (invoice) {
|
||||
// open modal
|
||||
const modalInstance = $uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/invoices/avoirModal.html" %>',
|
||||
templateUrl: '/admin/invoices/avoirModal.html',
|
||||
controller: 'AvoirModalController',
|
||||
resolve: {
|
||||
invoice () { return invoice; },
|
||||
closedPeriods() { return AccountingPeriod.query().$promise; },
|
||||
lastClosingEnd() { return AccountingPeriod.lastClosingEnd().$promise; }
|
||||
closedPeriods () { return AccountingPeriod.query().$promise; },
|
||||
lastClosingEnd () { return AccountingPeriod.lastClosingEnd().$promise; }
|
||||
}
|
||||
});
|
||||
|
||||
@ -311,10 +311,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
growl.success(_t('app.admin.invoices.invoice_reference_successfully_saved'));
|
||||
}
|
||||
, function (error) {
|
||||
if (error.status === 304) return;
|
||||
if (error.status === 304) return;
|
||||
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_invoice_reference'));
|
||||
console.error(error);
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_invoice_reference'));
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -352,10 +352,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
}
|
||||
}
|
||||
, function (error) {
|
||||
if (error.status === 304) return;
|
||||
if (error.status === 304) return;
|
||||
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_invoicing_code'));
|
||||
console.error(error);
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_invoicing_code'));
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
return Setting.update({ name: 'invoice_code-active' }, { value: result.active ? 'true' : 'false' }, function (data) {
|
||||
@ -367,10 +367,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
}
|
||||
}
|
||||
, function (error) {
|
||||
if (error.status === 304) return;
|
||||
if (error.status === 304) return;
|
||||
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_activating_the_invoicing_code'));
|
||||
console.error(error);
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_activating_the_invoicing_code'));
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -401,10 +401,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
return growl.success(_t('app.admin.invoices.order_number_successfully_saved'));
|
||||
}
|
||||
, function (error) {
|
||||
if (error.status === 304) return;
|
||||
if (error.status === 304) return;
|
||||
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_order_number'));
|
||||
console.error(error);
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_order_number'));
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -440,15 +440,14 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
$scope.ok = function () { $uibModalInstance.close({ rate: $scope.rate, active: $scope.isSelected }); };
|
||||
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
||||
|
||||
|
||||
const initialize = function() {
|
||||
const initialize = function () {
|
||||
rateHistory.setting.history.forEach(function (rate) {
|
||||
$scope.history.push({ date: rate.created_at, rate: rate.value, user: rate.user })
|
||||
$scope.history.push({ date: rate.created_at, rate: rate.value, user: rate.user });
|
||||
});
|
||||
activeHistory.setting.history.forEach(function (v) {
|
||||
$scope.history.push({ date: v.created_at, enabled: v.value === 'true', user: v.user })
|
||||
$scope.history.push({ date: v.created_at, enabled: v.value === 'true', user: v.user });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
initialize();
|
||||
}]
|
||||
@ -462,10 +461,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
}
|
||||
}
|
||||
, function (error) {
|
||||
if (error.status === 304) return;
|
||||
if (error.status === 304) return;
|
||||
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_VAT_rate'));
|
||||
console.error(error);
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_VAT_rate'));
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
return Setting.update({ name: 'invoice_VAT-active' }, { value: result.active ? 'true' : 'false' }, function (data) {
|
||||
@ -477,10 +476,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
}
|
||||
}
|
||||
, function (error) {
|
||||
if (error.status === 304) return;
|
||||
if (error.status === 304) return;
|
||||
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_activating_the_VAT'));
|
||||
console.error(error);
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_activating_the_VAT'));
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -494,7 +493,7 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
templateUrl: $scope.file.templateUrl,
|
||||
size: 'lg',
|
||||
resolve: {
|
||||
model () { return $scope.file.prefix;}
|
||||
model () { return $scope.file.prefix; }
|
||||
},
|
||||
controller: ['$scope', '$uibModalInstance', 'model', function ($scope, $uibModalInstance, model) {
|
||||
$scope.model = model;
|
||||
@ -505,15 +504,15 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
|
||||
return modalInstance.result.then(function (model) {
|
||||
Setting.update({ name: 'invoice_prefix' }, { value: model }, function (data) {
|
||||
$scope.file.prefix = model;
|
||||
return growl.success(_t('app.admin.invoices.prefix_successfully_saved'));
|
||||
}
|
||||
, function (error) {
|
||||
if (error.status === 304) return;
|
||||
$scope.file.prefix = model;
|
||||
return growl.success(_t('app.admin.invoices.prefix_successfully_saved'));
|
||||
}
|
||||
, function (error) {
|
||||
if (error.status === 304) return;
|
||||
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_prefix'));
|
||||
console.error(error);
|
||||
});
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_prefix'));
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@ -527,10 +526,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
return growl.success(_t('app.admin.invoices.text_successfully_saved'));
|
||||
}
|
||||
, function (error) {
|
||||
if (error.status === 304) return;
|
||||
if (error.status === 304) return;
|
||||
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_text'));
|
||||
console.error(error);
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_text'));
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
@ -544,10 +543,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
return growl.success(_t('app.admin.invoices.address_and_legal_information_successfully_saved'));
|
||||
}
|
||||
, function (error) {
|
||||
if (error.status === 304) return;
|
||||
if (error.status === 304) return;
|
||||
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_address_and_the_legal_information'));
|
||||
console.error(error);
|
||||
growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_address_and_the_legal_information'));
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
@ -557,7 +556,7 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
*/
|
||||
$scope.handleFilterChange = function () {
|
||||
if (searchTimeout) clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(function() {
|
||||
searchTimeout = setTimeout(function () {
|
||||
resetSearchInvoice();
|
||||
invoiceSearch();
|
||||
}, 300);
|
||||
@ -576,47 +575,47 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
* Open a modal allowing the user to close an accounting period and to
|
||||
* view all periods already closed.
|
||||
*/
|
||||
$scope.closeAnAccountingPeriod = function() {
|
||||
$scope.closeAnAccountingPeriod = function () {
|
||||
// open modal
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/invoices/closePeriodModal.html" %>',
|
||||
templateUrl: '/admin/invoices/closePeriodModal.html',
|
||||
controller: 'ClosePeriodModalController',
|
||||
backdrop: 'static',
|
||||
keyboard: false,
|
||||
size: 'lg',
|
||||
resolve: {
|
||||
periods() { return AccountingPeriod.query().$promise; },
|
||||
lastClosingEnd() { return AccountingPeriod.lastClosingEnd().$promise; }
|
||||
periods () { return AccountingPeriod.query().$promise; },
|
||||
lastClosingEnd () { return AccountingPeriod.lastClosingEnd().$promise; }
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleExportModal = function() {
|
||||
$scope.toggleExportModal = function () {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/invoices/accountingExportModal.html" %>',
|
||||
templateUrl: '/admin/invoices/accountingExportModal.html',
|
||||
controller: 'AccountingExportModalController',
|
||||
size: 'xl'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test if the given date is within a closed accounting period
|
||||
* @param date {Date} date to test
|
||||
* @returns {boolean} true if closed, false otherwise
|
||||
*/
|
||||
$scope.isDateClosed = function(date) {
|
||||
$scope.isDateClosed = function (date) {
|
||||
for (const period of closedPeriods) {
|
||||
if (moment(date).isBetween(moment.utc(period.start_at).startOf('day'), moment.utc(period.end_at).endOf('day'), null, '[]')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback to bulk save all settings in the page to the database with their values
|
||||
*/
|
||||
$scope.save = function() {
|
||||
$scope.save = function () {
|
||||
Setting.bulkUpdate(
|
||||
{ settings: Object.values($scope.settings) },
|
||||
function () { growl.success(_t('app.admin.invoices.codes_customization_success')); },
|
||||
@ -625,29 +624,29 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
console.error(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the name of the operator that creates the invoice
|
||||
*/
|
||||
$scope.operatorName = function(invoice) {
|
||||
$scope.operatorName = function (invoice) {
|
||||
if (!invoice.operator) return '';
|
||||
|
||||
return `${invoice.operator.first_name} ${invoice.operator.last_name}`;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Open a modal dialog which ask for the stripe keys
|
||||
* @param onlinePaymentModule {{name: String, value: String}} setting that defines the next status of the online payment module
|
||||
* @return {boolean} false if the keys were not provided
|
||||
*/
|
||||
$scope.requireStripeKeys = function(onlinePaymentModule) {
|
||||
$scope.requireStripeKeys = function (onlinePaymentModule) {
|
||||
// if the online payment is about to be disabled, accept the change without any further question
|
||||
if (onlinePaymentModule.value === false) return true;
|
||||
|
||||
// otherwise, open a modal to ask for the stripe keys
|
||||
const modalInstance = $uibModal.open({
|
||||
templateUrl: 'stripeKeys.html',
|
||||
templateUrl: '/admin/invoices/settings/stripeKeys.html',
|
||||
controller: 'StripeKeysModalController',
|
||||
resolve: {
|
||||
stripeKeys: ['Setting', function (Setting) { return Setting.query({ names: "['stripe_public_key', 'stripe_secret_key']" }).$promise; }]
|
||||
@ -658,19 +657,19 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
if (success) {
|
||||
Setting.get({ name: 'stripe_public_key' }, function (res) {
|
||||
$scope.allSettings.stripe_public_key = res.setting.value;
|
||||
})
|
||||
});
|
||||
Setting.isPresent({ name: 'stripe_secret_key' }, function (res) {
|
||||
$scope.stripeSecretKey = (res.isPresent ? STRIPE_SK_HIDDEN : '');
|
||||
})
|
||||
});
|
||||
Payment.onlinePaymentStatus(function (res) {
|
||||
$scope.onlinePaymentStatus = res.status;
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// return the promise
|
||||
return modalInstance.result;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup the feature-tour for the admin/invoices page.
|
||||
@ -814,7 +813,7 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
if (settings.feature_tour_display !== 'manual' && $scope.currentUser.profile.tours.indexOf('invoices') < 0) {
|
||||
uitour.start();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
@ -827,18 +826,18 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
}
|
||||
|
||||
// retrieve settings from the DB through the API
|
||||
$scope.invoice.legals.content = settings['invoice_legals'];
|
||||
$scope.invoice.text.content = settings['invoice_text'];
|
||||
$scope.invoice.legals.content = settings.invoice_legals;
|
||||
$scope.invoice.text.content = settings.invoice_text;
|
||||
$scope.invoice.VAT.rate = parseFloat(settings['invoice_VAT-rate']);
|
||||
$scope.invoice.VAT.active = (settings['invoice_VAT-active'] === 'true');
|
||||
$scope.invoice.number.model = settings['invoice_order-nb'];
|
||||
$scope.invoice.code.model = settings['invoice_code-value'];
|
||||
$scope.invoice.code.active = (settings['invoice_code-active'] === 'true');
|
||||
$scope.invoice.reference.model = settings['invoice_reference'];
|
||||
$scope.invoice.reference.model = settings.invoice_reference;
|
||||
$scope.invoice.logo = {
|
||||
filetype: 'image/png',
|
||||
filename: 'logo.png',
|
||||
base64: settings['invoice_logo']
|
||||
base64: settings.invoice_logo
|
||||
};
|
||||
|
||||
// Watch the logo, when a change occurs, save it
|
||||
@ -990,7 +989,7 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
|
||||
$scope.ok = function () {
|
||||
// check that at least 1 element of the invoice is refunded
|
||||
$scope.avoir.invoice_items_ids = [];
|
||||
for (let itemId in $scope.partial) {
|
||||
for (const itemId in $scope.partial) {
|
||||
if (Object.prototype.hasOwnProperty.call($scope.partial, itemId)) {
|
||||
const refundItem = $scope.partial[itemId];
|
||||
if (refundItem) {
|
||||
@ -1024,14 +1023,14 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
|
||||
* @param date {Date} date to test
|
||||
* @returns {boolean} true if closed, false otherwise
|
||||
*/
|
||||
$scope.isDateClosed = function(date) {
|
||||
$scope.isDateClosed = function (date) {
|
||||
for (const period of closedPeriods) {
|
||||
if (moment(date).isBetween(moment.utc(period.start_at).startOf('day'), moment.utc(period.end_at).endOf('day'), null, '[]')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
@ -1058,11 +1057,10 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* Controller used in the modal window allowing an admin to close an accounting period
|
||||
*/
|
||||
Application.Controllers.controller('ClosePeriodModalController', ['$scope', '$uibModalInstance', '$window', '$sce', 'Invoice', 'AccountingPeriod', 'periods', 'lastClosingEnd','dialogs', 'growl', '_t',
|
||||
Application.Controllers.controller('ClosePeriodModalController', ['$scope', '$uibModalInstance', '$window', '$sce', 'Invoice', 'AccountingPeriod', 'periods', 'lastClosingEnd', 'dialogs', 'growl', '_t',
|
||||
function ($scope, $uibModalInstance, $window, $sce, Invoice, AccountingPeriod, periods, lastClosingEnd, dialogs, growl, _t) {
|
||||
const YESTERDAY = moment.utc({ h: 0, m: 0, s: 0, ms: 0 }).subtract(1, 'day').toDate();
|
||||
const LAST_CLOSING = moment.utc(lastClosingEnd.last_end_date).toDate();
|
||||
@ -1124,11 +1122,11 @@ Application.Controllers.controller('ClosePeriodModalController', ['$scope', '$ui
|
||||
_t(
|
||||
'app.admin.invoices.confirm_close_START_END',
|
||||
{ START: moment.utc($scope.period.start_at).format('LL'), END: moment.utc($scope.period.end_at).format('LL') }
|
||||
)
|
||||
+ '<br/><br/><strong>'
|
||||
+ _t('app.admin.invoices.period_must_match_fiscal_year')
|
||||
+ '</strong><br/><br/>'
|
||||
+ _t('app.admin.invoices.this_may_take_a_while')
|
||||
) +
|
||||
'<br/><br/><strong>' +
|
||||
_t('app.admin.invoices.period_must_match_fiscal_year') +
|
||||
'</strong><br/><br/>' +
|
||||
_t('app.admin.invoices.this_may_take_a_while')
|
||||
)
|
||||
};
|
||||
}
|
||||
@ -1151,7 +1149,7 @@ Application.Controllers.controller('ClosePeriodModalController', ['$scope', '$ui
|
||||
));
|
||||
$uibModalInstance.close(resp);
|
||||
},
|
||||
function(error) {
|
||||
function (error) {
|
||||
$scope.pendingCreation = false;
|
||||
growl.error(_t('app.admin.invoices.failed_to_close_period'));
|
||||
$scope.errors = error.data;
|
||||
@ -1159,7 +1157,6 @@ Application.Controllers.controller('ClosePeriodModalController', ['$scope', '$ui
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1170,147 +1167,145 @@ Application.Controllers.controller('ClosePeriodModalController', ['$scope', '$ui
|
||||
/**
|
||||
* Trigger the API call to download the JSON archive of the closed accounting period
|
||||
*/
|
||||
$scope.downloadArchive = function(period) {
|
||||
$scope.downloadArchive = function (period) {
|
||||
$window.location.href = `/api/accounting_periods/${period.id}/archive`;
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
Application.Controllers.controller('AccountingExportModalController', ['$scope', '$uibModalInstance', 'Invoice', 'Export', 'CSRF', 'growl', '_t',
|
||||
function ($scope, $uibModalInstance, Invoice, Export, CSRF, growl, _t) {
|
||||
// Retrieve Anti-CSRF tokens from cookies
|
||||
CSRF.setMetaTags();
|
||||
CSRF.setMetaTags();
|
||||
|
||||
const SETTINGS = {
|
||||
acd: {
|
||||
format: 'csv',
|
||||
encoding: 'ISO-8859-1',
|
||||
separator: ';',
|
||||
dateFormat: '%d/%m/%Y',
|
||||
labelMaxLength: 50,
|
||||
decimalSeparator: ',',
|
||||
exportInvoicesAtZero: false,
|
||||
columns: ['journal_code', 'date', 'account_code', 'account_label', 'piece', 'line_label', 'debit_origin', 'credit_origin', 'debit_euro', 'credit_euro', 'lettering']
|
||||
}
|
||||
};
|
||||
const SETTINGS = {
|
||||
acd: {
|
||||
format: 'csv',
|
||||
encoding: 'ISO-8859-1',
|
||||
separator: ';',
|
||||
dateFormat: '%d/%m/%Y',
|
||||
labelMaxLength: 50,
|
||||
decimalSeparator: ',',
|
||||
exportInvoicesAtZero: false,
|
||||
columns: ['journal_code', 'date', 'account_code', 'account_label', 'piece', 'line_label', 'debit_origin', 'credit_origin', 'debit_euro', 'credit_euro', 'lettering']
|
||||
}
|
||||
};
|
||||
|
||||
/* PUBLIC SCOPE */
|
||||
/* PUBLIC SCOPE */
|
||||
|
||||
// API URL where the form will be posted
|
||||
$scope.actionUrl = '/api/accounting/export';
|
||||
// API URL where the form will be posted
|
||||
$scope.actionUrl = '/api/accounting/export';
|
||||
|
||||
// Form action on the above URL
|
||||
$scope.method = 'post';
|
||||
// Form action on the above URL
|
||||
$scope.method = 'post';
|
||||
|
||||
// Anti-CSRF token to inject into the download form
|
||||
$scope.csrfToken = angular.element('meta[name="csrf-token"]')[0].content;
|
||||
// Anti-CSRF token to inject into the download form
|
||||
$scope.csrfToken = angular.element('meta[name="csrf-token"]')[0].content;
|
||||
|
||||
// API request body to generate the export
|
||||
$scope.query = null;
|
||||
// API request body to generate the export
|
||||
$scope.query = null;
|
||||
|
||||
// binding to radio button "export to"
|
||||
$scope.exportTarget = {
|
||||
software: null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
settings: null
|
||||
};
|
||||
// binding to radio button "export to"
|
||||
$scope.exportTarget = {
|
||||
software: null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
settings: null
|
||||
};
|
||||
|
||||
// AngularUI-Bootstrap datepicker parameters to define export dates range
|
||||
$scope.datePicker = {
|
||||
format: Fablab.uibDateFormat,
|
||||
opened: { // default: datePickers are not shown
|
||||
start: false,
|
||||
end: false
|
||||
},
|
||||
options: {
|
||||
startingDay: Fablab.weekStartingDay
|
||||
}
|
||||
};
|
||||
// AngularUI-Bootstrap datepicker parameters to define export dates range
|
||||
$scope.datePicker = {
|
||||
format: Fablab.uibDateFormat,
|
||||
opened: { // default: datePickers are not shown
|
||||
start: false,
|
||||
end: false
|
||||
},
|
||||
options: {
|
||||
startingDay: Fablab.weekStartingDay
|
||||
}
|
||||
};
|
||||
|
||||
// Date of the first invoice
|
||||
$scope.firstInvoice = null;
|
||||
// Date of the first invoice
|
||||
$scope.firstInvoice = null;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Validate the export
|
||||
*/
|
||||
$scope.ok = function () {
|
||||
const statusQry = mkQuery();
|
||||
$scope.query = statusQry;
|
||||
$scope.ok = function () {
|
||||
const statusQry = mkQuery();
|
||||
$scope.query = statusQry;
|
||||
|
||||
Export.status(statusQry).then(function (res) {
|
||||
if (!res.data.exists) {
|
||||
growl.success(_t('app.admin.invoices.export_is_running'));
|
||||
}
|
||||
$uibModalInstance.close(res);
|
||||
});
|
||||
};
|
||||
Export.status(statusQry).then(function (res) {
|
||||
if (!res.data.exists) {
|
||||
growl.success(_t('app.admin.invoices.export_is_running'));
|
||||
}
|
||||
$uibModalInstance.close(res);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Callback to open/close one of the datepickers
|
||||
* @param event {Object} see https://docs.angularjs.org/guide/expression#-event-
|
||||
* @param picker {string} start | end
|
||||
*/
|
||||
$scope.toggleDatePicker = function(event, picker) {
|
||||
event.preventDefault();
|
||||
$scope.datePicker.opened[picker] = !$scope.datePicker.opened[picker];
|
||||
};
|
||||
$scope.toggleDatePicker = function (event, picker) {
|
||||
event.preventDefault();
|
||||
$scope.datePicker.opened[picker] = !$scope.datePicker.opened[picker];
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Will fill the export settings, according to the selected software
|
||||
* @param software {String} must be one of SETTINGS.*
|
||||
*/
|
||||
$scope.fillSettings = function(software) {
|
||||
$scope.exportTarget.settings = SETTINGS[software];
|
||||
};
|
||||
$scope.fillSettings = function (software) {
|
||||
$scope.exportTarget.settings = SETTINGS[software];
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Just dismiss the modal window
|
||||
*/
|
||||
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
||||
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
/**
|
||||
/**
|
||||
* Kind of constructor: these actions will be realized first when the controller is loaded
|
||||
*/
|
||||
const initialize = function () {
|
||||
const initialize = function () {
|
||||
// if the invoice was payed with stripe, allow to refund through stripe
|
||||
Invoice.first(function (data) {
|
||||
$scope.firstInvoice = data.date;
|
||||
$scope.exportTarget.startDate = data.date;
|
||||
$scope.exportTarget.endDate = moment().toISOString();
|
||||
});
|
||||
};
|
||||
Invoice.first(function (data) {
|
||||
$scope.firstInvoice = data.date;
|
||||
$scope.exportTarget.startDate = data.date;
|
||||
$scope.exportTarget.endDate = moment().toISOString();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Prepare the query for the export API
|
||||
* @returns {{extension: *, query: *, category: string, type: *, key: *}}
|
||||
*/
|
||||
const mkQuery = function() {
|
||||
return {
|
||||
category: 'accounting',
|
||||
type: $scope.exportTarget.software,
|
||||
extension: $scope.exportTarget.settings.format,
|
||||
key: $scope.exportTarget.settings.separator,
|
||||
query: JSON.stringify({
|
||||
columns: $scope.exportTarget.settings.columns,
|
||||
encoding: $scope.exportTarget.settings.encoding,
|
||||
date_format: $scope.exportTarget.settings.dateFormat,
|
||||
start_date: $scope.exportTarget.startDate,
|
||||
end_date: $scope.exportTarget.endDate,
|
||||
label_max_length: $scope.exportTarget.settings.labelMaxLength,
|
||||
decimal_separator: $scope.exportTarget.settings.decimalSeparator,
|
||||
export_invoices_at_zero: $scope.exportTarget.settings.exportInvoicesAtZero
|
||||
})
|
||||
const mkQuery = function () {
|
||||
return {
|
||||
category: 'accounting',
|
||||
type: $scope.exportTarget.software,
|
||||
extension: $scope.exportTarget.settings.format,
|
||||
key: $scope.exportTarget.settings.separator,
|
||||
query: JSON.stringify({
|
||||
columns: $scope.exportTarget.settings.columns,
|
||||
encoding: $scope.exportTarget.settings.encoding,
|
||||
date_format: $scope.exportTarget.settings.dateFormat,
|
||||
start_date: $scope.exportTarget.startDate,
|
||||
end_date: $scope.exportTarget.endDate,
|
||||
label_max_length: $scope.exportTarget.settings.labelMaxLength,
|
||||
decimal_separator: $scope.exportTarget.settings.decimalSeparator,
|
||||
export_invoices_at_zero: $scope.exportTarget.settings.exportInvoicesAtZero
|
||||
})
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// !!! MUST BE CALLED AT THE END of the controller
|
||||
return initialize();
|
||||
}]);
|
||||
|
||||
|
||||
// !!! MUST BE CALLED AT THE END of the controller
|
||||
return initialize();
|
||||
}]);
|
||||
|
||||
/**
|
||||
* Controller used in the modal window allowing an admin to close an accounting period
|
||||
@ -1343,15 +1338,14 @@ Application.Controllers.controller('StripeKeysModalController', ['$scope', '$uib
|
||||
method: 'GET',
|
||||
url: 'https://api.stripe.com/v1/charges',
|
||||
headers: {
|
||||
Authorization: `Bearer ${$scope.secretKey}`,
|
||||
Authorization: `Bearer ${$scope.secretKey}`
|
||||
}
|
||||
}).then(function () {
|
||||
$scope.secretKeyStatus = true;
|
||||
}, function (err) {
|
||||
if (err.status === 401) $scope.secretKeyStatus = false;
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger the test of the secret key and set the result in $scope.secretKeyStatus
|
||||
@ -1370,14 +1364,14 @@ Application.Controllers.controller('StripeKeysModalController', ['$scope', '$uib
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
data: $httpParamSerializerJQLike({
|
||||
'pii[id_number]': 'test',
|
||||
'pii[id_number]': 'test'
|
||||
})
|
||||
}).then(function () {
|
||||
$scope.publicKeyStatus = true;
|
||||
}, function (err) {
|
||||
if (err.status === 401) $scope.publicKeyStatus = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate the keys
|
||||
@ -1385,7 +1379,8 @@ Application.Controllers.controller('StripeKeysModalController', ['$scope', '$uib
|
||||
$scope.ok = function () {
|
||||
if ($scope.secretKeyStatus && $scope.publicKeyStatus) {
|
||||
Setting.bulkUpdate(
|
||||
{ settings: [
|
||||
{
|
||||
settings: [
|
||||
{
|
||||
name: 'stripe_public_key',
|
||||
value: $scope.publicKey
|
||||
@ -1394,7 +1389,8 @@ Application.Controllers.controller('StripeKeysModalController', ['$scope', '$uib
|
||||
name: 'stripe_secret_key',
|
||||
value: $scope.secretKey
|
||||
}
|
||||
] },
|
||||
]
|
||||
},
|
||||
function () {
|
||||
growl.success(_t('app.admin.invoices.payment.stripe_keys_saved'));
|
||||
$uibModalInstance.close(true);
|
||||
@ -1405,7 +1401,7 @@ Application.Controllers.controller('StripeKeysModalController', ['$scope', '$uib
|
||||
}
|
||||
);
|
||||
} else {
|
||||
growl.error(_t('app.admin.invoices.payment.error_check_keys'))
|
||||
growl.error(_t('app.admin.invoices.payment.error_check_keys'));
|
||||
}
|
||||
};
|
||||
|
@ -236,7 +236,7 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
|
||||
$scope.openPartnerNewModal = function () {
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "shared/_partner_new_modal.html" %>',
|
||||
templateUrl: '/shared/_partner_new_modal.html',
|
||||
size: 'lg',
|
||||
controller: ['$scope', '$uibModalInstance', 'User', function ($scope, $uibModalInstance, User) {
|
||||
$scope.partner = {};
|
||||
@ -702,7 +702,7 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
|
||||
$scope.changeUserRole = function() {
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "admin/members/change_role_modal.html" %>',
|
||||
templateUrl: '/admin/members/change_role_modal.html',
|
||||
size: 'lg',
|
||||
resolve: {
|
||||
user() { return $scope.user; }
|
||||
@ -750,7 +750,7 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
|
||||
$scope.updateSubscriptionModal = function (subscription, free) {
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "admin/subscriptions/expired_at_modal.html" %>',
|
||||
templateUrl: '/admin/subscriptions/expired_at_modal.html',
|
||||
size: 'lg',
|
||||
controller: ['$scope', '$uibModalInstance', 'Subscription', function ($scope, $uibModalInstance, Subscription) {
|
||||
$scope.new_expired_at = angular.copy(subscription.expired_at);
|
||||
@ -797,7 +797,7 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
|
||||
$scope.createSubscriptionModal = function (user, plans) {
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "admin/subscriptions/create_modal.html" %>',
|
||||
templateUrl: '/admin/subscriptions/create_modal.html',
|
||||
size: 'lg',
|
||||
controller: ['$scope', '$uibModalInstance', 'Subscription', 'Group', function ($scope, $uibModalInstance, Subscription, Group) {
|
||||
// selected user
|
||||
@ -845,7 +845,7 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
|
||||
$scope.createWalletCreditModal = function (user, wallet) {
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "wallet/credit_modal.html" %>',
|
||||
templateUrl: '/wallet/credit_modal.html',
|
||||
controller: ['$scope', '$uibModalInstance', 'Wallet', function ($scope, $uibModalInstance, Wallet) {
|
||||
// default: do not generate a refund invoice
|
||||
$scope.generate_avoir = false;
|
@ -114,7 +114,7 @@ Application.Controllers.controller('NewPlanController', ['$scope', '$uibModal',
|
||||
$scope.openPartnerNewModal = function (subscription) {
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "shared/_partner_new_modal.html" %>',
|
||||
templateUrl: '/shared/_partner_new_modal.html',
|
||||
size: 'lg',
|
||||
controller: ['$scope', '$uibModalInstance', 'User', function ($scope, $uibModalInstance, User) {
|
||||
$scope.partner = {};
|
@ -570,7 +570,7 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
|
||||
*/
|
||||
$scope.sendCouponToUser = function (coupon) {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/pricing/sendCoupon.html" %>',
|
||||
templateUrl: '/admin/pricing/sendCoupon.html',
|
||||
resolve: {
|
||||
coupon () { return coupon; }
|
||||
},
|
@ -173,7 +173,7 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope'
|
||||
$scope.savePrivacyPolicy = function () {
|
||||
// open modal
|
||||
const modalInstance = $uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/settings/save_policy.html" %>',
|
||||
templateUrl: '/admin/settings/save_policy.html',
|
||||
controller: 'SavePolicyController',
|
||||
resolve: {
|
||||
saveCb () { return $scope.save; },
|
||||
@ -274,7 +274,7 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope'
|
||||
*/
|
||||
$scope.analyticsModal = function() {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/settings/analyticsModal.html" %>',
|
||||
templateUrl: '/admin/settings/analyticsModal.html',
|
||||
controller: 'AnalyticsModalController',
|
||||
size: 'lg',
|
||||
resolve: {
|
@ -311,7 +311,7 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
|
||||
*/
|
||||
$scope.exportToExcel = function () {
|
||||
const options = {
|
||||
templateUrl: '<%= asset_path "admin/statistics/export.html" %>',
|
||||
templateUrl: '/admin/statistics/export.html',
|
||||
size: 'sm',
|
||||
controller: 'ExportStatisticsController',
|
||||
resolve: {
|
@ -221,7 +221,7 @@ Application.Controllers.controller('TrainingsAdminController', ['$scope', '$stat
|
||||
*/
|
||||
$scope.showReservations = function (training, availability) {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/trainings/validTrainingModal.html" %>',
|
||||
templateUrl: '/admin/trainings/validTrainingModal.html',
|
||||
controller: ['$scope', '$uibModalInstance', function ($scope, $uibModalInstance) {
|
||||
$scope.availability = availability;
|
||||
|
@ -89,7 +89,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
|
||||
<% else %>
|
||||
|
||||
return $uibModal.open({
|
||||
templateUrl: '<%= asset_path "shared/signupModal.html" %>',
|
||||
templateUrl: '/shared/signupModal.html',
|
||||
size: 'md',
|
||||
resolve: {
|
||||
settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['phone_required', 'recaptcha_site_key', 'confirmation_required']" }).$promise; }]
|
||||
@ -192,7 +192,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
|
||||
*/
|
||||
$scope.editPassword = function (token) {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "shared/passwordEditModal.html" %>',
|
||||
templateUrl: '/shared/passwordEditModal.html',
|
||||
size: 'md',
|
||||
controller: ['$scope', '$uibModalInstance', '$http', function ($scope, $uibModalInstance, $http) {
|
||||
$scope.user = { reset_password_token: token };
|
||||
@ -282,7 +282,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
|
||||
if ($rootScope.currentUser.role !== 'admin') return;
|
||||
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/versions/upgradeModal.html" %>',
|
||||
templateUrl: '/admin/versions/upgradeModal.html',
|
||||
controller: 'VersionModalController',
|
||||
resolve: {
|
||||
version() { return $scope.version; }
|
||||
@ -407,7 +407,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
|
||||
$window.location.href = '/sso-redirect';
|
||||
<% else %>
|
||||
return $uibModal.open({
|
||||
templateUrl: '<%= asset_path "shared/deviseModal.html" %>',
|
||||
templateUrl: '/shared/deviseModal.html',
|
||||
size: 'sm',
|
||||
resolve: {
|
||||
settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['confirmation_required']" }).$promise; }]
|
||||
@ -470,7 +470,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
|
||||
} else if (reason === 'resetPassword') {
|
||||
// open the 'reset password' modal
|
||||
return $uibModal.open({
|
||||
templateUrl: '<%= asset_path "shared/passwordNewModal.html" %>',
|
||||
templateUrl: '/shared/passwordNewModal.html',
|
||||
size: 'sm',
|
||||
controller: ['$scope', '$uibModalInstance', '$http', function ($scope, $uibModalInstance, $http) {
|
||||
$scope.user = { email: '' };
|
||||
@ -488,7 +488,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
|
||||
} else if (reason === 'confirmationNew') {
|
||||
// open the 'reset password' modal
|
||||
return $uibModal.open({
|
||||
templateUrl: '<%= asset_path "shared/ConfirmationNewModal.html" %>',
|
||||
templateUrl: '/shared/ConfirmationNewModal.html',
|
||||
size: 'sm',
|
||||
controller: ['$scope', '$uibModalInstance', '$http', function ($scope, $uibModalInstance, $http) {
|
||||
$scope.user = { email: '' };
|
@ -55,7 +55,12 @@ Application.Controllers.controller('CalendarController', ['$scope', '$state', '$
|
||||
evt: filter.evt,
|
||||
dispo: filter.dispo
|
||||
});
|
||||
$scope.calendarConfig.events = availabilitySourceUrl();
|
||||
// remove all
|
||||
$scope.eventSources.splice(0, $scope.eventSources.length);
|
||||
// recreate source for trainings/machines/events with new filters
|
||||
$scope.eventSources.push({
|
||||
url: availabilitySourceUrl()
|
||||
});
|
||||
// external iCalendar events sources
|
||||
$scope.externals.forEach(e => {
|
||||
if (e.checked) {
|
||||
@ -74,7 +79,7 @@ Application.Controllers.controller('CalendarController', ['$scope', '$state', '$
|
||||
}
|
||||
}
|
||||
});
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('refetchEventSources');
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');
|
||||
};
|
||||
|
||||
/**
|
||||
@ -84,7 +89,7 @@ Application.Controllers.controller('CalendarController', ['$scope', '$state', '$
|
||||
$scope.calendarStyle = function (calendar) {
|
||||
return {
|
||||
'border-color': calendar.color,
|
||||
'color': calendar.text_color
|
||||
color: calendar.text_color
|
||||
};
|
||||
};
|
||||
|
||||
@ -101,12 +106,12 @@ Application.Controllers.controller('CalendarController', ['$scope', '$state', '$
|
||||
// toggle to select all formation/machine
|
||||
$scope.toggleFilter = function (type, filter) {
|
||||
$scope[type].forEach(t => t.checked = filter[type]);
|
||||
return $scope.filterAvailabilities(filter, $scope);
|
||||
$scope.filterAvailabilities(filter, $scope);
|
||||
};
|
||||
|
||||
$scope.openFilterAside = () =>
|
||||
$aside.open({
|
||||
templateUrl: 'filterAside.html',
|
||||
templateUrl: '/calendar/filterAside.html',
|
||||
placement: 'right',
|
||||
size: 'md',
|
||||
backdrop: false,
|
||||
@ -148,8 +153,8 @@ Application.Controllers.controller('CalendarController', ['$scope', '$state', '$
|
||||
$uibModalInstance.dismiss();
|
||||
return e.stopPropagation();
|
||||
};
|
||||
}
|
||||
] });
|
||||
}]
|
||||
});
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
@ -159,7 +164,6 @@ Application.Controllers.controller('CalendarController', ['$scope', '$state', '$
|
||||
const initialize = () => {
|
||||
// fullCalendar (v2) configuration
|
||||
$scope.calendarConfig = CalendarConfig({
|
||||
events: availabilitySourceUrl(),
|
||||
slotEventOverlap: true,
|
||||
header: {
|
||||
left: 'month agendaWeek agendaDay',
|
||||
@ -175,10 +179,13 @@ Application.Controllers.controller('CalendarController', ['$scope', '$state', '$
|
||||
viewRender (view, element) {
|
||||
return viewRenderCb(view, element);
|
||||
},
|
||||
eventRender (event, element, view) {
|
||||
eventRender (event, element) {
|
||||
return eventRenderCb(event, element);
|
||||
}
|
||||
});
|
||||
$scope.eventSources = [{
|
||||
url: availabilitySourceUrl()
|
||||
}];
|
||||
$scope.externals.forEach(e => {
|
||||
if (e.checked) {
|
||||
$scope.eventSources.push({
|
||||
@ -194,7 +201,7 @@ Application.Controllers.controller('CalendarController', ['$scope', '$state', '$
|
||||
/**
|
||||
* Callback triggered when an event object is clicked in the fullCalendar view
|
||||
*/
|
||||
const calendarEventClickCb = function (event, jsEvent, view) {
|
||||
const calendarEventClickCb = function (event) {
|
||||
// current calendar object
|
||||
const { calendar } = uiCalendarConfig.calendars;
|
||||
if (event.available_type === 'machines') {
|
||||
@ -240,7 +247,7 @@ Application.Controllers.controller('CalendarController', ['$scope', '$state', '$
|
||||
* This function is called when calendar view is rendered or changed
|
||||
* @see https://fullcalendar.io/docs/v3/viewRender#v2
|
||||
*/
|
||||
const viewRenderCb = function (view, element) {
|
||||
const viewRenderCb = function (view) {
|
||||
toggleSlotEventOverlap(view);
|
||||
if (view.type === 'agendaDay') {
|
||||
// get availabilties by 1 day for show machine slots
|
||||
@ -255,7 +262,7 @@ Application.Controllers.controller('CalendarController', ['$scope', '$state', '$
|
||||
const eventRenderCb = function (event, element) {
|
||||
if (event.tags && event.tags.length > 0) {
|
||||
let html = '';
|
||||
for (let tag of Array.from(event.tags)) {
|
||||
for (const tag of Array.from(event.tags)) {
|
||||
html += `<span class='label label-success text-white'>${tag.name}</span> `;
|
||||
}
|
||||
element.find('.fc-title').append(`<br/>${html}`);
|
||||
@ -269,7 +276,7 @@ Application.Controllers.controller('CalendarController', ['$scope', '$state', '$
|
||||
return { t, m, s, evt: $scope.filter.evt, dispo: $scope.filter.dispo };
|
||||
};
|
||||
|
||||
var availabilitySourceUrl = () => `/api/availabilities/public?${$.param(getFilter())}`;
|
||||
const availabilitySourceUrl = () => `/api/availabilities/public?${$.param(getFilter())}`;
|
||||
|
||||
// !!! MUST BE CALLED AT THE END of the controller
|
||||
return initialize();
|
@ -42,7 +42,7 @@ Application.Controllers.controller('EventsController', ['$scope', '$state', 'Eve
|
||||
age_range_id: null
|
||||
};
|
||||
|
||||
$scope.monthNames = [<%= t('date.month_names')[1..-1].map { |m| "\"#{m}\"" }.join(', ') %>];
|
||||
$scope.monthNames = [<%= I18n.t('date.month_names')[1..-1].map { |m| "\"#{m}\"" }.join(', ') %>];
|
||||
|
||||
/**
|
||||
* Adds a resultset of events to the bottom of the page, grouped by month
|
||||
@ -186,7 +186,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
|
||||
// open a confirmation dialog
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "events/deleteRecurrent.html" %>',
|
||||
templateUrl: '/events/deleteRecurrent.html',
|
||||
size: 'md',
|
||||
controller: 'DeleteRecurrentEventController',
|
||||
resolve: {
|
||||
@ -416,7 +416,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
|
||||
$scope.modifyReservation = function (reservation) {
|
||||
const index = $scope.reservations.indexOf(reservation);
|
||||
return $uibModal.open({
|
||||
templateUrl: '<%= asset_path "events/modify_event_reservation_modal.html" %>',
|
||||
templateUrl: '/events/modify_event_reservation_modal.html',
|
||||
resolve: {
|
||||
event () { return $scope.event; },
|
||||
reservation () { return reservation; }
|
||||
@ -671,7 +671,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
|
||||
*/
|
||||
const payByStripe = function (reservation) {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "stripe/payment_modal.html" %>',
|
||||
templateUrl: '/stripe/payment_modal.html',
|
||||
size: 'md',
|
||||
resolve: {
|
||||
reservation () {
|
||||
@ -739,7 +739,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
|
||||
*/
|
||||
const payOnSite = function (reservation) {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "shared/valid_reservation_modal.html" %>',
|
||||
templateUrl: '/shared/valid_reservation_modal.html',
|
||||
size: 'sm',
|
||||
resolve: {
|
||||
reservation () {
|
||||
@ -858,7 +858,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
|
||||
const showReserveSlotSameTimeModal = function(sameTimeReservations, callback) {
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "shared/_reserve_slot_same_time.html" %>',
|
||||
templateUrl: '/shared/_reserve_slot_same_time.html',
|
||||
size: 'md',
|
||||
controller: 'ReserveSlotSameTimeController',
|
||||
resolve: {
|
@ -121,7 +121,7 @@ const _reserveMachine = function (machine, e) {
|
||||
// the training before he can book the reservation
|
||||
if (machine.current_user_training_reservation) {
|
||||
return _this.$uibModal.open({
|
||||
templateUrl: '<%= asset_path "machines/training_reservation_modal.html" %>',
|
||||
templateUrl: '/machines/training_reservation_modal.html',
|
||||
controller: ['$scope', '$uibModalInstance', function ($scope, $uibModalInstance) {
|
||||
$scope.machine = machine;
|
||||
return $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
||||
@ -136,7 +136,7 @@ const _reserveMachine = function (machine, e) {
|
||||
// otherwise open the information modal
|
||||
} else {
|
||||
return _this.$uibModal.open({
|
||||
templateUrl: '<%= asset_path "machines/request_training_modal.html" %>',
|
||||
templateUrl: '/machines/request_training_modal.html',
|
||||
controller: ['$scope', '$uibModalInstance', '$state', function ($scope, $uibModalInstance, $state) {
|
||||
$scope.machine = machine;
|
||||
$scope.member = _this.$scope.currentUser;
|
||||
@ -495,7 +495,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
|
||||
$scope.markSlotAsAdded = function () {
|
||||
$scope.selectedEvent.backgroundColor = FREE_SLOT_BORDER_COLOR;
|
||||
$scope.selectedEvent.title = _t('app.logged.machines_reserve.i_reserve');
|
||||
return updateCalendar();
|
||||
updateEvents($scope.selectedEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -506,11 +506,11 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
|
||||
slot.borderColor = FREE_SLOT_BORDER_COLOR;
|
||||
slot.title = '';
|
||||
slot.isValid = false;
|
||||
slot.id = null;
|
||||
slot.slot_id = null;
|
||||
slot.is_reserved = false;
|
||||
slot.can_modify = false;
|
||||
slot.offered = false;
|
||||
return updateCalendar();
|
||||
updateEvents(slot);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -524,7 +524,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
|
||||
$scope.markSlotAsModifying = function () {
|
||||
$scope.selectedEvent.backgroundColor = '#eee';
|
||||
$scope.selectedEvent.title = _t('app.logged.machines_reserve.i_change');
|
||||
return updateCalendar();
|
||||
updateEvents($scope.selectedEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -534,34 +534,45 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
|
||||
if ($scope.events.placable) {
|
||||
$scope.events.placable.backgroundColor = 'white';
|
||||
$scope.events.placable.title = '';
|
||||
updateEvents($scope.events.placable);
|
||||
}
|
||||
if (!$scope.events.placable || ($scope.events.placable._id !== $scope.selectedEvent._id)) {
|
||||
$scope.selectedEvent.backgroundColor = '#bbb';
|
||||
$scope.selectedEvent.title = _t('app.logged.machines_reserve.i_shift');
|
||||
updateEvents($scope.selectedEvent);
|
||||
}
|
||||
return updateCalendar();
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* When modifying an already booked reservation, callback when the modification was successfully done.
|
||||
*/
|
||||
$scope.modifyMachineSlot = function () {
|
||||
$scope.events.placable.title = $scope.currentUser.id === $scope.events.modifiable.user.id ? _t('app.logged.machines_reserve.i_ve_reserved') : _t('app.logged.machines_reserve.not_available');
|
||||
$scope.events.placable.backgroundColor = 'white';
|
||||
$scope.events.placable.borderColor = $scope.events.modifiable.borderColor;
|
||||
$scope.events.placable.id = $scope.events.modifiable.id;
|
||||
$scope.events.placable.is_reserved = true;
|
||||
$scope.events.placable.can_modify = true;
|
||||
$scope.events.placable.user = angular.copy($scope.events.modifiable.user);
|
||||
const save = {
|
||||
slotId: $scope.events.modifiable.slot_id,
|
||||
borderColor: $scope.events.modifiable.borderColor,
|
||||
user: angular.copy($scope.events.modifiable.user),
|
||||
title: $scope.currentUser.id === $scope.events.modifiable.user.id ? _t('app.logged.machines_reserve.i_ve_reserved') : _t('app.logged.machines_reserve.not_available')
|
||||
};
|
||||
|
||||
$scope.events.modifiable.backgroundColor = 'white';
|
||||
$scope.events.modifiable.title = '';
|
||||
$scope.events.modifiable.borderColor = FREE_SLOT_BORDER_COLOR;
|
||||
$scope.events.modifiable.id = null;
|
||||
$scope.events.modifiable.slot_id = null;
|
||||
$scope.events.modifiable.is_reserved = false;
|
||||
$scope.events.modifiable.can_modify = false;
|
||||
updateEvents($scope.events.modifiable);
|
||||
|
||||
return updateCalendar();
|
||||
$scope.events.placable.title = save.title;
|
||||
$scope.events.placable.backgroundColor = 'white';
|
||||
$scope.events.placable.borderColor = save.borderColor;
|
||||
$scope.events.placable.slot_id = save.slotId;
|
||||
$scope.events.placable.is_reserved = true;
|
||||
$scope.events.placable.can_modify = true;
|
||||
$scope.events.placable.user = angular.copy(save.user);
|
||||
updateEvents($scope.events.placable);
|
||||
|
||||
refetchCalendar();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -575,7 +586,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
|
||||
$scope.events.modifiable.title = $scope.currentUser.id === $scope.events.modifiable.user.id ? _t('app.logged.machines_reserve.i_ve_reserved') : _t('app.logged.machines_reserve.not_available');
|
||||
$scope.events.modifiable.backgroundColor = 'white';
|
||||
|
||||
return updateCalendar();
|
||||
updateEvents($scope.events.placable, $scope.events.modifiable);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -648,7 +659,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
|
||||
$scope.selectedPlan = null;
|
||||
}
|
||||
|
||||
return refetchCalendar();
|
||||
refetchCalendar();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -662,11 +673,13 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
|
||||
* Kind of constructor: these actions will be realized first when the controller is loaded
|
||||
*/
|
||||
const initialize = function () {
|
||||
Availability.machine({ machineId: $stateParams.id }, function (availabilities) {
|
||||
$scope.eventSources.push({
|
||||
events: availabilities,
|
||||
textColor: 'black'
|
||||
});
|
||||
$scope.eventSources.push({
|
||||
events: function (start, end, timezone, callback) {
|
||||
Availability.machine({ machineId: $stateParams.id }, function (availabilities) {
|
||||
callback(availabilities);
|
||||
});
|
||||
},
|
||||
textColor: 'black'
|
||||
});
|
||||
|
||||
if ($scope.currentUser.role !== 'admin') {
|
||||
@ -680,7 +693,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
|
||||
* the user's subscription (current or about to be took) and the time (the user cannot modify a booked reservation
|
||||
* if it's too late).
|
||||
*/
|
||||
var calendarEventClickCb = function (event, jsEvent, view) {
|
||||
const calendarEventClickCb = function (event, jsEvent, view) {
|
||||
$scope.selectedEvent = event;
|
||||
return $scope.selectionTime = new Date();
|
||||
};
|
||||
@ -690,7 +703,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
|
||||
* Append the event tag into the block, just after the event title.
|
||||
* @see http://fullcalendar.io/docs/event_rendering/eventRender/
|
||||
*/
|
||||
var eventRenderCb = function (event, element) {
|
||||
const eventRenderCb = function (event, element) {
|
||||
if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) {
|
||||
let html = '';
|
||||
for (let tag of Array.from(event.tags)) {
|
||||
@ -708,28 +721,30 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
|
||||
* @param reservation {Object}
|
||||
* @param user {Object} user associated with the slot
|
||||
*/
|
||||
var updateMachineSlot = function (slot, reservation, user) {
|
||||
const updateMachineSlot = function (slot, reservation, user) {
|
||||
angular.forEach(reservation.slots, function (s) {
|
||||
if (slot.start.isSame(s.start_at)) {
|
||||
slot.id = s.id;
|
||||
return slot.user = user;
|
||||
slot.slot_id = s.id;
|
||||
slot.user = user;
|
||||
}
|
||||
});
|
||||
updateEvents(slot);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the calendar's display to render the new attributes of the events
|
||||
* @param events Object[] events to update in full-calendar
|
||||
*/
|
||||
var updateCalendar = function () { uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents'); };
|
||||
const updateEvents = function (...events) {
|
||||
const realEvents = events.filter(e => !_.isNil(e));
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('updateEvents', realEvents);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronously fetch the events from the API and refresh the calendar's view with these new events
|
||||
*/
|
||||
var refetchCalendar = function () {
|
||||
$timeout(function () {
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');
|
||||
return uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents');
|
||||
});
|
||||
const refetchCalendar = function () {
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');
|
||||
};
|
||||
|
||||
// !!! MUST BE CALLED AT THE END of the controller
|
@ -235,7 +235,7 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
|
||||
*/
|
||||
const payByStripe = function () {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "stripe/payment_modal.html" %>',
|
||||
templateUrl: '/stripe/payment_modal.html',
|
||||
size: 'md',
|
||||
resolve: {
|
||||
selectedPlan () { return $scope.selectedPlan; },
|
||||
@ -299,7 +299,7 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
|
||||
*/
|
||||
const payOnSite = function () {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "plans/payment_modal.html" %>',
|
||||
templateUrl: '/plans/payment_modal.html',
|
||||
size: 'sm',
|
||||
resolve: {
|
||||
selectedPlan () { return $scope.selectedPlan; },
|
@ -167,7 +167,7 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
|
||||
event.stopPropagation();
|
||||
dialogs.confirm(
|
||||
{
|
||||
templateUrl: '<%= asset_path "profile/resend_code_modal.html" %>',
|
||||
templateUrl: '/profile/resend_code_modal.html',
|
||||
resolve: {
|
||||
object () {
|
||||
return { email: memberPromise.email };
|
@ -588,7 +588,7 @@ Application.Controllers.controller('ShowProjectController', ['$scope', '$state',
|
||||
if (e) { e.preventDefault(); }
|
||||
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "shared/signalAbuseModal.html" %>',
|
||||
templateUrl: '/shared/signalAbuseModal.html',
|
||||
size: 'md',
|
||||
resolve: {
|
||||
project () { return $scope.project; }
|
@ -307,8 +307,8 @@ Application.Controllers.controller('ShowSpaceController', ['$scope', '$state', '
|
||||
* per slots.
|
||||
*/
|
||||
|
||||
Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateParams', 'Auth', '$timeout', 'Availability', 'Member', 'availabilitySpacesPromise', 'plansPromise', 'groupsPromise', 'settingsPromise', 'spacePromise', '_t', 'uiCalendarConfig', 'CalendarConfig',
|
||||
function ($scope, $stateParams, Auth, $timeout, Availability, Member, availabilitySpacesPromise, plansPromise, groupsPromise, settingsPromise, spacePromise, _t, uiCalendarConfig, CalendarConfig) {
|
||||
Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateParams', 'Auth', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'spacePromise', '_t', 'uiCalendarConfig', 'CalendarConfig',
|
||||
function ($scope, $stateParams, Auth, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, spacePromise, _t, uiCalendarConfig, CalendarConfig) {
|
||||
/* PRIVATE STATIC CONSTANTS */
|
||||
|
||||
// Color of the selected event backgound
|
||||
@ -323,7 +323,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
|
||||
/* PUBLIC SCOPE */
|
||||
|
||||
// bind the spaces availabilities with full-Calendar events
|
||||
$scope.eventSources = [ { events: availabilitySpacesPromise, textColor: 'black' } ];
|
||||
$scope.eventSources = [];
|
||||
|
||||
// the user to deal with, ie. the current user for non-admins
|
||||
$scope.ctrl =
|
||||
@ -394,7 +394,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
|
||||
*/
|
||||
$scope.markSlotAsAdded = function () {
|
||||
$scope.selectedEvent.backgroundColor = SELECTED_EVENT_BG_COLOR;
|
||||
return updateCalendar();
|
||||
updateEvents($scope.selectedEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -404,13 +404,13 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
|
||||
slot.backgroundColor = 'white';
|
||||
slot.title = '';
|
||||
slot.borderColor = FREE_SLOT_BORDER_COLOR;
|
||||
slot.id = null;
|
||||
slot.slot_id = null;
|
||||
slot.isValid = false;
|
||||
slot.is_reserved = false;
|
||||
slot.can_modify = false;
|
||||
slot.offered = false;
|
||||
if (slot.is_completed) { slot.is_completed = false; }
|
||||
return updateCalendar();
|
||||
updateEvents(slot);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -424,50 +424,60 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
|
||||
$scope.markSlotAsModifying = function () {
|
||||
$scope.selectedEvent.backgroundColor = '#eee';
|
||||
$scope.selectedEvent.title = _t('app.logged.space_reserve.i_change');
|
||||
return updateCalendar();
|
||||
updateEvents($scope.selectedEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the last selected slot's appearence to looks like 'the slot being exchanged will take this place'
|
||||
*/
|
||||
$scope.changeModifyTrainingSlot = function () {
|
||||
$scope.changeModifySpaceSlot = function () {
|
||||
if ($scope.events.placable) {
|
||||
$scope.events.placable.backgroundColor = 'white';
|
||||
$scope.events.placable.title = '';
|
||||
updateEvents($scope.events.placable);
|
||||
}
|
||||
if (!$scope.events.placable || ($scope.events.placable._id !== $scope.selectedEvent._id)) {
|
||||
$scope.selectedEvent.backgroundColor = '#bbb';
|
||||
$scope.selectedEvent.title = _t('app.logged.space_reserve.i_shift');
|
||||
updateEvents($scope.selectedEvent);
|
||||
}
|
||||
return updateCalendar();
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* When modifying an already booked reservation, callback when the modification was successfully done.
|
||||
*/
|
||||
$scope.modifyTrainingSlot = function () {
|
||||
$scope.events.placable.title = _t('app.logged.space_reserve.i_ve_reserved');
|
||||
$scope.events.placable.backgroundColor = 'white';
|
||||
$scope.events.placable.borderColor = $scope.events.modifiable.borderColor;
|
||||
$scope.events.placable.id = $scope.events.modifiable.id;
|
||||
$scope.events.placable.is_reserved = true;
|
||||
$scope.events.placable.can_modify = true;
|
||||
$scope.modifySpaceSlot = function () {
|
||||
const save = {
|
||||
slotId: $scope.events.modifiable.slot_id,
|
||||
borderColor: $scope.events.modifiable.borderColor,
|
||||
title: _t('app.logged.space_reserve.i_ve_reserved')
|
||||
};
|
||||
|
||||
$scope.events.modifiable.backgroundColor = 'white';
|
||||
$scope.events.modifiable.title = '';
|
||||
$scope.events.modifiable.borderColor = FREE_SLOT_BORDER_COLOR;
|
||||
$scope.events.modifiable.id = null;
|
||||
$scope.events.modifiable.slot_id = null;
|
||||
$scope.events.modifiable.is_reserved = false;
|
||||
$scope.events.modifiable.can_modify = false;
|
||||
if ($scope.events.modifiable.is_completed) { $scope.events.modifiable.is_completed = false; }
|
||||
updateEvents($scope.events.modifiable);
|
||||
|
||||
return updateCalendar();
|
||||
$scope.events.placable.title = save.title;
|
||||
$scope.events.placable.backgroundColor = 'white';
|
||||
$scope.events.placable.borderColor = save.borderColor;
|
||||
$scope.events.placable.slot_id = save.slotId;
|
||||
$scope.events.placable.is_reserved = true;
|
||||
$scope.events.placable.can_modify = true;
|
||||
updateEvents($scope.events.placable);
|
||||
|
||||
refetchCalendar();
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel the current booking modification, reseting the whole process
|
||||
*/
|
||||
$scope.cancelModifyTrainingSlot = function () {
|
||||
$scope.cancelModifySpaceSlot = function () {
|
||||
if ($scope.events.placable) {
|
||||
$scope.events.placable.backgroundColor = 'white';
|
||||
$scope.events.placable.title = '';
|
||||
@ -475,7 +485,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
|
||||
$scope.events.modifiable.title = _t('app.logged.space_reserve.i_ve_reserved');
|
||||
$scope.events.modifiable.backgroundColor = 'white';
|
||||
|
||||
return updateCalendar();
|
||||
updateEvents($scope.events.placable, $scope.events.modifiable);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -544,7 +554,8 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
|
||||
spaceSlot.title = _t('app.logged.space_reserve.i_ve_reserved');
|
||||
spaceSlot.backgroundColor = 'white';
|
||||
spaceSlot.borderColor = RESERVED_SLOT_BORDER_COLOR;
|
||||
return updateSpaceSlotId(spaceSlot, reservation);
|
||||
updateSpaceSlotId(spaceSlot, reservation);
|
||||
updateEvents(spaceSlot);
|
||||
});
|
||||
|
||||
if ($scope.selectedPlan) {
|
||||
@ -558,7 +569,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
|
||||
Auth._currentUser.training_credits = angular.copy(reservation.user.training_credits);
|
||||
Auth._currentUser.machine_credits = angular.copy(reservation.user.machine_credits);
|
||||
|
||||
return refetchCalendar();
|
||||
refetchCalendar();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -573,8 +584,18 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
|
||||
*/
|
||||
const initialize = function () {
|
||||
if ($scope.currentUser.role !== 'admin') {
|
||||
return Member.get({ id: $scope.currentUser.id }, function (member) { $scope.ctrl.member = member; });
|
||||
Member.get({ id: $scope.currentUser.id }, function (member) { $scope.ctrl.member = member; });
|
||||
}
|
||||
// we load the availabilities from a callback function of the $scope.eventSources, instead of resolving a promise
|
||||
// in the router because this allows to refetchEvents from fullCalendar API.
|
||||
$scope.eventSources.push({
|
||||
events: function (start, end, timezone, callback) {
|
||||
Availability.spaces({ spaceId: $stateParams.id }, function (availabilities) {
|
||||
callback(availabilities);
|
||||
});
|
||||
},
|
||||
textColor: 'black'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -584,12 +605,9 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
|
||||
* if it's too late).
|
||||
* @see http://fullcalendar.io/docs/mouse/eventClick/
|
||||
*/
|
||||
var calendarEventClickCb = function (event, jsEvent, view) {
|
||||
const calendarEventClickCb = function (event, jsEvent, view) {
|
||||
$scope.selectedEvent = event;
|
||||
if ($stateParams.id === 'all') {
|
||||
$scope.training = event.training;
|
||||
}
|
||||
return $scope.selectionTime = new Date();
|
||||
$scope.selectionTime = new Date();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -597,7 +615,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
|
||||
* Append the event tag into the block, just after the event title.
|
||||
* @see http://fullcalendar.io/docs/event_rendering/eventRender/
|
||||
*/
|
||||
var eventRenderCb = function (event, element, view) {
|
||||
const eventRenderCb = function (event, element, view) {
|
||||
if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) {
|
||||
let html = '';
|
||||
for (let tag of Array.from(event.tags)) {
|
||||
@ -613,27 +631,29 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
|
||||
* @param slot {Object}
|
||||
* @param reservation {Object}
|
||||
*/
|
||||
var updateSpaceSlotId = function (slot, reservation) {
|
||||
const updateSpaceSlotId = function (slot, reservation) {
|
||||
angular.forEach(reservation.slots, function (s) {
|
||||
if (slot.start_at === slot.start_at) {
|
||||
return slot.id = s.id;
|
||||
if (slot.start.isSame(s.start_at)) {
|
||||
slot.slot_id = s.id;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the calendar's display to render the new attributes of the events
|
||||
* @param events Object[] events to update in full-calendar
|
||||
*/
|
||||
var updateCalendar = function () { uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents'); };
|
||||
const updateEvents = function (...events) {
|
||||
const realEvents = events.filter(e => !_.isNil(e));
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('updateEvents', realEvents);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Asynchronously fetch the events from the API and refresh the calendar's view with these new events
|
||||
*/
|
||||
var refetchCalendar = function () {
|
||||
$timeout(function () {
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');
|
||||
return uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents');
|
||||
});
|
||||
const refetchCalendar = function () {
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');
|
||||
};
|
||||
|
||||
// !!! MUST BE CALLED AT THE END of the controller
|
@ -91,8 +91,8 @@ Application.Controllers.controller('ShowTrainingController', ['$scope', '$state'
|
||||
* training can be reserved during the reservation process (the shopping cart may contains only one training and a subscription).
|
||||
*/
|
||||
|
||||
Application.Controllers.controller('ReserveTrainingController', ['$scope', '$stateParams', 'Auth', '$timeout', 'Availability', 'Member', 'availabilityTrainingsPromise', 'plansPromise', 'groupsPromise', 'settingsPromise', 'trainingPromise', '_t', 'uiCalendarConfig', 'CalendarConfig',
|
||||
function ($scope, $stateParams, Auth, $timeout, Availability, Member, availabilityTrainingsPromise, plansPromise, groupsPromise, settingsPromise, trainingPromise, _t, uiCalendarConfig, CalendarConfig) {
|
||||
Application.Controllers.controller('ReserveTrainingController', ['$scope', '$stateParams', 'Auth', 'AuthService', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'trainingPromise', '_t', 'uiCalendarConfig', 'CalendarConfig',
|
||||
function ($scope, $stateParams, Auth, AuthService, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, trainingPromise, _t, uiCalendarConfig, CalendarConfig) {
|
||||
/* PRIVATE STATIC CONSTANTS */
|
||||
|
||||
// Color of the selected event backgound
|
||||
@ -104,7 +104,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
|
||||
/* PUBLIC SCOPE */
|
||||
|
||||
// bind the trainings availabilities with full-Calendar events
|
||||
$scope.eventSources = [ { events: availabilityTrainingsPromise, textColor: 'black' } ];
|
||||
$scope.eventSources = [];
|
||||
|
||||
// the user to deal with, ie. the current user for non-admins
|
||||
$scope.ctrl =
|
||||
@ -177,15 +177,15 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
|
||||
$scope.trainingInformationMessage = settingsPromise.training_information_message;
|
||||
|
||||
/**
|
||||
* Change the last selected slot's appearence to looks like 'added to cart'
|
||||
* Change the last selected slot's appearance to looks like 'added to cart'
|
||||
*/
|
||||
$scope.markSlotAsAdded = function () {
|
||||
$scope.selectedEvent.backgroundColor = SELECTED_EVENT_BG_COLOR;
|
||||
return updateCalendar();
|
||||
updateEvents($scope.selectedEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the last selected slot's appearence to looks like 'never added to cart'
|
||||
* Change the last selected slot's appearance to looks like 'never added to cart'
|
||||
*/
|
||||
$scope.markSlotAsRemoved = function (slot) {
|
||||
slot.backgroundColor = 'white';
|
||||
@ -197,7 +197,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
|
||||
slot.can_modify = false;
|
||||
slot.offered = false;
|
||||
if (slot.is_completed) { slot.is_completed = false; }
|
||||
return updateCalendar();
|
||||
updateEvents(slot);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -211,44 +211,56 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
|
||||
$scope.markSlotAsModifying = function () {
|
||||
$scope.selectedEvent.backgroundColor = '#eee';
|
||||
$scope.selectedEvent.title = $scope.selectedEvent.training.name + ' - ' + _t('app.logged.trainings_reserve.i_change');
|
||||
return updateCalendar();
|
||||
updateEvents($scope.selectedEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the last selected slot's appearence to looks like 'the slot being exchanged will take this place'
|
||||
*/
|
||||
$scope.changeModifyTrainingSlot = function () {
|
||||
if ($scope.selectedEvent.training.id !== $scope.events.modifiable.training.id) return false;
|
||||
|
||||
if ($scope.events.placable) {
|
||||
$scope.events.placable.backgroundColor = 'white';
|
||||
$scope.events.placable.title = $scope.events.placable.training.name;
|
||||
updateEvents($scope.events.placable);
|
||||
}
|
||||
if (!$scope.events.placable || ($scope.events.placable._id !== $scope.selectedEvent._id)) {
|
||||
$scope.selectedEvent.backgroundColor = '#bbb';
|
||||
$scope.selectedEvent.title = $scope.selectedEvent.training.name + ' - ' + _t('app.logged.trainings_reserve.i_shift');
|
||||
updateEvents($scope.selectedEvent);
|
||||
}
|
||||
return updateCalendar();
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* When modifying an already booked reservation, callback when the modification was successfully done.
|
||||
*/
|
||||
$scope.modifyTrainingSlot = function () {
|
||||
$scope.events.placable.title = $scope.currentUser.role !== 'admin' ? $scope.events.placable.training.name + ' - ' + _t('app.logged.trainings_reserve.i_ve_reserved') : $scope.events.placable.training.name;
|
||||
$scope.events.placable.backgroundColor = 'white';
|
||||
$scope.events.placable.borderColor = $scope.events.modifiable.borderColor;
|
||||
$scope.events.placable.id = $scope.events.modifiable.id;
|
||||
$scope.events.placable.is_reserved = true;
|
||||
$scope.events.placable.can_modify = true;
|
||||
const save = {
|
||||
slotId: $scope.events.modifiable.slot_id,
|
||||
borderColor: $scope.events.modifiable.borderColor,
|
||||
title: !AuthService.isAuthorized(['admin', 'manager']) ? $scope.events.placable.training.name + ' - ' + _t('app.logged.trainings_reserve.i_ve_reserved') : $scope.events.placable.training.name,
|
||||
};
|
||||
|
||||
$scope.events.modifiable.backgroundColor = 'white';
|
||||
$scope.events.modifiable.title = $scope.events.modifiable.training.name;
|
||||
$scope.events.modifiable.borderColor = FREE_SLOT_BORDER_COLOR;
|
||||
$scope.events.modifiable.id = null;
|
||||
$scope.events.modifiable.slot_id = null;
|
||||
$scope.events.modifiable.is_reserved = false;
|
||||
$scope.events.modifiable.can_modify = false;
|
||||
if ($scope.events.modifiable.is_completed) { $scope.events.modifiable.is_completed = false; }
|
||||
updateEvents($scope.events.modifiable);
|
||||
|
||||
return updateCalendar();
|
||||
$scope.events.placable.title = save.title;
|
||||
$scope.events.placable.backgroundColor = 'white';
|
||||
$scope.events.placable.borderColor = save.borderColor;
|
||||
$scope.events.placable.slot_id = save.slotId;
|
||||
$scope.events.placable.is_reserved = true;
|
||||
$scope.events.placable.can_modify = true;
|
||||
updateEvents($scope.events.placable);
|
||||
|
||||
refetchCalendar();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -262,7 +274,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
|
||||
$scope.events.modifiable.title = $scope.currentUser.role !== 'admin' ? $scope.events.modifiable.training.name + ' - ' + _t('app.logged.trainings_reserve.i_ve_reserved') : $scope.events.modifiable.training.name;
|
||||
$scope.events.modifiable.backgroundColor = 'white';
|
||||
|
||||
return updateCalendar();
|
||||
updateEvents($scope.events.placable, $scope.events.modifiable);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -326,12 +338,15 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
|
||||
* @param reservation {Object}
|
||||
*/
|
||||
$scope.afterPayment = function (reservation) {
|
||||
$scope.events.paid[0].backgroundColor = 'white';
|
||||
$scope.events.paid[0].is_reserved = true;
|
||||
$scope.events.paid[0].can_modify = true;
|
||||
updateTrainingSlotId($scope.events.paid[0], reservation);
|
||||
$scope.events.paid[0].borderColor = '#b2e774';
|
||||
$scope.events.paid[0].title = $scope.events.paid[0].training.name + ' - ' + _t('app.logged.trainings_reserve.i_ve_reserved');
|
||||
angular.forEach($scope.events.paid, function (trainingSlot, key) {
|
||||
trainingSlot.backgroundColor = 'white';
|
||||
trainingSlot.is_reserved = true;
|
||||
trainingSlot.can_modify = true;
|
||||
updateTrainingSlotId(trainingSlot, reservation);
|
||||
trainingSlot.borderColor = '#b2e774';
|
||||
trainingSlot.title = trainingSlot.training.name + ' - ' + _t('app.logged.trainings_reserve.i_ve_reserved');
|
||||
updateEvents(trainingSlot);
|
||||
});
|
||||
|
||||
if ($scope.selectedPlan) {
|
||||
$scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);
|
||||
@ -344,7 +359,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
|
||||
Auth._currentUser.training_credits = angular.copy(reservation.user.training_credits);
|
||||
Auth._currentUser.machine_credits = angular.copy(reservation.user.machine_credits);
|
||||
|
||||
return refetchCalendar();
|
||||
refetchCalendar();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -361,6 +376,16 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
|
||||
if ($scope.currentUser.role !== 'admin') {
|
||||
return Member.get({ id: $scope.currentUser.id }, function (member) { $scope.ctrl.member = member; });
|
||||
}
|
||||
// we load the availabilities from a callback function of the $scope.eventSources, instead of resolving a promise
|
||||
// in the router because this allows to refetchEvents from fullCalendar API.
|
||||
$scope.eventSources.push({
|
||||
events: function (start, end, timezone, callback) {
|
||||
Availability.trainings({ trainingId: $stateParams.id }, function (availabilities) {
|
||||
callback(availabilities);
|
||||
});
|
||||
},
|
||||
textColor: 'black'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -370,7 +395,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
|
||||
* if it's too late).
|
||||
* @see http://fullcalendar.io/docs/mouse/eventClick/
|
||||
*/
|
||||
var calendarEventClickCb = function (event, jsEvent, view) {
|
||||
const calendarEventClickCb = function (event, jsEvent, view) {
|
||||
$scope.selectedEvent = event;
|
||||
if ($stateParams.id === 'all') {
|
||||
$scope.training = event.training;
|
||||
@ -383,7 +408,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
|
||||
* Append the event tag into the block, just after the event title.
|
||||
* @see http://fullcalendar.io/docs/event_rendering/eventRender/
|
||||
*/
|
||||
var eventRenderCb = function (event, element, view) {
|
||||
const eventRenderCb = function (event, element, view) {
|
||||
if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) {
|
||||
let html = '';
|
||||
for (let tag of Array.from(event.tags)) {
|
||||
@ -399,27 +424,29 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
|
||||
* @param slot {Object}
|
||||
* @param reservation {Object}
|
||||
*/
|
||||
var updateTrainingSlotId = function (slot, reservation) {
|
||||
const updateTrainingSlotId = function (slot, reservation) {
|
||||
angular.forEach(reservation.slots, function (s) {
|
||||
if (slot.start_at === slot.start_at) {
|
||||
return slot.id = s.id;
|
||||
if (slot.start.isSame(s.start_at)) {
|
||||
return slot.slot_id = s.id;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the calendar's display to render the new attributes of the events
|
||||
* @param events Object[] events to update in full-calendar
|
||||
*/
|
||||
var updateCalendar = function () { uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents'); };
|
||||
const updateEvents = function (...events) {
|
||||
const realEvents = events.filter(e => !_.isNil(e));
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('updateEvents', realEvents);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Asynchronously fetch the events from the API and refresh the calendar's view with these new events
|
||||
*/
|
||||
var refetchCalendar = function () {
|
||||
$timeout(function () {
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');
|
||||
return uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents');
|
||||
});
|
||||
const refetchCalendar = function () {
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');
|
||||
};
|
||||
|
||||
// !!! MUST BE CALLED AT THE END of the controller
|
@ -10,7 +10,7 @@
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', 'growl', 'Auth', 'Price', 'Wallet', 'CustomAsset', 'Slot', 'AuthService', 'helpers', '_t',
|
||||
Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', 'growl', 'Auth', 'Price', 'Wallet', 'CustomAsset', 'Slot', 'AuthService', 'helpers', '_t',
|
||||
function ($rootScope, $uibModal, dialogs, growl, Auth, Price, Wallet, CustomAsset, Slot, AuthService, helpers, _t) {
|
||||
return ({
|
||||
restrict: 'E',
|
||||
@ -28,7 +28,6 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
onSlotAddedToCart: '=',
|
||||
onSlotRemovedFromCart: '=',
|
||||
onSlotStartToModify: '=',
|
||||
onSlotModifyDestination: '=',
|
||||
onSlotModifySuccess: '=',
|
||||
onSlotModifyCancel: '=',
|
||||
onSlotModifyUnselect: '=',
|
||||
@ -39,7 +38,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
reservableName: '@',
|
||||
limitToOneSlot: '@'
|
||||
},
|
||||
templateUrl: '<%= asset_path "shared/_cart.html" %>',
|
||||
templateUrl: '/shared/_cart.html',
|
||||
link ($scope, element, attributes) {
|
||||
// will store the user's plan if he choosed to buy one
|
||||
$scope.selectedPlan = null;
|
||||
@ -78,8 +77,8 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
validateSameTimeReservations(slot, function () {
|
||||
slot.isValid = true;
|
||||
updateCartPrice();
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -121,15 +120,15 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
// first, we ensure that a user was selected (admin/manager) or logged (member)
|
||||
const isSelectedUser = Object.keys($scope.user).length > 0;
|
||||
// all slots are in future
|
||||
const areFutureSlots = _.every($scope.events.reserved, function(s) {
|
||||
const areFutureSlots = _.every($scope.events.reserved, function (s) {
|
||||
return s.start.isAfter();
|
||||
});
|
||||
if (isSelectedUser && areFutureSlots) {
|
||||
return $scope.modePlans = true;
|
||||
} else if (!isSelectedUser){
|
||||
} else if (!isSelectedUser) {
|
||||
// otherwise we alert, this error musn't occur when the current user hasn't the admin role
|
||||
return growl.error(_t('app.shared.cart.please_select_a_member_first'));
|
||||
} else if (!areFutureSlots){
|
||||
} else if (!areFutureSlots) {
|
||||
return growl.error(_t('app.shared.cart.unable_to_select_plan_if_slots_in_the_past'));
|
||||
}
|
||||
};
|
||||
@ -140,7 +139,6 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
$scope.payCart = function () {
|
||||
// first, we check that a user was selected
|
||||
if (Object.keys($scope.user).length > 0) {
|
||||
|
||||
// check selected user has a subscription, if any slot is restricted for subscriptions
|
||||
const slotValidations = [];
|
||||
let slotNotValid;
|
||||
@ -148,16 +146,16 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
$scope.events.reserved.forEach(function (slot) {
|
||||
if (slot.plan_ids.length > 0) {
|
||||
if (
|
||||
($scope.selectedPlan && _.include(slot.plan_ids, $scope.selectedPlan.id)) ||
|
||||
($scope.user.subscribed_plan && _.include(slot.plan_ids, $scope.user.subscribed_plan.id))
|
||||
($scope.selectedPlan && _.includes(slot.plan_ids, $scope.selectedPlan.id)) ||
|
||||
($scope.user.subscribed_plan && _.includes(slot.plan_ids, $scope.user.subscribed_plan.id))
|
||||
) {
|
||||
slotValidations.push(true);
|
||||
} else {
|
||||
slotNotValid = slot;
|
||||
if ($scope.selectedPlan && !_.include(slot.plan_ids, $scope.selectedPlan.id)) {
|
||||
if ($scope.selectedPlan && !_.includes(slot.plan_ids, $scope.selectedPlan.id)) {
|
||||
slotNotValidError = 'selectedPlanError';
|
||||
}
|
||||
if ($scope.user.subscribed_plan && !_.include(slot.plan_ids, $scope.user.subscribed_plan.id)) {
|
||||
if ($scope.user.subscribed_plan && !_.includes(slot.plan_ids, $scope.user.subscribed_plan.id)) {
|
||||
slotNotValidError = 'userPlanError';
|
||||
}
|
||||
if (!$scope.selectedPlan || !$scope.user.subscribed_plan) {
|
||||
@ -174,15 +172,15 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
} else {
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "shared/_reserve_slot_without_plan.html" %>',
|
||||
templateUrl: '/shared/_reserve_slot_without_plan.html',
|
||||
size: 'md',
|
||||
controller: 'ReserveSlotWithoutPlanController',
|
||||
resolve: {
|
||||
slot: function() { return slotNotValid; },
|
||||
slotNotValidError: function() { return slotNotValidError; },
|
||||
slot: function () { return slotNotValid; },
|
||||
slotNotValidError: function () { return slotNotValidError; }
|
||||
}
|
||||
});
|
||||
modalInstance.result.then(function(res) {
|
||||
modalInstance.result.then(function (res) {
|
||||
return paySlots();
|
||||
});
|
||||
}
|
||||
@ -199,7 +197,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
* When modifying an already booked reservation, confirm the modification.
|
||||
*/
|
||||
$scope.modifySlot = function () {
|
||||
Slot.update({ id: $scope.events.modifiable.id }, {
|
||||
Slot.update({ id: $scope.events.modifiable.slot_id }, {
|
||||
slot: {
|
||||
start_at: $scope.events.placable.start,
|
||||
end_at: $scope.events.placable.end,
|
||||
@ -216,23 +214,23 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
};
|
||||
// -> reset the 'moving' status
|
||||
$scope.events.placable = null;
|
||||
return $scope.events.modifiable = null;
|
||||
$scope.events.modifiable = null;
|
||||
}
|
||||
, function (err) { // failure
|
||||
growl.error(_t('app.shared.cart.unable_to_change_the_reservation'));
|
||||
return console.error(err);
|
||||
console.error(err);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel the current booking modification, reseting the whole process
|
||||
* @param event {Object} see https://docs.angularjs.org/guide/expression#-event-
|
||||
* @param [event] {Object} see https://docs.angularjs.org/guide/expression#-event-
|
||||
*/
|
||||
$scope.cancelModifySlot = function (event) {
|
||||
if (event) { event.preventDefault(); }
|
||||
if (typeof $scope.onSlotModifyCancel === 'function') { $scope.onSlotModifyCancel(); }
|
||||
$scope.events.placable = null;
|
||||
return $scope.events.modifiable = null;
|
||||
$scope.events.modifiable = null;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -242,7 +240,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
$scope.removeSlotToPlace = function (e) {
|
||||
e.preventDefault();
|
||||
if (typeof $scope.onSlotModifyUnselect === 'function') { $scope.onSlotModifyUnselect(); }
|
||||
return $scope.events.placable = null;
|
||||
$scope.events.placable = null;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -251,7 +249,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
*/
|
||||
$scope.tagMissmatch = function () {
|
||||
if ($scope.events.placable.tag_ids.length === 0) { return false; }
|
||||
for (let tag of Array.from($scope.events.modifiable.tags)) {
|
||||
for (const tag of Array.from($scope.events.modifiable.tags)) {
|
||||
if (!Array.from($scope.events.placable.tag_ids).includes(tag.id)) {
|
||||
return true;
|
||||
}
|
||||
@ -271,7 +269,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
@ -318,20 +316,20 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
// ask confirmation
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "shared/_reserve_slot_tags_mismatch.html" %>',
|
||||
templateUrl: '/shared/_reserve_slot_tags_mismatch.html',
|
||||
size: 'md',
|
||||
controller: 'ReserveSlotTagsMismatchController',
|
||||
resolve: {
|
||||
slotTags: function() { return slot.tags; },
|
||||
slotTags: function () { return slot.tags; },
|
||||
userTags: function () { return $scope.user.tags; },
|
||||
userName: function () { return $scope.user.name; }
|
||||
}
|
||||
});
|
||||
modalInstance.result.then(function(res) {
|
||||
modalInstance.result.then(function (res) {
|
||||
if (typeof callback === 'function') callback(res);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates that no other reservations were made that conflict the current slot and alert the user about the conflict.
|
||||
@ -346,32 +344,32 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
'space_reservations',
|
||||
'events_reservations'
|
||||
].map(function (k) {
|
||||
return _.filter($scope.user[k], function(r) {
|
||||
return _.filter($scope.user[k], function (r) {
|
||||
return slot.start.isSame(r.start_at) ||
|
||||
(slot.end.isAfter(r.start_at) && slot.end.isBefore(r.end_at)) ||
|
||||
(slot.start.isAfter(r.start_at) && slot.start.isBefore(r.end_at)) ||
|
||||
(slot.start.isBefore(r.start_at) && slot.end.isAfter(r.end_at));
|
||||
})
|
||||
});
|
||||
});
|
||||
sameTimeReservations = _.union.apply(null, sameTimeReservations);
|
||||
if (sameTimeReservations.length > 0) {
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "shared/_reserve_slot_same_time.html" %>',
|
||||
templateUrl: '/shared/_reserve_slot_same_time.html',
|
||||
size: 'md',
|
||||
controller: 'ReserveSlotSameTimeController',
|
||||
resolve: {
|
||||
sameTimeReservations: function() { return sameTimeReservations; },
|
||||
sameTimeReservations: function () { return sameTimeReservations; },
|
||||
bookOverlappingSlotsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'book_overlapping_slots' }).$promise; }]
|
||||
}
|
||||
});
|
||||
modalInstance.result.then(function(res) {
|
||||
modalInstance.result.then(function (res) {
|
||||
if (typeof callback === 'function') callback(res);
|
||||
});
|
||||
} else {
|
||||
if (typeof callback === 'function') callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback triggered when the selected slot changed
|
||||
@ -381,13 +379,13 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
// if this slot is restricted for subscribers...
|
||||
if ($scope.slot.plan_ids.length > 0) {
|
||||
// ... we select all the plans matching these restrictions...
|
||||
const _plans = _.filter($scope.plans, function (p) { return _.include($scope.slot.plan_ids, p.id) });
|
||||
const _plans = _.filter($scope.plans, function (p) { return _.includes($scope.slot.plan_ids, p.id); });
|
||||
// ... and we group these plans, by Group...
|
||||
$scope.slot.plansGrouped = [];
|
||||
$scope.slot.group_ids = [];
|
||||
for (let group of Array.from($scope.groups)) {
|
||||
for (const group of Array.from($scope.groups)) {
|
||||
const groupObj = { id: group.id, name: group.name, plans: [] };
|
||||
for (let plan of Array.from(_plans)) {
|
||||
for (const plan of Array.from(_plans)) {
|
||||
if (plan.group_id === group.id) { groupObj.plans.push(plan); }
|
||||
}
|
||||
if (groupObj.plans.length > 0) {
|
||||
@ -400,13 +398,13 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
}
|
||||
}
|
||||
}
|
||||
$scope.slot.group_ids = $scope.slot.plansGrouped.map(function(g) { return g.id; });
|
||||
$scope.slot.group_ids = $scope.slot.plansGrouped.map(function (g) { return g.id; });
|
||||
}
|
||||
|
||||
if (!$scope.slot.is_reserved && !$scope.events.modifiable && !$scope.slot.is_completed) {
|
||||
// slot is not reserved and we are not currently modifying a slot
|
||||
// -> can be added to cart or removed if already present
|
||||
const index = $scope.events.reserved.indexOf($scope.slot);
|
||||
const index = _.findIndex($scope.events.reserved, (e) => e._id === $scope.slot._id);
|
||||
if (index === -1) {
|
||||
if (($scope.limitToOneSlot === 'true') && $scope.events.reserved[0]) {
|
||||
// if we limit the number of slots in the cart to 1, and there is already
|
||||
@ -427,7 +425,11 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
} else if (!$scope.slot.is_reserved && !$scope.slot.is_completed && $scope.events.modifiable) {
|
||||
// slot is not reserved but we are currently modifying a slot
|
||||
// -> we request the calender to change the rendering
|
||||
if (typeof $scope.onSlotModifyUnselect === 'function') { $scope.onSlotModifyUnselect(); }
|
||||
if (typeof $scope.onSlotModifyUnselect === 'function') {
|
||||
// if the callback return false, cancel the selection for the current modification
|
||||
const res = $scope.onSlotModifyUnselect();
|
||||
if (!res) return;
|
||||
}
|
||||
// -> then, we re-affect the destination slot
|
||||
if (!$scope.events.placable || ($scope.events.placable._id !== $scope.slot._id)) {
|
||||
return $scope.events.placable = $scope.slot;
|
||||
@ -437,17 +439,17 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
} else if ($scope.slot.is_reserved && $scope.events.modifiable && ($scope.slot.is_reserved._id === $scope.events.modifiable._id)) {
|
||||
// slot is reserved and currently modified
|
||||
// -> we cancel the modification
|
||||
return $scope.cancelModifySlot();
|
||||
$scope.cancelModifySlot();
|
||||
} else if ($scope.slot.is_reserved && (slotCanBeModified($scope.slot) || slotCanBeCanceled($scope.slot)) && !$scope.events.modifiable && ($scope.events.reserved.length === 0)) {
|
||||
// slot is reserved and is ok to be modified or cancelled
|
||||
// but we are not currently running a modification or having any slots in the cart
|
||||
// -> first the affect the modification/cancellation rights attributes to the current slot
|
||||
// -> first affect the modification/cancellation rights attributes to the current slot
|
||||
resetCartState();
|
||||
$scope.slot.movable = slotCanBeModified($scope.slot);
|
||||
$scope.slot.cancelable = slotCanBeCanceled($scope.slot);
|
||||
// -> then, we open a dialog to ask to the user to choose an action
|
||||
return dialogs.confirm({
|
||||
templateUrl: '<%= asset_path "shared/confirm_modify_slot_modal.html" %>',
|
||||
templateUrl: '/shared/confirm_modify_slot_modal.html',
|
||||
resolve: {
|
||||
object () { return $scope.slot; }
|
||||
}
|
||||
@ -456,9 +458,9 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
// the user has chosen an action, so we proceed
|
||||
if (type === 'move') {
|
||||
if (typeof $scope.onSlotStartToModify === 'function') { $scope.onSlotStartToModify(); }
|
||||
return $scope.events.modifiable = $scope.slot;
|
||||
$scope.events.modifiable = $scope.slot;
|
||||
} else if (type === 'cancel') {
|
||||
return dialogs.confirm(
|
||||
dialogs.confirm(
|
||||
{
|
||||
resolve: {
|
||||
object () {
|
||||
@ -470,7 +472,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
}
|
||||
},
|
||||
function () { // cancel confirmed
|
||||
Slot.cancel({ id: $scope.slot.id }, function () { // successfully canceled
|
||||
Slot.cancel({ id: $scope.slot.slot_id }, function () { // successfully canceled
|
||||
growl.success(_t('app.shared.cart.reservation_was_cancelled_successfully'));
|
||||
if (typeof $scope.onSlotCancelSuccess === 'function') { return $scope.onSlotCancelSuccess(); }
|
||||
}
|
||||
@ -494,7 +496,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
$scope.events.moved = null;
|
||||
$scope.events.paid = [];
|
||||
$scope.events.modifiable = null;
|
||||
return $scope.events.placable = null;
|
||||
$scope.events.placable = null;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -612,7 +614,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
*/
|
||||
const payByStripe = function (reservation) {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "stripe/payment_modal.html" %>',
|
||||
templateUrl: '/stripe/payment_modal.html',
|
||||
size: 'md',
|
||||
resolve: {
|
||||
reservation () {
|
||||
@ -666,14 +668,14 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
};
|
||||
}
|
||||
]
|
||||
}).result['finally'](null).then(function (reservation) { afterPayment(reservation); });
|
||||
}).result.finally(null).then(function (reservation) { afterPayment(reservation); });
|
||||
};
|
||||
/**
|
||||
* Open a modal window that allows the user to process a local payment for his current shopping cart (admin only).
|
||||
*/
|
||||
const payOnSite = function (reservation) {
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "shared/valid_reservation_modal.html" %>',
|
||||
templateUrl: '/shared/valid_reservation_modal.html',
|
||||
size: 'sm',
|
||||
resolve: {
|
||||
reservation () {
|
||||
@ -735,7 +737,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
||||
}
|
||||
]
|
||||
}).result['finally'](null).then(function (reservation) { afterPayment(reservation); });
|
||||
}).result.finally(null).then(function (reservation) { afterPayment(reservation); });
|
||||
};
|
||||
/**
|
||||
* Actions to run after the payment was successful
|
||||
@ -756,22 +758,22 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
/**
|
||||
* Actions to pay slots
|
||||
*/
|
||||
const paySlots = function() {
|
||||
const paySlots = function () {
|
||||
const reservation = mkReservation($scope.user, $scope.events.reserved, $scope.selectedPlan);
|
||||
|
||||
return Wallet.getWalletByUser({ user_id: $scope.user.id }, function (wallet) {
|
||||
const amountToPay = helpers.getAmountToPay($scope.amountTotal, wallet.amount);
|
||||
if ((AuthService.isAuthorized(['member']) && amountToPay > 0)
|
||||
|| (AuthService.isAuthorized('manager') && $scope.user.id === $rootScope.currentUser.id && amountToPay > 0)) {
|
||||
if ((AuthService.isAuthorized(['member']) && amountToPay > 0) ||
|
||||
(AuthService.isAuthorized('manager') && $scope.user.id === $rootScope.currentUser.id && amountToPay > 0)) {
|
||||
if ($scope.settings.online_payment_module !== 'true') {
|
||||
growl.error(_t('app.shared.cart.online_payment_disabled'));
|
||||
} else {
|
||||
return payByStripe(reservation);
|
||||
}
|
||||
} else {
|
||||
if (AuthService.isAuthorized(['admin'])
|
||||
|| (AuthService.isAuthorized('manager') && $scope.user.id !== $rootScope.currentUser.id)
|
||||
|| amountToPay === 0) {
|
||||
if (AuthService.isAuthorized(['admin']) ||
|
||||
(AuthService.isAuthorized('manager') && $scope.user.id !== $rootScope.currentUser.id) ||
|
||||
amountToPay === 0) {
|
||||
return payOnSite(reservation);
|
||||
}
|
||||
}
|
||||
@ -798,17 +800,16 @@ Application.Controllers.controller('ReserveSlotSameTimeController', ['$scope', '
|
||||
*/
|
||||
$scope.ok = function () {
|
||||
$uibModalInstance.close({});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Cancellation callback
|
||||
*/
|
||||
$scope.cancel = function () {
|
||||
$uibModalInstance.dismiss('cancel');
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* Controller of the modal showing the slot tags
|
||||
*/
|
||||
@ -823,13 +824,13 @@ Application.Controllers.controller('ReserveSlotTagsMismatchController', ['$scope
|
||||
*/
|
||||
$scope.ok = function () {
|
||||
$uibModalInstance.close({});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Cancellation callback
|
||||
*/
|
||||
$scope.cancel = function () {
|
||||
$uibModalInstance.dismiss('cancel');
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
@ -845,12 +846,12 @@ Application.Controllers.controller('ReserveSlotWithoutPlanController', ['$scope'
|
||||
*/
|
||||
$scope.ok = function () {
|
||||
$uibModalInstance.close({});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Cancellation callback
|
||||
*/
|
||||
$scope.cancel = function () {
|
||||
$uibModalInstance.dismiss('cancel');
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
@ -18,7 +18,7 @@ Application.Directives.directive('coupon', [ '$rootScope', 'Coupon', '_t', funct
|
||||
total: '=',
|
||||
userId: '@'
|
||||
},
|
||||
templateUrl: '<%= asset_path "shared/_coupon.html" %>',
|
||||
templateUrl: '/shared/_coupon.html',
|
||||
link ($scope, element, attributes) {
|
||||
// Whether code input is shown or not (ie. the link 'I have a coupon' is shown)
|
||||
$scope.code =
|
@ -15,6 +15,6 @@ Application.Directives.directive('fabUserAvatar', [ function () {
|
||||
userAvatar: '=ngModel',
|
||||
avatarClass: '@'
|
||||
},
|
||||
templateUrl: '<%= asset_path "shared/_user_avatar.html" %>'
|
||||
templateUrl: '/shared/_user_avatar.html'
|
||||
});
|
||||
}]);
|
@ -2,7 +2,7 @@ Application.Directives.directive('events', [ 'Event',
|
||||
function (Event) {
|
||||
return ({
|
||||
restrict: 'E',
|
||||
templateUrl: '<%= asset_path "home/events.html" %>',
|
||||
templateUrl: '/home/events.html',
|
||||
link ($scope, element, attributes) {
|
||||
// The closest upcoming events
|
||||
$scope.upcomingEvents = null;
|
@ -2,7 +2,7 @@ Application.Directives.directive('news', [ 'Setting',
|
||||
function (Setting) {
|
||||
return ({
|
||||
restrict: 'E',
|
||||
templateUrl: '<%= asset_path "home/news.html" %>',
|
||||
templateUrl: '/home/news.html',
|
||||
link ($scope, element, attributes) {
|
||||
// The admin blogpost
|
||||
$scope.homeBlogpost = null;
|
@ -2,7 +2,7 @@ Application.Directives.directive('projects', [ 'Project',
|
||||
function (Project) {
|
||||
return ({
|
||||
restrict: 'E',
|
||||
templateUrl: '<%= asset_path "home/projects.html" %>',
|
||||
templateUrl: '/home/projects.html',
|
||||
link ($scope, element, attributes) {
|
||||
// The last projects published/documented on the platform
|
||||
$scope.lastProjects = null;
|
@ -8,7 +8,7 @@ Application.Directives.directive('twitter', ['Setting',
|
||||
function (Setting) {
|
||||
return ({
|
||||
restrict: 'E',
|
||||
templateUrl: '<%= asset_path "home/twitter.html" %>',
|
||||
templateUrl: '/home/twitter.html',
|
||||
link ($scope, element, attributes) {
|
||||
// Twitter username
|
||||
$scope.twitterName = null;
|
@ -2,7 +2,7 @@ Application.Directives.directive('members', [ 'Member',
|
||||
function (Member) {
|
||||
return ({
|
||||
restrict: 'E',
|
||||
templateUrl: '<%= asset_path "home/members.html" %>',
|
||||
templateUrl: '/home/members.html',
|
||||
link ($scope, element, attributes) {
|
||||
// The last registered members who confirmed their addresses
|
||||
$scope.lastMembers = null;
|
@ -11,7 +11,7 @@
|
||||
Application.Directives.directive('selectMember', [ 'Diacritics', 'Member', function (Diacritics, Member) {
|
||||
return ({
|
||||
restrict: 'E',
|
||||
templateUrl: '<%= asset_path "shared/_member_select.html" %>',
|
||||
templateUrl: '/shared/_member_select.html',
|
||||
link (scope, element, attributes) {
|
||||
return scope.autoCompleteName = function (nameLookup) {
|
||||
if (!nameLookup) {
|
@ -11,7 +11,7 @@ Application.Directives.directive('booleanSetting', ['Setting', 'growl', '_t',
|
||||
classes: '@',
|
||||
onBeforeSave: '='
|
||||
},
|
||||
templateUrl: '<%= asset_path "admin/settings/boolean.html" %>',
|
||||
templateUrl: '/admin/settings/boolean.html',
|
||||
link ($scope, element, attributes) {
|
||||
// The setting
|
||||
$scope.setting = {
|
||||
@ -20,8 +20,8 @@ Application.Directives.directive('booleanSetting', ['Setting', 'growl', '_t',
|
||||
};
|
||||
|
||||
// default values for the switch labels
|
||||
$scope.yesLabel = $scope.yesLabel || 'app.admin.settings.enabled';
|
||||
$scope.noLabel = $scope.noLabel || 'app.admin.settings.disabled';
|
||||
$scope.yesLabel = $scope.yesLabel || 'app.shared.buttons.yes';
|
||||
$scope.noLabel = $scope.noLabel || 'app.shared.buttons.no';
|
||||
|
||||
/**
|
||||
* Callback to save the setting value to the database
|
@ -12,7 +12,7 @@ Application.Directives.directive('numberSetting', ['Setting', 'growl', '_t',
|
||||
min: '@',
|
||||
required: '<'
|
||||
},
|
||||
templateUrl: '<%= asset_path "admin/settings/number.html" %>',
|
||||
templateUrl: '/admin/settings/number.html',
|
||||
link ($scope, element, attributes) {
|
||||
// The setting
|
||||
$scope.setting = {
|
@ -12,7 +12,7 @@ Application.Directives.directive('selectMultipleSetting', ['Setting', 'growl', '
|
||||
descriptionNew: '@',
|
||||
beforeAdd: '='
|
||||
},
|
||||
templateUrl: '<%= asset_path "admin/settings/select-multiple.html" %>',
|
||||
templateUrl: '/admin/settings/select-multiple.html',
|
||||
link ($scope, element, attributes) {
|
||||
// The setting
|
||||
$scope.setting = {
|
||||
@ -29,22 +29,22 @@ Application.Directives.directive('selectMultipleSetting', ['Setting', 'growl', '
|
||||
/**
|
||||
* Remove the items in the selection from the options and update setting.value
|
||||
*/
|
||||
$scope.removeItem = function() {
|
||||
$scope.removeItem = function () {
|
||||
const options = $scope.options.filter(function (opt) {
|
||||
return $scope.selection.indexOf(opt) < 0;
|
||||
})
|
||||
});
|
||||
$scope.options = options;
|
||||
$scope.setting.value = options.join(' ');
|
||||
growl.success(_t('app.admin.settings.COUNT_items_removed', { COUNT: $scope.selection.length }));
|
||||
$scope.selection = [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Open a modal dialog asking for the value of a new item to add
|
||||
*/
|
||||
$scope.addItem = function() {
|
||||
$scope.addItem = function () {
|
||||
$uibModal.open({
|
||||
templateUrl: 'newSelectOption.html',
|
||||
templateUrl: '/admin/settings/newSelectOption.html',
|
||||
resolve: {
|
||||
titleNew: function () { return $scope.titleNew; },
|
||||
descriptionNew: function () { return $scope.descriptionNew; }
|
||||
@ -60,7 +60,7 @@ Application.Directives.directive('selectMultipleSetting', ['Setting', 'growl', '
|
||||
$uibModalInstance.dismiss('cancel');
|
||||
};
|
||||
}
|
||||
}).result['finally'](null).then(function(val) {
|
||||
}).result.finally(null).then(function (val) {
|
||||
const options = Array.from($scope.options);
|
||||
if (typeof $scope.beforeAdd === 'function') { val = $scope.beforeAdd(val); }
|
||||
options.push(val);
|
||||
@ -68,14 +68,14 @@ Application.Directives.directive('selectMultipleSetting', ['Setting', 'growl', '
|
||||
$scope.setting.value = options.join(' ');
|
||||
growl.success(_t('app.admin.settings.item_added'));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback to save the setting value to the database
|
||||
* @param setting {{value:*, name:string}} note that the value will be stringified
|
||||
*/
|
||||
$scope.save = function (setting) {
|
||||
let { value } = setting;
|
||||
const { value } = setting;
|
||||
|
||||
Setting.update(
|
||||
{ name: setting.name },
|
@ -14,7 +14,7 @@ Application.Directives.directive('selectSetting', ['Setting', 'growl', '_t',
|
||||
option4: '<',
|
||||
option5: '<'
|
||||
},
|
||||
templateUrl: '<%= asset_path "admin/settings/select.html" %>',
|
||||
templateUrl: '/admin/settings/select.html',
|
||||
link ($scope, element, attributes) {
|
||||
// The setting
|
||||
$scope.setting = {
|
@ -15,7 +15,7 @@ Application.Directives.directive('textSetting', ['Setting', 'growl', '_t',
|
||||
minLength: '@',
|
||||
readOnly: '<'
|
||||
},
|
||||
templateUrl: '<%= asset_path "admin/settings/text.html" %>',
|
||||
templateUrl: '/admin/settings/text.html',
|
||||
link ($scope, element, attributes) {
|
||||
// if type is not specified, use text as default
|
||||
if (typeof $scope.type === 'undefined') {
|
@ -16,13 +16,13 @@ Application.Directives.directive('socialLink', [ function () {
|
||||
network: '@?',
|
||||
user: '='
|
||||
},
|
||||
templateUrl: '<%= asset_path "shared/_social_link.html" %>',
|
||||
templateUrl: '/shared/_social_link.html',
|
||||
link (scope, element, attributes) {
|
||||
if (scope.network === 'dailymotion') {
|
||||
scope.image = "<%= asset_path('social/dailymotion.png') %>";
|
||||
scope.image = "social/dailymotion.png";
|
||||
return scope.altText = 'd';
|
||||
} else if (scope.network === 'echosciences') {
|
||||
scope.image = "<%= asset_path('social/echosciences.png') %>";
|
||||
scope.image = "social/echosciences.png";
|
||||
return scope.altText = 'E)';
|
||||
} else {
|
||||
if (scope.network === 'website') {
|