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:
parent
ec5a080d56
commit
86598fbd76
5 changed files with 160 additions and 132 deletions
|
@ -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 →</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>
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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 →</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>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue