1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-12-12 23:09:03 +01:00
fab-manager/app/assets/javascripts/controllers/admin/events.coffee.erb
2016-08-25 13:56:07 +02:00

496 lines
15 KiB
Plaintext

'use strict'
### COMMON CODE ###
##
# Provides a set of common properties and methods to the $scope parameter. They are used
# in the various events' admin controllers.
#
# Provides :
# - $scope.datePicker = {}
# - $scope.submited(content)
# - $scope.cancel()
# - $scope.addFile()
# - $scope.deleteFile(file)
# - $scope.fileinputClass(v)
# - $scope.toggleStartDatePicker($event)
# - $scope.toggleEndDatePicker($event)
# - $scope.toggleRecurrenceEnd(e)
#
# Requires :
# - $scope.event.event_files_attributes = []
# - $state (Ui-Router) [ 'app.public.events_list' ]
##
class EventsController
constructor: ($scope, $state) ->
## default parameters for AngularUI-Bootstrap datepicker
$scope.datePicker =
format: Fablab.uibDateFormat
startOpened: false # default: datePicker is not shown
endOpened: false
recurrenceEndOpened: false
options:
startingDay: Fablab.weekStartingDay
##
# For use with ngUpload (https://github.com/twilson63/ngUpload).
# Intended to be the callback when an upload is done: any raised error will be stacked in the
# $scope.alerts array. If everything goes fine, the user is redirected to the project page.
# @param content {Object} JSON - The upload's result
##
$scope.submited = (content) ->
if !content.id?
$scope.alerts = []
angular.forEach content, (v, k)->
angular.forEach v, (err)->
$scope.alerts.push({msg: k+': '+err, type: 'danger'})
else
$state.go('app.public.events_list')
##
# Changes the user's view to the events list page
##
$scope.cancel = ->
$state.go('app.public.events_list')
##
# For use with 'ng-class', returns the CSS class name for the uploads previews.
# The preview may show a placeholder or the content of the file depending on the upload state.
# @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)
##
$scope.fileinputClass = (v)->
if v
'fileinput-exists'
else
'fileinput-new'
##
# This will create a single new empty entry into the event's attachements list.
##
$scope.addFile = ->
$scope.event.event_files_attributes.push {}
##
# This will remove the given file from the event's attachements list. If the file was previously uploaded
# to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from
# the attachements array.
# @param file {Object} the file to delete
##
$scope.deleteFile = (file) ->
index = $scope.event.event_files_attributes.indexOf(file)
if file.id?
file._destroy = true
else
$scope.event.event_files_attributes.splice(index, 1)
##
# Show/Hide the "start" datepicker (open the drop down/close it)
##
$scope.toggleStartDatePicker = ($event) ->
$event.preventDefault()
$event.stopPropagation()
$scope.datePicker.startOpened = !$scope.datePicker.startOpened
##
# Show/Hide the "end" datepicker (open the drop down/close it)
##
$scope.toggleEndDatePicker = ($event) ->
$event.preventDefault()
$event.stopPropagation()
$scope.datePicker.endOpened = !$scope.datePicker.endOpened
##
# Masks/displays the recurrence pane allowing the admin to set the current event as recursive
##
$scope.toggleRecurrenceEnd = (e)->
e.preventDefault()
e.stopPropagation()
$scope.datePicker.recurrenceEndOpened = !$scope.datePicker.recurrenceEndOpened
##
# Initialize a new price item in the additional prices list
##
$scope.addPrice = ->
$scope.event.prices.push({
category: null,
amount: null,
})
##
# Controller used in the events listing page (admin view)
##
Application.Controllers.controller "AdminEventsController", ["$scope", "$state", 'dialogs', '$uibModal', 'growl', 'Event', 'Category', 'EventTheme', 'AgeRange', 'PriceCategory', 'eventsPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '_t'
, ($scope, $state, dialogs, $uibModal, growl, Event, Category, EventTheme, AgeRange, PriceCategory, eventsPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, _t) ->
### PUBLIC SCOPE ###
## By default, the pagination mode is activated to limit the page size
$scope.paginateActive = true
## The events displayed on the page
$scope.events = eventsPromise
## Current virtual page
$scope.page = 2
## Temporary datastore for creating new elements
$scope.inserted =
category: null
theme: null
age_range: null
## List of categories for the events
$scope.categories = categoriesPromise
## List of events themes
$scope.themes = themesPromise
## List of age ranges
$scope.ageRanges = ageRangesPromise
## List of price categories for the events
$scope.priceCategories = priceCategoriesPromise
##
# Adds a bucket of events to the bottom of the page, grouped by month
##
$scope.loadMoreEvents = ->
Event.query {page: $scope.page}, (data)->
$scope.events = $scope.events.concat data
paginationCheck(data, $scope.events)
$scope.page += 1
##
# Saves a new element / Update an existing one to the server (form validation callback)
# @param model {string} model name
# @param data {Object} element name
# @param [id] {number} element id, in case of update
##
$scope.saveElement = (model, data, id) ->
if id?
getModel(model)[0].update {id: id}, data
else
getModel(model)[0].save data, (resp)->
getModel(model)[1][getModel(model)[1].length-1].id = resp.id
##
# Deletes the element at the specified index
# @param model {string} model name
# @param index {number} element index in the $scope[model] array
##
$scope.removeElement = (model, index) ->
if model == 'category' and getModel(model)[1].length == 1
growl.error(_t('at_least_one_category_is_required')+' '+_t('unable_to_delete_the_last_one'))
return false
if getModel(model)[1][index].related_to > 0
growl.error(_t('unable_to_delete_ELEMENT_already_in_use_NUMBER_times', {ELEMENT:model, NUMBER:getModel(model)[1][index].related_to}, "messageformat"))
return false
dialogs.confirm
resolve:
object: ->
title: _t('confirmation_required')
msg: _t('do_you_really_want_to_delete_this_ELEMENT', {ELEMENT:model}, "messageformat")
, -> # delete confirmed
getModel(model)[0].delete getModel(model)[1][index], null, ->
getModel(model)[1].splice(index, 1)
, ->
growl.error(_t('unable_to_delete_an_error_occured'))
##
# Creates a new empty entry in the $scope[model] array
# @param model {string} model name
##
$scope.addElement = (model) ->
$scope.inserted[model] =
name: ''
related_to: 0
getModel(model)[1].push($scope.inserted[model])
##
# Removes the newly inserted but not saved element / Cancel the current element modification
# @param model {string} model name
# @param rowform {Object} see http://vitalets.github.io/angular-xeditable/
# @param index {number} element index in the $scope[model] array
##
$scope.cancelElement = (model, rowform, index) ->
if getModel(model)[1][index].id?
rowform.$cancel()
else
getModel(model)[1].splice(index, 1)
##
# Open a modal dialog allowing the definition of a new price category.
# Save it once filled and handle the result.
##
$scope.newPriceCategory = ->
$uibModal.open
templateUrl: '<%= asset_path "admin/events/price_form.html" %>'
size: 'md'
resolve:
category: -> {}
controller: 'PriceCategoryController'
.result['finally'](null).then (p_cat) ->
# save the price category to the API
PriceCategory.save p_cat, (cat) ->
$scope.priceCategories.push(cat)
growl.success(_t('price_category_successfully_created'))
, (err)->
growl.error(_t('unable_to_add_the_price_category_check_name_already_used'))
console.error(err)
##
# Update the given price category with the new properties
# to specify in a modal dialog
# @param index {number} index of the caterory in the $scope.priceCategories array
# @param id {number} price category ID, must match the ID of the category at the index specified above
##
$scope.editPriceCategory = (id, index) ->
if $scope.priceCategories[index].id != id
growl.error(_t('unexpected_error_occurred_please_refresh'))
else
$uibModal.open
templateUrl: '<%= asset_path "admin/events/price_form.html" %>'
size: 'md'
resolve:
category: -> $scope.priceCategories[index]
controller: 'PriceCategoryController'
.result['finally'](null).then (p_cat) ->
# update the price category to the API
PriceCategory.update {id: id}, {price_category: p_cat}, (cat) ->
$scope.priceCategories[index] = cat
growl.success(_t('price_category_successfully_updated'))
, (err)->
growl.error(_t('unable_to_update_the_price_category'))
console.error(err)
##
# Delete the given price category from the API
# @param index {number} index of the caterory in the $scope.priceCategories array
# @param id {number} price category ID, must match the ID of the category at the index specified above
##
$scope.removePriceCategory = (id, index) ->
if $scope.priceCategories[index].id != id
growl.error(_t('unexpected_error_occurred_please_refresh'))
else if $scope.priceCategories[index].events > 0
growl.error(_t('unable_to_delete_this_price_category_because_it_is_already_used'))
else
dialogs.confirm
resolve:
object: ->
title: _t('confirmation_required')
msg: _t('do_you_really_want_to_delete_this_price_category')
, -> # delete confirmed
PriceCategory.remove {id: id}, -> # successfully deleted
growl.success _t('price_category_successfully_deleted')
$scope.priceCategories.splice(index, 1)
, ->
growl.error _t('price_category_deletion_failed')
### PRIVATE SCOPE ###
##
# Kind of constructor: these actions will be realized first when the controller is loaded
##
initialize = ->
paginationCheck(eventsPromise, $scope.events)
##
# Check if all events are already displayed OR if the button 'load more events'
# is required
# @param lastEvents {Array} last events loaded onto the diplay (ie. last "page")
# @param events {Array} full list of events displayed on the page (not only the last retrieved)
##
paginationCheck = (lastEvents, events)->
if lastEvents.length > 0
$scope.paginateActive = false if events.length >= lastEvents[0].nb_total_events
else
$scope.paginateActive = false
##
# Return the model and the datastore matching the given name
# @param name {string} 'category', 'theme' or 'age_range'
# @return {[Object, Array]} model and datastore
##
getModel = (name) ->
switch name
when 'category' then [Category, $scope.categories]
when 'theme' then [EventTheme, $scope.themes]
when 'age_range' then [AgeRange, $scope.ageRanges]
else [null, []]
# init the controller (call at the end !)
initialize()
]
##
# Controller used in the reservations listing page for a specific event
##
Application.Controllers.controller "ShowEventReservationsController", ["$scope", 'eventPromise', 'reservationsPromise', ($scope, eventPromise, reservationsPromise) ->
## retrieve the event from the ID provided in the current URL
$scope.event = eventPromise
## list of reservations for the current event
$scope.reservations = reservationsPromise
]
##
# Controller used in the event creation page
##
Application.Controllers.controller "NewEventController", ["$scope", "$state", "$locale", 'CSRF', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '_t'
, ($scope, $state, $locale, CSRF, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, _t) ->
CSRF.setMetaTags()
## API URL where the form will be posted
$scope.actionUrl = "/api/events/"
## Form action on the above URL
$scope.method = 'post'
## List of categories for the events
$scope.categories = categoriesPromise
## List of events themes
$scope.themes = themesPromise
## List of age ranges
$scope.ageRanges = ageRangesPromise
## List of availables price's categories
$scope.priceCategories = priceCategoriesPromise
## Default event parameters
$scope.event =
event_files_attributes: []
start_date: new Date()
end_date: new Date()
start_time: new Date()
end_time: new Date()
all_day: 'false'
recurrence: 'none'
category_id: null
prices: []
## Possible types of recurrences for an event
$scope.recurrenceTypes = [
{label: _t('none'), value: 'none'},
{label: _t('every_days'), value: 'day'},
{label: _t('every_week'), value: 'week'},
{label: _t('every_month'), value: 'month'},
{label: _t('every_year'), value: 'year'}
]
## currency symbol for the current locale (cf. angular-i18n)
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM;
## Using the EventsController
new EventsController($scope, $state)
]
##
# Controller used in the events edition page
##
Application.Controllers.controller "EditEventController", ["$scope", "$state", "$stateParams", "$locale", 'CSRF', 'eventPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise'
, ($scope, $state, $stateParams, $locale, CSRF, eventPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise) ->
### PUBLIC SCOPE ###
## API URL where the form will be posted
$scope.actionUrl = "/api/events/" + $stateParams.id
## Form action on the above URL
$scope.method = 'put'
## Retrieve the event details, in case of error the user is redirected to the events listing
$scope.event = eventPromise
## currency symbol for the current locale (cf. angular-i18n)
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM;
## List of categories for the events
$scope.categories = categoriesPromise
## List of availables price's categories
$scope.priceCategories = priceCategoriesPromise
## List of events themes
$scope.themes = themesPromise
## List of age ranges
$scope.ageRanges = ageRangesPromise
### PRIVATE SCOPE ###
##
# Kind of constructor: these actions will be realized first when the controller is loaded
##
initialize = ->
CSRF.setMetaTags()
# init the dates to JS objects
$scope.event.start_date = moment($scope.event.start_date).toDate()
$scope.event.end_date = moment($scope.event.end_date).toDate()
## Using the EventsController
new EventsController($scope, $state)
## !!! MUST BE CALLED AT THE END of the controller
initialize()
]