2023-07-20 15:00:04 +01:00
|
|
|
|
import ButtonGroup from '../../../../admin-x-ds/global/ButtonGroup';
|
2023-09-04 07:00:37 +01:00
|
|
|
|
import ColorPickerField from '../../../../admin-x-ds/global/form/ColorPickerField';
|
2023-08-07 12:44:30 +01:00
|
|
|
|
import ConfirmationModal from '../../../../admin-x-ds/global/modal/ConfirmationModal';
|
2023-08-03 18:26:59 +01:00
|
|
|
|
import Form from '../../../../admin-x-ds/global/form/Form';
|
2023-07-17 09:12:05 +01:00
|
|
|
|
import Heading from '../../../../admin-x-ds/global/Heading';
|
|
|
|
|
import Hint from '../../../../admin-x-ds/global/Hint';
|
2023-08-03 18:26:59 +01:00
|
|
|
|
import HtmlField from '../../../../admin-x-ds/global/form/HtmlField';
|
2023-07-17 09:12:05 +01:00
|
|
|
|
import Icon from '../../../../admin-x-ds/global/Icon';
|
|
|
|
|
import ImageUpload from '../../../../admin-x-ds/global/form/ImageUpload';
|
2023-07-19 09:48:55 +01:00
|
|
|
|
import NewsletterPreview from './NewsletterPreview';
|
2023-08-03 18:26:59 +01:00
|
|
|
|
import NiceModal, {useModal} from '@ebay/nice-modal-react';
|
2023-08-02 08:37:51 +01:00
|
|
|
|
import React, {useState} from 'react';
|
|
|
|
|
import Select, {SelectOption} from '../../../../admin-x-ds/global/form/Select';
|
2023-07-17 09:12:05 +01:00
|
|
|
|
import StickyFooter from '../../../../admin-x-ds/global/StickyFooter';
|
2023-08-02 08:37:51 +01:00
|
|
|
|
import TabView, {Tab} from '../../../../admin-x-ds/global/TabView';
|
2023-07-17 09:12:05 +01:00
|
|
|
|
import TextArea from '../../../../admin-x-ds/global/form/TextArea';
|
|
|
|
|
import TextField from '../../../../admin-x-ds/global/form/TextField';
|
|
|
|
|
import Toggle from '../../../../admin-x-ds/global/form/Toggle';
|
2023-08-02 16:10:50 +02:00
|
|
|
|
import ToggleGroup from '../../../../admin-x-ds/global/form/ToggleGroup';
|
2023-09-04 07:00:37 +01:00
|
|
|
|
import useFeatureFlag from '../../../../hooks/useFeatureFlag';
|
2023-08-30 10:08:31 +01:00
|
|
|
|
import useForm, {ErrorMessages} from '../../../../hooks/useForm';
|
2023-08-10 13:04:23 +01:00
|
|
|
|
import useRouting from '../../../../hooks/useRouting';
|
2023-09-14 13:04:31 +03:00
|
|
|
|
import useSettingGroup from '../../../../hooks/useSettingGroup';
|
2023-08-03 18:26:59 +01:00
|
|
|
|
import validator from 'validator';
|
2023-09-04 07:00:37 +01:00
|
|
|
|
import {Newsletter, useBrowseNewsletters, useEditNewsletter} from '../../../../api/newsletters';
|
2023-08-02 08:37:51 +01:00
|
|
|
|
import {PreviewModalContent} from '../../../../admin-x-ds/global/modal/PreviewModal';
|
2023-09-04 07:00:37 +01:00
|
|
|
|
import {RoutingModalProps} from '../../../providers/RoutingProvider';
|
2023-08-08 21:34:07 +01:00
|
|
|
|
import {fullEmailAddress} from '../../../../api/site';
|
|
|
|
|
import {getImageUrl, useUploadImage} from '../../../../api/images';
|
|
|
|
|
import {getSettingValues} from '../../../../api/settings';
|
2023-08-03 18:26:59 +01:00
|
|
|
|
import {showToast} from '../../../../admin-x-ds/global/Toast';
|
2023-09-04 07:00:37 +01:00
|
|
|
|
import {textColorForBackgroundColor} from '@tryghost/color-utils';
|
2023-08-03 18:26:59 +01:00
|
|
|
|
import {toast} from 'react-hot-toast';
|
2023-08-03 09:29:14 +01:00
|
|
|
|
import {useGlobalData} from '../../../providers/GlobalDataProvider';
|
2023-07-17 09:12:05 +01:00
|
|
|
|
|
2023-08-01 18:24:23 +01:00
|
|
|
|
const Sidebar: React.FC<{
|
|
|
|
|
newsletter: Newsletter;
|
|
|
|
|
updateNewsletter: (fields: Partial<Newsletter>) => void;
|
2023-08-03 18:26:59 +01:00
|
|
|
|
validate: () => void;
|
2023-08-30 10:08:31 +01:00
|
|
|
|
errors: ErrorMessages;
|
2023-08-03 18:26:59 +01:00
|
|
|
|
clearError: (field: string) => void;
|
|
|
|
|
}> = ({newsletter, updateNewsletter, validate, errors, clearError}) => {
|
|
|
|
|
const {settings, siteData, config} = useGlobalData();
|
2023-09-13 08:10:33 +01:00
|
|
|
|
const [membersSupportAddress, icon] = getSettingValues<string>(settings, ['members_support_address', 'icon']);
|
2023-08-01 18:24:23 +01:00
|
|
|
|
const {mutateAsync: uploadImage} = useUploadImage();
|
|
|
|
|
const [selectedTab, setSelectedTab] = useState('generalSettings');
|
2023-09-04 07:00:37 +01:00
|
|
|
|
const hasEmailCustomization = useFeatureFlag('emailCustomization');
|
2023-09-14 13:04:31 +03:00
|
|
|
|
const {localSettings} = useSettingGroup();
|
|
|
|
|
const [siteTitle] = getSettingValues(localSettings, ['title']) as string[];
|
2023-07-17 09:12:05 +01:00
|
|
|
|
|
2023-08-01 18:24:23 +01:00
|
|
|
|
const replyToEmails = [
|
|
|
|
|
{label: `Newsletter address (${fullEmailAddress(newsletter.sender_email || 'noreply', siteData)})`, value: 'newsletter'},
|
|
|
|
|
{label: `Support address (${fullEmailAddress(membersSupportAddress || 'noreply', siteData)})`, value: 'support'}
|
|
|
|
|
];
|
2023-07-17 09:12:05 +01:00
|
|
|
|
|
2023-08-01 18:24:23 +01:00
|
|
|
|
const fontOptions: SelectOption[] = [
|
|
|
|
|
{value: 'serif', label: 'Elegant serif', className: 'font-serif'},
|
|
|
|
|
{value: 'sans_serif', label: 'Clean sans-serif'}
|
|
|
|
|
];
|
2023-07-17 09:12:05 +01:00
|
|
|
|
|
2023-09-04 07:00:37 +01:00
|
|
|
|
const backgroundColorIsDark = () => {
|
|
|
|
|
if (newsletter.background_color === 'dark') {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (newsletter.background_color === 'light') {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return textColorForBackgroundColor(newsletter.background_color).hex().toLowerCase() === '#ffffff';
|
|
|
|
|
};
|
|
|
|
|
|
2023-07-17 09:12:05 +01:00
|
|
|
|
const tabs: Tab[] = [
|
|
|
|
|
{
|
|
|
|
|
id: 'generalSettings',
|
2023-07-19 09:48:55 +01:00
|
|
|
|
title: 'General',
|
2023-08-02 16:10:50 +02:00
|
|
|
|
contents:
|
|
|
|
|
<>
|
|
|
|
|
<Form className='mt-6' gap='sm' margins='lg' title='Name and description'>
|
2023-08-03 18:26:59 +01:00
|
|
|
|
<TextField
|
|
|
|
|
error={Boolean(errors.name)}
|
|
|
|
|
hint={errors.name}
|
|
|
|
|
placeholder="Weekly Roundup"
|
|
|
|
|
title="Name"
|
|
|
|
|
value={newsletter.name || ''}
|
|
|
|
|
onBlur={validate}
|
|
|
|
|
onChange={e => updateNewsletter({name: e.target.value})}
|
|
|
|
|
onKeyDown={() => clearError('name')}
|
|
|
|
|
/>
|
2023-08-02 16:10:50 +02:00
|
|
|
|
<TextArea rows={2} title="Description" value={newsletter.description || ''} onChange={e => updateNewsletter({description: e.target.value})} />
|
|
|
|
|
</Form>
|
|
|
|
|
<Form className='mt-6' gap='sm' margins='lg' title='Email addresses'>
|
2023-09-14 13:04:31 +03:00
|
|
|
|
<TextField placeholder={siteTitle} title="Sender name" value={newsletter.sender_name || ''} onChange={e => updateNewsletter({sender_name: e.target.value})} />
|
2023-08-03 18:26:59 +01:00
|
|
|
|
<TextField
|
|
|
|
|
error={Boolean(errors.sender_email)}
|
|
|
|
|
hint={errors.sender_email}
|
2023-09-14 13:04:31 +03:00
|
|
|
|
placeholder={fullEmailAddress(newsletter.sender_email || 'noreply', siteData)}
|
2023-08-03 18:26:59 +01:00
|
|
|
|
title="Sender email address"
|
|
|
|
|
value={newsletter.sender_email || ''}
|
|
|
|
|
onBlur={validate}
|
|
|
|
|
onChange={e => updateNewsletter({sender_email: e.target.value})}
|
|
|
|
|
onKeyDown={() => clearError('sender_email')}
|
|
|
|
|
/>
|
2023-08-02 16:10:50 +02:00
|
|
|
|
<Select options={replyToEmails} selectedOption={newsletter.sender_reply_to} title="Reply-to email" onSelect={value => updateNewsletter({sender_reply_to: value})}/>
|
|
|
|
|
</Form>
|
|
|
|
|
<Form className='mt-6' gap='sm' margins='lg' title='Member settings'>
|
|
|
|
|
<Toggle
|
|
|
|
|
checked={newsletter.subscribe_on_signup}
|
|
|
|
|
direction='rtl'
|
|
|
|
|
label='Subscribe new members on signup'
|
|
|
|
|
labelStyle='value'
|
|
|
|
|
onChange={e => updateNewsletter({subscribe_on_signup: e.target.checked})}
|
|
|
|
|
/>
|
|
|
|
|
</Form>
|
|
|
|
|
</>
|
2023-07-17 09:12:05 +01:00
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'design',
|
|
|
|
|
title: 'Design',
|
2023-08-02 16:10:50 +02:00
|
|
|
|
contents:
|
|
|
|
|
<>
|
|
|
|
|
<Form className='mt-6' gap='sm' margins='lg' title='Header'>
|
2023-07-17 09:12:05 +01:00
|
|
|
|
<div>
|
2023-08-02 16:10:50 +02:00
|
|
|
|
<div>
|
|
|
|
|
<Heading className="mb-2" level={6}>Header image</Heading>
|
|
|
|
|
</div>
|
|
|
|
|
<div className='flex-column flex gap-1'>
|
|
|
|
|
<ImageUpload
|
|
|
|
|
deleteButtonClassName='!top-1 !right-1'
|
|
|
|
|
height={newsletter.header_image ? '66px' : '64px'}
|
|
|
|
|
id='logo'
|
|
|
|
|
imageURL={newsletter.header_image || undefined}
|
|
|
|
|
onDelete={() => {
|
|
|
|
|
updateNewsletter({header_image: null});
|
|
|
|
|
}}
|
|
|
|
|
onUpload={async (file) => {
|
|
|
|
|
const imageUrl = getImageUrl(await uploadImage({file}));
|
|
|
|
|
updateNewsletter({header_image: imageUrl});
|
|
|
|
|
}}
|
|
|
|
|
>
|
2023-07-17 09:12:05 +01:00
|
|
|
|
Upload header image
|
2023-08-02 16:10:50 +02:00
|
|
|
|
</ImageUpload>
|
|
|
|
|
<Hint>Optional, recommended size 1200x600</Hint>
|
|
|
|
|
</div>
|
2023-07-17 09:12:05 +01:00
|
|
|
|
</div>
|
2023-08-02 16:10:50 +02:00
|
|
|
|
<ToggleGroup>
|
2023-09-13 08:10:33 +01:00
|
|
|
|
{icon && <Toggle
|
|
|
|
|
checked={newsletter.show_header_icon}
|
|
|
|
|
direction="rtl"
|
|
|
|
|
label='Publication icon'
|
2023-09-14 13:04:31 +03:00
|
|
|
|
labelStyle='heading'
|
2023-09-13 08:10:33 +01:00
|
|
|
|
onChange={e => updateNewsletter({show_header_icon: e.target.checked})}
|
|
|
|
|
/>}
|
2023-08-02 16:10:50 +02:00
|
|
|
|
<Toggle
|
|
|
|
|
checked={newsletter.show_header_title}
|
|
|
|
|
direction="rtl"
|
|
|
|
|
label='Publication title'
|
2023-09-14 13:04:31 +03:00
|
|
|
|
labelStyle='heading'
|
2023-08-02 16:10:50 +02:00
|
|
|
|
onChange={e => updateNewsletter({show_header_title: e.target.checked})}
|
|
|
|
|
/>
|
|
|
|
|
<Toggle
|
|
|
|
|
checked={newsletter.show_header_name}
|
|
|
|
|
direction="rtl"
|
|
|
|
|
label='Newsletter name'
|
2023-09-14 13:04:31 +03:00
|
|
|
|
labelStyle='heading'
|
2023-08-02 16:10:50 +02:00
|
|
|
|
onChange={e => updateNewsletter({show_header_name: e.target.checked})}
|
|
|
|
|
/>
|
|
|
|
|
</ToggleGroup>
|
|
|
|
|
</Form>
|
2023-07-17 09:12:05 +01:00
|
|
|
|
|
2023-08-02 16:10:50 +02:00
|
|
|
|
<Form className='mt-6' gap='sm' margins='lg' title='Body'>
|
2023-09-04 07:00:37 +01:00
|
|
|
|
{hasEmailCustomization && <>
|
|
|
|
|
<ColorPickerField
|
|
|
|
|
direction='rtl'
|
|
|
|
|
swatches={[
|
|
|
|
|
{
|
|
|
|
|
hex: '#f0f0f0',
|
|
|
|
|
title: 'Light grey'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
hex: '#ffffff',
|
|
|
|
|
value: 'light',
|
|
|
|
|
title: 'White'
|
|
|
|
|
}
|
|
|
|
|
]}
|
|
|
|
|
title='Background color'
|
|
|
|
|
value={newsletter.background_color || 'light'}
|
|
|
|
|
onChange={color => updateNewsletter({background_color: color!})}
|
|
|
|
|
/>
|
|
|
|
|
<ColorPickerField
|
|
|
|
|
clearButtonValue={null}
|
|
|
|
|
direction='rtl'
|
|
|
|
|
swatches={[
|
|
|
|
|
{
|
|
|
|
|
hex: siteData.accent_color,
|
|
|
|
|
value: 'accent',
|
|
|
|
|
title: 'Accent'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
hex: backgroundColorIsDark() ? '#ffffff' : '#000000',
|
|
|
|
|
value: 'auto',
|
|
|
|
|
title: 'Auto'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
value: null,
|
|
|
|
|
title: 'Transparent',
|
|
|
|
|
hex: '#00000000'
|
|
|
|
|
}
|
|
|
|
|
]}
|
|
|
|
|
title='Border color'
|
|
|
|
|
value={newsletter.border_color}
|
|
|
|
|
onChange={color => updateNewsletter({border_color: color})}
|
|
|
|
|
/>
|
|
|
|
|
</>}
|
2023-08-02 16:10:50 +02:00
|
|
|
|
<Toggle
|
|
|
|
|
checked={newsletter.show_post_title_section}
|
|
|
|
|
direction="rtl"
|
|
|
|
|
label='Post title'
|
|
|
|
|
labelStyle='heading'
|
|
|
|
|
onChange={e => updateNewsletter({show_post_title_section: e.target.checked})}
|
|
|
|
|
/>
|
|
|
|
|
<div className={newsletter.show_post_title_section ? 'mt-[-16px] flex items-end' : 'hidden'}>
|
|
|
|
|
<div className="w-full pr-4">
|
|
|
|
|
<Select
|
|
|
|
|
disabled={!newsletter.show_post_title_section}
|
|
|
|
|
options={fontOptions}
|
|
|
|
|
selectedOption={newsletter.title_font_category}
|
|
|
|
|
onSelect={value => updateNewsletter({title_font_category: value})}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<ButtonGroup buttons={[
|
|
|
|
|
{
|
|
|
|
|
icon: 'align-left',
|
|
|
|
|
label: 'Align left',
|
|
|
|
|
hideLabel: true,
|
|
|
|
|
link: false,
|
|
|
|
|
size: 'sm',
|
|
|
|
|
color: newsletter.title_alignment === 'left' ? 'clear' : 'clear',
|
|
|
|
|
iconColorClass: newsletter.title_alignment === 'left' ? 'text-grey-900' : 'text-grey-500',
|
|
|
|
|
onClick: () => updateNewsletter({title_alignment: 'left'}),
|
|
|
|
|
disabled: !newsletter.show_post_title_section
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
icon: 'align-center',
|
|
|
|
|
label: 'Align center',
|
|
|
|
|
hideLabel: true,
|
|
|
|
|
link: false,
|
|
|
|
|
size: 'sm',
|
|
|
|
|
color: newsletter.title_alignment === 'center' ? 'clear' : 'clear',
|
|
|
|
|
iconColorClass: newsletter.title_alignment === 'center' ? 'text-grey-900' : 'text-grey-500',
|
|
|
|
|
onClick: () => updateNewsletter({title_alignment: 'center'}),
|
|
|
|
|
disabled: !newsletter.show_post_title_section
|
|
|
|
|
}
|
|
|
|
|
]}
|
|
|
|
|
className="mb-1 !gap-0"
|
2023-08-01 18:24:23 +01:00
|
|
|
|
/>
|
2023-07-20 15:00:04 +01:00
|
|
|
|
</div>
|
2023-09-04 07:00:37 +01:00
|
|
|
|
{hasEmailCustomization && <ColorPickerField
|
|
|
|
|
direction='rtl'
|
|
|
|
|
swatches={[
|
|
|
|
|
{
|
|
|
|
|
value: 'accent',
|
|
|
|
|
title: 'Accent',
|
|
|
|
|
hex: siteData.accent_color
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
value: null,
|
|
|
|
|
title: 'Auto',
|
|
|
|
|
hex: backgroundColorIsDark() ? '#ffffff' : '#000000'
|
|
|
|
|
}
|
|
|
|
|
]}
|
|
|
|
|
title='Heading color'
|
|
|
|
|
value={newsletter.title_color}
|
|
|
|
|
onChange={color => updateNewsletter({title_color: color})}
|
|
|
|
|
/>}
|
2023-08-02 16:10:50 +02:00
|
|
|
|
<Select
|
|
|
|
|
options={fontOptions}
|
|
|
|
|
selectedOption={newsletter.body_font_category}
|
|
|
|
|
title='Body style'
|
|
|
|
|
onSelect={value => updateNewsletter({body_font_category: value})}
|
2023-07-20 15:00:04 +01:00
|
|
|
|
/>
|
2023-08-02 16:10:50 +02:00
|
|
|
|
<Toggle
|
|
|
|
|
checked={newsletter.show_feature_image}
|
|
|
|
|
direction="rtl"
|
|
|
|
|
label='Feature image'
|
2023-09-12 17:11:12 +03:00
|
|
|
|
labelStyle='heading'
|
2023-08-02 16:10:50 +02:00
|
|
|
|
onChange={e => updateNewsletter({show_feature_image: e.target.checked})}
|
|
|
|
|
/>
|
|
|
|
|
</Form>
|
2023-07-17 09:12:05 +01:00
|
|
|
|
|
2023-08-02 16:10:50 +02:00
|
|
|
|
<Form className='mt-6' gap='sm' margins='lg' title='Footer'>
|
2023-09-12 17:11:12 +03:00
|
|
|
|
<ToggleGroup gap='lg'>
|
2023-08-02 16:10:50 +02:00
|
|
|
|
<Toggle
|
|
|
|
|
checked={newsletter.feedback_enabled}
|
|
|
|
|
direction="rtl"
|
|
|
|
|
label='Ask your readers for feedback'
|
2023-09-12 17:11:12 +03:00
|
|
|
|
labelStyle='heading'
|
2023-08-02 16:10:50 +02:00
|
|
|
|
onChange={e => updateNewsletter({feedback_enabled: e.target.checked})}
|
|
|
|
|
/>
|
|
|
|
|
<Toggle
|
|
|
|
|
checked={newsletter.show_comment_cta}
|
|
|
|
|
direction="rtl"
|
|
|
|
|
label='Add a link to your comments'
|
2023-09-12 17:11:12 +03:00
|
|
|
|
labelStyle='heading'
|
2023-08-02 16:10:50 +02:00
|
|
|
|
onChange={e => updateNewsletter({show_comment_cta: e.target.checked})}
|
|
|
|
|
/>
|
|
|
|
|
<Toggle
|
|
|
|
|
checked={newsletter.show_latest_posts}
|
|
|
|
|
direction="rtl"
|
|
|
|
|
label='Share your latest posts'
|
2023-09-12 17:11:12 +03:00
|
|
|
|
labelStyle='heading'
|
2023-08-02 16:10:50 +02:00
|
|
|
|
onChange={e => updateNewsletter({show_latest_posts: e.target.checked})}
|
|
|
|
|
/>
|
|
|
|
|
<Toggle
|
|
|
|
|
checked={newsletter.show_subscription_details}
|
|
|
|
|
direction="rtl"
|
|
|
|
|
label='Show subscription details'
|
2023-09-12 17:11:12 +03:00
|
|
|
|
labelStyle='heading'
|
2023-08-02 16:10:50 +02:00
|
|
|
|
onChange={e => updateNewsletter({show_subscription_details: e.target.checked})}
|
|
|
|
|
/>
|
|
|
|
|
</ToggleGroup>
|
2023-08-03 18:26:59 +01:00
|
|
|
|
<HtmlField
|
|
|
|
|
config={config}
|
|
|
|
|
hint='Any extra information or legal text'
|
|
|
|
|
nodes='MINIMAL_NODES'
|
2023-09-14 15:09:51 +01:00
|
|
|
|
placeholder=' '
|
2023-08-03 18:26:59 +01:00
|
|
|
|
title='Email footer'
|
2023-08-02 16:10:50 +02:00
|
|
|
|
value={newsletter.footer_content || ''}
|
2023-08-03 18:26:59 +01:00
|
|
|
|
onChange={html => updateNewsletter({footer_content: html})}
|
2023-08-02 16:10:50 +02:00
|
|
|
|
/>
|
|
|
|
|
</Form>
|
|
|
|
|
</>
|
2023-07-17 09:12:05 +01:00
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const handleTabChange = (id: string) => {
|
|
|
|
|
setSelectedTab(id);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className='flex h-full flex-col justify-between'>
|
|
|
|
|
<div className='px-7 pb-7 pt-5'>
|
|
|
|
|
<TabView selectedTab={selectedTab} tabs={tabs} onTabChange={handleTabChange} />
|
|
|
|
|
</div>
|
|
|
|
|
<StickyFooter height={96}>
|
|
|
|
|
<div className='flex w-full items-start px-7'>
|
|
|
|
|
<span>
|
2023-07-26 12:47:52 +02:00
|
|
|
|
<Icon className='mr-2 mt-[-1px]' colorClass='text-red' name='heart'/>
|
2023-07-17 09:12:05 +01:00
|
|
|
|
</span>
|
|
|
|
|
<Form marginBottom={false}>
|
|
|
|
|
<Toggle
|
2023-08-01 18:24:23 +01:00
|
|
|
|
checked={newsletter.show_badge}
|
2023-07-17 09:12:05 +01:00
|
|
|
|
direction='rtl'
|
2023-09-07 17:39:30 +03:00
|
|
|
|
label={
|
|
|
|
|
<div className='flex flex-col gap-0.5'>
|
|
|
|
|
<span className='text-sm md:text-base'>Promote independent publishing</span>
|
|
|
|
|
<span className='text-[11px] leading-tight text-grey-700 md:text-xs md:leading-tight'>Show you’re a part of the indie publishing movement with a small badge in the footer</span>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
2023-07-17 09:12:05 +01:00
|
|
|
|
labelStyle='value'
|
2023-08-01 18:24:23 +01:00
|
|
|
|
onChange={e => updateNewsletter({show_badge: e.target.checked})}
|
2023-07-17 09:12:05 +01:00
|
|
|
|
/>
|
|
|
|
|
</Form>
|
|
|
|
|
</div>
|
|
|
|
|
</StickyFooter>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2023-09-04 07:00:37 +01:00
|
|
|
|
const NewsletterDetailModalContent: React.FC<{newsletter: Newsletter}> = ({newsletter}) => {
|
2023-08-01 18:24:23 +01:00
|
|
|
|
const modal = useModal();
|
2023-08-07 12:44:30 +01:00
|
|
|
|
const {siteData} = useGlobalData();
|
2023-08-01 18:24:23 +01:00
|
|
|
|
const {mutateAsync: editNewsletter} = useEditNewsletter();
|
2023-08-10 13:04:23 +01:00
|
|
|
|
const {updateRoute} = useRouting();
|
2023-08-01 18:24:23 +01:00
|
|
|
|
|
2023-08-03 18:26:59 +01:00
|
|
|
|
const {formState, updateForm, handleSave, validate, errors, clearError} = useForm({
|
2023-08-01 18:24:23 +01:00
|
|
|
|
initialState: newsletter,
|
|
|
|
|
onSave: async () => {
|
2023-08-07 12:44:30 +01:00
|
|
|
|
const {newsletters, meta} = await editNewsletter(formState);
|
|
|
|
|
|
|
|
|
|
if (meta?.sent_email_verification) {
|
|
|
|
|
NiceModal.show(ConfirmationModal, {
|
|
|
|
|
title: 'Confirm newsletter email address',
|
|
|
|
|
prompt: <>
|
|
|
|
|
We‘ve sent a confirmation email to <strong>{formState.sender_email}</strong>.
|
|
|
|
|
Until the address has been verified newsletters will be sent from the
|
|
|
|
|
{newsletters[0].sender_email ? ' previous' : ' default'} email address
|
|
|
|
|
({fullEmailAddress(newsletters[0].sender_email || 'noreply', siteData)}).
|
|
|
|
|
</>,
|
|
|
|
|
cancelLabel: '',
|
|
|
|
|
onOk: (confirmModal) => {
|
|
|
|
|
confirmModal?.remove();
|
|
|
|
|
modal.remove();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
modal.remove();
|
|
|
|
|
}
|
2023-08-03 18:26:59 +01:00
|
|
|
|
},
|
|
|
|
|
onValidate: () => {
|
|
|
|
|
const newErrors: Record<string, string> = {};
|
|
|
|
|
|
|
|
|
|
if (!formState.name) {
|
|
|
|
|
newErrors.name = 'Please enter a name';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (formState.sender_email && !validator.isEmail(formState.sender_email)) {
|
|
|
|
|
newErrors.sender_email = 'Invalid email.';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return newErrors;
|
2023-08-01 18:24:23 +01:00
|
|
|
|
}
|
2023-08-02 08:37:51 +01:00
|
|
|
|
});
|
2023-08-01 18:24:23 +01:00
|
|
|
|
|
|
|
|
|
const updateNewsletter = (fields: Partial<Newsletter>) => {
|
|
|
|
|
updateForm(state => ({...state, ...fields}));
|
|
|
|
|
};
|
2023-07-19 09:48:55 +01:00
|
|
|
|
|
2023-08-01 18:24:23 +01:00
|
|
|
|
const preview = <NewsletterPreview newsletter={formState} />;
|
2023-08-03 18:26:59 +01:00
|
|
|
|
const sidebar = <Sidebar clearError={clearError} errors={errors} newsletter={formState} updateNewsletter={updateNewsletter} validate={validate} />;
|
2023-07-17 09:12:05 +01:00
|
|
|
|
|
|
|
|
|
return <PreviewModalContent
|
2023-08-10 13:04:23 +01:00
|
|
|
|
afterClose={() => updateRoute('newsletters')}
|
2023-07-17 09:12:05 +01:00
|
|
|
|
deviceSelector={false}
|
2023-08-01 18:24:23 +01:00
|
|
|
|
okLabel='Save & close'
|
2023-07-19 09:48:55 +01:00
|
|
|
|
preview={preview}
|
2023-07-17 09:12:05 +01:00
|
|
|
|
previewBgColor={'grey'}
|
2023-07-19 09:48:55 +01:00
|
|
|
|
previewToolbar={false}
|
2023-07-17 09:12:05 +01:00
|
|
|
|
sidebar={sidebar}
|
|
|
|
|
sidebarPadding={false}
|
|
|
|
|
testId='newsletter-modal'
|
|
|
|
|
title='Newsletter'
|
2023-08-03 18:26:59 +01:00
|
|
|
|
onOk={async () => {
|
|
|
|
|
toast.remove();
|
|
|
|
|
if (await handleSave()) {
|
|
|
|
|
modal.remove();
|
2023-08-10 13:04:23 +01:00
|
|
|
|
updateRoute('newsletters');
|
2023-08-03 18:26:59 +01:00
|
|
|
|
} else {
|
|
|
|
|
showToast({
|
|
|
|
|
type: 'pageError',
|
2023-09-14 13:04:31 +03:00
|
|
|
|
message: 'Can\'t save newsletter, please double check that you\'ve filled all mandatory fields.'
|
2023-08-03 18:26:59 +01:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}}
|
2023-07-17 09:12:05 +01:00
|
|
|
|
/>;
|
|
|
|
|
};
|
|
|
|
|
|
2023-09-04 07:00:37 +01:00
|
|
|
|
const NewsletterDetailModal: React.FC<RoutingModalProps> = ({params}) => {
|
|
|
|
|
const {data: {newsletters} = {}} = useBrowseNewsletters();
|
|
|
|
|
const newsletter = newsletters?.find(({id}) => id === params?.id);
|
|
|
|
|
|
|
|
|
|
if (newsletter) {
|
|
|
|
|
return <NewsletterDetailModalContent newsletter={newsletter} />;
|
|
|
|
|
} else {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-07-27 09:49:51 +02:00
|
|
|
|
export default NiceModal.create(NewsletterDetailModal);
|