1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-29 18:52:22 +01:00

admin interface to list coupons

This commit is contained in:
Sylvain 2016-08-04 14:26:07 +02:00
parent 0eaa81b0ba
commit ee03f1a79c
11 changed files with 152 additions and 11 deletions

View File

@ -3,8 +3,8 @@
##
# Controller used in the prices edition page
##
Application.Controllers.controller "EditPricingController", ["$scope", "$state", '$uibModal', 'TrainingsPricing', '$filter', 'Credit', 'Pricing', 'Plan', 'plans', 'groups', 'growl', 'machinesPricesPromise', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', '_t'
, ($scope, $state, $uibModal, TrainingsPricing, $filter, Credit, Pricing, Plan, plans, groups, growl, machinesPricesPromise, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, _t) ->
Application.Controllers.controller "EditPricingController", ["$scope", "$state", '$uibModal', 'TrainingsPricing', '$filter', 'Credit', 'Pricing', 'Plan', 'plans', 'groups', 'growl', 'machinesPricesPromise', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', 'couponsPromise', '_t'
, ($scope, $state, $uibModal, TrainingsPricing, $filter, Credit, Pricing, Plan, plans, groups, growl, machinesPricesPromise, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, couponsPromise, _t) ->
### PUBLIC SCOPE ###
## List of machines prices (not considering any plan)
@ -34,6 +34,9 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
## List of machines
$scope.machines = machinesPromise
## List of coupons
$scope.coupons = couponsPromise
## The plans list ordering. Default: by group
$scope.orderPlans = 'group_id'
@ -275,7 +278,7 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
##
$scope.deletePlan = (plans, id) ->
if typeof id != 'number'
console.error('[editPricingController::deletePlan] Error: invalid id parameter')
console.error('[EditPricingController::deletePlan] Error: invalid id parameter')
else
# open a confirmation dialog
dialogs.confirm
@ -287,10 +290,10 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
# the admin has confirmed, delete the plan
Plan.delete {id: id}, (res) ->
growl.success(_t('subscription_plan_was_successfully_deleted'))
$scope.plans.splice(findPlanIdxById(plans, id), 1)
$scope.plans.splice(findItemIdxById(plans, id), 1)
, (error) ->
console.error('[editPricingController::deletePlan] Error: '+error.statusText) if error.statusText
console.error('[EditPricingController::deletePlan] Error: '+error.statusText) if error.statusText
growl.error(_t('unable_to_delete_the_specified_subscription_an_error_occurred'))
@ -308,12 +311,50 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
### PRIVATE SCOPE ###
##
# Return a textual status concerning the given coupon
# @param coupon {Object}
# @return {string}
##
$scope.getCouponStatus = (coupon) ->
unless coupon.active
return _t('disabled')
unless moment(coupon.valid).isSameOrBefore()
return _t('expired')
unless coupon.usages <= coupon.max_usages
return _t('sold_out')
return _t('active')
findPlanIdxById = (plans, id)->
(plans.map (plan)->
plan.id
).indexOf(id)
##
# Delete a coupon from the server's database and, in case of success, from the list in memory
# @param coupons {Array<Object>} should be called with $scope.coupons
# @param id {number} ID of the coupon to delete
##
$scope.deleteCoupon = (coupons, id) ->
if typeof id != 'number'
console.error('[EditPricingController::deleteCoupon] Error: invalid id parameter')
else
# open a confirmation dialog
dialogs.confirm
resolve:
object: ->
title: _t('confirmation_required')
msg: _t('do_you_really_want_to_delete_this_coupon')
, ->
# the admin has confirmed, delete the coupon
Coupon.delete {id: id}, (res) ->
growl.success(_t('coupon_was_successfully_deleted'))
$scope.coupons.splice(findItemIdxById(coupons, id), 1)
, (error) ->
console.error('[EditPricingController::deleteCoupon] Error: '+error.statusText) if error.statusText
growl.error(_t('unable_to_delete_the_specified_coupon_an_error_occurred'))
### PRIVATE SCOPE ###
##
# Kind of constructor: these actions will be realized first when the controller is loaded
@ -329,6 +370,19 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
##
# Retrieve an item index by its ID from the given array of objects
# @param items {Array<{id:number}>}
# @param id {number}
# @returns {number} item index in the provided array
##
findItemIdxById = (items, id)->
(items.map (item)->
item.id
).indexOf(id)
##
# Group the given credits array into a map associating the plan ID with its associated trainings/machines
# @return {Object} the association map

View File

@ -742,6 +742,9 @@ angular.module('application.router', ['ui.router']).
trainingCreditsPromise: ['Credit', (Credit) ->
Credit.query({creditable_type: 'Training'}).$promise
]
couponsPromise: ['Coupon', (Coupon) ->
Coupon.query().$promise
]
# plans
.state 'app.admin.plans',
@ -786,6 +789,27 @@ angular.module('application.router', ['ui.router']).
Translations.query(['app.admin.plans.edit', 'app.shared.plan']).$promise
]
# coupons
.state 'app.admin.coupons.new',
url: '/admin/coupons/new'
views:
'main@':
templateUrl: '<%= asset_path "admin/coupons/new.html" %>'
controller: 'NewCouponController'
resolve:
translations: [ 'Translations', (Translations) ->
Translations.query(['app.admin.coupons.new', 'app.shared.coupon']).$promise
]
.state 'app.admin.coupons.edit',
url: '/admin/coupons/:id/edit'
views:
'main@':
templateUrl: '<%= asset_path "admin/coupons/edit.html" %>'
controller: 'EditCouponController'
resolve:
translations: [ 'Translations', (Translations) ->
Translations.query(['app.admin.coupons.edit', 'app.shared.coupon']).$promise
]

View File

@ -0,0 +1,8 @@
'use strict'
Application.Services.factory 'Coupon', ["$resource", ($resource)->
$resource "/api/coupons/:id",
{id: "@id"},
update:
method: 'PUT'
]

View File

@ -0,0 +1 @@
<ng-include src="'<%= asset_path 'admin/coupons/_coupon.html' %>'"></ng-include>

View File

@ -0,0 +1 @@
<ng-include src="'<%= asset_path 'admin/coupons/_coupon.html' %>'"></ng-include>

View File

@ -0,0 +1,24 @@
<h2 translate>{{ 'list_of_the_coupons' }}</h2>
<button type="button" class="btn btn-warning m-t-lg m-b" ui-sref="app.admin.coupons.new" translate>{{ 'add_a_new_coupon' }}</button>
<table class="table">
<thead>
<tr>
<th>{{ 'name' | translate }}</th>
<th>{{ 'percentage_off' | translate }}</th>
<th>{{ 'status' | translate }}</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="coupon in coupons">
<td>{{coupon.name}}</td>
<td>{{coupon.percent_off}} %</td>
<td>{{getCouponStatus(coupon)}}</td>
<td>
<button type="button" class="btn btn-default" ui-sref="app.admin.coupons.edit({id:coupon.id})"><i class="fa fa-pencil-square-o"></i></button>
<button type="button" class="btn btn-danger" ng-click="deleteCoupon(coupons, coupon.id)"><i class="fa fa-trash"></i></button>
</td>
</tr>
</tbody>
</table>

View File

@ -36,6 +36,10 @@
<uib-tab heading="{{ 'credits' | translate }}">
<ng-include src="'<%= asset_path 'admin/pricing/credits.html' %>'"></ng-include>
</uib-tab>
<uib-tab heading="{{ 'coupons' | translate }}">
<ng-include src="'<%= asset_path 'admin/pricing/coupons.html' %>'"></ng-include>
</uib-tab>
</uib-tabset>
</div>

View File

@ -142,8 +142,20 @@ en:
changes_have_been_successfully_saved: "Changes have been successfully saved."
credit_was_successfully_saved: "Credit was successfully saved."
do_you_really_want_to_delete_this_subscription_plan: "Do you really want to delete this subscription plan?"
subscription_plan_was_successfully_deleted: "Subscription plan was successfully delete."
subscription_plan_was_successfully_deleted: "Subscription plan was successfully deleted."
unable_to_delete_the_specified_subscription_an_error_occurred: "Unable to delete the specified subscription, an error occurred."
coupons: "Coupons"
list_of_the_coupons: "List of the coupons"
percentage_off: "Percentage off"
status: "Status"
add_a_new_coupon: "Add a new coupon"
disabled: "Disabled"
expired: "Expired"
sold_out: "Sold out"
active: "Active"
do_you_really_want_to_delete_this_coupon: "Do you really want to delete this coupon?"
coupon_was_successfully_deleted: "Coupon was successfully deleted."
unable_to_delete_the_specified_coupon_an_error_occurred: "Unable to delete the specified coupon, an error occurred."
plans:
new:

View File

@ -144,6 +144,18 @@ fr:
do_you_really_want_to_delete_this_subscription_plan: "Êtes-vous sûr(e) de vouloir supprimer cette formule d'abonnement ?"
subscription_plan_was_successfully_deleted: "La formule d'abonnement a bien été supprimée."
unable_to_delete_the_specified_subscription_an_error_occurred: "Impossible de supprimer l'abonnement spécifié, une erreur s'est produite."
coupons: "Codes promotionnels"
list_of_the_coupons: "Liste des codes promotionnels"
percentage_off: "Pourcentage de réduction"
status: "Statut"
add_a_new_coupon: "Ajouter un code promotionnel"
disabled: "Désactivé"
expired: "Expiré"
sold_out: "Épuisé"
active: "Actif"
do_you_really_want_to_delete_this_coupon: "Êtes-vous sûr(e) de vouloir supprimer ce code promotionnel ?"
coupon_was_successfully_deleted: "Le code promotionnel a bien été supprimé."
unable_to_delete_the_specified_coupon_an_error_occurred: "Impossible de supprimer le code promotionnel, une erreur s'est produite."
plans:
new:

View File

@ -69,6 +69,7 @@ Rails.application.routes.draw do
resources :prices, only: [:index, :update] do
post 'compute', on: :collection
end
resources :coupons
resources :trainings_pricings, only: [:index, :update]