mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-24 19:33:02 +03:00
Allow custom reply-to addresses for self-hosters and allow empty values (#19200)
fixes GRO-105 The newsletter value is mapped to an empty value when shown to the users, this matches the backend behaviour. When entering an empty value, this is stored internally as 'newsletter'. The replyToInput component now uses its own state for the input value. This avoids weird issues when the rendered value changes, e.g. when entering the text 'support' or 'newsletter' in the field.
This commit is contained in:
parent
642c7f39cd
commit
226900f040
@ -1,6 +1,6 @@
|
||||
import NewsletterPreview from './NewsletterPreview';
|
||||
import NiceModal, {useModal} from '@ebay/nice-modal-react';
|
||||
import React, {useEffect, useMemo, useState} from 'react';
|
||||
import React, {useCallback, useEffect, useMemo, useState} from 'react';
|
||||
import useFeatureFlag from '../../../../hooks/useFeatureFlag';
|
||||
import useSettingGroup from '../../../../hooks/useSettingGroup';
|
||||
import validator from 'validator';
|
||||
@ -16,6 +16,78 @@ import {renderReplyToEmail, renderSenderEmail} from '../../../../utils/newslette
|
||||
import {textColorForBackgroundColor} from '@tryghost/color-utils';
|
||||
import {useGlobalData} from '../../../providers/GlobalDataProvider';
|
||||
|
||||
const ReplyToEmailField: React.FC<{
|
||||
newsletter: Newsletter;
|
||||
updateNewsletter: (fields: Partial<Newsletter>) => void;
|
||||
errors: ErrorMessages;
|
||||
validate: () => void;
|
||||
clearError: (field: string) => void;
|
||||
}> = ({newsletter, updateNewsletter, errors, clearError, validate}) => {
|
||||
const {settings, config} = useGlobalData();
|
||||
const [defaultEmailAddress, supportEmailAddress] = getSettingValues<string>(settings, ['default_email_address', 'support_email_address']);
|
||||
const newEmailAddressesFlag = useFeatureFlag('newEmailAddresses');
|
||||
|
||||
// When editing the senderReplyTo, we use a state, so we don't cause jumps when the 'rendering' method decides to change the value
|
||||
// Because 'newsletter' 'support' or an empty value can be mapped to a default value, we don't want those changes to happen when entering text
|
||||
const [senderReplyTo, setSenderReplyTo] = useState(renderReplyToEmail(newsletter, config, supportEmailAddress, defaultEmailAddress) || '');
|
||||
|
||||
let newsletterAddress = renderSenderEmail(newsletter, config, defaultEmailAddress);
|
||||
const replyToEmails = useMemo(() => [
|
||||
{label: `Newsletter address (${newsletterAddress})`, value: 'newsletter'},
|
||||
{label: `Support address (${supportEmailAddress})`, value: 'support'}
|
||||
], [newsletterAddress, supportEmailAddress]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isManagedEmail(config) && !newEmailAddressesFlag) {
|
||||
// Autocorrect invalid values
|
||||
const foundValue = replyToEmails.find(option => option.value === newsletter.sender_reply_to);
|
||||
if (!foundValue) {
|
||||
updateNewsletter({sender_reply_to: 'newsletter'});
|
||||
}
|
||||
}
|
||||
}, [config, replyToEmails, updateNewsletter, newsletter.sender_reply_to, newEmailAddressesFlag]);
|
||||
|
||||
const onChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSenderReplyTo(e.target.value);
|
||||
updateNewsletter({sender_reply_to: e.target.value || 'newsletter'});
|
||||
}, [updateNewsletter, setSenderReplyTo]);
|
||||
|
||||
// Self-hosters, or legacy Pro users
|
||||
if (!isManagedEmail(config) && !newEmailAddressesFlag) {
|
||||
// Only allow some choices
|
||||
return (
|
||||
<Select
|
||||
options={replyToEmails}
|
||||
selectedOption={replyToEmails.find(option => option.value === newsletter.sender_reply_to)}
|
||||
title="Reply-to email"
|
||||
onSelect={option => updateNewsletter({sender_reply_to: option?.value})}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const onBlur = () => {
|
||||
validate();
|
||||
|
||||
// Update the senderReplyTo to the rendered value again
|
||||
const rendered = renderReplyToEmail(newsletter, config, supportEmailAddress, defaultEmailAddress) || '';
|
||||
setSenderReplyTo(rendered);
|
||||
};
|
||||
|
||||
// Pro users without custom sending domains
|
||||
return (
|
||||
<TextField
|
||||
error={Boolean(errors.sender_reply_to)}
|
||||
hint={errors.sender_reply_to}
|
||||
placeholder={''}
|
||||
title="Reply-to email"
|
||||
value={senderReplyTo}
|
||||
onBlur={onBlur}
|
||||
onChange={onChange}
|
||||
onKeyDown={() => clearError('sender_reply_to')}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const Sidebar: React.FC<{
|
||||
newsletter: Newsletter;
|
||||
onlyOne: boolean;
|
||||
@ -27,7 +99,7 @@ const Sidebar: React.FC<{
|
||||
const {mutateAsync: editNewsletter} = useEditNewsletter();
|
||||
const limiter = useLimiter();
|
||||
const {settings, siteData, config} = useGlobalData();
|
||||
const [icon, defaultEmailAddress, supportEmailAddress] = getSettingValues<string>(settings, ['icon', 'default_email_address', 'support_email_address']);
|
||||
const [icon, defaultEmailAddress] = getSettingValues<string>(settings, ['icon', 'default_email_address', 'support_email_address']);
|
||||
const {mutateAsync: uploadImage} = useUploadImage();
|
||||
const [selectedTab, setSelectedTab] = useState('generalSettings');
|
||||
const hasEmailCustomization = useFeatureFlag('emailCustomization');
|
||||
@ -37,11 +109,6 @@ const Sidebar: React.FC<{
|
||||
|
||||
let newsletterAddress = renderSenderEmail(newsletter, config, defaultEmailAddress);
|
||||
|
||||
const replyToEmails = useMemo(() => [
|
||||
{label: `Newsletter address (${newsletterAddress})`, value: 'newsletter'},
|
||||
{label: `Support address (${supportEmailAddress})`, value: 'support'}
|
||||
], [newsletterAddress, supportEmailAddress]);
|
||||
|
||||
const fontOptions: SelectOption[] = [
|
||||
{value: 'serif', label: 'Elegant serif', className: 'font-serif'},
|
||||
{value: 'sans_serif', label: 'Clean sans-serif'}
|
||||
@ -176,45 +243,6 @@ const Sidebar: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isManagedEmail(config)) {
|
||||
// Autocorrect invalid values
|
||||
const foundValue = replyToEmails.find(option => option.value === newsletter.sender_reply_to);
|
||||
if (!foundValue) {
|
||||
updateNewsletter({sender_reply_to: 'newsletter'});
|
||||
}
|
||||
}
|
||||
}, [config, replyToEmails, updateNewsletter, newsletter.sender_reply_to]);
|
||||
|
||||
const renderReplyToEmailField = () => {
|
||||
// Self-hosters, or legacy Pro users
|
||||
if (!isManagedEmail(config)) {
|
||||
return (
|
||||
<Select
|
||||
options={replyToEmails}
|
||||
selectedOption={replyToEmails.find(option => option.value === newsletter.sender_reply_to)}
|
||||
title="Reply-to email"
|
||||
onSelect={option => updateNewsletter({sender_reply_to: option?.value})}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const replyToRequired = !hasSendingDomain(config);
|
||||
// Pro users without custom sending domains
|
||||
return (
|
||||
<TextField
|
||||
error={Boolean(errors.sender_reply_to)}
|
||||
hint={errors.sender_reply_to}
|
||||
placeholder={replyToRequired ? (newsletterAddress || '') : ''}
|
||||
title="Reply-to email"
|
||||
value={renderReplyToEmail(newsletter, config, supportEmailAddress, defaultEmailAddress) || ''}
|
||||
onBlur={validate}
|
||||
onChange={e => updateNewsletter({sender_reply_to: e.target.value})}
|
||||
onKeyDown={() => clearError('sender_reply_to')}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const tabs: Tab[] = [
|
||||
{
|
||||
id: 'generalSettings',
|
||||
@ -237,7 +265,7 @@ const Sidebar: React.FC<{
|
||||
<Form className='mt-6' gap='sm' margins='lg' title='Email addresses'>
|
||||
<TextField placeholder={siteTitle} title="Sender name" value={newsletter.sender_name || ''} onChange={e => updateNewsletter({sender_name: e.target.value})} />
|
||||
{renderSenderEmailField()}
|
||||
{renderReplyToEmailField()}
|
||||
<ReplyToEmailField clearError={clearError} errors={errors} newsletter={newsletter} updateNewsletter={updateNewsletter} validate={validate} />
|
||||
</Form>
|
||||
<Form className='mt-6' gap='sm' margins='lg' title='Member settings'>
|
||||
<Toggle
|
||||
|
@ -21,7 +21,7 @@ export const renderSenderEmail = (newsletter: Newsletter, config: Config, defaul
|
||||
|
||||
export const renderReplyToEmail = (newsletter: Newsletter, config: Config, supportEmailAddress: string|undefined, defaultEmailAddress: string|undefined) => {
|
||||
if (newsletter.sender_reply_to === 'newsletter') {
|
||||
if (isManagedEmail(config) && hasSendingDomain(config)) {
|
||||
if (isManagedEmail(config) || !!config.labs.newEmailAddresses) {
|
||||
// No reply-to set
|
||||
// sender_reply_to currently doesn't allow empty values, we need to set it to 'newsletter'
|
||||
return '';
|
||||
|
Loading…
Reference in New Issue
Block a user