mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-17 06:52:27 +01:00
pricing tour
This commit is contained in:
parent
a1a96b9c03
commit
f8f1dde14a
@ -18,9 +18,10 @@
|
||||
/**
|
||||
* Controller used in the prices edition page
|
||||
*/
|
||||
Application.Controllers.controller('EditPricingController', ['$scope', '$state', '$uibModal', '$filter', 'TrainingsPricing', 'Credit', 'Pricing', 'Plan', 'Coupon', 'plans', 'groups', 'growl', 'machinesPricesPromise', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', 'couponsPromise', 'spacesPromise', 'spacesPricesPromise', 'spacesCreditsPromise', '_t',
|
||||
function ($scope, $state, $uibModal, $filter, TrainingsPricing, Credit, Pricing, Plan, Coupon, plans, groups, growl, machinesPricesPromise, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, couponsPromise, spacesPromise, spacesPricesPromise, spacesCreditsPromise, _t) {
|
||||
/* PUBLIC SCOPE */
|
||||
Application.Controllers.controller('EditPricingController', ['$scope', '$state', '$uibModal', '$filter', 'TrainingsPricing', 'Credit', 'Pricing', 'Plan', 'Coupon', 'plans', 'groups', 'growl', 'machinesPricesPromise', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', 'couponsPromise', 'spacesPromise', 'spacesPricesPromise', 'spacesCreditsPromise', '_t', 'Member', 'uiTourService',
|
||||
function ($scope, $state, $uibModal, $filter, TrainingsPricing, Credit, Pricing, Plan, Coupon, plans, groups, growl, machinesPricesPromise, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, couponsPromise, spacesPromise, spacesPricesPromise, spacesCreditsPromise, _t, Member, uiTourService) {
|
||||
/* PUBLIC SCOPE */
|
||||
|
||||
// List of machines prices (not considering any plan)
|
||||
$scope.machinesPrices = machinesPricesPromise;
|
||||
|
||||
@ -84,7 +85,7 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
|
||||
|
||||
// Default: we do not filter coupons
|
||||
$scope.filter = {
|
||||
coupon: 'all',
|
||||
coupon: 'all'
|
||||
};
|
||||
|
||||
// Available status for filtering coupons
|
||||
@ -96,6 +97,16 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
|
||||
'active'
|
||||
];
|
||||
|
||||
// default tab: plans list
|
||||
$scope.tabs = { active: 0 };
|
||||
|
||||
/**
|
||||
* Retrieve a training price from all the trainings prices
|
||||
* @param trainingsPricings {Array<Object>} all trainings prices
|
||||
* @param trainingId {number}
|
||||
* @param groupId {number}
|
||||
* @returns {float}
|
||||
*/
|
||||
$scope.findTrainingsPricing = function (trainingsPricings, trainingId, groupId) {
|
||||
for (let trainingsPricing of Array.from(trainingsPricings)) {
|
||||
if ((trainingsPricing.training_id === trainingId) && (trainingsPricing.group_id === groupId)) {
|
||||
@ -104,6 +115,12 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the price of a training for the given parameters
|
||||
* @param data {float} the new price
|
||||
* @param trainingsPricing {Object} the training pricing to update
|
||||
* @returns {Promise|string}
|
||||
*/
|
||||
$scope.updateTrainingsPricing = function (data, trainingsPricing) {
|
||||
if (data != null) {
|
||||
return TrainingsPricing.update({ id: trainingsPricing.id }, { trainings_pricing: { amount: data } }).$promise;
|
||||
@ -600,6 +617,105 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the feature-tour for the admin/pricing page.
|
||||
* This is intended as a contextual help (when pressing F1)
|
||||
*/
|
||||
$scope.setupPricingTour = function () {
|
||||
// get the tour defined by the ui-tour directive
|
||||
const uitour = uiTourService.getTourByName('pricing');
|
||||
// TODO add the steps
|
||||
uitour.createStep({
|
||||
selector: 'body',
|
||||
stepId: 'welcome',
|
||||
order: 0,
|
||||
title: _t('app.admin.tour.pricing.welcome.title'),
|
||||
content: _t('app.admin.tour.pricing.welcome.content'),
|
||||
placement: 'bottom',
|
||||
orphan: true
|
||||
});
|
||||
uitour.createStep({
|
||||
selector: '.plans-pricing .new-plan-button',
|
||||
stepId: 'new_plan',
|
||||
order: 1,
|
||||
title: _t('app.admin.tour.pricing.new_plan.title'),
|
||||
content: _t('app.admin.tour.pricing.new_plan.content'),
|
||||
placement: 'bottom'
|
||||
});
|
||||
uitour.createStep({
|
||||
selector: '.plans-pricing .trainings-tab',
|
||||
stepId: 'trainings',
|
||||
order: 2,
|
||||
title: _t('app.admin.tour.pricing.trainings.title'),
|
||||
content: _t('app.admin.tour.pricing.trainings.content'),
|
||||
placement: 'bottom'
|
||||
});
|
||||
uitour.createStep({
|
||||
selector: '.plans-pricing .machines-tab',
|
||||
stepId: 'machines',
|
||||
order: 3,
|
||||
title: _t('app.admin.tour.pricing.machines.title'),
|
||||
content: _t('app.admin.tour.pricing.machines.content'),
|
||||
placement: 'bottom'
|
||||
});
|
||||
uitour.createStep({
|
||||
selector: '.plans-pricing .spaces-tab',
|
||||
stepId: 'spaces',
|
||||
order: 4,
|
||||
title: _t('app.admin.tour.pricing.spaces.title'),
|
||||
content: _t('app.admin.tour.pricing.spaces.content'),
|
||||
placement: 'bottom'
|
||||
});
|
||||
uitour.createStep({
|
||||
selector: '.plans-pricing .credits-tab',
|
||||
stepId: 'credits',
|
||||
order: 5,
|
||||
title: _t('app.admin.tour.pricing.credits.title'),
|
||||
content: _t('app.admin.tour.pricing.credits.content'),
|
||||
placement: 'bottom'
|
||||
});
|
||||
uitour.createStep({
|
||||
selector: '.plans-pricing .coupons-tab',
|
||||
stepId: 'coupons',
|
||||
order: 6,
|
||||
title: _t('app.admin.tour.pricing.coupons.title'),
|
||||
content: _t('app.admin.tour.pricing.coupons.content'),
|
||||
placement: 'bottom'
|
||||
});
|
||||
uitour.createStep({
|
||||
selector: 'body',
|
||||
stepId: 'conclusion',
|
||||
order: 7,
|
||||
title: _t('app.admin.tour.conclusion.title'),
|
||||
content: _t('app.admin.tour.conclusion.content'),
|
||||
placement: 'bottom',
|
||||
orphan: true
|
||||
});
|
||||
// on step change, change the active tab if needed
|
||||
uitour.on('stepChanged', function (nextStep) {
|
||||
if (nextStep.stepId === 'new_plan') { $scope.tabs.active = 0; }
|
||||
if (nextStep.stepId === 'trainings') { $scope.tabs.active = 1; }
|
||||
if (nextStep.stepId === 'machines') { $scope.tabs.active = 2; }
|
||||
if (nextStep.stepId === 'spaces') { $scope.tabs.active = 3; }
|
||||
if (nextStep.stepId === 'credits') { $scope.tabs.active = 4; }
|
||||
if (nextStep.stepId === 'coupons') { $scope.tabs.active = 5; }
|
||||
});
|
||||
// on tour end, save the status in database
|
||||
uitour.on('ended', function () {
|
||||
if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile.tours.indexOf('pricing') < 0) {
|
||||
Member.completeTour({ id: $scope.currentUser.id }, { tour: 'pricing' }, function (res) {
|
||||
$scope.currentUser.profile.tours = res.tours;
|
||||
});
|
||||
}
|
||||
});
|
||||
// if the user has never seen the tour, show him now
|
||||
if ($scope.currentUser.profile.tours.indexOf('pricing') < 0) {
|
||||
uitour.start();
|
||||
}
|
||||
// start this tour when an user press F1 - this is contextual help
|
||||
window.addEventListener('keydown', handleF1);
|
||||
}
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
/**
|
||||
@ -608,6 +724,11 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
|
||||
const initialize = function () {
|
||||
$scope.trainingCreditsGroups = groupCreditsByPlan($scope.trainingCredits);
|
||||
|
||||
// listen the $destroy event of the controller to remove the F1 key binding
|
||||
$scope.$on('$destroy', function () {
|
||||
window.removeEventListener('keydown', handleF1);
|
||||
});
|
||||
|
||||
// adds empty array for plan which hasn't any credits yet
|
||||
return (function () {
|
||||
const result = [];
|
||||
@ -622,6 +743,18 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
|
||||
})();
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback used to trigger the feature tour when the user press the F1 key.
|
||||
* @param e {KeyboardEvent}
|
||||
*/
|
||||
const handleF1 = function (e) {
|
||||
if (e.key === 'F1') {
|
||||
e.preventDefault();
|
||||
const tour = uiTourService.getTourByName('pricing');
|
||||
if (tour) { tour.start(); }
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve an item index by its ID from the given array of objects
|
||||
* @param items {Array<{id:number}>}
|
||||
|
@ -111,14 +111,16 @@ Application.Controllers.controller('HomeController', ['$scope', '$stateParams',
|
||||
content: _t('app.public.tour.trainings.content'),
|
||||
placement: 'right'
|
||||
});
|
||||
uitour.createStep({
|
||||
selector: '.nav-primary li.reserve-space-link',
|
||||
stepId: 'spaces',
|
||||
order: 4,
|
||||
title: _t('app.public.tour.spaces.title'),
|
||||
content: _t('app.public.tour.spaces.content'),
|
||||
placement: 'right'
|
||||
});
|
||||
if (!Fablab.withoutSpaces) {
|
||||
uitour.createStep({
|
||||
selector: '.nav-primary li.reserve-space-link',
|
||||
stepId: 'spaces',
|
||||
order: 4,
|
||||
title: _t('app.public.tour.spaces.title'),
|
||||
content: _t('app.public.tour.spaces.content'),
|
||||
placement: 'right'
|
||||
});
|
||||
}
|
||||
uitour.createStep({
|
||||
selector: '.nav-primary li.reserve-event-link',
|
||||
stepId: 'events',
|
||||
|
@ -15,33 +15,38 @@
|
||||
</section>
|
||||
|
||||
|
||||
<section class="m-lg">
|
||||
<section class="m-lg plans-pricing"
|
||||
ui-tour="pricing"
|
||||
ui-tour-backdrop="true"
|
||||
ui-tour-template-url="'<%= asset_path "shared/tour-step-template.html" %>'"
|
||||
ui-tour-use-hotkeys="true"
|
||||
post-render="setupPricingTour">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-12">
|
||||
<uib-tabset justified="true">
|
||||
<uib-tabset justified="true" active="tabs.active">
|
||||
|
||||
<uib-tab heading="{{ 'app.admin.pricing.subscriptions' | translate }}">
|
||||
<uib-tab heading="{{ 'app.admin.pricing.subscriptions' | translate }}" index="0">
|
||||
<ng-include src="'<%= asset_path "admin/pricing/subscriptions.html" %>'"></ng-include>
|
||||
</uib-tab>
|
||||
|
||||
<uib-tab heading="{{ 'app.admin.pricing.trainings' | translate }}">
|
||||
<uib-tab heading="{{ 'app.admin.pricing.trainings' | translate }}" index="1" class="trainings-tab">
|
||||
<ng-include src="'<%= asset_path "admin/pricing/trainings.html" %>'"></ng-include>
|
||||
</uib-tab>
|
||||
|
||||
<uib-tab heading="{{ 'app.admin.pricing.machine_hours' | translate }}">
|
||||
<uib-tab heading="{{ 'app.admin.pricing.machine_hours' | translate }}" index="2" class="machines-tab">
|
||||
<ng-include src="'<%= asset_path "admin/pricing/machine_hours.html" %>'"></ng-include>
|
||||
</uib-tab>
|
||||
|
||||
<uib-tab heading="{{ 'app.admin.pricing.spaces' | translate }}" ng-hide="fablabWithoutSpaces">
|
||||
<uib-tab heading="{{ 'app.admin.pricing.spaces' | translate }}" ng-hide="fablabWithoutSpaces" index="3" class="spaces-tab">
|
||||
<ng-include src="'<%= asset_path "admin/pricing/spaces.html" %>'"></ng-include>
|
||||
</uib-tab>
|
||||
|
||||
<uib-tab heading="{{ 'app.admin.pricing.credits' | translate }}">
|
||||
<uib-tab heading="{{ 'app.admin.pricing.credits' | translate }}" index="4" class="credits-tab">
|
||||
<ng-include src="'<%= asset_path "admin/pricing/credits.html" %>'"></ng-include>
|
||||
</uib-tab>
|
||||
|
||||
<uib-tab heading="{{ 'app.admin.pricing.coupons' | translate }}">
|
||||
<uib-tab heading="{{ 'app.admin.pricing.coupons' | translate }}" index="5" class="coupons-tab">
|
||||
<ng-include src="'<%= asset_path "admin/pricing/coupons.html" %>'"></ng-include>
|
||||
</uib-tab>
|
||||
</uib-tabset>
|
||||
|
@ -7,7 +7,7 @@
|
||||
</div>
|
||||
|
||||
<div class="m-t-lg">
|
||||
<button type="button" class="btn btn-warning" ui-sref="app.admin.plans.new">
|
||||
<button type="button" class="btn btn-warning new-plan-button" ui-sref="app.admin.plans.new">
|
||||
<i class="fa fa-plus m-r"></i>
|
||||
<span translate>{{ 'app.admin.pricing.add_a_new_subscription_plan' }}</span>
|
||||
</button>
|
||||
|
@ -1151,4 +1151,26 @@ fr:
|
||||
periods:
|
||||
title: "Clôturer les périodes comptables"
|
||||
content: "<p>La réglementation de votre pays peut vous imposer de clôturer régulièrement vos comptes. L'interface accessible depuis ce bouton permet de le faire.</p> <p><strong>En France,</strong> si vous êtes soumis à la certification anti-fraude TVA, cette clôture est obligatoire au moins une fois par an.</p><p>Pour rappel, si vous récupérez la TVA pour le compte de l'état et que certains de vos clients sont des particuliers, vous êtes dans l'obligation légale de fournir une attestation de conformité du logiciel à la certification anti-fraude.</p>"
|
||||
pricing:
|
||||
welcome:
|
||||
title: "Abonnements & Tarifs"
|
||||
content: "Gérez les formules d'abonnement et les prix des différents services que vous proposez à vos membres"
|
||||
new_plan:
|
||||
title: "Nouvelle formule d'abonnement"
|
||||
content: "Créez des formules d'abonnement pour proposer des prix préférentiels sur les machines et les espaces, aux utilisateurs réguliers."
|
||||
trainings:
|
||||
title: "Formations"
|
||||
content: "Définissez ici les prix des formations, par groupe d'utilisateurs."
|
||||
machines:
|
||||
title: "Machines"
|
||||
content: "Définissez ici les prix des créneaux machine, par groupe d'utilisateurs. Ces prix seront appliqués aux utilisateurs qui n'ont pas d'abonnement."
|
||||
spaces:
|
||||
title: "Espaces"
|
||||
content: "De la même manière, définissez ici les prix des créneaux espace pour les utilisateurs sans abonnement."
|
||||
credits:
|
||||
title: "Crédits"
|
||||
content: "<p>Les crédits vous permettent d'offir certains services aux utilisateurs qui souscrivent à un abonnement.</p><p>Vous pouvez, par exemple, offrir 2h d'imprimante 3D pour tous les abonnements annuels ; ou une formation au choix pour les abonnés étudiants, etc.</p>"
|
||||
coupons:
|
||||
title: "Codes promotionnels"
|
||||
content: "Créez et gérez des codes promotionnels permettant d'offir des réductions ponctuelles à leurs détenteurs."
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user