mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-03 08:25:06 +03:00
Updated launch wizard pricing step to show portal preview
refs - dropped the portal service in favour of using the existing `membersUtils` service - renamed `getPreviewUrl()` to `getPortalPreviewUrl()` - update the iframe src to point to the portal preview url when on the pricing step - added free/monthly/yearly checkboxes to pricing step - update iframe src with regenerated portal preview params when making changes
This commit is contained in:
parent
fbd42ef33e
commit
7687571b12
@ -52,18 +52,66 @@
|
||||
<GhErrorMessage @errors={{this.settings.errors}} @property="stripePlans" class="w-100 red"/>
|
||||
</div>
|
||||
|
||||
<div class="gh-setting-first">
|
||||
<div class="gh-setting-content">
|
||||
<h4 class="gh-setting-title">Allow free member signup</h4>
|
||||
<p class="gh-setting-desc pa0 ma0">If disabled, members can only be signed up via payment checkout or API integration</p>
|
||||
<div>
|
||||
<div class="mb3">
|
||||
<h4 class="gh-portal-setting-title">Plans available at signup</h4>
|
||||
</div>
|
||||
<div class="gh-setting-action">
|
||||
<div class="for-switch">
|
||||
<label class="switch" for="members-allow-self-signup" {{action "toggleSelfSignup" bubbles="false"}}>
|
||||
<input type="checkbox" checked={{this.settings.membersAllowFreeSignup}} class="gh-input" {{on "click" this.toggleSelfSignup}} data-test-checkbox="members-allow-self-signup">
|
||||
<span class="input-toggle-component mt1"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group mb0 for-checkbox">
|
||||
<label
|
||||
class="checkbox"
|
||||
for="free-plan"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={{this.isFreeChecked}}
|
||||
id="free-plan"
|
||||
name="free-plan"
|
||||
disabled={{not this.settings.membersAllowFreeSignup}}
|
||||
class="gh-input post-settings-featured"
|
||||
{{on "click" this.toggleFreePlan}}
|
||||
data-test-checkbox="featured"
|
||||
>
|
||||
<span class="input-toggle-component"></span>
|
||||
<p>Free</p>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group mb0 for-checkbox">
|
||||
<label
|
||||
class="checkbox"
|
||||
for="monthly-plan"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="monthly-plan"
|
||||
name="monthly-plan"
|
||||
checked={{this.isMonthlyChecked}}
|
||||
disabled={{not this.membersUtils.isStripeEnabled}}
|
||||
class="gh-input post-settings-featured"
|
||||
{{on "click" this.toggleMonthlyPlan}}
|
||||
data-test-checkbox="featured"
|
||||
>
|
||||
<span class="input-toggle-component"></span>
|
||||
<p>Monthly</p>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group mb0 for-checkbox">
|
||||
<label
|
||||
class="checkbox"
|
||||
for="yearly-plan"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="yearly-plan"
|
||||
name="yearly-plan"
|
||||
checked={{this.isYearlyChecked}}
|
||||
disabled={{not this.membersUtils.isStripeEnabled}}
|
||||
class="gh-input post-settings-featured"
|
||||
{{on "click" this.toggleYearlyPlan}}
|
||||
data-test-checkbox="featured"
|
||||
>
|
||||
<span class="input-toggle-component"></span>
|
||||
<p>Yearly</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -6,6 +6,8 @@ import {task} from 'ember-concurrency-decorators';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class GhLaunchWizardSetPricingComponent extends Component {
|
||||
@service config;
|
||||
@service membersUtils;
|
||||
@service settings;
|
||||
|
||||
currencies = CURRENCIES;
|
||||
@ -34,9 +36,30 @@ export default class GhLaunchWizardSetPricingComponent extends Component {
|
||||
return this.currencies.findBy('value', this.stripePlans.monthly.currency);
|
||||
}
|
||||
|
||||
get isFreeChecked() {
|
||||
const allowedPlans = this.settings.get('portalPlans') || [];
|
||||
return (this.settings.get('membersAllowFreeSignup') && allowedPlans.includes('free'));
|
||||
}
|
||||
|
||||
get isMonthlyChecked() {
|
||||
const allowedPlans = this.settings.get('portalPlans') || [];
|
||||
return (this.membersUtils.isStripeEnabled && allowedPlans.includes('monthly'));
|
||||
}
|
||||
|
||||
get isYearlyChecked() {
|
||||
const allowedPlans = this.settings.get('portalPlans') || [];
|
||||
return (this.membersUtils.isStripeEnabled && allowedPlans.includes('yearly'));
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.updatePreviewUrl();
|
||||
}
|
||||
|
||||
willDestroy() {
|
||||
// clear any unsaved settings changes when going back/forward/closing
|
||||
this.settings.rollbackAttributes();
|
||||
this.args.updatePreview('');
|
||||
}
|
||||
|
||||
@action
|
||||
@ -66,11 +89,22 @@ export default class GhLaunchWizardSetPricingComponent extends Component {
|
||||
}
|
||||
|
||||
this.settings.set('stripePlans', updatedPlans);
|
||||
this.updatePreviewUrl();
|
||||
}
|
||||
|
||||
@action
|
||||
toggleSelfSignup() {
|
||||
this.settings.set('membersAllowFreeSignup', !this.settings.get('membersAllowFreeSignup'));
|
||||
toggleFreePlan(event) {
|
||||
this.updateAllowedPlan('free', event.target.checked);
|
||||
}
|
||||
|
||||
@action
|
||||
toggleMonthlyPlan(event) {
|
||||
this.updateAllowedPlan('monthly', event.target.checked);
|
||||
}
|
||||
|
||||
@action
|
||||
toggleYearlyPlan(event) {
|
||||
this.updateAllowedPlan('yearly', event.target.checked);
|
||||
}
|
||||
|
||||
@action
|
||||
@ -109,6 +143,7 @@ export default class GhLaunchWizardSetPricingComponent extends Component {
|
||||
});
|
||||
|
||||
this.settings.set('stripePlans', updatedPlans);
|
||||
this.updatePreviewUrl();
|
||||
} catch (err) {
|
||||
this.settings.errors.add('stripePlans', err.message);
|
||||
} finally {
|
||||
@ -127,4 +162,31 @@ export default class GhLaunchWizardSetPricingComponent extends Component {
|
||||
yield this.settings.save();
|
||||
this.args.nextStep();
|
||||
}
|
||||
|
||||
updateAllowedPlan(plan, isChecked) {
|
||||
const allowedPlans = this.settings.get('portalPlans') || [];
|
||||
|
||||
if (!isChecked) {
|
||||
this.settings.set('portalPlans', allowedPlans.filter(p => p !== plan));
|
||||
} else {
|
||||
allowedPlans.push(plan);
|
||||
this.settings.set('portalPlans', [...allowedPlans]);
|
||||
}
|
||||
|
||||
this.updatePreviewUrl();
|
||||
}
|
||||
|
||||
updatePreviewUrl() {
|
||||
const options = {
|
||||
disableBackground: true,
|
||||
currency: this.selectedCurrency.value,
|
||||
monthlyPrice: this.stripePlans.monthly.amount,
|
||||
yearlyPrice: this.stripePlans.yearly.amount,
|
||||
isMonthly: this.isMonthlyChecked,
|
||||
isYearly: this.isYearlyChecked,
|
||||
isFree: this.isFreeChecked
|
||||
};
|
||||
const url = this.membersUtils.getPortalPreviewUrl(options);
|
||||
this.args.updatePreview(url);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<iframe id="site-frame" class="site-frame {{this.classNames}}" src="{{this.srcUrl}}" frameborder="0" allowtransparency="true" ...attributes></iframe>
|
||||
<iframe id="site-frame" class="site-frame {{this.classNames}}" src={{this.srcUrl}} frameborder="0" allowtransparency="true" ...attributes></iframe>
|
||||
|
||||
<style>
|
||||
.site-frame {
|
||||
|
@ -35,7 +35,6 @@ export const ICON_MAPPING = [
|
||||
export default ModalComponent.extend({
|
||||
config: service(),
|
||||
membersUtils: service(),
|
||||
portal: service(),
|
||||
settings: service(),
|
||||
|
||||
page: 'signup',
|
||||
@ -73,7 +72,7 @@ export default ModalComponent.extend({
|
||||
|
||||
portalPreviewUrl: computed('buttonIcon', 'page', 'isFreeChecked', 'isMonthlyChecked', 'isYearlyChecked', 'settings.{portalName,portalButton,portalButtonSignupText,portalButtonStyle,accentColor}', function () {
|
||||
const options = this.getProperties(['buttonIcon', 'page', 'isFreeChecked', 'isMonthlyChecked', 'isYearlyChecked']);
|
||||
return this.portal.getPreviewUrl(options);
|
||||
return this.membersUtils.getPortalPreviewUrl(options);
|
||||
}),
|
||||
|
||||
showIconSetting: computed('selectedButtonStyle', function () {
|
||||
|
@ -75,6 +75,7 @@ export default class LaunchController extends Controller {
|
||||
|
||||
@action
|
||||
updatePreview(url) {
|
||||
console.log({url});
|
||||
this.previewSrc = url;
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Service from '@ember/service';
|
||||
import {ICON_MAPPING} from 'ghost-admin/components/modal-portal-settings';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class MembersUtilsService extends Service {
|
||||
@service settings;
|
||||
@service config;
|
||||
@service settings;
|
||||
|
||||
get isStripeEnabled() {
|
||||
const stripeDirect = this.config.get('stripeDirect');
|
||||
@ -17,4 +17,60 @@ export default class MembersUtilsService extends Service {
|
||||
|
||||
return hasConnectKeys || hasDirectKeys;
|
||||
}
|
||||
|
||||
getPortalPreviewUrl(args) {
|
||||
let {
|
||||
disableBackground,
|
||||
buttonIcon,
|
||||
page = 'signup',
|
||||
isFree = true,
|
||||
isMonthly = true,
|
||||
isYearly = true,
|
||||
monthlyPrice,
|
||||
yearlyPrice,
|
||||
currency
|
||||
} = args;
|
||||
|
||||
if (!buttonIcon) {
|
||||
const defaultIconKeys = ICON_MAPPING.map(icon => icon.value);
|
||||
buttonIcon = this.settings.get('portalButtonIcon') || defaultIconKeys[0];
|
||||
}
|
||||
|
||||
const baseUrl = this.config.get('blogUrl');
|
||||
const portalBase = '/#/portal/preview';
|
||||
const settingsParam = new URLSearchParams();
|
||||
const signupButtonText = this.settings.get('portalButtonSignupText') || '';
|
||||
|
||||
settingsParam.append('button', this.settings.get('portalButton'));
|
||||
settingsParam.append('name', this.settings.get('portalName'));
|
||||
settingsParam.append('isFree', isFree);
|
||||
settingsParam.append('isMonthly', isMonthly);
|
||||
settingsParam.append('isYearly', isYearly);
|
||||
settingsParam.append('page', page);
|
||||
settingsParam.append('buttonIcon', encodeURIComponent(buttonIcon));
|
||||
settingsParam.append('signupButtonText', encodeURIComponent(signupButtonText));
|
||||
|
||||
if (this.settings.get('accentColor') === '' || this.settings.get('accentColor')) {
|
||||
settingsParam.append('accentColor', encodeURIComponent(`${this.settings.get('accentColor')}`));
|
||||
}
|
||||
if (this.settings.get('portalButtonStyle')) {
|
||||
settingsParam.append('buttonStyle', encodeURIComponent(this.settings.get('portalButtonStyle')));
|
||||
}
|
||||
|
||||
if (monthlyPrice) {
|
||||
settingsParam.append('monthlyPrice', monthlyPrice);
|
||||
}
|
||||
if (yearlyPrice) {
|
||||
settingsParam.append('yearlyPrice', monthlyPrice);
|
||||
}
|
||||
if (currency) {
|
||||
settingsParam.append('currency', currency);
|
||||
}
|
||||
|
||||
if (disableBackground) {
|
||||
settingsParam.append('disableBackground', true);
|
||||
}
|
||||
|
||||
return `${baseUrl}${portalBase}?${settingsParam.toString()}`;
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
import Service from '@ember/service';
|
||||
import {ICON_MAPPING} from 'ghost-admin/components/modal-portal-settings';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class PortalService extends Service {
|
||||
@service config;
|
||||
@service settings;
|
||||
|
||||
getPreviewUrl(args) {
|
||||
let {
|
||||
buttonIcon,
|
||||
page = 'signup',
|
||||
isFreeChecked = true,
|
||||
isMonthlyChecked = true,
|
||||
isYearlyChecked = true,
|
||||
monthlyPrice,
|
||||
yearlyPrice
|
||||
} = args;
|
||||
|
||||
if (!buttonIcon) {
|
||||
const defaultIconKeys = ICON_MAPPING.map(icon => icon.value);
|
||||
buttonIcon = this.settings.get('portalButtonIcon') || defaultIconKeys[0];
|
||||
}
|
||||
|
||||
const baseUrl = this.config.get('blogUrl');
|
||||
const portalBase = '/#/portal/preview';
|
||||
const settingsParam = new URLSearchParams();
|
||||
const signupButtonText = this.settings.get('portalButtonSignupText') || '';
|
||||
|
||||
settingsParam.append('button', this.settings.get('portalButton'));
|
||||
settingsParam.append('name', this.settings.get('portalName'));
|
||||
settingsParam.append('isFree', isFreeChecked);
|
||||
settingsParam.append('isMonthly', isMonthlyChecked);
|
||||
settingsParam.append('isYearly', isYearlyChecked);
|
||||
settingsParam.append('page', page);
|
||||
settingsParam.append('buttonIcon', encodeURIComponent(buttonIcon));
|
||||
settingsParam.append('signupButtonText', encodeURIComponent(signupButtonText));
|
||||
|
||||
if (this.settings.get('accentColor') === '' || this.settings.get('accentColor')) {
|
||||
settingsParam.append('accentColor', encodeURIComponent(`${this.settings.get('accentColor')}`));
|
||||
}
|
||||
if (this.settings.get('portalButtonStyle')) {
|
||||
settingsParam.append('buttonStyle', encodeURIComponent(this.settings.get('portalButtonStyle')));
|
||||
}
|
||||
|
||||
if (monthlyPrice) {
|
||||
settingsParam.append('monthlyPrice', monthlyPrice);
|
||||
}
|
||||
if (yearlyPrice) {
|
||||
settingsParam.append('yearlyPrice', monthlyPrice);
|
||||
}
|
||||
|
||||
return `${baseUrl}${portalBase}?${settingsParam.toString()}`;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user