mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-26 20:54:21 +01:00
Ask for confirmation before booking a slot for a member without the required tag
This commit is contained in:
parent
47a0fca481
commit
5f7287cec7
@ -5,6 +5,7 @@
|
||||
- Interface to manage partners
|
||||
- Ability to define, per availability, a custom duration for the reservation slots
|
||||
- Ability to promote a user to a higher role (member > manager > admin)
|
||||
- Ask for confirmation before booking a slot for a member without the required tag
|
||||
- Corrected the documentation about BOOK_SLOT_AT_SAME_TIME
|
||||
- Auto-adjusts text colors based on the selected theme colors
|
||||
- Fix a bug: unable to change group if the previous was deactivated
|
||||
|
@ -74,38 +74,12 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
* @param slot {Object} fullCalendar event object
|
||||
*/
|
||||
$scope.validateSlot = function (slot) {
|
||||
let sameTimeReservations = [
|
||||
'training_reservations',
|
||||
'machine_reservations',
|
||||
'space_reservations',
|
||||
'events_reservations'
|
||||
].map(function (k) {
|
||||
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));
|
||||
validateTags(slot, function () {
|
||||
validateSameTimeReservations(slot, function () {
|
||||
slot.isValid = true;
|
||||
updateCartPrice();
|
||||
})
|
||||
})
|
||||
});
|
||||
sameTimeReservations = _.union.apply(null, sameTimeReservations);
|
||||
if (sameTimeReservations.length > 0) {
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "shared/_reserve_slot_same_time.html" %>',
|
||||
size: 'md',
|
||||
controller: 'ReserveSlotSameTimeController',
|
||||
resolve: {
|
||||
sameTimeReservations: function() { return sameTimeReservations; }
|
||||
}
|
||||
});
|
||||
modalInstance.result.then(function(res) {
|
||||
slot.isValid = true;
|
||||
return updateCartPrice();
|
||||
});
|
||||
} else {
|
||||
slot.isValid = true;
|
||||
return updateCartPrice();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -330,6 +304,74 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates that the current slot is reserved by a member with an authorized tag. Admin and managers can overpass
|
||||
* the mismatch.
|
||||
* @param slot {Object} fullCalendar event object.
|
||||
* @param callback {function}
|
||||
*/
|
||||
const validateTags = function (slot, callback) {
|
||||
const interTags = _.intersection.apply(null, [slot.tag_ids, $scope.user.tag_ids]);
|
||||
if (slot.tag_ids.length === 0 || interTags.length > 0) {
|
||||
if (typeof callback === 'function') callback();
|
||||
} else {
|
||||
// ask confirmation
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "shared/_reserve_slot_tags_mismatch.html" %>',
|
||||
size: 'md',
|
||||
controller: 'ReserveSlotTagsMismatchController',
|
||||
resolve: {
|
||||
slotTags: function() { return slot.tags; },
|
||||
userTags: function () { return $scope.user.tags; },
|
||||
userName: function () { return $scope.user.name; }
|
||||
}
|
||||
});
|
||||
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.
|
||||
* If the user is an administrator or a manager, he can overpass the conflict.
|
||||
* @param slot {Object} fullCalendar event object.
|
||||
* @param callback {function}
|
||||
*/
|
||||
const validateSameTimeReservations = function (slot, callback) {
|
||||
let sameTimeReservations = [
|
||||
'training_reservations',
|
||||
'machine_reservations',
|
||||
'space_reservations',
|
||||
'events_reservations'
|
||||
].map(function (k) {
|
||||
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" %>',
|
||||
size: 'md',
|
||||
controller: 'ReserveSlotSameTimeController',
|
||||
resolve: {
|
||||
sameTimeReservations: function() { return sameTimeReservations; }
|
||||
}
|
||||
});
|
||||
modalInstance.result.then(function(res) {
|
||||
if (typeof callback === 'function') callback(res);
|
||||
});
|
||||
} else {
|
||||
if (typeof callback === 'function') callback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback triggered when the selected slot changed
|
||||
*/
|
||||
@ -504,12 +546,12 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
return Price.compute(mkRequestParams(r, $scope.coupon.applied), function (res) {
|
||||
$scope.amountTotal = res.price;
|
||||
$scope.totalNoCoupon = res.price_without_coupon;
|
||||
return setSlotsDetails(res.details);
|
||||
setSlotsDetails(res.details);
|
||||
});
|
||||
} else {
|
||||
// otherwise we alert, this error musn't occur when the current user is not admin
|
||||
growl.warning(_t('app.shared.cart.please_select_a_member_first'));
|
||||
return $scope.amountTotal = null;
|
||||
$scope.amountTotal = null;
|
||||
}
|
||||
};
|
||||
|
||||
@ -518,7 +560,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
angular.forEach(details.slots, function (s) {
|
||||
if (moment(s.start_at).isSame(slot.start)) {
|
||||
slot.promo = s.promo;
|
||||
return slot.price = s.price;
|
||||
slot.price = s.price;
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -739,10 +781,10 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
]);
|
||||
|
||||
/**
|
||||
* Controller of modal for show reservations the same date at the same time
|
||||
* Controller of the modal showing the reservations the same date at the same time
|
||||
*/
|
||||
Application.Controllers.controller('ReserveSlotSameTimeController', ['$scope', '$uibModalInstance', 'AuthService', 'sameTimeReservations', 'growl', '_t',
|
||||
function ($scope, $uibModalInstance, AuthService, sameTimeReservations, growl, _t) {
|
||||
Application.Controllers.controller('ReserveSlotSameTimeController', ['$scope', '$uibModalInstance', 'AuthService', 'sameTimeReservations',
|
||||
function ($scope, $uibModalInstance, AuthService, sameTimeReservations) {
|
||||
$scope.sameTimeReservations = sameTimeReservations;
|
||||
$scope.bookSlotAtSameTime = Fablab.bookSlotAtSameTime;
|
||||
$scope.isAuthorized = AuthService.isAuthorized;
|
||||
@ -761,6 +803,31 @@ Application.Controllers.controller('ReserveSlotSameTimeController', ['$scope', '
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* Controller of the modal showing the slot tags
|
||||
*/
|
||||
Application.Controllers.controller('ReserveSlotTagsMismatchController', ['$scope', '$uibModalInstance', 'AuthService', 'slotTags', 'userTags', 'userName',
|
||||
function ($scope, $uibModalInstance, AuthService, slotTags, userTags, userName) {
|
||||
$scope.slotTags = slotTags;
|
||||
$scope.userTags = userTags;
|
||||
$scope.userName = userName;
|
||||
$scope.isAuthorized = AuthService.isAuthorized;
|
||||
/**
|
||||
* Confirmation callback
|
||||
*/
|
||||
$scope.ok = function () {
|
||||
$uibModalInstance.close({});
|
||||
}
|
||||
/**
|
||||
* Cancellation callback
|
||||
*/
|
||||
$scope.cancel = function () {
|
||||
$uibModalInstance.dismiss('cancel');
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
/**
|
||||
* Controller used to alert admin reserve slot without plan
|
||||
*/
|
||||
|
@ -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.shared.cart.tags_mismatch' }}</h1>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p ng-show="isAuthorized(['admin', 'manager'])" translate translate-values="{USER: userName}">{{ 'app.shared.cart.confirm_book_slot_tags_mismatch' }}</p>
|
||||
<p ng-hide="isAuthorized(['admin', 'manager'])" translate>{{ 'app.shared.cart.unable_to_book_slot_tags_mismatch' }}</p>
|
||||
<h3 translate>{{ 'app.shared.cart.slot_tags' }}</h3>
|
||||
<ul class="list-unstyled" ng-show="slotTags.length > 0">
|
||||
<li ng-repeat="t in slotTags">
|
||||
<span class="label label-default">{{t.name}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<span ng-hide="slotTags.length > 0" translate>{{ 'app.shared.cart.no_tags' }}</span>
|
||||
<h3 translate>{{ 'app.shared.cart.user_tags' }}</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li ng-repeat="t in userTags" ng-show="userTags.length > 0">
|
||||
<span class="label label-default">{{t.name}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<span ng-hide="userTags.length > 0" translate>{{ 'app.shared.cart.no_tags' }}</span>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button ng-if="isAuthorized(['admin', 'manager'])" class="btn btn-info" ng-click="ok()" translate>{{ 'app.shared.buttons.confirm' }}</button>
|
||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
||||
</div>
|
@ -425,6 +425,12 @@ en:
|
||||
slot_at_same_time: "Conflict with others reservations"
|
||||
do_you_really_want_to_book_slot_at_same_time: "Do you really want to book this slot? Other bookings take place at the same time"
|
||||
unable_to_book_slot_because_really_have_reservation_at_same_time: "Unable to book this slot because the following reservation occurs at the same time."
|
||||
tags_mismatch: "Tags mismatch"
|
||||
confirm_book_slot_tags_mismatch: "Do you really want to book this slot? {USER} does not have any of the required tags."
|
||||
unable_to_book_slot_tags_mismatch: "Unable to book this slot because you don't have any of the required tags."
|
||||
slot_tags: "Slot tags"
|
||||
user_tags: "User tags"
|
||||
no_tags: "No tags"
|
||||
# feature-tour modal
|
||||
tour:
|
||||
previous: "Previous"
|
||||
|
Loading…
x
Reference in New Issue
Block a user