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:
Justin DiRose
2021-01-13 11:47:22 -06:00
committed by GitHub
parent a6de862ba9
commit 400313cded
14 changed files with 422 additions and 0 deletions
@@ -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();
},
},
});
@@ -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;
@@ -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();
},
},
});
@@ -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>