FEATURE: Campaigns (#67)
Co-authored-by: Jordan Vidrine <[email protected]> See https://github.com/discourse/discourse-subscriptions/pull/67 for the full description.
This commit is contained in:
co-authored by
Jordan Vidrine
parent
dcec7703f8
commit
f596a0f78a
@@ -0,0 +1,120 @@
|
||||
import { action } from "@ember/object";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import { setting } from "discourse/lib/computed";
|
||||
import Component from "@ember/component";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default Component.extend({
|
||||
router: service(),
|
||||
dismissed: false,
|
||||
loading: false,
|
||||
isSidebar: equal(
|
||||
"siteSettings.discourse_subscriptions_campaign_banner_location",
|
||||
"Sidebar"
|
||||
),
|
||||
subscribers: setting("discourse_subscriptions_campaign_subscribers"),
|
||||
subscriberGoal: equal(
|
||||
"siteSettings.discourse_subscriptions_campaign_type",
|
||||
"Subscribers"
|
||||
),
|
||||
currency: setting("discourse_subscriptions_currency"),
|
||||
goalTarget: setting("discourse_subscriptions_campaign_goal"),
|
||||
product: setting("discourse_subscriptions_campaign_product"),
|
||||
showContributors: setting(
|
||||
"discourse_subscriptions_campaign_show_contributors"
|
||||
),
|
||||
classNameBindings: [
|
||||
"isSidebar:campaign-banner-sidebar",
|
||||
"shouldShow:campaign-banner",
|
||||
],
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.set("contributors", []);
|
||||
|
||||
if (this.showContributors) {
|
||||
return ajax("/s/contributors", { method: "get" }).then((result) => {
|
||||
this.setProperties({
|
||||
contributors: result,
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
if (this.isSidebar && this.shouldShow) {
|
||||
document.body.classList.add("subscription-campaign-sidebar");
|
||||
} else {
|
||||
document.body.classList.remove("subscription-campaign-sidebar");
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed(
|
||||
"router.currentRouteName",
|
||||
"currentUser",
|
||||
"siteSettings.discourse_subscriptions_campaign_enabled",
|
||||
"visible"
|
||||
)
|
||||
shouldShow(currentRoute, currentUser, enabled, visible) {
|
||||
// do not show on admin or subscriptions pages
|
||||
const showOnRoute =
|
||||
currentRoute !== "discovery.s" &&
|
||||
!currentRoute.split(".")[0].includes("admin") &&
|
||||
currentRoute.split(".")[0] !== "s";
|
||||
|
||||
return showOnRoute && currentUser && enabled && visible;
|
||||
},
|
||||
|
||||
@observes("dismissed")
|
||||
_updateBodyClasses() {
|
||||
if (this.dismissed) {
|
||||
document.body.classList.remove("subscription-campaign-sidebar");
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("dismissed")
|
||||
visible(dismissed) {
|
||||
const dismissedBannerKey = this.keyValueStore.get(
|
||||
"dismissed_campaign_banner"
|
||||
);
|
||||
const threeMonths = 2628000000 * 3;
|
||||
|
||||
const bannerDismissedTime = new Date(dismissedBannerKey);
|
||||
const now = Date.now();
|
||||
|
||||
return (
|
||||
(!dismissedBannerKey || now - bannerDismissedTime > threeMonths) &&
|
||||
!dismissed
|
||||
);
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
amountRaised() {
|
||||
return (
|
||||
this.siteSettings.discourse_subscriptions_campaign_amount_raised / 100
|
||||
);
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
isGoalMet() {
|
||||
const currentVolume = this.subscriberGoal
|
||||
? this.subscribers
|
||||
: this.amountRaised;
|
||||
|
||||
return currentVolume >= this.goalTarget;
|
||||
},
|
||||
|
||||
@action
|
||||
dismissBanner() {
|
||||
this.set("dismissed", true);
|
||||
this.keyValueStore.set({
|
||||
key: "dismissed_campaign_banner",
|
||||
value: Date.now(),
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
import { action } from "@ember/object";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import Controller from "@ember/controller";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Controller.extend({
|
||||
loading: false,
|
||||
|
||||
@discourseComputed
|
||||
stripeConfigured() {
|
||||
return !!this.siteSettings.discourse_subscriptions_public_key;
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
campaignEnabled() {
|
||||
return this.siteSettings.discourse_subscriptions_campaign_enabled;
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
campaignProductSet() {
|
||||
return !!this.siteSettings.discourse_subscriptions_campaign_product;
|
||||
},
|
||||
|
||||
@action
|
||||
triggerManualRefresh() {
|
||||
ajax(`/s/admin/refresh`, {
|
||||
method: "post",
|
||||
}).then(() => {
|
||||
bootbox.alert(
|
||||
I18n.t("discourse_subscriptions.campaign.refresh_page"),
|
||||
() => {
|
||||
this.transitionToRoute(
|
||||
"adminPlugins.discourse-subscriptions.products"
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
createOneClickCampaign() {
|
||||
bootbox.confirm(
|
||||
I18n.t("discourse_subscriptions.campaign.confirm_creation"),
|
||||
(result) => {
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set("loading", true);
|
||||
|
||||
ajax(`/s/admin/create-campaign`, {
|
||||
method: "post",
|
||||
})
|
||||
.then(() => {
|
||||
this.set("loading", false);
|
||||
bootbox.alert(
|
||||
I18n.t("discourse_subscriptions.campaign.created"),
|
||||
() => {
|
||||
this.send("showSettings");
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -14,7 +14,7 @@ export default Controller.extend({
|
||||
this._super(...arguments);
|
||||
this.set(
|
||||
"stripe",
|
||||
Stripe(Discourse.SiteSettings.discourse_subscriptions_public_key)
|
||||
Stripe(this.siteSettings.discourse_subscriptions_public_key)
|
||||
);
|
||||
const elements = this.get("stripe").elements();
|
||||
|
||||
@@ -76,7 +76,7 @@ export default Controller.extend({
|
||||
plan.type === "recurring"
|
||||
? "user.billing.subscriptions"
|
||||
: "user.billing.payments",
|
||||
Discourse.User.current().username.toLowerCase()
|
||||
this.currentUser.username.toLowerCase()
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ export default {
|
||||
|
||||
map() {
|
||||
this.route("discourse-subscriptions", function () {
|
||||
this.route("dashboard");
|
||||
|
||||
this.route("products", function () {
|
||||
this.route("show", { path: "/:product-id" }, function () {
|
||||
this.route("plans", function () {
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
import Route from "@ember/routing/route";
|
||||
|
||||
export default Route.extend({});
|
||||
export default Route.extend({
|
||||
actions: {
|
||||
showSettings() {
|
||||
const controller = this.controllerFor("adminSiteSettings");
|
||||
this.transitionTo("adminSiteSettingsCategory", "plugins").then(() => {
|
||||
controller.set("filter", "plugin:discourse-subscriptions campaign");
|
||||
controller.set("_skipBounce", true);
|
||||
controller.filterContentNow("plugins");
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{{#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>
|
||||
<p><a href="https://meta.discourse.org/t/discourse-subscriptions/140818/">{{i18n 'discourse_subscriptions.admin.on_meta'}}</a></p>
|
||||
{{else}}
|
||||
{{#if model}}
|
||||
<table class="table discourse-patrons-table">
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{{#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>
|
||||
<p><a href="https://meta.discourse.org/t/discourse-subscriptions/140818/">{{i18n 'discourse_subscriptions.admin.on_meta'}}</a></p>
|
||||
{{else}}
|
||||
<p class="btn-right">
|
||||
{{#link-to 'adminPlugins.discourse-subscriptions.products.show' 'new' class="btn btn-primary"}}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{{#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>
|
||||
<p><a href="https://meta.discourse.org/t/discourse-subscriptions/140818/">{{i18n 'discourse_subscriptions.admin.on_meta'}}</a></p>
|
||||
{{else}}
|
||||
{{#load-more selector=".discourse-patrons-table tr" action=(action "loadMore")}}
|
||||
<table class="table discourse-patrons-table">
|
||||
|
||||
@@ -1,15 +1,38 @@
|
||||
|
||||
<h2>{{i18n 'discourse_subscriptions.title' site_name=siteSettings.title}}</h2>
|
||||
|
||||
<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>
|
||||
{{#if stripeConfigured}}
|
||||
<div class="discourse-subscriptions-buttons">
|
||||
{{#if campaignEnabled}}
|
||||
{{d-button
|
||||
label="discourse_subscriptions.campaign.refresh_campaign"
|
||||
icon="sync-alt"
|
||||
action=(action 'triggerManualRefresh')
|
||||
}}
|
||||
{{else}}
|
||||
{{#unless campaignProductSet}}
|
||||
{{d-button
|
||||
label="discourse_subscriptions.campaign.one_click_campaign"
|
||||
icon="plus-square"
|
||||
action=(action 'createOneClickCampaign')
|
||||
isLoading=loading
|
||||
}}
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<ul class="nav nav-pills">
|
||||
{{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>
|
||||
|
||||
<div id="discourse-subscriptions-admin">
|
||||
{{outlet}}
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div id="discourse-subscriptions-admin">
|
||||
{{outlet}}
|
||||
</div>
|
||||
{{else}}
|
||||
<p>{{i18n 'discourse_subscriptions.admin.unconfigured'}}</p>
|
||||
<p><a href="https://meta.discourse.org/t/discourse-subscriptions/140818/">{{i18n 'discourse_subscriptions.admin.on_meta'}}</a></p>
|
||||
{{/if}}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
{{#if shouldShow}}
|
||||
{{d-button
|
||||
icon="times"
|
||||
action="dismissBanner"
|
||||
class="close"
|
||||
}}
|
||||
<div class="campaign-banner-info">
|
||||
<h2 class="campaign-banner-info-header">{{i18n 'discourse_subscriptions.campaign.title'}}</h2>
|
||||
<p class="campaign-banner-info-description">{{i18n 'discourse_subscriptions.campaign.body'}}</p>
|
||||
{{#if product}}
|
||||
{{#link-to "s.show" product disabled=product.subscribed class="btn btn-primary campaign-banner-info-button"}}
|
||||
{{d-icon "far-heart"}} {{d-icon "heart" class="hover-heart"}} {{i18n 'discourse_subscriptions.campaign.button'}}
|
||||
{{/link-to}}
|
||||
{{else}}
|
||||
{{#link-to "s" class="btn btn-primary campaign-banner-info-button"}}
|
||||
{{d-icon "far-heart"}} {{d-icon "heart" class="hover-heart"}} {{i18n 'discourse_subscriptions.campaign.button'}}
|
||||
{{/link-to}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="campaign-banner-progress">
|
||||
{{#if isGoalMet}}
|
||||
<p class="campaign-banner-progress-success">{{i18n 'discourse_subscriptions.campaign.goal'}}!</p>
|
||||
{{#if subscriberGoal}}
|
||||
<p class="campaign-banner-progress-description">
|
||||
{{i18n 'discourse_subscriptions.campaign.goal_comparison' current=subscribers goal=goalTarget}}
|
||||
{{i18n 'discourse_subscriptions.campaign.subscribers'}}
|
||||
</p>
|
||||
{{else}}
|
||||
<p class="campaign-banner-progress-description">
|
||||
{{html-safe (i18n 'discourse_subscriptions.campaign.goal_comparison' current=(format-currency currency amountRaised) goal=(format-currency currency goalTarget))}}
|
||||
{{i18n 'discourse_subscriptions.campaign.raised'}}
|
||||
</p>
|
||||
{{#if showContributors}}
|
||||
{{#conditional-loading-spinner condition=loading size="small"}}
|
||||
<div class="campaign-banner-progress-users">
|
||||
<p class="campaign-banner-progress-users-title">
|
||||
<strong>{{i18n 'discourse_subscriptions.campaign.recent_contributors'}}</strong>
|
||||
</p>
|
||||
<div class="campaign-banner-progress-users-avatars">
|
||||
{{#each contributors as |contributor|}}
|
||||
{{avatar contributor avatarTemplatePath="avatar_template" usernamePath="username" namePath="name" imageSize="small"}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/conditional-loading-spinner}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if subscriberGoal}}
|
||||
<progress class="campaign-banner-progress-bar" value="{{subscribers}}" max="{{siteSettings.discourse_subscriptions_campaign_goal}}"/>
|
||||
<p class="campaign-banner-progress-description">
|
||||
{{i18n 'discourse_subscriptions.campaign.goal_comparison' current=subscribers goal=goalTarget}}
|
||||
{{i18n 'discourse_subscriptions.campaign.subscribers'}}
|
||||
</p>
|
||||
{{else}}
|
||||
<progress class="campaign-banner-progress-bar" value="{{amountRaised}}" max="{{siteSettings.discourse_subscriptions_campaign_goal}}"/>
|
||||
<p class="campaign-banner-progress-description">
|
||||
{{html-safe (i18n 'discourse_subscriptions.campaign.goal_comparison' current=(format-currency currency amountRaised) goal=(format-currency currency goalTarget))}}
|
||||
{{i18n 'discourse_subscriptions.campaign.raised'}}
|
||||
</p>
|
||||
{{/if}}
|
||||
{{#if showContributors}}
|
||||
{{#conditional-loading-spinner condition=loading size="small"}}
|
||||
<div class="campaign-banner-progress-users">
|
||||
<p class="campaign-banner-progress-users-title">
|
||||
<strong>{{i18n 'discourse_subscriptions.campaign.recent_contributors'}}</strong>
|
||||
</p>
|
||||
<div class="campaign-banner-progress-users-avatars">
|
||||
{{#each contributors as |contributor|}}
|
||||
{{avatar contributor avatarTemplatePath="avatar_template" usernamePath="username" namePath="name" imageSize="small"}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/conditional-loading-spinner}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{{#unless (eq siteSettings.discourse_subscriptions_campaign_banner_location "Sidebar")}}
|
||||
{{campaign-banner}}
|
||||
{{/unless}}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{{#if (eq siteSettings.discourse_subscriptions_campaign_banner_location "Sidebar")}}
|
||||
{{campaign-banner}}
|
||||
{{/if}}
|
||||
@@ -44,7 +44,11 @@
|
||||
label="discourse_subscriptions.plans.payment_button"
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
{{else}}
|
||||
<h2>{{i18n 'discourse_subscriptions.subscribe.already_purchased'}}</h2>
|
||||
{{#link-to "user.billing.subscriptions" currentUser.username class="btn btn-primary"}}
|
||||
{{i18n 'discourse_subscriptions.subscribe.go_to_billing'}}
|
||||
{{/link-to}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user