mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-25 02:31:59 -05:00
Refined newsletter management for logged-in members
refs https://github.com/TryGhost/Team/issues/1559 - extracts newsletter management in a common component for use across pages
This commit is contained in:
parent
2ab6093d9e
commit
926df30ccd
2 changed files with 160 additions and 117 deletions
140
ghost/portal/src/components/common/NewsletterManagement.js
Normal file
140
ghost/portal/src/components/common/NewsletterManagement.js
Normal file
|
@ -0,0 +1,140 @@
|
|||
import AppContext from '../../AppContext';
|
||||
import CloseButton from '../common/CloseButton';
|
||||
import BackButton from '../common/BackButton';
|
||||
import {useContext, useState} from 'react';
|
||||
import Switch from '../common/Switch';
|
||||
import {getSiteNewsletters} from '../../utils/helpers';
|
||||
import ActionButton from '../common/ActionButton';
|
||||
|
||||
const React = require('react');
|
||||
|
||||
function AccountHeader() {
|
||||
const {brandColor, lastPage, onAction} = useContext(AppContext);
|
||||
return (
|
||||
<header className='gh-portal-detail-header'>
|
||||
<BackButton brandColor={brandColor} hidden={!lastPage} onClick={(e) => {
|
||||
onAction('back');
|
||||
}} />
|
||||
<h3 className='gh-portal-main-title'>Email preferences</h3>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
function NewsletterPrefSection({newsletter, subscribedNewsletters, setSubscribedNewsletters}) {
|
||||
const isChecked = subscribedNewsletters.some((d) => {
|
||||
return d.id === newsletter?.id;
|
||||
});
|
||||
const [description, setDescription] = useState(newsletter?.description || '');
|
||||
const [timeoutId, setTimeoutId] = useState(null);
|
||||
let finalDescription = description;
|
||||
if (!description) {
|
||||
finalDescription = isChecked ? 'Subscribed' : 'Unsubscribed';
|
||||
}
|
||||
return (
|
||||
<section className='gh-portal-list-toggle-wrapper'>
|
||||
<div className='gh-portal-list-detail'>
|
||||
<h3>{newsletter.name}</h3>
|
||||
<p>{finalDescription}</p>
|
||||
</div>
|
||||
<div>
|
||||
<Switch id={newsletter.id} onToggle={(e, checked) => {
|
||||
let updatedNewsletters = [];
|
||||
if (!checked) {
|
||||
updatedNewsletters = subscribedNewsletters.filter((d) => {
|
||||
return d.id !== newsletter.id;
|
||||
});
|
||||
setDescription('Unsubscribed');
|
||||
clearTimeout(timeoutId);
|
||||
let newTimeoutId = setTimeout(() => {
|
||||
setDescription(newsletter?.description);
|
||||
}, 3000);
|
||||
setTimeoutId(newTimeoutId);
|
||||
} else {
|
||||
updatedNewsletters = subscribedNewsletters.filter((d) => {
|
||||
return d.id !== newsletter.id;
|
||||
}).concat(newsletter);
|
||||
setDescription('Subscribed');
|
||||
clearTimeout(timeoutId);
|
||||
let newTimeoutId = setTimeout(() => {
|
||||
setDescription(newsletter?.description);
|
||||
}, 3000);
|
||||
setTimeoutId(newTimeoutId);
|
||||
}
|
||||
setSubscribedNewsletters(updatedNewsletters);
|
||||
}} checked={isChecked} />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function NewsletterPrefs({subscribedNewsletters, setSubscribedNewsletters}) {
|
||||
const {site} = useContext(AppContext);
|
||||
const newsletters = getSiteNewsletters({site});
|
||||
return newsletters.map((newsletter) => {
|
||||
return (
|
||||
<NewsletterPrefSection
|
||||
key={newsletter?.id}
|
||||
newsletter={newsletter}
|
||||
subscribedNewsletters={subscribedNewsletters}
|
||||
setSubscribedNewsletters={setSubscribedNewsletters}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function ShowPaidMemberMessage({site, isPaid}) {
|
||||
if (isPaid) {
|
||||
return (
|
||||
<p style={{textAlign: 'center', marginTop: '12px', marginBottom: '0', color: 'var(--grey6)'}}>Unsubscribing from emails will not cancel your paid subscription to {site?.title}</p>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default function NewsletterManagement({
|
||||
subscribedNewsletters,
|
||||
updateSubscribedNewsletters,
|
||||
unsubscribeAll,
|
||||
isPaidMember
|
||||
}) {
|
||||
const isDisabled = !subscribedNewsletters?.length;
|
||||
const {brandColor, site} = useContext(AppContext);
|
||||
return (
|
||||
<div className='gh-portal-content with-footer'>
|
||||
<CloseButton />
|
||||
<AccountHeader />
|
||||
<div className='gh-portal-section'>
|
||||
<div className='gh-portal-list'>
|
||||
<NewsletterPrefs
|
||||
subscribedNewsletters={subscribedNewsletters}
|
||||
setSubscribedNewsletters={(updatedNewsletters) => {
|
||||
let newsletters = updatedNewsletters.map((d) => {
|
||||
return {
|
||||
id: d.id
|
||||
};
|
||||
});
|
||||
updateSubscribedNewsletters(newsletters);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<footer className='gh-portal-action-footer'>
|
||||
<div style={{width: '100%'}}>
|
||||
<ActionButton
|
||||
isRunning={false}
|
||||
onClick={(e) => {
|
||||
unsubscribeAll();
|
||||
}}
|
||||
disabled={isDisabled}
|
||||
brandColor={brandColor}
|
||||
isPrimary={false}
|
||||
label='Unsubscribe from all'
|
||||
isDestructive={true}
|
||||
style={{width: '100%'}}
|
||||
/>
|
||||
<ShowPaidMemberMessage isPaid={isPaidMember} site={site} />
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,131 +1,34 @@
|
|||
import AppContext from '../../AppContext';
|
||||
import CloseButton from '../common/CloseButton';
|
||||
import BackButton from '../common/BackButton';
|
||||
import {useContext, useEffect, useState} from 'react';
|
||||
import Switch from '../common/Switch';
|
||||
import {getSiteNewsletters} from '../../utils/helpers';
|
||||
import ActionButton from '../common/ActionButton';
|
||||
import {isPaidMember} from '../../utils/helpers';
|
||||
import NewsletterManagement from '../common/NewsletterManagement';
|
||||
|
||||
const React = require('react');
|
||||
|
||||
function AccountHeader() {
|
||||
const {brandColor, lastPage, onAction} = useContext(AppContext);
|
||||
return (
|
||||
<header className='gh-portal-detail-header'>
|
||||
<BackButton brandColor={brandColor} hidden={!lastPage} onClick={(e) => {
|
||||
onAction('back');
|
||||
}} />
|
||||
<h3 className='gh-portal-main-title'>Email preferences</h3>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
function NewsletterPrefSection({newsletter, subscribedNewsletters, setSubscribedNewsletters}) {
|
||||
const isChecked = subscribedNewsletters.some((d) => {
|
||||
return d.id === newsletter?.id;
|
||||
});
|
||||
return (
|
||||
<section className='gh-portal-list-toggle-wrapper'>
|
||||
<div className='gh-portal-list-detail'>
|
||||
<h3>{newsletter.name}</h3>
|
||||
<p>{newsletter.description}</p>
|
||||
</div>
|
||||
<div>
|
||||
<Switch id={newsletter.id} onToggle={(e, checked) => {
|
||||
let updatedNewsletters = [];
|
||||
if (!checked) {
|
||||
updatedNewsletters = subscribedNewsletters.filter((d) => {
|
||||
return d.id !== newsletter.id;
|
||||
});
|
||||
} else {
|
||||
updatedNewsletters = subscribedNewsletters.filter((d) => {
|
||||
return d.id !== newsletter.id;
|
||||
}).concat(newsletter);
|
||||
}
|
||||
setSubscribedNewsletters(updatedNewsletters);
|
||||
}} checked={isChecked} />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function NewsletterPrefs({subscribedNewsletters, setSubscribedNewsletters}) {
|
||||
const {site} = useContext(AppContext);
|
||||
const newsletters = getSiteNewsletters({site});
|
||||
return newsletters.map((newsletter) => {
|
||||
return (
|
||||
<NewsletterPrefSection
|
||||
key={newsletter?.id}
|
||||
newsletter={newsletter}
|
||||
subscribedNewsletters={subscribedNewsletters}
|
||||
setSubscribedNewsletters={setSubscribedNewsletters}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default function AccountEmailPage() {
|
||||
const {brandColor, member, onAction} = useContext(AppContext);
|
||||
const {member, onAction} = useContext(AppContext);
|
||||
const defaultSubscribedNewsletters = [...(member.newsletters || [])];
|
||||
const [subscribedNewsletters, setSubscribedNewsletters] = useState(defaultSubscribedNewsletters);
|
||||
useEffect(() => {
|
||||
setSubscribedNewsletters(member.newsletters);
|
||||
setSubscribedNewsletters(member?.newsletters || []);
|
||||
}, [member.newsletters]);
|
||||
|
||||
return (
|
||||
<div className='gh-portal-content with-footer'>
|
||||
<CloseButton />
|
||||
<AccountHeader />
|
||||
<div className='gh-portal-section'>
|
||||
<div className='gh-portal-list'>
|
||||
<NewsletterPrefs
|
||||
subscribedNewsletters={subscribedNewsletters}
|
||||
setSubscribedNewsletters={setSubscribedNewsletters}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<footer className='gh-portal-action-footer'>
|
||||
<div style={{width: '100%'}}>
|
||||
<div style={{marginBottom: '12px'}}>
|
||||
<ActionButton
|
||||
isRunning={false}
|
||||
onClick={(e) => {
|
||||
let newsletters = subscribedNewsletters.map((d) => {
|
||||
return {
|
||||
id: d.id
|
||||
};
|
||||
});
|
||||
onAction('showPopupNotification', {
|
||||
action: 'updated:success',
|
||||
message: `Newsletter preference updated.`
|
||||
});
|
||||
onAction('updateNewsletterPreference', {newsletters});
|
||||
}}
|
||||
disabled={false}
|
||||
brandColor={brandColor}
|
||||
label='Update'
|
||||
style={{width: '100%'}}
|
||||
/>
|
||||
</div>
|
||||
<ActionButton
|
||||
isRunning={false}
|
||||
onClick={(e) => {
|
||||
onAction('showPopupNotification', {
|
||||
action: 'updated:success',
|
||||
message: `Newsletter preference updated.`
|
||||
});
|
||||
onAction('updateNewsletterPreference', {newsletters: []});
|
||||
}}
|
||||
disabled={false}
|
||||
brandColor={brandColor}
|
||||
isPrimary={false}
|
||||
label='Unsubscribe from all'
|
||||
isDestructive={true}
|
||||
style={{width: '100%'}}
|
||||
/>
|
||||
<p style={{textAlign: 'center', marginTop: '12px', marginBottom: '0', color: 'var(--grey6)'}}>Unsubscribing from emails will not cancel your paid subscription to The Chinese Cinema</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<NewsletterManagement
|
||||
subscribedNewsletters={subscribedNewsletters}
|
||||
updateSubscribedNewsletters={(updatedNewsletters) => {
|
||||
setSubscribedNewsletters(updatedNewsletters);
|
||||
onAction('updateNewsletterPreference', {newsletters: updatedNewsletters});
|
||||
}}
|
||||
unsubscribeAll={() => {
|
||||
setSubscribedNewsletters([]);
|
||||
onAction('showPopupNotification', {
|
||||
action: 'updated:success',
|
||||
message: `Newsletter preference updated.`
|
||||
});
|
||||
onAction('updateNewsletterPreference', {newsletters: []});
|
||||
}}
|
||||
isPaidMember={isPaidMember({member})}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue