Wired up in-memory onboarding step completion (#19940)

ref https://linear.app/tryghost/issue/IPC-92/add-logic-for-completing-steps

- added in-memory step completion to `onboarding` service
- wired up the onboarding checklist to mark steps as completed when clicked
- extracted re-used step template and logic into components/helpers
This commit is contained in:
Kevin Ansfield 2024-03-27 18:27:43 +00:00 committed by GitHub
parent 919ec733e7
commit 90d8b41f63
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 105 additions and 85 deletions

View File

@ -11,67 +11,48 @@
<div>
{{!-- Step 1 --}}
<div class="gh-onboarding-item gh-onboarding-item--completed">
<div class="gh-onboarding-item-content">
{{svg-jar "rocket" }}
<div class="gh-onboarding-item-details">
<span class="gh-onboarding-item-title">Start a new Ghost publication</span>
</div>
</div>
<div class="gh-onboarding-item-checkmark">
{{svg-jar "check-circle-simple" }}
</div>
<Dashboard::Onboarding::Step
@icon="rocket"
@title="Start a new Ghost publication"
@complete={{true}}
/>
</div>
{{!-- Step 2 --}}
<LinkTo @route="settings-x.settings-x" @model="design/edit?ref=setup" class="gh-onboarding-item gh-onboarding-item--next">
<div class="gh-onboarding-item-content">
{{svg-jar "brush" }}
<div class="gh-onboarding-item-details">
<span class="gh-onboarding-item-title">Customize your publication</span>
<span class="gh-onboarding-item-description">Match the look and feel to your style and make it yours.</span>
</div>
</div>
<div class="gh-onboarding-item-action">
{{svg-jar "arrow-right-tail" }}
</div>
<LinkTo @route="settings-x.settings-x" @model="design/edit?ref=setup" class="gh-onboarding-item {{onboarding-step-class "customize-design"}}" {{on "click" (fn this.onboarding.markStepCompleted "customize-design")}}>
<Dashboard::Onboarding::Step
@icon="brush"
@title="Customize your publication"
@description="Match the look and feel to your style and make it yours."
@complete={{is-onboarding-step-completed "customize-design"}}
/>
</LinkTo>
{{!-- Step 3 --}}
<LinkTo @route="lexical-editor.new" @model="post" class="gh-onboarding-item">
<div class="gh-onboarding-item-content">
{{svg-jar "writing" }}
<div class="gh-onboarding-item-details">
<span class="gh-onboarding-item-title">Create your first post</span>
<span class="gh-onboarding-item-description">Explore the editor and tell your story.</span>
</div>
</div>
<div class="gh-onboarding-item-action">
{{svg-jar "arrow-right-tail" }}
</div>
<LinkTo @route="lexical-editor.new" @model="post" class="gh-onboarding-item {{onboarding-step-class "first-post"}}" {{on "click" (fn this.onboarding.markStepCompleted "first-post")}}>
<Dashboard::Onboarding::Step
@icon="writing"
@title="Create your first post"
@description="Explore the editor and tell your story."
@complete={{is-onboarding-step-completed "first-post"}}
/>
</LinkTo>
{{!-- Step 4 --}}
<LinkTo @route="members" class="gh-onboarding-item">
<div class="gh-onboarding-item-content">
{{svg-jar "member-add" }}
<div class="gh-onboarding-item-details">
<span class="gh-onboarding-item-title">Build your audience</span>
<span class="gh-onboarding-item-description">Add members and grow your readership.</span>
</div>
</div>
<div class="gh-onboarding-item-action">
{{svg-jar "arrow-right-tail" }}
</div>
<LinkTo @route="members" class="gh-onboarding-item {{onboarding-step-class "build-audience"}}" {{on "click" (fn this.onboarding.markStepCompleted "build-audience")}}>
<Dashboard::Onboarding::Step
@icon="member-add"
@title="Build your audience"
@description="Add members and grow your readership."
@complete={{is-onboarding-step-completed "build-audience"}}
/>
</LinkTo>
{{!-- Step 5 --}}
<div role="button" {{on "click" (toggle-action "showShareModal" this)}} class="gh-onboarding-item">
<div class="gh-onboarding-item-content">
{{svg-jar "megaphone" }}
<div class="gh-onboarding-item-details">
<span class="gh-onboarding-item-title">Share your publication</span>
<span class="gh-onboarding-item-description">Share your publication on social media.</span>
</div>
</div>
<div class="gh-onboarding-item-action">
{{svg-jar "arrow-right-tail" }}
</div>
<div role="button" {{on "click" (toggle-action "showShareModal" this)}} class="gh-onboarding-item {{onboarding-step-class "share-publication"}}">
<Dashboard::Onboarding::Step
@icon="megaphone"
@title="Share your publication"
@description="Share your publication on social media."
@complete={{is-onboarding-step-completed "share-publication"}}
role="presentation"
/>
</div>
</div>
</div>

View File

@ -1,45 +1,16 @@
import Component from '@glimmer/component';
import {action} from '@ember/object';
import {inject} from 'ghost-admin/decorators/inject';
import {inject as service} from '@ember/service';
import {tracked} from '@glimmer/tracking';
export default class OnboardingChecklist extends Component {
@service onboarding;
@inject config;
@tracked customizePublication = false;
@tracked createPost = false;
@tracked buildAudience = false;
@tracked tellWorld = false;
@tracked showMemberTierModal = false;
get siteUrl() {
return this.config.blogTitle;
}
@action
completeStep(step) {
this.completed = !this.completed;
switch (step) {
case 'customizePublication':
this.customizePublication = !this.customizePublication;
break;
case 'createPost':
this.createPost = !this.createPost;
break;
case 'buildAudience':
this.buildAudience = !this.buildAudience;
break;
case 'tellWorld':
this.tellWorld = !this.tellWorld;
break;
default:
break;
}
}
@action
closeModal() {
this.closeModal();
}
}

View File

@ -0,0 +1,16 @@
<div class="gh-onboarding-item-content">
{{svg-jar @icon}}
<div class="gh-onboarding-item-details">
<span class="gh-onboarding-item-title">{{@title}}</span>
{{#if @description}}
<span class="gh-onboarding-item-description">{{@description}}</span>
{{/if}}
</div>
</div>
<div class={{if @complete "gh-onboarding-item-checkmark" "gh-onboarding-item-action"}}>
{{#if @complete}}
{{svg-jar "check-circle-simple"}}
{{else}}
{{svg-jar "arrow-right-tail"}}
{{/if}}
</div>

View File

@ -0,0 +1,10 @@
import Helper from '@ember/component/helper';
import {inject as service} from '@ember/service';
export default class IsOnboardingStepCompleted extends Helper {
@service onboarding;
compute([step]) {
return this.onboarding.isStepCompleted(step);
}
}

View File

@ -0,0 +1,16 @@
import Helper from '@ember/component/helper';
import {inject as service} from '@ember/service';
export default class OnboardingStepClasses extends Helper {
@service onboarding;
compute([step]) {
if (this.onboarding.isStepCompleted(step)) {
return 'gh-onboarding-item--completed';
}
if (this.onboarding.nextStep === step) {
return 'gh-onboarding-item--next';
}
}
}

View File

@ -1,11 +1,37 @@
import Service, {inject as service} from '@ember/service';
import {TrackedSet} from 'tracked-built-ins';
import {action} from '@ember/object';
import {tracked} from '@glimmer/tracking';
export default class OnboardingService extends Service {
@service feature;
@service session;
@tracked _completedSteps = new TrackedSet();
ONBOARDING_STEPS = [
'customize-design',
'first-post',
'build-audience',
'share-publication'
];
get isChecklistShown() {
return this.feature.onboardingChecklist
&& this.session.user.isOwnerOnly;
}
get nextStep() {
return this.ONBOARDING_STEPS.find(step => !this.isStepCompleted(step));
}
@action
isStepCompleted(step) {
return this._completedSteps.has(step);
}
@action
markStepCompleted(step) {
this._completedSteps.add(step);
}
}