1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-19 13:54:25 +01:00

[bug] create a training availability with calendar in month view result in wrong dates

This commit is contained in:
Sylvain 2021-03-29 16:05:53 +02:00
parent e38228ae7e
commit 10dd5d2cca
5 changed files with 52 additions and 26 deletions

View File

@ -4,6 +4,7 @@
- Fix a bug: the view is not refreshed when deleting a recurring slot
- Fix a bug: unable to add a new authorized file type for project's CAD files
- Fix a bug: unable to update a coupon
- Fix a bug: create a training availability with calendar in month view result in wrong dates
## v4.7.6 2021 March 24
- Ability to disable the trainings module

View File

@ -400,6 +400,9 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
const calendarSelectCb = function (start, end, jsEvent, view) {
start = moment.tz(start.toISOString(), Fablab.timezone);
end = moment.tz(end.toISOString(), Fablab.timezone);
if (view.name === 'month') {
end = end.subtract(1, 'day').startOf('day');
}
// check if slot is not in the past
const today = new Date();
@ -412,7 +415,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
const slots = Math.trunc((end.valueOf() - start.valueOf()) / (60 * 1000)) / SLOT_MULTIPLE;
if (!Number.isInteger(slots)) {
// otherwise, round it to upper decimal
const upper = Math.ceil(slots) * SLOT_MULTIPLE;
const upper = (Math.ceil(slots) || 1) * SLOT_MULTIPLE;
end = moment(start).add(upper, 'minutes');
}
@ -706,6 +709,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
$scope.next = function () {
if ($scope.step === 1) { return validateType(); }
if ($scope.step === 2) { return validateSelection(); }
if ($scope.step === 3) { return validateTimes(); }
if ($scope.step === 5) { return validateRecurrence(); }
return $scope.step++;
};
@ -775,16 +779,16 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
$scope.$watch('availability.slot_duration', function (newValue, oldValue, scope) {
if (newValue === undefined) return;
start = moment($scope.start);
start.add(newValue * $scope.slots_nb, 'minutes');
$scope.end = start.toDate();
const startSlot = moment($scope.start);
startSlot.add(newValue * $scope.slots_nb, 'minutes');
$scope.end = startSlot.toDate();
});
// 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();
const startSlot = moment($scope.start);
startSlot.add($scope.availability.slot_duration * newValue, 'minutes');
$scope.end = startSlot.toDate();
});
// When we configure a machine/space availability, do not let the user change the end time, as the total
@ -793,7 +797,8 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
$scope.$watch('availability.available_type', function (newValue, oldValue, scope) {
if (isTypeDivided(newValue)) {
$scope.endDateReadOnly = true;
const slotsCurrentRange = Math.trunc(($scope.end.valueOf() - $scope.start.valueOf()) / (60 * 1000)) / $scope.availability.slot_duration;
const slotDuration = $scope.availability.slot_duration || parseInt(slotDurationPromise.setting.value, 10);
const slotsCurrentRange = Math.trunc(($scope.end.valueOf() - $scope.start.valueOf()) / (60 * 1000)) / slotDuration;
if (!Number.isInteger(slotsCurrentRange)) {
// otherwise, round it to upper decimal
const upperSlots = Math.ceil(slotsCurrentRange);
@ -812,29 +817,25 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
// When the start date is changed, if we are configuring a machine/space availability,
// maintain the relative length of the slot (ie. change the end time accordingly)
$scope.$watch('start', function (newValue, oldValue, scope) {
// for machine or space availabilities, adjust the end time
if ($scope.isTypeDivided()) {
end = moment($scope.end);
end.add(moment(newValue).diff(oldValue), 'milliseconds');
$scope.end = end.toDate();
} else { // for training availabilities
// prevent the admin from setting the beginning after the end
if (moment(newValue).add($scope.availability.slot_duration, 'minutes').isAfter($scope.end)) {
$scope.start = oldValue;
}
}
// adjust the end time
const endSlot = moment($scope.end);
endSlot.add(moment(newValue).diff(oldValue), 'milliseconds');
$scope.end = endSlot.toDate();
// update availability object
$scope.availability.start_at = $scope.start;
});
// Maintain consistency between the end time and the date object in the availability object
$scope.$watch('end', function (newValue, oldValue, scope) {
// we prevent the admin from setting the end of the availability before its beginning
if (moment($scope.start).add($scope.availability.slot_duration, 'minutes').isAfter(newValue)) {
$scope.end = oldValue;
if (newValue.valueOf() !== oldValue.valueOf()) {
// we prevent the admin from setting the end of the availability before its beginning
if (moment($scope.start).add($scope.availability.slot_duration, 'minutes').isAfter(newValue)) {
$scope.end = oldValue;
}
// update availability object
$scope.availability.end_at = $scope.end;
}
// update availability object
$scope.availability.end_at = $scope.end;
});
};
@ -857,6 +858,24 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
$scope.step++;
};
/**
* Validates that the slots/availability date and times are correct
*/
const validateTimes = function () {
if (moment($scope.end).isSameOrBefore($scope.start)) {
return growl.error(_t('app.admin.calendar.inconsistent_times'));
}
if ($scope.isTypeDivided()) {
if (!$scope.slots_nb) {
return growl.error(_t('app.admin.calendar.min_one_slot'));
}
if (!$scope.availability.slot_duration) {
return growl.error(_t('app.admin.calendar.min_slot_duration'));
}
}
$scope.step++;
};
/**
* Validates that the recurrence parameters were correctly set before continuing to step 5 (summary)
*/

View File

@ -80,7 +80,7 @@
<div class="row">
<div class="col-md-5">
<div class="input-group">
<input type="number" class="form-control" ng-model="slots_nb" step="1" />
<input type="number" class="form-control" ng-model="slots_nb" step="1" min="1" required="true" />
<span class="input-group-addon" translate>{{ 'app.admin.calendar.slots' }}</span>
</div>
</div>
@ -89,7 +89,7 @@
</p>
<div class="col-md-5">
<div class="input-group">
<input type="number" class="form-control" ng-model="availability.slot_duration" step="5" />
<input type="number" class="form-control" ng-model="availability.slot_duration" step="5" min="1" required="true" />
<span class="input-group-addon" translate>{{ 'app.admin.calendar.minutes' }}</span>
</div>
</div>

View File

@ -77,6 +77,9 @@ en:
unable_to_delete_the_slot: "Unable to delete the slot {START} - {END}, probably because it's already reserved by a member"
slots_not_deleted: "On {TOTAL} slots, {COUNT, plural, =1{one was not deleted} other{{COUNT} were not deleted}}. Some reservations may exist on {COUNT, plural, =1{it} other{them}}."
you_should_select_at_least_a_machine: "You should select at least one machine on this slot."
inconsistent_times: "Error: the end of the availability is before its beginning."
min_one_slot: "The availability must be split in one slot at least."
min_slot_duration: "You must specify a valid duration for the slots."
export_is_running_you_ll_be_notified_when_its_ready: "Export is running. You'll be notified when it's ready."
actions: "Actions"
block_reservations: "Block reservations"

View File

@ -77,6 +77,9 @@ fr:
unable_to_delete_the_slot: "Le créneau {START} - {END} n'a pu être supprimé, probablement car il est déjà réservé par un membre"
slots_not_deleted: "Sur {TOTAL} créneaux, {COUNT, plural, =1{un n'a pas pu être supprimé} other{{COUNT} n'ont pas pu être supprimés}}. Il est possible que des réservations existent sur {COUNT, plural, =1{celui-ci} other{ceux-ci}}."
you_should_select_at_least_a_machine: "Vous devriez sélectionner au moins une machine pour ce créneau."
inconsistent_times: "Erreur : la fin de la plage de disponibilité est avant son début."
min_one_slot: "La plage de disponibilité doit être scindée en au moins un créneau."
min_slot_duration: "Vous devez indiquer une durée valide pour les créneaux."
export_is_running_you_ll_be_notified_when_its_ready: "L'export est en cours. Vous serez notifié lorsqu'il sera prêt."
actions: "Actions"
block_reservations: "Bloquer les réservations"