Reverted launch wizard prototype
no issue - removing launch wizard from master ready to re-apply in 4.0 branch
This commit is contained in:
parent
39eec85180
commit
e88e8f88e8
|
@ -1,94 +0,0 @@
|
|||
<h2>Connect Stripe</h2>
|
||||
|
||||
<div class="flex mb4 br3 bg-white">
|
||||
<div class="pa4">
|
||||
{{#if this.config.stripeDirect}}
|
||||
<div class="flex flex-column flex-row-l items-start justify-between mb4 mt6">
|
||||
<div class="w-100 w-50-l">
|
||||
<div class="mb4">
|
||||
<label for="stripe-publishable-key" class="fw6 f8">Stripe Publishable key</label>
|
||||
<GhTextInput
|
||||
@id="stripe-publishable-key"
|
||||
@type="password"
|
||||
@value={{readonly this.settings.stripeDirectPublicKey}}
|
||||
class="mt1 password"
|
||||
{{on "input" this.setStripeDirectPublicKey}}
|
||||
/>
|
||||
</div>
|
||||
<div class="nudge-top--3">
|
||||
<label for="stripe-secret-key" class="fw6 f8 mt4">Stripe Secret key</label>
|
||||
<GhTextInput
|
||||
@id="stripe-secret-key"
|
||||
@type="password"
|
||||
@value={{readonly this.settings.stripeDirectSecretKey}}
|
||||
class="mt1 password"
|
||||
{{on "input" this.setStripeDirectSecretKey}}
|
||||
/>
|
||||
<a href="https://dashboard.stripe.com/account/apikeys" target="_blank" rel="noopener noreferrer" class="mt1 fw4 f8">
|
||||
Find your Stripe API keys here »
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml0 ml5-l mt6">
|
||||
<div class="gh-members-stripe-info">
|
||||
<div class="gh-members-stripe-info-header">
|
||||
<h4>How you get paid</h4>
|
||||
{{svg-jar "stripe-verified-partner-badge" class="gh-members-stripe-badge"}}
|
||||
</div>
|
||||
<p class="f8 mt2 mb0">
|
||||
Stripe is our exclusive direct payments partner.<br />
|
||||
Ghost collects <strong>no fees</strong> on any payments! If you don’t have a Stripe account yet, you can <a href="https://stripe.com" target="_blank" rel="noopener noreferrer" class="gh-members-stripe-link">sign up here</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="flex flex-column flex-row-l items-start justify-between">
|
||||
<div class="w-100 w-50-l">
|
||||
<label class="fw6 f8">Generate secure key</label>
|
||||
<div class="flex items-center mb4 justify-between gh-members-connectbutton-container mt2">
|
||||
<a href="{{this.stripeConnectAuthUrl}}" class="stripe-connect light-blue" target="_blank" rel="noopener noreferrer"><span>Connect with Stripe</span></a>
|
||||
<div class="ml2 flex items-center flex-nowrap">
|
||||
<span class="mr2 f8 midgrey nowrap {{if this.stripeConnectTestMode "gh-members-connect-testmodeon"}}">{{if this.stripeConnectTestMode "Using" "Use"}} test mode</span>
|
||||
<div class="for-switch small">
|
||||
<label class="switch" for="stripe-connect-test-mode" {{on "click" this.toggleStripeConnectTestMode}}>
|
||||
<input type="checkbox" class="gh-input" checked={{this.stripeConnectTestMode}} {{on "click" this.toggleStripeConnectTestMode}} data-test-checkbox="stripe-connect-test-mode">
|
||||
<span class="input-toggle-component mt1"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nudge-top--3">
|
||||
<GhTextarea
|
||||
class="gh-members-stripe-connect-token"
|
||||
placeholder="Paste your secure key here"
|
||||
{{on "input" this.setStripeConnectIntegrationToken}}
|
||||
/>
|
||||
{{#if this.stripeConnectError}}<p class="mb0 mt2 f8 red">{{this.stripeConnectError}}</p>{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt5 mt5-m mt8-l ml0 ml5-l">
|
||||
<div class="gh-members-stripe-info">
|
||||
<div class="gh-members-stripe-info-header">
|
||||
<h4>How you get paid</h4>
|
||||
{{svg-jar "stripe-verified-partner-badge" class="gh-members-stripe-badge"}}
|
||||
</div>
|
||||
<p class="f8 mt2 mb0">
|
||||
Stripe is our exclusive direct payments partner.<br />
|
||||
Ghost collects <strong>no fees</strong> on any payments! If you don’t have a Stripe account yet, you can <a href="https://stripe.com" target="_blank" rel="noopener noreferrer" class="gh-members-stripe-link">sign up here</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{!-- TODO: reset "failed" state automatically --}}
|
||||
<GhTaskButton
|
||||
@buttonText={{if this.settings.stripeConnectIntegrationToken "Save & continue" "Skip"}}
|
||||
@task={{this.saveAndContinue}}
|
||||
@runningText="Saving"
|
||||
@class="right gh-btn gh-btn-blue gh-btn-icon"
|
||||
data-test-button="wizard-next"
|
||||
/>
|
|
@ -1,67 +0,0 @@
|
|||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency-decorators';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class GhLaunchWizardConnectStripeComponent extends Component {
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service settings;
|
||||
|
||||
@tracked stripeConnectTestMode = false;
|
||||
@tracked stripeConnectError = null;
|
||||
|
||||
get stripeConnectAuthUrl() {
|
||||
const mode = this.stripeConnectTestMode ? 'test' : 'live';
|
||||
return `${this.ghostPaths.url.api('members/stripe_connect')}?mode=${mode}`;
|
||||
}
|
||||
|
||||
willDestroy() {
|
||||
// clear any unsaved settings changes when going back/forward/closing
|
||||
this.settings.rollbackAttributes();
|
||||
}
|
||||
|
||||
@action
|
||||
setStripeDirectPublicKey(event) {
|
||||
this.settings.set('stripeProductName', this.settings.get('title'));
|
||||
this.settings.set('stripePublishableKey', event.target.value);
|
||||
}
|
||||
|
||||
@action
|
||||
setStripeDirectSecretKey(event) {
|
||||
this.settings.set('stripeProductName', this.settings.get('title'));
|
||||
this.settings.set('stripePublishableKey', event.target.value);
|
||||
}
|
||||
|
||||
@action
|
||||
toggleStripeConnectTestMode() {
|
||||
this.stripeConnectTestMode = !this.stripeConnectTestMode;
|
||||
}
|
||||
|
||||
@action
|
||||
setStripeConnectIntegrationToken(event) {
|
||||
this.settings.set('stripeProductName', this.settings.get('title'));
|
||||
this.settings.set('stripeConnectIntegrationToken', event.target.value);
|
||||
this.stripeConnectError = null;
|
||||
}
|
||||
|
||||
@task
|
||||
*saveAndContinue() {
|
||||
if (this.settings.get('stripeConnectIntegrationToken')) {
|
||||
try {
|
||||
yield this.settings.save();
|
||||
} catch (error) {
|
||||
if (error.payload?.errors) {
|
||||
this.stripeConnectError = 'Invalid secure key';
|
||||
return false;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// skip when no token supplied
|
||||
this.args.afterComplete();
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
<div class="flex mb4 br3 bg-white">
|
||||
<div class="w-30 pa4">
|
||||
<h2>Customise</h2>
|
||||
|
||||
<div class="mb6" data-test-setting="icon">
|
||||
<GhUploader
|
||||
@extensions={{this.iconExtensions}}
|
||||
@paramsHash={{hash purpose="icon"}}
|
||||
@onComplete={{action "imageUploaded" "icon"}}
|
||||
as |uploader|
|
||||
>
|
||||
<div class="gh-setting-content pb2">
|
||||
<div class="gh-setting-title">Publication icon</div>
|
||||
<div class="gh-setting-desc">A square, social icon used in the UI of your publication, at least 60x60px</div>
|
||||
{{#each uploader.errors as |error|}}
|
||||
<div class="gh-setting-error" data-test-error="icon">{{or error.context error.message}}</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
<div class="gh-setting-action gh-setting-action-smallimg">
|
||||
{{#if uploader.isUploading}}
|
||||
{{uploader.progressBar}}
|
||||
{{else if this.settings.icon}}
|
||||
<img class="blog-icon" src="{{this.settings.icon}}" {{on "click" this.triggerFileDialog}} alt="icon" data-test-icon-img>
|
||||
<button type="button" class="gh-setting-action-smallimg-delete" {{on "click" (fn this.removeImage "icon")}} data-test-delete-image="icon">
|
||||
<span>delete</span>
|
||||
</button>
|
||||
{{else}}
|
||||
<button type="button" class="gh-btn" {{on "click" triggerFileDialog}} data-test-image-upload-btn="icon">
|
||||
<span>Upload Image</span>
|
||||
</button>
|
||||
{{/if}}
|
||||
<div style="display:none">
|
||||
<GhFileInput @multiple={{false}} @action={{uploader.setFiles}} @accept={{this.iconMimeTypes}} data-test-file-input="icon" />
|
||||
</div>
|
||||
</div>
|
||||
</GhUploader>
|
||||
</div>
|
||||
|
||||
<div class="mb6" data-test-setting="logo">
|
||||
<GhUploader
|
||||
@extensions={{this.imageExtensions}}
|
||||
@onComplete={{action "imageUploaded" "logo"}}
|
||||
as |uploader|
|
||||
>
|
||||
<div class="gh-setting-content pb2">
|
||||
<div class="gh-setting-title">Publication logo</div>
|
||||
<div class="gh-setting-desc">The primary logo for your brand displayed across your theme, should be transparent and at least 600px x 72px</div>
|
||||
{{#each uploader.errors as |error|}}
|
||||
<div class="gh-setting-error" data-test-error="logo">{{or error.context error.message}}</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="gh-setting-action gh-setting-action-smallimg">
|
||||
{{#if uploader.isUploading}}
|
||||
{{uploader.progressBar}}
|
||||
{{else if this.settings.logo}}
|
||||
<img class="blog-logo" src="{{this.settings.logo}}" {{on "click" this.triggerFileDialog}} alt="logo" data-test-logo-img>
|
||||
<button type="button" class="gh-setting-action-smallimg-delete" {{on "click" (fn this.removeImage "logo")}} data-test-delete-image="logo">
|
||||
<span>delete</span>
|
||||
</button>
|
||||
{{else}}
|
||||
<button type="button" class="gh-btn" {{on "click" this.triggerFileDialog}} data-test-image-upload-btn="logo">
|
||||
<span>Upload Image</span>
|
||||
</button>
|
||||
{{/if}}
|
||||
<div style="display:none">
|
||||
<GhFileInput @multiple={{false}} @action={{uploader.setFiles}} @accept={{this.imageMimeTypes}} data-test-file-input="logo" />
|
||||
</div>
|
||||
</div>
|
||||
</GhUploader>
|
||||
</div>
|
||||
|
||||
<div class="mb6" data-test-setting="coverImage">
|
||||
<GhUploader
|
||||
@extensions={{this.imageExtensions}}
|
||||
@onComplete={{action "imageUploaded" "coverImage"}}
|
||||
as |uploader|
|
||||
>
|
||||
<div class="gh-setting-content pb2">
|
||||
<div class="gh-setting-title">Publication cover</div>
|
||||
<div class="gh-setting-desc">An optional large background image for your site</div>
|
||||
{{#each uploader.errors as |error|}}
|
||||
<div class="gh-setting-error" data-test-error="coverImage">{{or error.context error.message}}</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="gh-setting-action gh-setting-action-largeimg">
|
||||
{{#if uploader.isUploading}}
|
||||
{{uploader.progressBar}}
|
||||
{{else if this.settings.coverImage}}
|
||||
<img class="blog-cover" src="{{this.settings.coverImage}}" {{on "click" this.triggerFileDialog}} alt="cover photo" data-test-cover-img>
|
||||
<button type="button" class="gh-setting-action-largeimg-delete" {{on "click" (fn this.removeImage "coverImage")}} data-test-delete-image="coverImage">
|
||||
<span>delete</span>
|
||||
</button>
|
||||
{{else}}
|
||||
<button type="button" class="gh-btn" {{on "click" this.triggerFileDialog}} data-test-image-upload-btn="coverImage">
|
||||
<span>Upload Image</span>
|
||||
</button>
|
||||
{{/if}}
|
||||
<div style="display:none">
|
||||
<GhFileInput @multiple={{false}} @action={{uploader.setFiles}} @accept={{this.imageMimeTypes}} data-test-file-input="coverImage" />
|
||||
</div>
|
||||
</div>
|
||||
</GhUploader>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="relative flex-grow-1">
|
||||
<GhSiteIframe class="br3 br--right" @guid={{this.previewGuid}}></GhSiteIframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="right gh-btn gh-btn-blue" {{on "click" @afterComplete}} data-test-button="wizard-next"><span>Next</span></button>
|
|
@ -1,51 +0,0 @@
|
|||
import Component from '@glimmer/component';
|
||||
import {
|
||||
ICON_EXTENSIONS,
|
||||
ICON_MIME_TYPES,
|
||||
IMAGE_EXTENSIONS,
|
||||
IMAGE_MIME_TYPES
|
||||
} from 'ghost-admin/components/gh-image-uploader';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class GhLaunchWizardCustomiseDesignComponent extends Component {
|
||||
@service settings;
|
||||
|
||||
@tracked previewGuid;
|
||||
|
||||
iconExtensions = ICON_EXTENSIONS;
|
||||
iconMimeTypes = ICON_MIME_TYPES;
|
||||
imageExtensions = IMAGE_EXTENSIONS;
|
||||
imageMimeTypes = IMAGE_MIME_TYPES;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.refreshPreview();
|
||||
}
|
||||
|
||||
@action
|
||||
triggerFileDialog({target}) {
|
||||
target.closest('.gh-setting-action')?.querySelector('input[type="file"]')?.click();
|
||||
}
|
||||
|
||||
@action
|
||||
async imageUploaded(property, results) {
|
||||
if (results[0]) {
|
||||
this.settings.set(property, results[0].url);
|
||||
await this.settings.save();
|
||||
this.refreshPreview();
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async removeImage(imageName) {
|
||||
this.settings.set(imageName, '');
|
||||
await this.settings.save();
|
||||
this.refreshPreview();
|
||||
}
|
||||
|
||||
refreshPreview() {
|
||||
this.previewGuid = (new Date()).valueOf();
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
<h2>Set subscription pricing</h2>
|
||||
|
||||
<div class="flex mb4 br3 bg-white">
|
||||
<div class="pa4">
|
||||
<div class="w-100 w-50-l flex flex-column flex-row-ns">
|
||||
<div class="w-100">
|
||||
<GhFormGroup @class="for-select">
|
||||
<label class="fw6 f8"for="currency">Plan currency</label>
|
||||
<span class="gh-select mt1">
|
||||
<OneWaySelect
|
||||
@value={{this.selectedCurrency}}
|
||||
id="currency"
|
||||
name="currency"
|
||||
@options={{this.currencies}}
|
||||
@optionValuePath="value"
|
||||
@optionLabelPath="label"
|
||||
@update={{this.setStripePlansCurrency}}
|
||||
/>
|
||||
{{svg-jar "arrow-down-small"}}
|
||||
</span>
|
||||
</GhFormGroup>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100 w-50-l flex flex-column flex-row-ns">
|
||||
<div class="w-100 w-50-ns mr3-ns">
|
||||
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="stripePlans">
|
||||
<label class="fw6 f8">Monthly price</label>
|
||||
|
||||
<div class="flex items-center justify-center mt1 gh-input-group gh-labs-price-label">
|
||||
<GhTextInput
|
||||
@value={{readonly this.stripePlans.monthly.amount}}
|
||||
@type="number"
|
||||
@input={{action (mut this.stripeMonthlyAmount) value="target.value"}}
|
||||
@focus-out={{action "validateStripePlans"}}
|
||||
/>
|
||||
<span class="gh-input-append"><span class="ttu">{{this.stripePlans.monthly.currency}}</span>/month</span>
|
||||
</div>
|
||||
</GhFormGroup>
|
||||
</div>
|
||||
<div class="w-100 w-50-ns ml2-ns">
|
||||
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="stripePlans">
|
||||
<label class="fw6 f8">Yearly price</label>
|
||||
<div class="flex items-center justify-center mt1 gh-input-group gh-labs-price-label">
|
||||
<GhTextInput
|
||||
@value={{readonly this.stripePlans.yearly.amount}}
|
||||
@type="number"
|
||||
@input={{action (mut this.stripeYearlyAmount) value="target.value"}}
|
||||
@focus-out={{action "validateStripePlans"}}
|
||||
/>
|
||||
<span class="gh-input-append"><span class="ttu">{{this.stripePlans.yearly.currency}}</span>/year</span>
|
||||
</div>
|
||||
</GhFormGroup>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100 w-50-l flex flex-column flex-row-ns">
|
||||
<GhErrorMessage @errors={{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="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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{!-- TODO: reset "failed" state automatically --}}
|
||||
<GhTaskButton
|
||||
@buttonText="Launch my site"
|
||||
@task={{this.saveAndContinue}}
|
||||
@runningText="Launching"
|
||||
@class="right gh-btn gh-btn-green gh-btn-icon"
|
||||
data-test-button="wizard-next"
|
||||
/>
|
|
@ -1,130 +0,0 @@
|
|||
import Component from '@glimmer/component';
|
||||
import {CURRENCIES} from 'ghost-admin/components/gh-members-lab-setting';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency-decorators';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class GhLaunchWizardSetPricingComponent extends Component {
|
||||
@service settings;
|
||||
|
||||
currencies = CURRENCIES;
|
||||
|
||||
@tracked stripeMonthlyAmount = null;
|
||||
@tracked stripeYearlyAmount = null;
|
||||
|
||||
get stripePlans() {
|
||||
const plans = this.settings.get('stripePlans') || [];
|
||||
const monthly = plans.find(plan => plan.interval === 'month');
|
||||
const yearly = plans.find(plan => plan.interval === 'year' && plan.name !== 'Complimentary');
|
||||
|
||||
return {
|
||||
monthly: {
|
||||
amount: (parseInt(monthly?.amount) || 0) / 100 || 5,
|
||||
currency: monthly?.currency || this.currencies[0].value
|
||||
},
|
||||
yearly: {
|
||||
amount: (parseInt(yearly?.amount) || 0) / 100 || 50,
|
||||
currency: yearly?.currency || this.currencies[0].value
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get selectedCurrency() {
|
||||
return this.currencies.findBy('value', this.stripePlans.monthly.currency);
|
||||
}
|
||||
|
||||
willDestroy() {
|
||||
// clear any unsaved settings changes when going back/forward/closing
|
||||
this.settings.rollbackAttributes();
|
||||
}
|
||||
|
||||
@action
|
||||
setStripePlansCurrency(event) {
|
||||
const newCurrency = event.value;
|
||||
|
||||
const updatedPlans = this.settings.get('stripePlans').map((plan) => {
|
||||
if (plan.name !== 'Complimentary') {
|
||||
return Object.assign({}, plan, {
|
||||
currency: newCurrency
|
||||
});
|
||||
}
|
||||
return plan;
|
||||
});
|
||||
|
||||
const currentComplimentaryPlan = updatedPlans.find((plan) => {
|
||||
return plan.name === 'Complimentary' && plan.currency === event.value;
|
||||
});
|
||||
|
||||
if (!currentComplimentaryPlan) {
|
||||
updatedPlans.push({
|
||||
name: 'Complimentary',
|
||||
currency: event.value,
|
||||
interval: 'year',
|
||||
amount: 0
|
||||
});
|
||||
}
|
||||
|
||||
this.settings.set('stripePlans', updatedPlans);
|
||||
}
|
||||
|
||||
@action
|
||||
toggleSelfSignup() {
|
||||
this.settings.set('membersAllowFreeSignup', !this.settings.get('membersAllowFreeSignup'));
|
||||
}
|
||||
|
||||
@action
|
||||
validateStripePlans() {
|
||||
this.settings.errors.remove('stripePlans');
|
||||
this.settings.hasValidated.removeObject('stripePlans');
|
||||
|
||||
if (this.stripeYearlyAmount === null) {
|
||||
this.stripeYearlyAmount = this.stripePlans.yearly.amount;
|
||||
}
|
||||
if (this.stripeMonthlyAmount === null) {
|
||||
this.stripeMonthlyAmount = this.stripePlans.monthly.amount;
|
||||
}
|
||||
|
||||
try {
|
||||
const selectedCurrency = this.selectedCurrency;
|
||||
const yearlyAmount = parseInt(this.stripeYearlyAmount);
|
||||
const monthlyAmount = parseInt(this.stripeMonthlyAmount);
|
||||
if (!yearlyAmount || yearlyAmount < 1 || !monthlyAmount || monthlyAmount < 1) {
|
||||
throw new TypeError(`Subscription amount must be at least ${selectedCurrency.symbol}1.00`);
|
||||
}
|
||||
|
||||
const updatedPlans = this.settings.get('stripePlans').map((plan) => {
|
||||
if (plan.name !== 'Complimentary') {
|
||||
let newAmount;
|
||||
if (plan.interval === 'year') {
|
||||
newAmount = yearlyAmount * 100;
|
||||
} else if (plan.interval === 'month') {
|
||||
newAmount = monthlyAmount * 100;
|
||||
}
|
||||
return Object.assign({}, plan, {
|
||||
amount: newAmount
|
||||
});
|
||||
}
|
||||
return plan;
|
||||
});
|
||||
|
||||
this.settings.set('stripePlans', updatedPlans);
|
||||
} catch (err) {
|
||||
this.settings.errors.add('stripePlans', err.message);
|
||||
} finally {
|
||||
this.settings.hasValidated.pushObject('stripePlans');
|
||||
}
|
||||
}
|
||||
|
||||
@task
|
||||
*saveAndContinue() {
|
||||
yield this.validateStripePlans();
|
||||
|
||||
if (this.settings.errors.length > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
yield this.settings.save();
|
||||
this.args.afterComplete();
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchController extends Controller {
|
||||
@service router;
|
||||
|
||||
@action
|
||||
close() {
|
||||
this.router.transitionTo('dashboard');
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchCompleteController extends Controller {
|
||||
@service router;
|
||||
|
||||
@action
|
||||
finish() {
|
||||
this.router.transitionTo('dashboard');
|
||||
}
|
||||
|
||||
@action
|
||||
goBack() {
|
||||
this.router.transitionTo('launch.set-pricing');
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchConnectStripeController extends Controller {
|
||||
@service router;
|
||||
|
||||
@action
|
||||
goToNext() {
|
||||
this.router.transitionTo('launch.set-pricing');
|
||||
}
|
||||
|
||||
@action
|
||||
goBack() {
|
||||
this.router.transitionTo('launch.customise-design');
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchCustomiseDesignController extends Controller {
|
||||
@service router;
|
||||
|
||||
@action
|
||||
goToNext() {
|
||||
this.router.transitionTo('launch.connect-stripe');
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchSetPricingController extends Controller {
|
||||
@service router;
|
||||
|
||||
@action
|
||||
goToNext() {
|
||||
this.router.transitionTo('launch.complete');
|
||||
}
|
||||
|
||||
@action
|
||||
goBack() {
|
||||
this.router.transitionTo('launch.connect-stripe');
|
||||
}
|
||||
}
|
|
@ -21,13 +21,6 @@ Router.map(function () {
|
|||
this.route('signup', {path: '/signup/:token'});
|
||||
this.route('reset', {path: '/reset/:token'});
|
||||
|
||||
this.route('launch', function () {
|
||||
this.route('customise-design');
|
||||
this.route('connect-stripe');
|
||||
this.route('set-pricing');
|
||||
this.route('complete');
|
||||
});
|
||||
|
||||
this.route('about');
|
||||
this.route('site');
|
||||
this.route('dashboard');
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchRoute extends AuthenticatedRoute {
|
||||
@service config;
|
||||
|
||||
beforeModel() {
|
||||
if (!this.config.get('enableDeveloperExperiments')) {
|
||||
this.transitionTo('site');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class LaunchCompleteRoute extends Route {
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class LaunchConnectStripeRoute extends Route {
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class LaunchCustomiseDesignRoute extends Route {
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
|
||||
|
||||
export default class LaunchIndexRoute extends AuthenticatedRoute {
|
||||
beforeModel() {
|
||||
this.transitionTo('launch.customise-design');
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class LaunchSetPricingRoute extends Route {
|
||||
}
|
|
@ -4,8 +4,4 @@
|
|||
Dashboard
|
||||
</h2>
|
||||
</GhCanvasHeader>
|
||||
|
||||
<section class="view-container">
|
||||
<LinkTo @route="launch">Launch site - Finish setup</LinkTo>
|
||||
</section>
|
||||
</section>
|
|
@ -1,12 +0,0 @@
|
|||
<button type="button" class="absolute top-6 left-6 w6" title="Previous step" {{on "click" this.goBack}} data-test-button="wizard-back">
|
||||
{{svg-jar "arrow-left"}}
|
||||
<span class="hidden">Go to previous step</span>
|
||||
</button>
|
||||
|
||||
<section class="ma19">
|
||||
<h2>Congrats</h2>
|
||||
<div class="flex mb4 br3 bg-white">
|
||||
<div class="pa4">You're all set up!</div>
|
||||
</div>
|
||||
<button type="button" class="right gh-btn gh-btn-blue" {{on "click" this.finish}} data-test-button="wizard-next"><span>Start publishing</span></button>
|
||||
</section>
|
|
@ -1,10 +0,0 @@
|
|||
<button type="button" class="absolute top-6 left-6 w6" title="Previous step" {{on "click" this.goBack}} data-test-button="wizard-back">
|
||||
{{svg-jar "arrow-left"}}
|
||||
<span class="hidden">Go to previous step</span>
|
||||
</button>
|
||||
|
||||
<section class="ma19">
|
||||
<GhLaunchWizard::ConnectStripe
|
||||
@afterComplete={{this.goToNext}}
|
||||
/>
|
||||
</section>
|
|
@ -1,5 +0,0 @@
|
|||
<section class="ma19">
|
||||
<GhLaunchWizard::CustomiseDesign
|
||||
@afterComplete={{this.goToNext}}
|
||||
/>
|
||||
</section>
|
|
@ -1,10 +0,0 @@
|
|||
<button type="button" class="absolute top-6 left-6 w6" title="Previous step" {{on "click" this.goBack}} data-test-button="wizard-back">
|
||||
{{svg-jar "arrow-left"}}
|
||||
<span class="hidden">Go to previous step</span>
|
||||
</button>
|
||||
|
||||
<section class="ma19">
|
||||
<GhLaunchWizard::SetPricing
|
||||
@afterComplete={{this.goToNext}}
|
||||
/>
|
||||
</section>
|
|
@ -1,104 +0,0 @@
|
|||
import {authenticateSession} from 'ember-simple-auth/test-support';
|
||||
import {currentURL, visit} from '@ember/test-helpers';
|
||||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
import {setupApplicationTest} from 'ember-mocha';
|
||||
import {setupMirage} from 'ember-cli-mirage/test-support';
|
||||
|
||||
describe('Acceptance: Launch flow', function () {
|
||||
const hooks = setupApplicationTest();
|
||||
setupMirage(hooks);
|
||||
|
||||
it('is not accessible when logged out', async function () {
|
||||
await visit('/launch');
|
||||
expect(currentURL()).to.equal('/signin');
|
||||
|
||||
await visit('/launch/customise-design');
|
||||
expect(currentURL()).to.equal('/signin');
|
||||
|
||||
await visit('/launch/connect-stripe');
|
||||
expect(currentURL()).to.equal('/signin');
|
||||
|
||||
await visit('/launch/set-pricing');
|
||||
expect(currentURL()).to.equal('/signin');
|
||||
|
||||
await visit('/launch/complete');
|
||||
expect(currentURL()).to.equal('/signin');
|
||||
});
|
||||
|
||||
describe('when logged in', function () {
|
||||
beforeEach(async function () {
|
||||
// TODO: remove this setup when out of dev experiments
|
||||
this.server.loadFixtures('configs');
|
||||
const config = this.server.schema.configs.first();
|
||||
config.update({
|
||||
enableDeveloperExperiments: true
|
||||
});
|
||||
|
||||
let role = this.server.create('role', {name: 'Administrator'});
|
||||
this.server.create('user', {roles: [role]});
|
||||
|
||||
return await authenticateSession();
|
||||
});
|
||||
|
||||
it('can visit /launch', async function () {
|
||||
await visit('/launch');
|
||||
expect(currentURL()).to.equal('/launch/customise-design');
|
||||
});
|
||||
|
||||
it('can visit /launch/customise-design', async function () {
|
||||
await visit('/launch/customise-design');
|
||||
expect(currentURL()).to.equal('/launch/customise-design');
|
||||
});
|
||||
|
||||
it('can visit /launch/connect-stripe', async function () {
|
||||
await visit('/launch/connect-stripe');
|
||||
expect(currentURL()).to.equal('/launch/connect-stripe');
|
||||
});
|
||||
|
||||
it('can visit /launch/set-pricing', async function () {
|
||||
await visit('/launch/set-pricing');
|
||||
expect(currentURL()).to.equal('/launch/set-pricing');
|
||||
});
|
||||
|
||||
it('can visit /launch/complete', async function () {
|
||||
await visit('/launch/complete');
|
||||
expect(currentURL()).to.equal('/launch/complete');
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: remove this whole section when out of dev experiments
|
||||
describe('developer experiments', function () {
|
||||
describe('when disabled', function () {
|
||||
beforeEach(async function () {
|
||||
this.server.loadFixtures('configs');
|
||||
const config = this.server.schema.configs.first();
|
||||
config.update({
|
||||
enableDeveloperExperiments: false
|
||||
});
|
||||
|
||||
let role = this.server.create('role', {name: 'Administrator'});
|
||||
this.server.create('user', {roles: [role]});
|
||||
|
||||
return await authenticateSession();
|
||||
});
|
||||
|
||||
it('redirects all routes to /site', async function () {
|
||||
await visit('/launch');
|
||||
expect(currentURL()).to.equal('/site');
|
||||
|
||||
await visit('/launch/customise-design');
|
||||
expect(currentURL()).to.equal('/site');
|
||||
|
||||
await visit('/launch/connect-stripe');
|
||||
expect(currentURL()).to.equal('/site');
|
||||
|
||||
await visit('/launch/set-pricing');
|
||||
expect(currentURL()).to.equal('/site');
|
||||
|
||||
await visit('/launch/complete');
|
||||
expect(currentURL()).to.equal('/site');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,18 +0,0 @@
|
|||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
import {hbs} from 'ember-cli-htmlbars';
|
||||
import {render} from '@ember/test-helpers';
|
||||
import {setupRenderingTest} from 'ember-mocha';
|
||||
|
||||
describe('Integration: Component: gh-launch-wizard/connect-stripe', function () {
|
||||
setupRenderingTest();
|
||||
|
||||
it('renders', async function () {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<GhLaunchWizard::ConnectStripe />`);
|
||||
|
||||
expect(this.element.textContent.trim()).to.have.string('Connect Stripe');
|
||||
});
|
||||
});
|
|
@ -1,18 +0,0 @@
|
|||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
import {hbs} from 'ember-cli-htmlbars';
|
||||
import {render} from '@ember/test-helpers';
|
||||
import {setupRenderingTest} from 'ember-mocha';
|
||||
|
||||
describe('Integration: Component: gh-launch-wizard/customise-design', function () {
|
||||
setupRenderingTest();
|
||||
|
||||
it('renders', async function () {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<GhLaunchWizard::CustomiseDesign />`);
|
||||
|
||||
expect(this.element.textContent.trim()).to.have.string('Customise');
|
||||
});
|
||||
});
|
|
@ -1,18 +0,0 @@
|
|||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
import {hbs} from 'ember-cli-htmlbars';
|
||||
import {render} from '@ember/test-helpers';
|
||||
import {setupRenderingTest} from 'ember-mocha';
|
||||
|
||||
describe('Integration: Component: gh-launch-wizard/set-pricing', function () {
|
||||
setupRenderingTest();
|
||||
|
||||
it('renders', async function () {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<GhLaunchWizard::SetPricing />`);
|
||||
|
||||
expect(this.element.textContent.trim()).to.have.string('Set subscription pricing');
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue