0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-17 23:44:39 -05:00

Extracted newsletter management section into separate component

refs https://github.com/TryGhost/Team/issues/1441

- pulls newsletter-related functionality into one place to keep higher-level components from knowing about too many concepts and becoming bloated
- updated temporary newsletters service to have fully tracked objects so the `active/archivedNewsletters` properties can be closer to how they will work with full models
This commit is contained in:
Kevin Ansfield 2022-04-01 16:05:26 +01:00
parent ec5a080d56
commit 86598fbd76
5 changed files with 160 additions and 132 deletions

View file

@ -25,95 +25,7 @@
</section>
{{#if this.emailNewsletterEnabled}}
<div class="gh-main-section gh-newsletters">
<div class="flex justify-between items-center">
<h4 class="gh-main-section-header small bn">Newsletters</h4>
{{#if (not-eq this.archivedNewsletterCount 0)}}
<div>
<div class="gh-contentfilter-menu gh-contentfilter-type {{if (not (eq this.selectedType.value "active")) "gh-contentfilter-selected"}}" data-test-type-select="true">
{{!-- <PowerSelect
@selected={{this.selectedType}}
@options={{this.availableTypes}}
@searchEnabled={{false}}
@onChange={{this.onTypeChange}}
@triggerComponent="gh-power-select/trigger"
@triggerClass="gh-contentfilter-menu-trigger gh-contentfilter-menu-trigger-tiers"
@dropdownClass="gh-contentfilter-menu-dropdown"
@matchTriggerWidth={{false}}
as |type|
>
{{#if type.name}}{{type.name}}{{else}}<span class="red">Unknown type</span>{{/if}}
</PowerSelect> --}}
<span>Active</span>
<span>{{svg-jar "arrow-down-small" class="w2"}}</span>
</div>
</div>
{{/if}}
</div>
<section class="gh-expandable">
<div class="gh-expandable-block">
{{#each this.newsletters.newsletters as |newsletter|}}
{{#if (eq newsletter.status "active")}}
<div class="gh-main-content-card gh-newsletter-card {{if (gt this.activeNewsletterCount 1) "multiple"}}">
{{svg-jar "grab" class="grab-newsletter"}}
<div class="gh-newsletter-card-block title-block">
<h3 class="gh-newsletter-card-name">
{{newsletter.name}}
</h3>
<p class="gh-newsletter-card-description">
{{newsletter.description}}
</p>
</div>
<div class="gh-newsletter-card-block stats-block {{if (gt this.activeNewsletterCount 1) "multiple"}}">
<div>
<h3 class="gh-newsletter-card-name">{{newsletter.members.total}}</h3>
<p class="gh-newsletter-card-description">Subscribers</p>
</div>
<div>
<h3 class="gh-newsletter-card-name">{{newsletter.posts.total}}</h3>
<p class="gh-newsletter-card-description">Posts sent</p>
</div>
</div>
<div class="gh-newsletter-card-block cta-block">
{{#if (eq this.activeNewsletterCount 1)}}
<button class="gh-btn gh-btn-green" type="button" {{on "click" @toggleEmailDesignSettings}}><span>Customize &rarr;</span></button>
{{else}}
<span class="dropdown">
<GhDropdownButton
@dropdownName="newsletter-actions-menu-newsletter-{{newsletter.id}}"
@classNames="gh-btn gh-btn-action-icon gh-btn-icon gh-btn-outline gh-product-card-actions-button icon-only"
>
<span>
{{svg-jar "dotdotdot"}}
<span class="hidden">Actions</span>
</span>
</GhDropdownButton>
<GhDropdown
@name="newsletter-actions-menu-newsletter-{{newsletter.id}}"
@tagName="ul"
@classNames="gh-newsletter-actions-menu dropdown-menu dropdown-triangle-top-right"
>
<li>
<button class="mr2" type="button" {{on "click" @toggleEmailDesignSettings}}>
<span>Edit</span>
</button>
</li>
<li>
<button class="mr2" type="button" {{on "click" (fn this.archiveNewsletter newsletter.id)}}>
<span>Archive</span>
</button>
</li>
</GhDropdown>
</span>
{{/if}}
</div>
</div>
{{/if}}
{{/each}}
</div>
</section>
<button type="button" class="gh-add-newsletter" {{on "click" @toggleEmailDesignSettings}} {{on "click" this.addNewsletter}}>{{svg-jar "add-stroke"}}Add newsletter</button>
</div>
<Settings::MembersEmailLabs::NewsletterManagement @toggleEmailDesignSettings={{@toggleEmailDesignSettings}} />
<section class="gh-main-section">
<h4 class="gh-main-section-header small bn">General settings</h4>

View file

@ -12,7 +12,6 @@ export default class MembersEmailLabs extends Component {
@service ghostPaths;
@service ajax;
@service settings;
@service newsletters;
// set recipientsSelectValue as a static property because within this
// component's lifecycle it's not always derived from the settings values.
@ -74,14 +73,6 @@ export default class MembersEmailLabs extends Component {
};
}
get activeNewsletterCount() {
return this.newsletters.newsletters.filter(n => n.status === 'active').length;
}
get archivedNewsletterCount() {
return this.newsletters.newsletters.filter(n => n.status === 'archived').length;
}
@action
toggleFromAddressConfirmation() {
this.showFromAddressConfirmation = !this.showFromAddressConfirmation;
@ -184,16 +175,6 @@ export default class MembersEmailLabs extends Component {
this.settings.set('editorDefaultEmailRecipientsFilter', filter);
}
@action
archiveNewsletter(id) {
this.newsletters.archive(id);
}
@action
addNewsletter() {
this.newsletters.add();
}
@task({drop: true})
*updateFromAddress() {
let url = this.ghostPaths.url.api('/settings/members/email');

View file

@ -0,0 +1,89 @@
<div class="gh-main-section gh-newsletters">
<div class="flex justify-between items-center">
<h4 class="gh-main-section-header small bn">Newsletters</h4>
{{#if this.archivedNewsletters}}
<div>
<div class="gh-contentfilter-menu gh-contentfilter-type {{if (not (eq this.selectedType.value "active")) "gh-contentfilter-selected"}}" data-test-type-select="true">
{{!-- <PowerSelect
@selected={{this.selectedType}}
@options={{this.availableTypes}}
@searchEnabled={{false}}
@onChange={{this.onTypeChange}}
@triggerComponent="gh-power-select/trigger"
@triggerClass="gh-contentfilter-menu-trigger gh-contentfilter-menu-trigger-tiers"
@dropdownClass="gh-contentfilter-menu-dropdown"
@matchTriggerWidth={{false}}
as |type|
>
{{#if type.name}}{{type.name}}{{else}}<span class="red">Unknown type</span>{{/if}}
</PowerSelect> --}}
<span>Active</span>
<span>{{svg-jar "arrow-down-small" class="w2"}}</span>
</div>
</div>
{{/if}}
</div>
<section class="gh-expandable">
<div class="gh-expandable-block">
{{#each this.newsletters.newsletters as |newsletter|}}
{{#if (eq newsletter.status "active")}}
<div class="gh-main-content-card gh-newsletter-card {{if this.hasMultiple "multiple"}}">
{{svg-jar "grab" class="grab-newsletter"}}
<div class="gh-newsletter-card-block title-block">
<h3 class="gh-newsletter-card-name">
{{newsletter.name}}
</h3>
<p class="gh-newsletter-card-description">
{{newsletter.description}}
</p>
</div>
<div class="gh-newsletter-card-block stats-block {{if this.hasMultiple "multiple"}}">
<div>
<h3 class="gh-newsletter-card-name">{{newsletter.members.total}}</h3>
<p class="gh-newsletter-card-description">Subscribers</p>
</div>
<div>
<h3 class="gh-newsletter-card-name">{{newsletter.posts.total}}</h3>
<p class="gh-newsletter-card-description">Posts sent</p>
</div>
</div>
<div class="gh-newsletter-card-block cta-block">
{{#if this.hasMultiple}}
<span class="dropdown">
<GhDropdownButton
@dropdownName="newsletter-actions-menu-newsletter-{{newsletter.id}}"
@classNames="gh-btn gh-btn-action-icon gh-btn-icon gh-btn-outline gh-product-card-actions-button icon-only"
>
<span>
{{svg-jar "dotdotdot"}}
<span class="hidden">Actions</span>
</span>
</GhDropdownButton>
<GhDropdown
@name="newsletter-actions-menu-newsletter-{{newsletter.id}}"
@tagName="ul"
@classNames="gh-newsletter-actions-menu dropdown-menu dropdown-triangle-top-right"
>
<li>
<button class="mr2" type="button" {{on "click" @toggleEmailDesignSettings}}>
<span>Edit</span>
</button>
</li>
<li>
<button class="mr2" type="button" {{on "click" (fn this.archiveNewsletter newsletter.id)}}>
<span>Archive</span>
</button>
</li>
</GhDropdown>
</span>
{{else}}
<button class="gh-btn gh-btn-green" type="button" {{on "click" @toggleEmailDesignSettings}}><span>Customize &rarr;</span></button>
{{/if}}
</div>
</div>
{{/if}}
{{/each}}
</div>
</section>
<button type="button" class="gh-add-newsletter" {{on "click" this.addNewsletter}} {{on "click" @toggleEmailDesignSettings}}>{{svg-jar "add-stroke"}}Add newsletter</button>
</div>

View file

@ -0,0 +1,30 @@
import Component from '@glimmer/component';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
export default class NewsletterManagementComponent extends Component {
@service newsletters;
@service store;
get activeNewsletters() {
return this.newsletters.newsletters.filter(n => n.status === 'active');
}
get archivedNewsletters() {
return this.newsletters.newsletters.filter(n => n.status === 'archived');
}
get hasMultiple() {
return this.activeNewsletters.length > 1;
}
@action
addNewsletter() {
this.newsletters.add();
}
@action
archiveNewsletter(id) {
this.newsletters.archive(id);
}
}

View file

@ -1,11 +1,29 @@
import Service, {inject as service} from '@ember/service';
import {TrackedArray} from 'tracked-built-ins';
import {set} from '@ember/object';
import {tracked} from '@glimmer/tracking';
class Newsletter {
@tracked name;
@tracked description;
@tracked sender_name;
@tracked sender_email;
@tracked sender_reply_to;
@tracked default;
@tracked status;
@tracked recipient_filter;
@tracked subscribe_on_signup;
@tracked sort_order;
constructor(obj) {
Object.assign(this, obj);
}
}
let counter = 0;
function getFakeNewsletter() {
counter += 1;
return {
return new Newsletter({
id: Math.floor(Math.random() * 1e9),
name: 'Daily roundup ' + counter,
description: 'Daily news delivered to your inbox every morning.',
@ -23,7 +41,7 @@ function getFakeNewsletter() {
posts: {
total: Math.floor(Math.random() * 100)
}
};
});
}
export default class NewslettersService extends Service {
@ -32,9 +50,8 @@ export default class NewslettersService extends Service {
@service feature;
@service store;
@tracked
newsletters = [
{
newsletters = new TrackedArray([
new Newsletter({
id: '123',
name: 'Daily roundup',
description: 'Daily news delivered to your inbox every morning.',
@ -52,13 +69,12 @@ export default class NewslettersService extends Service {
posts: {
total: 17
}
}
];
})
]);
add() {
this.newsletters.push(getFakeNewsletter());
this.newsletters.sort((a,b) => a.sort_order - b.sort_order);
this.newsletters = [...this.newsletters]; //trigger UI refresh
return this.newsletters;
}