1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-20 14:54:15 +01:00

[ongoing] reservation cart refactoring

This commit is contained in:
Sylvain 2017-02-16 17:57:14 +01:00
parent 8343c1503d
commit 049606b450
4 changed files with 410 additions and 222 deletions

View File

@ -322,6 +322,10 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
$scope.coupon =
applied: null
$scope.selectionTime = null
$scope.selectedEvent = null
## is the user allowed to change the date of his booking
$scope.enableBookingMove = true
@ -593,6 +597,13 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
return true
false
$scope.updateCalendar = ->
uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents'
$scope.refetchCalendar = ->
$timeout ->
uiCalendarConfig.calendars.calendar.fullCalendar 'refetchEvents'
uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents'
### PRIVATE SCOPE ###
@ -687,67 +698,8 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
# if it's too late).
##
calendarEventClickCb = (event, jsEvent, view) ->
if !event.is_reserved && !$scope.slotToModify
index = $scope.eventsReserved.indexOf(event)
if index == -1
event.backgroundColor = FREE_SLOT_BORDER_COLOR
event.title = _t('i_reserve')
$scope.eventsReserved.push event
else
$scope.removeMachineSlot(event)
$scope.paidMachineSlots = null
$scope.selectedPlan = null
$scope.modifiedSlots = null
else if !event.is_reserved && $scope.slotToModify
if $scope.slotToPlace
$scope.slotToPlace.backgroundColor = 'white'
$scope.slotToPlace.title = ''
$scope.slotToPlace = event
event.backgroundColor = '#bbb'
event.title = _t('i_shift')
else if event.is_reserved and (slotCanBeModified(event) or slotCanBeCanceled(event)) and !$scope.slotToModify and $scope.eventsReserved.length == 0
event.movable = slotCanBeModified(event)
event.cancelable = slotCanBeCanceled(event)
dialogs.confirm
templateUrl: '<%= asset_path "shared/confirm_modify_slot_modal.html" %>'
resolve:
object: -> event
, (type) ->
if type == 'move'
$scope.modifiedSlots = null
$scope.slotToModify = event
event.backgroundColor = '#eee'
event.title = _t('i_change')
uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents'
else if type == 'cancel'
dialogs.confirm
resolve:
object: ->
title: _t('confirmation_required')
msg: _t('do_you_really_want_to_cancel_this_reservation')
, -> # cancel confirmed
Slot.cancel {id: event.id}, -> # successfully canceled
growl.success _t('reservation_was_cancelled_successfully')
$scope.canceledSlot = event
$scope.canceledSlot.backgroundColor = 'white'
$scope.canceledSlot.title = ''
$scope.canceledSlot.borderColor = FREE_SLOT_BORDER_COLOR
$scope.canceledSlot.id = null
$scope.canceledSlot.is_reserved = false
$scope.canceledSlot.can_modify = false
$scope.canceledSlot = null
uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents'
, -> # error while canceling
growl.error _t('cancellation_failed')
, ->
$scope.paidMachineSlots = null
$scope.selectedPlan = null
$scope.modifiedSlots = null
uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents'
updateCartPrice()
$scope.selectedEvent = event
$scope.selectionTime = new Date()

View File

@ -0,0 +1,231 @@
### PRIVATE STATIC CONSTANTS ###
# Slot already booked by the current user
FREE_SLOT_BORDER_COLOR = '<%= AvailabilityHelper::MACHINE_COLOR %>'
# Slot already booked by another user
UNAVAILABLE_SLOT_BORDER_COLOR = '<%= AvailabilityHelper::MACHINE_IS_RESERVED_BY_USER %>'
# Slot free to be booked
BOOKED_SLOT_BORDER_COLOR = '<%= AvailabilityHelper::IS_RESERVED_BY_CURRENT_USER %>'
Application.Directives.directive 'cart', [ '$rootScope', 'dialogs', 'growl', 'Price', '_t', ($rootScope, dialogs, growl, Price, _t) ->
{
restrict: 'E'
scope:
slot: '='
selectionTime: '='
onUpdate: '='
onOutdated: '='
user: '='
templateUrl: '<%= asset_path "shared/_cart.html" %>'
link: ($scope, element, attributes) ->
## fullCalendar event. An already booked slot that the user want to modify
$scope.slotToModify = null
## array of fullCalendar events. Slots where the user want to book
$scope.eventsReserved = []
## fullCalendar event. The last selected slot that the user want to book
$scope.slotToPlace = null
$scope.paidMachineSlots = null
## will store the user's plan if he choosed to buy one
$scope.selectedPlan = null
$scope.modifiedSlots = null
$scope.canceledSlot = null
## total amount of the bill to pay
$scope.amountTotal = 0
## total amount of the elements in the cart, without considering any coupon
$scope.totalNoCoupon = 0
## Discount coupon to apply to the basket, if any
$scope.coupon =
applied: null
# What the binded slot
$scope.$watch 'selectionTime', (newValue, oldValue) ->
if newValue != oldValue
slotSelectionChanged()
##
# Add the provided slot to the shopping cart (state transition from free to 'about to be reserved')
# and increment the total amount of the cart if needed.
# @param machineSlot {Object} fullCalendar event object
##
$scope.validMachineSlot = (machineSlot)->
machineSlot.isValid = true
updateCartPrice()
##
# Remove the provided slot from the shopping cart (state transition from 'about to be reserved' to free)
# and decrement the total amount of the cart if needed.
# @param machineSlot {Object} fullCalendar event object
# @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
##
$scope.removeMachineSlot = (machineSlot, e)->
e.preventDefault() if e
machineSlot.backgroundColor = 'white'
machineSlot.borderColor = FREE_SLOT_BORDER_COLOR
machineSlot.title = ''
machineSlot.isValid = false
if machineSlot.machine.is_reduced_amount
angular.forEach $scope.user.machine_credits, (credit)->
if credit.machine_id = machineSlot.machine.id
credit.hours_used--
machineSlot.machine.is_reduced_amount = false
index = $scope.eventsReserved.indexOf(machineSlot)
$scope.eventsReserved.splice(index, 1)
if $scope.eventsReserved.length == 0
if $scope.plansAreShown
$scope.selectedPlan = null
$scope.plansAreShown = false
updateCartPrice()
$scope.onOutdated() if typeof $scope.onOutdated == 'function'
##
# Callback triggered when the selected slot changed
##
slotSelectionChanged = ->
if !$scope.slot.is_reserved && !$scope.slotToModify
index = $scope.eventsReserved.indexOf($scope.slot)
if index == -1
$scope.slot.backgroundColor = FREE_SLOT_BORDER_COLOR
$scope.slot.title = _t('i_reserve')
$scope.eventsReserved.push $scope.slot
else
$scope.removeMachineSlot($scope.slot)
$scope.paidMachineSlots = null
$scope.selectedPlan = null
$scope.modifiedSlots = null
else if !$scope.slot.is_reserved && $scope.slotToModify
if $scope.slotToPlace
$scope.slotToPlace.backgroundColor = 'white'
$scope.slotToPlace.title = ''
$scope.slotToPlace = $scope.slot
$scope.slot.backgroundColor = '#bbb'
$scope.slot.title = _t('i_shift')
else if $scope.slot.is_reserved and (slotCanBeModified($scope.slot) or slotCanBeCanceled($scope.slot)) and !$scope.slotToModify and $scope.eventsReserved.length == 0
$scope.slot.movable = slotCanBeModified($scope.slot)
$scope.slot.cancelable = slotCanBeCanceled($scope.slot)
dialogs.confirm
templateUrl: '<%= asset_path "shared/confirm_modify_slot_modal.html" %>'
resolve:
object: -> $scope.slot
, (type) ->
if type == 'move'
$scope.modifiedSlots = null
$scope.slotToModify = $scope.slot
$scope.slot.backgroundColor = '#eee'
$scope.slot.title = _t('i_change')
$scope.onUpdate() if typeof $scope.onUpdate == 'function'
else if type == 'cancel'
dialogs.confirm
resolve:
object: ->
title: _t('confirmation_required')
msg: _t('do_you_really_want_to_cancel_this_reservation')
, -> # cancel confirmed
Slot.cancel {id: $scope.slot.id}, -> # successfully canceled
growl.success _t('reservation_was_cancelled_successfully')
$scope.canceledSlot = $scope.slot
$scope.canceledSlot.backgroundColor = 'white'
$scope.canceledSlot.title = ''
$scope.canceledSlot.borderColor = FREE_SLOT_BORDER_COLOR
$scope.canceledSlot.id = null
$scope.canceledSlot.is_reserved = false
$scope.canceledSlot.can_modify = false
$scope.canceledSlot = null
$scope.onUpdate() if typeof $scope.onUpdate == 'function'
, -> # error while canceling
growl.error _t('cancellation_failed')
, ->
$scope.paidMachineSlots = null
$scope.selectedPlan = null
$scope.modifiedSlots = null
$scope.onUpdate() if typeof $scope.onUpdate == 'function'
updateCartPrice()
##
# Update the total price of the current selection/reservation
##
updateCartPrice = ->
if Object.keys($scope.user).length > 0
r = mkReservation($scope.user, $scope.eventsReserved, $scope.selectedPlan)
Price.compute mkRequestParams(r, $scope.coupon.applied), (res) ->
$scope.amountTotal = res.price
$scope.totalNoCoupon = res.price_without_coupon
setSlotsDetails(res.details)
else
# otherwise we alert, this error musn't occur when the current user is not admin
growl.warning(_t('please_select_a_member_first'))
$scope.amountTotal = null
setSlotsDetails = (details) ->
angular.forEach $scope.eventsReserved, (slot) ->
angular.forEach details.slots, (s) ->
if moment(s.start_at).isSame(slot.start)
slot.promo = s.promo
slot.price = s.price
##
# Format the parameters expected by /api/prices/compute or /api/reservations and return the resulting object
# @param reservation {Object} as returned by mkReservation()
# @param coupon {Object} Coupon as returned from the API
# @return {{reservation:Object, coupon_code:string}}
##
mkRequestParams = (reservation, coupon) ->
params =
reservation: reservation
coupon_code: (coupon.code if coupon)
params
##
# Create an hash map implementing the Reservation specs
# @param member {Object} User as retreived from the API: current user / selected user if current is admin
# @param slots {Array<Object>} Array of fullCalendar events: slots selected on the calendar
# @param [plan] {Object} Plan as retrived from the API: plan to buy with the current reservation
# @return {{user_id:Number, reservable_id:Number, reservable_type:String, slots_attributes:Array<Object>, plan_id:Number|null}}
##
mkReservation = (member, slots, plan = null) ->
reservation =
user_id: member.id
reservable_id: (slots[0].machine.id if slots.length > 0)
reservable_type: 'Machine'
slots_attributes: []
plan_id: (plan.id if plan)
angular.forEach slots, (slot, key) ->
reservation.slots_attributes.push
start_at: slot.start
end_at: slot.end
availability_id: slot.availability_id
offered: slot.offered || false
reservation
}
]

View File

@ -40,167 +40,11 @@
</div>
<div class="widget panel b-a m m-t-lg" ng-if="ctrl.member && !slotToModify && !modifiedSlots">
<div class="panel-heading b-b small">
<h3 translate>{{ 'summary' }}</h3>
</div>
<div class="widget-content no-bg auto wrapper" ng-show="eventsReserved.length == 0 && (!paidMachineSlots || paidMachineSlots.length == 0)">
<p class="font-felt fleche-left text-lg"><%= image_tag("fleche-left.png", class: 'fleche-left visible-lg') %>
{{ 'select_one_or_more_slots_in_the_calendar' | translate }}</p>
</div>
<div class="widget-content no-bg auto wrapper" ng-if="eventsReserved.length > 0">
<div class="font-sbold m-b-sm " translate>{{ 'you_ve_just_selected_the_slot' }}</div>
<div class="panel panel-default bg-light" ng-repeat="machineSlot in eventsReserved">
<div class="panel-body">
<div class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(machineSlot.start | amDateFormat:'LLLL'), END_TIME:(machineSlot.end | amDateFormat:'LT') } }}</div>
<div class="text-base">{{ 'cost_of_a_machine_hour' | translate }} <span ng-class="{'text-blue': !machineSlot.promo, 'red': machineSlot.promo}">{{machineSlot.price | currency}}</span></div>
<div ng-show="currentUser.role == 'admin'" class="m-t">
<label for="offerSlot" class="control-label m-r" translate>{{ 'offer_this_slot' }}</label>
<input bs-switch
ng-model="machineSlot.offered"
id="offerSlot"
type="checkbox"
class="form-control"
switch-on-text="{{ 'yes' | translate}}"
switch-off-text="{{ 'no' | translate}}"
switch-animate="true"
switch-readonly="{{machineSlot.isValid}}"/>
</div>
</div>
<div>
<button class="btn btn-valid btn-warning btn-block text-u-c r-b" ng-click="validMachineSlot(machineSlot)" ng-if="!machineSlot.isValid" translate>{{ 'confirm_this_slot' }}</button>
</div>
<div class="clear"><a class="pull-right m-b-sm text-u-l ng-scope m-r-sm" href="#" ng-click="removeMachineSlot(machineSlot, $event)" ng-if="machineSlot.isValid" translate>{{ 'remove_this_slot' }}</a></div>
</div>
<coupon show="machineSlotsValid() && (!plansAreShown || selectedPlan)" coupon="coupon.applied" total="totalNoCoupon" user-id="{{ctrl.member.id}}"></coupon>
<span ng-hide="fablabWithoutPlans">
<div ng-if="machineSlotsValid() && !ctrl.member.subscribed_plan" ng-show="!plansAreShown">
<p class="font-sbold text-base l-h-2x" translate>{{ 'to_benefit_from_attractive_prices' }}</p>
<div><button class="btn btn-warning-full rounded btn-block text-xs" ng-click="showPlans()" translate>{{ 'view_our_subscriptions' }}</button></div>
<p class="font-bold text-base text-u-c text-center m-b-xs" translate>{{ 'or' }}</p>
</div>
<div ng-if="selectedPlan">
<div class="m-t-md m-b-sm text-base">{{ 'you_ve_just_selected_a_' | translate }} <br> <span class="font-sbold" translate>{{ '_subscription' }}</span> :</div>
<div class="panel panel-default bg-light m-n">
<div class="panel-body m-b-md">
<div class="font-sbold text-u-c">{{selectedPlan | humanReadablePlanName }}</div>
<div class="text-base">{{ 'cost_of_the_subscription' | translate }} <span class="text-blue">{{selectedPlan.amount | currency}}</span></div>
</div>
</div>
</div>
</span>
</div>
<div class="panel-footer no-padder" ng-if="eventsReserved.length > 0">
<button class="btn btn-valid btn-info btn-block p-l btn-lg text-u-c r-b text-base" ng-click="payMachine()" ng-if="machineSlotsValid() && (!plansAreShown || selectedPlan)">{{ 'confirm_and_pay' | translate }} {{amountTotal | currency}}</button>
</div>
<div class="widget-content no-bg auto wrapper" ng-if="paidMachineSlots">
{{ 'you_have_settled_the_following_machine_hours' | translate }} <strong>{{machine.name}}</strong>:
<div class="well well-warning m-t-sm" ng-repeat="paidSlot in paidMachineSlots">
<i class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(paidSlot.start | amDateFormat:'LLLL'), END_TIME:(paidSlot.end | amDateFormat:'LT') } }}</i>
<div class="font-sbold">{{ 'cost_of_a_machine_hour' | translate }} {{paidSlot.machine.amount() | currency}}</div>
</div>
<div ng-if="selectedPlan">
<div class="m-t-md m-b-sm text-base">{{ 'you_have_settled_a_' | translate }} <br> <span class="font-sbold" translate>{{ '_subscription' }}</span> :</div>
<div class="well well-warning m-t-sm">
<i class="font-sbold text-u-c">{{selectedPlan | humanReadablePlanName }}</i>
<div class="font-sbold">{{ 'cost_of_the_subscription' | translate }} {{selectedPlan.amount | currency}}</div>
</div>
</div>
<div class="m-t-md font-sbold">{{ 'total_' | translate }} {{amountTotal | currency}}</div>
<div class="alert alert-success" ng-if="ctrl.member.subscribed_plan">{{ 'thank_you_your_payment_has_been_successfully_registered' | translate }}<br>
{{ 'your_invoice_will_be_available_soon_from_your_' | translate }} <a ui-sref="app.logged.dashboard.invoices" translate>{{ 'dashboard' }}</a>
</div>
</div>
</div>
<div class="widget panel b-a m m-t-lg" ng-if="slotToModify || modifiedSlots">
<div class="panel-heading b-b small">
<h3 translate>{{ 'summary' }}</h3>
</div>
<div class="widget-content no-bg auto wrapper" ng-if="slotToModify">
<div class="font-sbold m-b-sm " translate>{{ 'i_want_to_change_the_following_reservation' }}</div>
<div class="panel panel-warning bg-yellow">
<div class="panel-body">
<div class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(slotToModify.start | amDateFormat:'LLLL'), END_TIME:(slotToModify.end | amDateFormat:'LT') } }}</div>
</div>
<div class="clear"><a class="pull-right m-b-sm text-u-l ng-scope m-r-sm" href="#" ng-click="removeSlotToModify($event)" translate>{{ 'cancel_my_modification' }}</a></div>
</div>
<div class="widget-content no-bg">
<p class="font-felt fleche-left text-lg"><%= image_tag("fleche-left.png", class: 'fleche-left visible-lg') %>
{{ 'select_a_new_slot_in_the_calendar' | translate }}</p>
</div>
<div class="panel panel-info bg-info text-white" ng-if="slotToPlace">
<div class="panel-body">
<div class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(slotToPlace.start | amDateFormat:'LLLL'), END_TIME:(slotToPlace.end | amDateFormat:'LT') } }}</div>
</div>
<div class="clear"><a class="pull-right m-b-sm text-u-l ng-scope m-r-sm" href="#" ng-click="removeSlotToPlace($event)" translate>{{ 'cancel_my_selection' }}</a></div>
</div>
<div ng-if="slotToPlace && slotToModify.tags.length > 0 && slotToPlace.tags.length > 0" ng-class="{'panel panel-danger bg-red': tagMissmatch()}">
<div class="panel-body">
<div id="fromTags">
{{ 'tags_of_the_original_slot' | translate }}<br/>
<span ng-repeat="tag in slotToModify.tags">
<span class='label label-success text-white' title="{{tag.name}}">{{tag.name}}</span>
</span>
</div><br/>
<div id="toTags">
{{ 'tags_of_the_destination_slot' | translate }}<br/>
<span ng-repeat="tag in slotToPlace.tags">
<span class='label label-success text-white' title="{{tag.name}}">{{tag.name}}</span>
</span>
</div>
</div>
</div>
</div>
<div class="panel-footer no-padder" ng-if="slotToModify && slotToPlace">
<button class="btn btn-invalid btn-default btn-block p-l btn-lg text-u-c r-n text-base" ng-click="cancelModifyMachineSlot()" translate>{{ 'cancel' }}</button>
<div>
<button class="btn btn-valid btn-info btn-block p-l btn-lg text-u-c r-b text-base" ng-click="modifyMachineSlot()" translate>{{ 'confirm_my_modification' }}</button>
</div>
</div>
<div class="widget-content no-bg auto wrapper" ng-if="modifiedSlots">
<div class="font-sbold m-b-sm " translate>{{ 'your_booking_slot_was_successfully_moved_from_' }}</div>
<div class="panel panel-default bg-light">
<div class="panel-body">
<div class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(modifiedSlots.oldReservedSlot.start | amDateFormat:'LLLL'), END_TIME:(modifiedSlots.oldReservedSlot.end | amDateFormat:'LT') } }}</div>
</div>
</div>
<p class="text-center font-bold m-b-sm text-u-c" translate>{{ 'to_date' }}</p>
<div class="panel panel-success bg-success bg-light">
<div class="panel-body">
<div class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(modifiedSlots.newReservedSlot.start | amDateFormat:'LLLL'), END_TIME:(modifiedSlots.newReservedSlot.end | amDateFormat:'LT') } }}</div>
</div>
</div>
</div>
</div>
<cart slot="selectedEvent"
selection-time="selectionTime"
on-update="updateCalendar"
on-outdated="refetchCalendar"
user="ctrl.member"></cart>
<uib-alert type="warning m">
<p class="text-sm">

View File

@ -0,0 +1,161 @@
<div class="widget panel b-a m m-t-lg" ng-if="user && !slotToModify && !modifiedSlots">
<div class="panel-heading b-b small">
<h3 translate>{{ 'summary' }}</h3>
</div>
<div class="widget-content no-bg auto wrapper" ng-show="eventsReserved.length == 0 && (!paidMachineSlots || paidMachineSlots.length == 0)">
<p class="font-felt fleche-left text-lg"><%= image_tag("fleche-left.png", class: 'fleche-left visible-lg') %>
{{ 'select_one_or_more_slots_in_the_calendar' | translate }}</p>
</div>
<div class="widget-content no-bg auto wrapper" ng-if="eventsReserved.length > 0">
<div class="font-sbold m-b-sm " translate>{{ 'you_ve_just_selected_the_slot' }}</div>
<div class="panel panel-default bg-light" ng-repeat="machineSlot in eventsReserved">
<div class="panel-body">
<div class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(machineSlot.start | amDateFormat:'LLLL'), END_TIME:(machineSlot.end | amDateFormat:'LT') } }}</div>
<div class="text-base">{{ 'cost_of_a_machine_hour' | translate }} <span ng-class="{'text-blue': !machineSlot.promo, 'red': machineSlot.promo}">{{machineSlot.price | currency}}</span></div>
<div ng-show="currentUser.role == 'admin'" class="m-t">
<label for="offerSlot" class="control-label m-r" translate>{{ 'offer_this_slot' }}</label>
<input bs-switch
ng-model="machineSlot.offered"
id="offerSlot"
type="checkbox"
class="form-control"
switch-on-text="{{ 'yes' | translate}}"
switch-off-text="{{ 'no' | translate}}"
switch-animate="true"
switch-readonly="{{machineSlot.isValid}}"/>
</div>
</div>
<div>
<button class="btn btn-valid btn-warning btn-block text-u-c r-b" ng-click="validMachineSlot(machineSlot)" ng-if="!machineSlot.isValid" translate>{{ 'confirm_this_slot' }}</button>
</div>
<div class="clear"><a class="pull-right m-b-sm text-u-l ng-scope m-r-sm" href="#" ng-click="removeMachineSlot(machineSlot, $event)" ng-if="machineSlot.isValid" translate>{{ 'remove_this_slot' }}</a></div>
</div>
<coupon show="machineSlotsValid() && (!plansAreShown || selectedPlan)" coupon="coupon.applied" total="totalNoCoupon" user-id="{{user.id}}"></coupon>
<span ng-hide="fablabWithoutPlans">
<div ng-if="machineSlotsValid() && !user.subscribed_plan" ng-show="!plansAreShown">
<p class="font-sbold text-base l-h-2x" translate>{{ 'to_benefit_from_attractive_prices' }}</p>
<div><button class="btn btn-warning-full rounded btn-block text-xs" ng-click="showPlans()" translate>{{ 'view_our_subscriptions' }}</button></div>
<p class="font-bold text-base text-u-c text-center m-b-xs" translate>{{ 'or' }}</p>
</div>
<div ng-if="selectedPlan">
<div class="m-t-md m-b-sm text-base">{{ 'you_ve_just_selected_a_' | translate }} <br> <span class="font-sbold" translate>{{ '_subscription' }}</span> :</div>
<div class="panel panel-default bg-light m-n">
<div class="panel-body m-b-md">
<div class="font-sbold text-u-c">{{selectedPlan | humanReadablePlanName }}</div>
<div class="text-base">{{ 'cost_of_the_subscription' | translate }} <span class="text-blue">{{selectedPlan.amount | currency}}</span></div>
</div>
</div>
</div>
</span>
</div>
<div class="panel-footer no-padder" ng-if="eventsReserved.length > 0">
<button class="btn btn-valid btn-info btn-block p-l btn-lg text-u-c r-b text-base" ng-click="payMachine()" ng-if="machineSlotsValid() && (!plansAreShown || selectedPlan)">{{ 'confirm_and_pay' | translate }} {{amountTotal | currency}}</button>
</div>
<div class="widget-content no-bg auto wrapper" ng-if="paidMachineSlots">
{{ 'you_have_settled_the_following_machine_hours' | translate }} <strong>{{machine.name}}</strong>:
<div class="well well-warning m-t-sm" ng-repeat="paidSlot in paidMachineSlots">
<i class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(paidSlot.start | amDateFormat:'LLLL'), END_TIME:(paidSlot.end | amDateFormat:'LT') } }}</i>
<div class="font-sbold">{{ 'cost_of_a_machine_hour' | translate }} {{paidSlot.machine.amount() | currency}}</div>
</div>
<div ng-if="selectedPlan">
<div class="m-t-md m-b-sm text-base">{{ 'you_have_settled_a_' | translate }} <br> <span class="font-sbold" translate>{{ '_subscription' }}</span> :</div>
<div class="well well-warning m-t-sm">
<i class="font-sbold text-u-c">{{selectedPlan | humanReadablePlanName }}</i>
<div class="font-sbold">{{ 'cost_of_the_subscription' | translate }} {{selectedPlan.amount | currency}}</div>
</div>
</div>
<div class="m-t-md font-sbold">{{ 'total_' | translate }} {{amountTotal | currency}}</div>
<div class="alert alert-success" ng-if="user.subscribed_plan">{{ 'thank_you_your_payment_has_been_successfully_registered' | translate }}<br>
{{ 'your_invoice_will_be_available_soon_from_your_' | translate }} <a ui-sref="app.logged.dashboard.invoices" translate>{{ 'dashboard' }}</a>
</div>
</div>
</div>
<div class="widget panel b-a m m-t-lg" ng-if="slotToModify || modifiedSlots">
<div class="panel-heading b-b small">
<h3 translate>{{ 'summary' }}</h3>
</div>
<div class="widget-content no-bg auto wrapper" ng-if="slotToModify">
<div class="font-sbold m-b-sm " translate>{{ 'i_want_to_change_the_following_reservation' }}</div>
<div class="panel panel-warning bg-yellow">
<div class="panel-body">
<div class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(slotToModify.start | amDateFormat:'LLLL'), END_TIME:(slotToModify.end | amDateFormat:'LT') } }}</div>
</div>
<div class="clear"><a class="pull-right m-b-sm text-u-l ng-scope m-r-sm" href="#" ng-click="removeSlotToModify($event)" translate>{{ 'cancel_my_modification' }}</a></div>
</div>
<div class="widget-content no-bg">
<p class="font-felt fleche-left text-lg"><%= image_tag("fleche-left.png", class: 'fleche-left visible-lg') %>
{{ 'select_a_new_slot_in_the_calendar' | translate }}</p>
</div>
<div class="panel panel-info bg-info text-white" ng-if="slotToPlace">
<div class="panel-body">
<div class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(slotToPlace.start | amDateFormat:'LLLL'), END_TIME:(slotToPlace.end | amDateFormat:'LT') } }}</div>
</div>
<div class="clear"><a class="pull-right m-b-sm text-u-l ng-scope m-r-sm" href="#" ng-click="removeSlotToPlace($event)" translate>{{ 'cancel_my_selection' }}</a></div>
</div>
<div ng-if="slotToPlace && slotToModify.tags.length > 0 && slotToPlace.tags.length > 0" ng-class="{'panel panel-danger bg-red': tagMissmatch()}">
<div class="panel-body">
<div id="fromTags">
{{ 'tags_of_the_original_slot' | translate }}<br/>
<span ng-repeat="tag in slotToModify.tags">
<span class='label label-success text-white' title="{{tag.name}}">{{tag.name}}</span>
</span>
</div><br/>
<div id="toTags">
{{ 'tags_of_the_destination_slot' | translate }}<br/>
<span ng-repeat="tag in slotToPlace.tags">
<span class='label label-success text-white' title="{{tag.name}}">{{tag.name}}</span>
</span>
</div>
</div>
</div>
</div>
<div class="panel-footer no-padder" ng-if="slotToModify && slotToPlace">
<button class="btn btn-invalid btn-default btn-block p-l btn-lg text-u-c r-n text-base" ng-click="cancelModifyMachineSlot()" translate>{{ 'cancel' }}</button>
<div>
<button class="btn btn-valid btn-info btn-block p-l btn-lg text-u-c r-b text-base" ng-click="modifyMachineSlot()" translate>{{ 'confirm_my_modification' }}</button>
</div>
</div>
<div class="widget-content no-bg auto wrapper" ng-if="modifiedSlots">
<div class="font-sbold m-b-sm " translate>{{ 'your_booking_slot_was_successfully_moved_from_' }}</div>
<div class="panel panel-default bg-light">
<div class="panel-body">
<div class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(modifiedSlots.oldReservedSlot.start | amDateFormat:'LLLL'), END_TIME:(modifiedSlots.oldReservedSlot.end | amDateFormat:'LT') } }}</div>
</div>
</div>
<p class="text-center font-bold m-b-sm text-u-c" translate>{{ 'to_date' }}</p>
<div class="panel panel-success bg-success bg-light">
<div class="panel-body">
<div class="font-sbold text-u-c">{{ 'datetime_to_time' | translate:{START_DATETIME:(modifiedSlots.newReservedSlot.start | amDateFormat:'LLLL'), END_TIME:(modifiedSlots.newReservedSlot.end | amDateFormat:'LT') } }}</div>
</div>
</div>
</div>
</div>