Skip to content

Commit

Permalink
Add x-discourse-subscriptions into discourse-subscription-server
Browse files Browse the repository at this point in the history
  • Loading branch information
angusmcleod committed Jan 4, 2024
1 parent d9a0fe7 commit b00c1a4
Show file tree
Hide file tree
Showing 33 changed files with 951 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class SubscriptionServer::UserAuthorizationsController < ApplicationController
before_action :ensure_logged_in

def destroy
params.require(:domain)
current_user.remove_subscription_domain(params[:domain])
render json: success_json
end
end
47 changes: 47 additions & 0 deletions assets/javascripts/discourse/components/create-coupon-form.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<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="product">{{i18n "discourse_subscriptions.admin.products.title"}}</label>
{{combo-box
content=products
value=productId
onChange=(action (mut productId))
options=(hash
maximum=1
)
}}
</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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<DModal
@closeModal={{@closeModal}}
@title={{i18n "discourse_subscriptions.user.invoices.modal.title"}}
class="discourse-subscriptions-user-invoices"
>
<:body>
{{i18n "discourse_subscriptions.user.invoices.modal.description" email=this.currentUser.email}}
</:body>
<:footer>
<a

Check failure on line 10 in assets/javascripts/discourse/components/modal/subscription-invoices.hbs

View workflow job for this annotation

GitHub Actions / ci / linting

links with target="_blank" must have rel="noopener noreferrer" or rel="noreferrer noopener"
href="https://billing.stripe.com/p/login/28oaGm8iF6S8eKQcMM"
target="_blank"
role="button"
class="btn btn-primary">
{{d-icon "external-link-alt"}}
<span class="d-button-label">
{{i18n "discourse_subscriptions.user.invoices.modal.btn"}}
</span>
</a>
<DModalCancel @close={{@closeModal}} />
</:footer>
</DModal>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Component from "@glimmer/component";
import { inject as service } from "@ember/service";

export default class SubscriptionInvoices extends Component {
@service currentUser;
}
12 changes: 12 additions & 0 deletions assets/javascripts/discourse/components/payment-plan.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<div class="interval">
<h3>
{{#if recurringPlan}}
{{i18n (concat "discourse_subscriptions.plans.interval.adverb." plan.recurring.interval)}}
{{else}}
{{i18n "discourse_subscriptions.one_time_payment"}}
{{/if}}
</h3>
</div>
<span class="amount">
{{format-currency plan.currency plan.amountDollars}}
</span>
37 changes: 37 additions & 0 deletions assets/javascripts/discourse/components/product-item.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<h2>{{product.name}}</h2>

<p class="product-description">
{{html-safe product.description}}
</p>

{{#if isLoggedIn}}
<div class="product-purchase">
{{#if product.custom}}
<a href={{product.btnHref}} class="btn btn-primary" target="_blank">

Check failure on line 10 in assets/javascripts/discourse/components/product-item.hbs

View workflow job for this annotation

GitHub Actions / ci / linting

links with target="_blank" must have rel="noopener noreferrer" or rel="noreferrer noopener"
{{product.btnLabel}}
</a>
{{else}}
{{#if product.repurchaseable}}
{{#link-to "subscribe.show" product.id class="btn btn-primary"}}
{{i18n "discourse_subscriptions.subscribe.title"}}
{{/link-to}}
{{#if product.subscribed}}
{{#link-to "user.billing.subscriptions" currentUser.username class="billing-link"}}
{{i18n "discourse_subscriptions.subscribe.view_past"}}
{{/link-to}}
{{/if}}
{{else}}
{{#if product.subscribed}}
<span class="purchased">&#x2713; {{i18n "discourse_subscriptions.subscribe.purchased"}}</span>
{{#link-to "user.billing.subscriptions" currentUser.username class="billing-link"}}
{{i18n "discourse_subscriptions.subscribe.go_to_billing"}}
{{/link-to}}
{{else}}
{{#link-to "subscribe.show" product.id disabled=product.subscribed class="btn btn-primary"}}
{{i18n "discourse_subscriptions.subscribe.title"}}
{{/link-to}}
{{/if}}
{{/if}}
{{/if}}
</div>
{{/if}}
21 changes: 21 additions & 0 deletions assets/javascripts/discourse/components/subscription-data.gjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Component from "@glimmer/component";
import SubscriptionDomains from "./subscription-domains";

export default class SubscriptionDomain extends Component {
<template>
<tr class='subscription-data'>
<td>{{@data.resource}}</td>
<td>
<ul>
{{#each @data.products as |product|}}
<li><span>{{product}}</span></li>
{{/each}}
</ul>
</td>
<td>
<SubscriptionDomains @domains={{@data.domains}} />
</td>
<td>{{@data.domain_limit}}</td>
</tr>
</template>
}
31 changes: 31 additions & 0 deletions assets/javascripts/discourse/components/subscription-domain.gjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import DButton from "discourse/components/d-button";
import { tracked } from "@glimmer/tracking";

export default class SubscriptionDomain extends Component {
@tracked removing;

@action
removeDomain() {
this.removing = true;
this.args.remove(this.args.domain)
.finally(() => {
if (this.isDestroying || this.isDestroyed) {
return;
}
this.removing = false;
})
}

<template>
<span>{{@domain}}</span>
<DButton
@icon="minus"
@class="remove-domain"
@action={{this.removeDomain}}
@title="discourse_subscriptions.user.authorizations.remove_domain.title"
@disabled={{this.removing}}
/>
</template>
}
40 changes: 40 additions & 0 deletions assets/javascripts/discourse/components/subscription-domains.gjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import DButton from "discourse/components/d-button";
import { tracked } from "@glimmer/tracking";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { ajax } from "discourse/lib/ajax";
import SubscriptionDomain from "./subscription-domain";

export default class SubscriptionDomains extends Component {
@tracked domains;

constructor() {
super(...arguments);
this.domains = this.args.domains;
}

@action
removeDomain(domain) {
return ajax('/subscription-server/user-authorizations', {
type: 'DELETE',
data: {
domain
}
})
.catch(popupAjaxError)
.then(() => {
this.domains = this.domains.filter((d) => (d !== domain));
});
}

<template>
<ul>
{{#each this.domains as |domain|}}
<li class="subscription-domain">
<SubscriptionDomain @domain={{domain}} @remove={{this.removeDomain}} />
</li>
{{/each}}
</ul>
</template>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { inject as service } from "@ember/service";
import DButton from "discourse/components/d-button";
import SubscriptionInvoicesModal from "./modal/subscription-invoices";

export default class SubscriptionInvoicesBtn extends Component {
@service modal;

@action
showModal() {
this.modal.show(SubscriptionInvoicesModal, { model: this.args });
}

<template>
<DButton
@class="discourse-subscriptions-invoices-btn btn-primary"
@action={{this.showModal}}
@label="discourse_subscriptions.user.invoices.btn.label"
@title="discourse_subscriptions.user.invoices.btn.title"
/>
</template>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{text}}
16 changes: 16 additions & 0 deletions assets/javascripts/discourse/components/subscriptions-banner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";

export default Component.extend({
classNameBindings: [":subscriptions-banner", "showBanner:visible"],

@discourseComputed("currentPath", "text")
showBanner(currentPath, text) {
return currentPath.includes('subscribe') && text && text.length > 2;
},

@discourseComputed()
text() {
return this.siteSettings.custom_wizard_subscription_banner;
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{subscriptions-banner currentPath=currentPath}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { withPluginApi } from "discourse/lib/plugin-api";
import discourseComputed from "discourse-common/utils/decorators";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { ajax } from "discourse/lib/ajax";
import { customProducts, productOrder } from '../lib/products';

export default {
name: 'subscription-servier-initializer',
initialize() {
withPluginApi('0.8.30', api => {
api.modifyClass('component:payment-plan', {
pluginId: 'discourse-subscription-server',
classNameBindings: [':btn-pavilion-subscribe', 'selectedClass'],
tagName: "div",

click() {
this.clickPlan(this.plan);
}
});

api.modifyClass('route:admin-plugins-discourse-subscriptions-coupons', {
pluginId: 'discourse-subscription-server',

afterModel() {
const AdminProduct = requirejs("discourse/plugins/discourse-subscriptions/discourse/models/admin-product").default;
return AdminProduct.findAll().then(products => {
this.set('products', products);
});
},

setupController(controller, model) {
controller.setProperties({
model,
products: this.products
})
}
});

api.modifyClass('controller:admin-plugins-discourse-subscriptions-coupons', {
pluginId: 'discourse-subscription-server',

actions: {
createNewCoupon(params) {
const data = {
promo: params.promo,
discount_type: params.discount_type,
discount: params.discount,
active: params.active,
applies_to_products: params.applies_to_products
};

return ajax("/s/admin/coupons", {
method: "post",
data,
})
.then(() => {
this.send("closeCreateForm");
this.send("reloadModel");
})
.catch(popupAjaxError);
}
}
});

const couponController = api._lookupContainer('controller:admin-plugins-discourse-subscriptions-coupons');
api.modifyClass('component:create-coupon-form', {
pluginId: 'discourse-subscription-server',

@discourseComputed
products() {
return couponController.get('products');
},

actions: {
createNewCoupon() {
const createParams = {
promo: this.promoCode,
discount_type: this.discountType,
discount: this.discount,
active: this.active,
applies_to_products: [this.productId]
};
this.create(createParams);
},
},
});

api.modifyClass('route:subscribe-index', {
pluginId: 'discourse-subscription-server',

setupController(controller, model) {
const stripeProducts = model;
const Product = requirejs("discourse/plugins/discourse-subscriptions/discourse/models/product").default;
const nonStripeProducts = customProducts().map((product) => Product.create(product));
const products = stripeProducts
.concat(nonStripeProducts)
.filter(p => (!p.hidden))
.sort(function(a,b) {
return productOrder.indexOf(a.name) - productOrder.indexOf(b.name);
});
controller.set('model', products);
}
});
})
}
}
Loading

0 comments on commit b00c1a4

Please sign in to comment.