mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-19 13:54:25 +01:00
Merge branch 'edit_event_recurrent' into dev
This commit is contained in:
commit
b7dda83060
@ -56,14 +56,7 @@ class EventsController {
|
||||
* @param content {Object} JSON - The upload's result
|
||||
*/
|
||||
$scope.submited = function (content) {
|
||||
if ((content.id == null)) {
|
||||
$scope.alerts = [];
|
||||
angular.forEach(content, function (v, k) {
|
||||
angular.forEach(v, function (err) { $scope.alerts.push({ msg: k + ': ' + err, type: 'danger' }); });
|
||||
});
|
||||
} else {
|
||||
$state.go('app.public.events_list');
|
||||
}
|
||||
$scope.onSubmited(content);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -490,6 +483,18 @@ Application.Controllers.controller('NewEventController', ['$scope', '$state', 'C
|
||||
{ label: _t('app.admin.events_new.every_year'), value: 'year' }
|
||||
];
|
||||
|
||||
// triggered when the new event form was submitted to the API and have received an answer
|
||||
$scope.onSubmited = function(content) {
|
||||
if ((content.id == null)) {
|
||||
$scope.alerts = [];
|
||||
angular.forEach(content, function (v, k) {
|
||||
angular.forEach(v, function (err) { $scope.alerts.push({ msg: k + ': ' + err, type: 'danger' }); });
|
||||
});
|
||||
} else {
|
||||
$state.go('app.public.events_list');
|
||||
}
|
||||
};
|
||||
|
||||
// Using the EventsController
|
||||
return new EventsController($scope, $state);
|
||||
}
|
||||
@ -498,9 +503,9 @@ Application.Controllers.controller('NewEventController', ['$scope', '$state', 'C
|
||||
/**
|
||||
* Controller used in the events edition page
|
||||
*/
|
||||
Application.Controllers.controller('EditEventController', ['$scope', '$state', '$stateParams', 'CSRF', 'eventPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise',
|
||||
function ($scope, $state, $stateParams, CSRF, eventPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise) {
|
||||
/* PUBLIC SCOPE */
|
||||
Application.Controllers.controller('EditEventController', ['$scope', '$state', '$stateParams', 'CSRF', 'eventPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '$uibModal', 'growl', '_t',
|
||||
function ($scope, $state, $stateParams, CSRF, eventPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, $uibModal, growl, _t) {
|
||||
/* PUBLIC SCOPE */
|
||||
|
||||
// API URL where the form will be posted
|
||||
$scope.actionUrl = `/api/events/${$stateParams.id}`;
|
||||
@ -511,6 +516,9 @@ Application.Controllers.controller('EditEventController', ['$scope', '$state', '
|
||||
// Retrieve the event details, in case of error the user is redirected to the events listing
|
||||
$scope.event = eventPromise;
|
||||
|
||||
// We'll keep track of the initial dates here, for later comparison
|
||||
$scope.initialDates = {};
|
||||
|
||||
// List of categories for the events
|
||||
$scope.categories = categoriesPromise;
|
||||
|
||||
@ -523,6 +531,83 @@ Application.Controllers.controller('EditEventController', ['$scope', '$state', '
|
||||
// List of age ranges
|
||||
$scope.ageRanges = ageRangesPromise;
|
||||
|
||||
// Default edit-mode for periodic event
|
||||
$scope.editMode = 'single';
|
||||
|
||||
// show edit-mode modal if event is recurrent
|
||||
$scope.isShowEditModeModal = $scope.event.recurrence_events.length > 0;
|
||||
|
||||
$scope.editRecurrent = function (e) {
|
||||
if ($scope.isShowEditModeModal && $scope.event.recurrence_events.length > 0) {
|
||||
e.preventDefault();
|
||||
|
||||
// open a choice edit-mode dialog
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "events/editRecurrent.html" %>',
|
||||
size: 'md',
|
||||
controller: 'EditRecurrentEventController',
|
||||
resolve: {
|
||||
editMode: function () { return $scope.editMode; },
|
||||
initialDates: function () { return $scope.initialDates; },
|
||||
currentEvent: function () { return $scope.event; }
|
||||
}
|
||||
});
|
||||
// submit form event by edit-mode
|
||||
modalInstance.result.then(function(res) {
|
||||
$scope.isShowEditModeModal = false;
|
||||
$scope.editMode = res.editMode;
|
||||
e.target.click();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// triggered when the edit event form was submitted to the API and have received an answer
|
||||
$scope.onSubmited = function(data) {
|
||||
if (data.total === data.updated) {
|
||||
if (data.updated > 1) {
|
||||
growl.success(_t(
|
||||
'app.admin.events_edit.events_updated',
|
||||
{COUNT: data.updated - 1}
|
||||
));
|
||||
} else {
|
||||
growl.success(_t(
|
||||
'app.admin.events_edit.event_successfully_updated'
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if (data.total > 1) {
|
||||
growl.warning(_t(
|
||||
'app.admin.events_edit.events_not_updated',
|
||||
{TOTAL: data.total, COUNT: data.total - data.updated}
|
||||
));
|
||||
if (_.find(data.details, { error: 'EventPriceCategory' })) {
|
||||
growl.error(_t(
|
||||
'app.admin.events_edit.error_deleting_reserved_price'
|
||||
));
|
||||
} else {
|
||||
growl.error(_t(
|
||||
'app.admin.events_edit.other_error'
|
||||
));
|
||||
}
|
||||
} else {
|
||||
growl.error(_t(
|
||||
'app.admin.events_edit.unable_to_update_the_event'
|
||||
));
|
||||
if (data.details[0].error === 'EventPriceCategory') {
|
||||
growl.error(_t(
|
||||
'app.admin.events_edit.error_deleting_reserved_price'
|
||||
));
|
||||
} else {
|
||||
growl.error(_t(
|
||||
'app.admin.events_edit.other_error'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
$state.go('app.public.events_list');
|
||||
};
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
/**
|
||||
@ -535,6 +620,11 @@ Application.Controllers.controller('EditEventController', ['$scope', '$state', '
|
||||
$scope.event.start_date = moment($scope.event.start_date).toDate();
|
||||
$scope.event.end_date = moment($scope.event.end_date).toDate();
|
||||
|
||||
$scope.initialDates = {
|
||||
start: new Date($scope.event.start_date.valueOf()),
|
||||
end: new Date($scope.event.end_date.valueOf())
|
||||
};
|
||||
|
||||
// Using the EventsController
|
||||
return new EventsController($scope, $state);
|
||||
};
|
||||
@ -543,3 +633,36 @@ Application.Controllers.controller('EditEventController', ['$scope', '$state', '
|
||||
return initialize();
|
||||
}
|
||||
]);
|
||||
|
||||
/**
|
||||
* Controller used in the event edit-mode modal window
|
||||
*/
|
||||
Application.Controllers.controller('EditRecurrentEventController', ['$scope', '$uibModalInstance', 'editMode', 'growl', 'initialDates', 'currentEvent', '_t',
|
||||
function ($scope, $uibModalInstance, editMode, growl, initialDates, currentEvent, _t) {
|
||||
// with recurrent slots: how many slots should we update?
|
||||
$scope.editMode = editMode;
|
||||
|
||||
/**
|
||||
* Confirmation callback
|
||||
*/
|
||||
$scope.ok = function () {
|
||||
$uibModalInstance.close({
|
||||
editMode: $scope.editMode
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if any of the dates of the event has changed
|
||||
*/
|
||||
$scope.hasDateChanged = function() {
|
||||
return (!moment(initialDates.start).isSame(currentEvent.start_date, 'day') || !moment(initialDates.end).isSame(currentEvent.end_date, 'day'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancellation callback
|
||||
*/
|
||||
$scope.cancel = function () {
|
||||
$uibModalInstance.dismiss('cancel');
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
@ -77,11 +77,13 @@
|
||||
|
||||
|
||||
</div> <!-- ./panel-body -->
|
||||
<input ng-model="editMode" type="hidden" name="edit_mode">
|
||||
<div class="panel-footer no-padder">
|
||||
<input type="submit"
|
||||
ng-value="submitName"
|
||||
class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c"
|
||||
ng-disabled="eventForm.$invalid || event.category_id === null"/>
|
||||
ng-value="submitName"
|
||||
class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c"
|
||||
ng-disabled="eventForm.$invalid || event.category_id === null"
|
||||
ng-click="editRecurrent($event)"/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
</section>
|
||||
|
||||
|
||||
<form role="form" name="eventForm" class="form-horizontal" novalidate action="{{ actionUrl }}" ng-upload="submited(content)" upload-options-enable-rails-csrf="true">
|
||||
<form role="form" name="eventForm" class="form-horizontal" novalidate action="{{ actionUrl }}" ng-upload="submited(content)" upload-options-enable-rails-csrf="true" upload-options-convert-hidden="true">
|
||||
|
||||
<ng-include src="'<%= asset_path "events/_form.html" %>'"></ng-include>
|
||||
|
||||
|
26
app/assets/templates/events/editRecurrent.html
Normal file
26
app/assets/templates/events/editRecurrent.html
Normal file
@ -0,0 +1,26 @@
|
||||
<div class="modal-header">
|
||||
<img ng-src="{{logoBlack.custom_asset_file_attributes.attachment_url}}" alt="{{logo.custom_asset_file_attributes.attachment}}" class="modal-logo"/>
|
||||
<h1 translate>{{ 'app.admin.events_edit.confirmation_required' }}</h1>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p translate>{{ 'app.admin.events_edit.edit_recurring_event' }}</p>
|
||||
<div class="form-group">
|
||||
<label class="checkbox">
|
||||
<input type="radio" name="edit_mode" ng-model="editMode" value="single" required/>
|
||||
<span translate>{{ 'app.admin.events_edit.edit_this_event' }}</span>
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="radio" name="edit_mode" ng-model="editMode" value="next" required/>
|
||||
<span translate>{{ 'app.admin.events_edit.edit_this_and_next' }}</span>
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="radio" name="edit_mode" ng-model="editMode" value="all" required/>
|
||||
<span translate>{{ 'app.admin.events_edit.edit_all' }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<p class="alert alert-warning" ng-show="hasDateChanged() && editMode !== 'single'" translate>{{ 'app.admin.events_edit.date_wont_change' }}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-info" ng-click="ok()" translate>{{ 'app.shared.buttons.apply' }}</button>
|
||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
||||
</div>
|
@ -55,21 +55,8 @@ class API::EventsController < API::ApiController
|
||||
|
||||
def update
|
||||
authorize Event
|
||||
begin
|
||||
if @event.update(event_params.permit!)
|
||||
render :show, status: :ok, location: @event
|
||||
else
|
||||
render json: @event.errors, status: :unprocessable_entity
|
||||
end
|
||||
rescue ActiveRecord::RecordNotDestroyed => e
|
||||
if e.record.class.name == 'EventPriceCategory'
|
||||
render json: { error: ["#{e.record.price_category.name}: #{t('events.error_deleting_reserved_price')}"] },
|
||||
status: :unprocessable_entity
|
||||
else
|
||||
render json: { error: [t('events.other_error')] }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
res = EventService.update(@event, event_params.permit!, params[:edit_mode])
|
||||
render json: { action: 'update', total: res.length, updated: res.select { |r| r[:status] }.length, details: res }, status: :ok, location: @event
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -72,4 +72,102 @@ class EventService
|
||||
end
|
||||
results
|
||||
end
|
||||
|
||||
# update one or more events (if periodic)
|
||||
def self.update(event, event_params, mode = 'single')
|
||||
results = []
|
||||
events = case mode
|
||||
when 'single'
|
||||
[event]
|
||||
when 'next'
|
||||
Event.includes(:availability, :event_price_categories, :event_files)
|
||||
.where(
|
||||
'availabilities.start_at >= ? AND events.recurrence_id = ?',
|
||||
event.availability.start_at,
|
||||
event.recurrence_id
|
||||
)
|
||||
.references(:availabilities, :events)
|
||||
when 'all'
|
||||
Event.includes(:availability, :event_price_categories, :event_files)
|
||||
.where(
|
||||
'recurrence_id = ?',
|
||||
event.recurrence_id
|
||||
)
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
events.each do |e|
|
||||
next unless e.id != event.id
|
||||
|
||||
start_at = event_params['availability_attributes']['start_at']
|
||||
end_at = event_params['availability_attributes']['end_at']
|
||||
event_price_categories_attributes = event_params['event_price_categories_attributes']
|
||||
event_files_attributes = event_params['event_files_attributes']
|
||||
e_params = event_params.merge(
|
||||
availability_id: e.availability_id,
|
||||
availability_attributes: {
|
||||
id: e.availability_id,
|
||||
start_at: e.availability.start_at.change(hour: start_at.hour, min: start_at.min),
|
||||
end_at: e.availability.end_at.change(hour: end_at.hour, min: end_at.min),
|
||||
available_type: e.availability.available_type
|
||||
}
|
||||
)
|
||||
epc_attributes = []
|
||||
event_price_categories_attributes&.each do |epca|
|
||||
epc = e.event_price_categories.find_by(price_category_id: epca['price_category_id'])
|
||||
if epc
|
||||
epc_attributes.push(
|
||||
id: epc.id,
|
||||
price_category_id: epc.price_category_id,
|
||||
amount: epca['amount'],
|
||||
_destroy: epca['_destroy']
|
||||
)
|
||||
elsif epca['id'].present?
|
||||
event_price = event.event_price_categories.find(epca['id'])
|
||||
epc_attributes.push(
|
||||
price_category_id: epca['price_category_id'],
|
||||
amount: event_price.amount,
|
||||
_destroy: ''
|
||||
)
|
||||
end
|
||||
end
|
||||
unless epc_attributes.empty?
|
||||
e_params = e_params.merge(
|
||||
event_price_categories_attributes: epc_attributes
|
||||
)
|
||||
end
|
||||
|
||||
ef_attributes = []
|
||||
event_files_attributes&.each do |efa|
|
||||
if efa['id'].present?
|
||||
event_file = event.event_files.find(efa['id'])
|
||||
ef = e.event_files.find_by(attachment: event_file.attachment.file.filename)
|
||||
if ef
|
||||
ef_attributes.push(
|
||||
id: ef.id,
|
||||
attachment: efa['attachment'],
|
||||
_destroy: efa['_destroy']
|
||||
)
|
||||
end
|
||||
else
|
||||
ef_attributes.push(efa)
|
||||
end
|
||||
end
|
||||
e_params = e_params.merge(
|
||||
event_files_attributes: ef_attributes
|
||||
)
|
||||
begin
|
||||
results.push status: !!e.update(e_params.permit!), event: e # rubocop:disable Style/DoubleNegation
|
||||
rescue StandardError => err
|
||||
results.push status: false, event: e, error: err.try(:record).try(:class).try(:name), message: err.message
|
||||
end
|
||||
end
|
||||
begin
|
||||
results.push status: !!event.update(event_params), event: event # rubocop:disable Style/DoubleNegation
|
||||
rescue StandardError => err
|
||||
results.push status: false, event: event, error: err.try(:record).try(:class).try(:name), message: err.message
|
||||
end
|
||||
results
|
||||
end
|
||||
end
|
||||
|
@ -230,6 +230,18 @@ en:
|
||||
events_edit:
|
||||
# edit an existing event
|
||||
edit_the_event: "Edit the event"
|
||||
confirmation_required: "Confirmation required"
|
||||
edit_recurring_event: "You're about to update a periodic event. What do you want to update ?"
|
||||
edit_this_event: "Only this event"
|
||||
edit_this_and_next: "This event and the following"
|
||||
edit_all: "All events"
|
||||
date_wont_change: "Warning: you have changed the event date. This modification won't be propagated to other occurrences of the periodic event."
|
||||
event_successfully_updated: "Event successfully updated"
|
||||
events_updated: "The event, and {COUNT, plural, =1{one other} other{{COUNT} others}}, have been updated"
|
||||
unable_to_update_the_event: "Unable to update the event"
|
||||
events_not_updated: "On {TOTAL} events, {COUNT, plural, =1{one was not updated} other{{COUNT} were not deleted}}."
|
||||
error_deleting_reserved_price: "Unable to delete the requested price because it is associated with some reservations"
|
||||
other_error: "An unexpected error occurred while updating the event"
|
||||
|
||||
event_reservations:
|
||||
# event reservations list
|
||||
|
@ -221,6 +221,19 @@ es:
|
||||
events_edit:
|
||||
#edit an existing event
|
||||
edit_the_event: "Editar el evento"
|
||||
confirmation_required: "Confirmation required"
|
||||
edit_recurring_event: "You're about to update a periodic event. What do you want to update ?"
|
||||
edit_this_event: "Only this event"
|
||||
edit_this_and_next: "This event and the following"
|
||||
edit_all: "All events"
|
||||
date_wont_change: "Warning: you have changed the event date. This modification won't be propagated to other occurrences of the periodic event."
|
||||
event_successfully_updated: "Event successfully updated"
|
||||
events_updated: "The event, and {COUNT, plural, =1{one other} other{{COUNT} others}}, have been updated"
|
||||
unable_to_update_the_event: "Unable to update the event"
|
||||
events_not_updated: "On {TOTAL} events, {COUNT, plural, =1{one was not updated} other{{COUNT} were not deleted}}."
|
||||
error_deleting_reserved_price: "No se puede eliminar el precio solicitado porque está asociado con algunas reservas."
|
||||
other_error: "Se ha producido un error inesperado al actualizar el evento."
|
||||
|
||||
event_reservations:
|
||||
#event reservations list
|
||||
the_reservations: "Reservas :"
|
||||
|
@ -230,6 +230,18 @@ fr:
|
||||
events_edit:
|
||||
# modifier un évènement existant
|
||||
edit_the_event: "Éditer l'évènement"
|
||||
confirmation_required: "Confirmation requise"
|
||||
edit_recurring_event: "Vous êtes sur le point de modifier un évènement périodique. Que voulez-vous modifier ?"
|
||||
edit_this_event: "Uniquement cet évènement"
|
||||
edit_this_and_next: "Cet évènement et tous les suivants"
|
||||
edit_all: "Tous les évènements"
|
||||
date_wont_change: "Attention : vous avez modifié la date de l'évènement. Cette modification ne sera pas être répercutée sur les autres occurrences de l'évènement périodique."
|
||||
event_successfully_updated: "L'évènement a bien été modifié."
|
||||
events_updated: "L'évènement, ainsi {COUNT, plural, =1{qu'un autre} other{que {COUNT} autres}}, ont été modifiés"
|
||||
unable_to_update_the_event: "L'évènement n'a pu être modifié"
|
||||
events_not_updated: "Sur {TOTAL} évènements, {COUNT, plural, =1{un n'a pas pu être modifié} other{{COUNT} n'ont pas pu être modifiés}}."
|
||||
error_deleting_reserved_price: "Impossible de supprimer le tarif demandé car il est associé à des réservations"
|
||||
other_error: "Une erreur inattendue est survenue lors de la mise à jour de l'évènement"
|
||||
|
||||
event_reservations:
|
||||
# liste des réservations sur un évènement
|
||||
|
@ -230,6 +230,18 @@ pt:
|
||||
events_edit:
|
||||
# edit an existing event
|
||||
edit_the_event: "Editar evento"
|
||||
confirmation_required: "Confirmation required"
|
||||
edit_recurring_event: "You're about to update a periodic event. What do you want to update ?"
|
||||
edit_this_event: "Only this event"
|
||||
edit_this_and_next: "This event and the following"
|
||||
edit_all: "All events"
|
||||
date_wont_change: "Warning: you have changed the event date. This modification won't be propagated to other occurrences of the periodic event."
|
||||
event_successfully_updated: "Event successfully updated"
|
||||
events_updated: "The event, and {COUNT, plural, =1{one other} other{{COUNT} others}}, have been updated"
|
||||
unable_to_update_the_event: "Unable to update the event"
|
||||
events_not_updated: "On {TOTAL} events, {COUNT, plural, =1{one was not updated} other{{COUNT} were not deleted}}."
|
||||
error_deleting_reserved_price: "Não permitido deletar o preço requisitado, pois está associado a algumas reservas"
|
||||
other_error: "Um erro inesperado ocorreu enquanto o evento era atualizado"
|
||||
|
||||
event_reservations:
|
||||
# event reservations list
|
||||
|
Loading…
x
Reference in New Issue
Block a user