FEATURE: Allow creation of coupons in admin panel (#43)
Adds full support to create coupon/promo codes in the Admin > Plugins > Subscriptions section of the plugin. The Create Coupon button opens a form on the same page, and the active checkboxes toggle the active status of the coupon code.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
@discourseComputed
|
||||
discountTypes() {
|
||||
return [
|
||||
{ id: "amount", name: "Amount" },
|
||||
{ id: "percent", name: "Percent" },
|
||||
];
|
||||
},
|
||||
discountType: "amount",
|
||||
discount: null,
|
||||
promoCode: null,
|
||||
active: false,
|
||||
|
||||
actions: {
|
||||
createNewCoupon() {
|
||||
const createParams = {
|
||||
promo: this.promoCode,
|
||||
discount_type: this.discountType,
|
||||
discount: this.discount,
|
||||
active: this.active,
|
||||
};
|
||||
|
||||
this.create(createParams);
|
||||
},
|
||||
cancelCreate() {
|
||||
this.cancel();
|
||||
},
|
||||
},
|
||||
});
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
import Controller from "@ember/controller";
|
||||
import AdminCoupon from "discourse/plugins/discourse-subscriptions/discourse/models/admin-coupon";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default Controller.extend({
|
||||
creating: null,
|
||||
|
||||
actions: {
|
||||
openCreateForm() {
|
||||
this.set("creating", true);
|
||||
},
|
||||
closeCreateForm() {
|
||||
this.set("creating", false);
|
||||
},
|
||||
createNewCoupon(params) {
|
||||
AdminCoupon.save(params)
|
||||
.then(() => {
|
||||
this.send("closeCreateForm");
|
||||
this.send("reloadModel");
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
deleteCoupon(coupon) {
|
||||
AdminCoupon.destroy(coupon)
|
||||
.then(() => {
|
||||
this.send("reloadModel");
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
toggleActive(coupon) {
|
||||
const couponData = {
|
||||
id: coupon.id,
|
||||
active: !coupon.active,
|
||||
};
|
||||
AdminCoupon.update(couponData)
|
||||
.then(() => {
|
||||
this.send("reloadModel");
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -14,6 +14,8 @@ export default {
|
||||
});
|
||||
});
|
||||
|
||||
this.route("coupons");
|
||||
|
||||
this.route("subscriptions");
|
||||
});
|
||||
},
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import EmberObject from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
const AdminCoupon = EmberObject.extend({
|
||||
@discourseComputed("coupon.amount_off", "coupon.percent_off")
|
||||
discount(amount_off, percent_off) {
|
||||
if (amount_off) {
|
||||
return `${parseFloat(amount_off * 0.01).toFixed(2)}`;
|
||||
} else if (percent_off) {
|
||||
return `${percent_off}%`;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
AdminCoupon.reopenClass({
|
||||
list() {
|
||||
return ajax("/s/admin/coupons", {
|
||||
method: "get",
|
||||
}).then((result) => {
|
||||
if (result === null) {
|
||||
return { unconfigured: true };
|
||||
}
|
||||
return result.map((coupon) => AdminCoupon.create(coupon));
|
||||
});
|
||||
},
|
||||
save(params) {
|
||||
const data = {
|
||||
promo: params.promo,
|
||||
discount_type: params.discount_type,
|
||||
discount: params.discount,
|
||||
active: params.active,
|
||||
};
|
||||
|
||||
return ajax("/s/admin/coupons", {
|
||||
method: "post",
|
||||
data,
|
||||
}).then((coupon) => AdminCoupon.create(coupon));
|
||||
},
|
||||
|
||||
update(params) {
|
||||
const data = {
|
||||
id: params.id,
|
||||
active: params.active,
|
||||
};
|
||||
|
||||
return ajax("/s/admin/coupons", {
|
||||
method: "put",
|
||||
data,
|
||||
}).then((coupon) => AdminCoupon.create(coupon));
|
||||
},
|
||||
|
||||
destroy(params) {
|
||||
const data = {
|
||||
coupon_id: params.coupon.id,
|
||||
};
|
||||
return ajax("/s/admin/coupons", {
|
||||
method: "delete",
|
||||
data,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default AdminCoupon;
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import Route from "@ember/routing/route";
|
||||
import AdminCoupon from "discourse/plugins/discourse-subscriptions/discourse/models/admin-coupon";
|
||||
|
||||
export default Route.extend({
|
||||
model() {
|
||||
return AdminCoupon.list();
|
||||
},
|
||||
|
||||
actions: {
|
||||
reloadModel() {
|
||||
this.refresh();
|
||||
},
|
||||
},
|
||||
});
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
{{#if model.unconfigured}}
|
||||
<p>{{i18n 'discourse_subscriptions.admin.unconfigured'}}</p>
|
||||
<p><a href="https://meta.discourse.org/t/discourse-subscriptions/140818/">Discourse Subscriptions on Meta</a></p>
|
||||
{{else}}
|
||||
{{#if model}}
|
||||
<table class="table discourse-patrons-table">
|
||||
<thead>
|
||||
<th>{{i18n 'discourse_subscriptions.admin.coupons.code'}}</th>
|
||||
<th>{{i18n 'discourse_subscriptions.admin.coupons.discount'}}</th>
|
||||
<th>{{i18n 'discourse_subscriptions.admin.coupons.times_redeemed'}}</th>
|
||||
<th>{{i18n 'discourse_subscriptions.admin.coupons.active'}}</th>
|
||||
<th>{{i18n 'discourse_subscriptions.admin.coupons.actions'}}</th>
|
||||
</thead>
|
||||
{{#each model as |coupon|}}
|
||||
<tr>
|
||||
<td>{{coupon.code}}</td>
|
||||
<td>{{coupon.discount}}</td>
|
||||
<td>{{coupon.times_redeemed}}</td>
|
||||
<td>{{input type="checkbox" checked=coupon.active click=(action "toggleActive" coupon)}}</td>
|
||||
<td>
|
||||
{{d-button
|
||||
action=(action "deleteCoupon")
|
||||
actionParam=coupon
|
||||
icon="trash-alt"
|
||||
class="btn-danger btn btn-icon btn-no-text"}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
{{/if}}
|
||||
|
||||
{{#unless creating}}
|
||||
{{d-button
|
||||
action=(action "openCreateForm")
|
||||
label="discourse_subscriptions.admin.coupons.create"
|
||||
title="discourse_subscriptions.admin.coupons.create"
|
||||
icon="plus"
|
||||
class="btn btn-icon btn-primary create-coupon"}}
|
||||
{{/unless}}
|
||||
|
||||
{{#if creating}}
|
||||
{{create-coupon-form cancel=(action 'closeCreateForm') create=(action 'createNewCoupon')}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
@@ -4,6 +4,7 @@
|
||||
<ul class="nav nav-pills">
|
||||
{{!-- {{nav-item route='adminPlugins.discourse-subscriptions.dashboard' label='discourse_subscriptions.admin.dashboard.title'}} --}}
|
||||
{{nav-item route='adminPlugins.discourse-subscriptions.products' label='discourse_subscriptions.admin.products.title'}}
|
||||
{{nav-item route='adminPlugins.discourse-subscriptions.coupons' label='discourse_subscriptions.admin.coupons.title'}}
|
||||
{{nav-item route='adminPlugins.discourse-subscriptions.subscriptions' label='discourse_subscriptions.admin.subscriptions.title'}}
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class='create-coupon-form'>
|
||||
<form class="form-horizontal">
|
||||
<p>
|
||||
<label for="promo_code">{{i18n 'discourse_subscriptions.admin.coupons.promo_code'}}</label>
|
||||
{{input type="text" name="promo_code" value=promoCode}}
|
||||
</p>
|
||||
<p>
|
||||
<label for="amount">{{i18n 'discourse_subscriptions.admin.coupons.discount'}}</label>
|
||||
{{combo-box
|
||||
content=discountTypes
|
||||
value=discountType
|
||||
onChange=(action (mut discountType))
|
||||
}}
|
||||
{{input class="discount-amount" type="text" name="amount" value=discount}}
|
||||
</p>
|
||||
<p>
|
||||
<label for="active">
|
||||
{{i18n 'discourse_subscriptions.admin.coupons.active'}}
|
||||
</label>
|
||||
{{input type="checkbox" name="active" checked=active}}
|
||||
</p>
|
||||
</form>
|
||||
|
||||
{{d-button
|
||||
action=(action "createNewCoupon")
|
||||
label="discourse_subscriptions.admin.coupons.create"
|
||||
title="discourse_subscriptions.admin.coupons.create"
|
||||
icon="plus"
|
||||
class="btn-primary btn btn-icon"}}
|
||||
{{d-button
|
||||
action=(action "cancelCreate")
|
||||
label="cancel"
|
||||
title="cancel"
|
||||
icon="times"
|
||||
class="btn btn-icon"}}
|
||||
</div>
|
||||
Reference in New Issue
Block a user