Fixed validation and edge cases for managed email UI (#19121)

refs GRO-73

- fixed validation for reply-to address
- fixed rendering of default values for reply-to and sender-from fields
- added a temporary generic message for the verification confirmation,
so that it's compatible with both reply-to and from address changes. The
message will be improved in a follow-up commit (pending an API change).
This commit is contained in:
Sag 2023-11-23 19:30:28 -03:00 committed by GitHub
parent 8a5e9fb9f6
commit 819ddccc72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 94 deletions

View File

@ -52,7 +52,7 @@ const Newsletters: React.FC<{ keywords: string[] }> = ({keywords}) => {
NiceModal.show(ConfirmationModal, {
title: 'Email address verified',
prompt: <>Success! From address for newsletter <NavigateToNewsletter id={updatedNewsletter.id}>{updatedNewsletter.name}</NavigateToNewsletter> changed to <strong>{updatedNewsletter.sender_email}</strong></>,
prompt: <>Success! Email address for newsletter <NavigateToNewsletter id={updatedNewsletter.id}>{updatedNewsletter.name}</NavigateToNewsletter> has been changed.</>,
okLabel: 'Close',
cancelLabel: '',
onOk: confirmModal => confirmModal?.remove()

View File

@ -15,12 +15,19 @@ import {getSettingValues} from '@tryghost/admin-x-framework/api/settings';
import {textColorForBackgroundColor} from '@tryghost/color-utils';
import {useGlobalData} from '../../../providers/GlobalDataProvider';
const renderFrom = (newsletter: Newsletter, config: Config, defaultEmailAddress: string|undefined) => {
if (isManagedEmail(config) && defaultEmailAddress) {
if (!hasSendingDomain(config)) {
const renderSenderEmail = (newsletter: Newsletter, config: Config, defaultEmailAddress: string|undefined) => {
if (isManagedEmail(config) && !hasSendingDomain(config) && defaultEmailAddress) {
// Not changeable: sender_email is ignored
return defaultEmailAddress;
}
if (isManagedEmail(config) && hasSendingDomain(config)) {
// Only return sender_email if the domain names match
if (newsletter.sender_email?.split('@')[1] === sendingDomain(config)) {
return newsletter.sender_email;
} else {
return '';
}
}
return newsletter.sender_email || defaultEmailAddress || '';
@ -32,12 +39,23 @@ const renderReplyToEmail = (newsletter: Newsletter, config: Config, supportEmail
}
if (newsletter.sender_reply_to === 'newsletter') {
return renderFrom(newsletter, config, defaultEmailAddress);
} else if (newsletter.sender_reply_to === 'support') {
return supportEmailAddress || defaultEmailAddress || '';
} else {
return newsletter.sender_reply_to;
return renderSenderEmail(newsletter, config, defaultEmailAddress);
}
if (newsletter.sender_reply_to === 'support') {
return supportEmailAddress || defaultEmailAddress || '';
}
if (isManagedEmail(config) && hasSendingDomain(config)) {
// Only return sender_reply_to if the domain names match
if (newsletter.sender_reply_to.split('@')[1] === sendingDomain(config)) {
return newsletter.sender_reply_to;
} else {
return '';
}
}
return newsletter.sender_reply_to;
};
const Sidebar: React.FC<{
@ -59,7 +77,7 @@ const Sidebar: React.FC<{
const [siteTitle] = getSettingValues(localSettings, ['title']) as string[];
const handleError = useHandleError();
let newsletterAddress = renderFrom(newsletter, config, defaultEmailAddress);
let newsletterAddress = renderSenderEmail(newsletter, config, defaultEmailAddress);
const replyToEmails = [
{label: `Newsletter address (${newsletterAddress})`, value: 'newsletter'},
@ -137,9 +155,26 @@ const Sidebar: React.FC<{
};
const renderSenderEmailField = () => {
if (isManagedEmail(config)) {
// Self-hosters, or legacy Pro users
if (!isManagedEmail(config)) {
return (
<TextField
error={Boolean(errors.sender_email)}
hint={errors.sender_email}
placeholder={newsletterAddress || ''}
title="Sender email address"
value={newsletter.sender_email || ''}
onBlur={validate}
onChange={e => updateNewsletter({sender_email: e.target.value})}
onKeyDown={() => clearError('sender_email')}
/>
);
}
// Pro users with custom sending domains
if (hasSendingDomain(config)) {
const sendingEmailUsername = newsletter.sender_email?.split('@')[0];
const sendingEmail = renderSenderEmail(newsletter, config, defaultEmailAddress);
const sendingEmailUsername = sendingEmail?.split('@')[0];
return (
<TextField
@ -157,7 +192,9 @@ const Sidebar: React.FC<{
onKeyDown={() => clearError('sender_email')}
/>
);
} else {
}
// Pro users without custom sending domains
return (
<SettingGroupContent
values={[
@ -170,59 +207,11 @@ const Sidebar: React.FC<{
]}
/>
);
}
}
return (
<TextField
error={Boolean(errors.sender_email)}
hint={errors.sender_email}
placeholder={newsletterAddress}
title="Sender email address"
value={newsletter.sender_email || ''}
onBlur={validate}
onChange={e => updateNewsletter({sender_email: e.target.value})}
onKeyDown={() => clearError('sender_email')}
/>
);
};
const renderReplyToEmailField = () => {
if (isManagedEmail(config)) {
if (hasSendingDomain(config)) {
const replyToEmailUsername = ['newsletter', 'support'].includes(newsletter.sender_reply_to) ? '' : newsletter.sender_reply_to?.split('@')[0];
return (
<TextField
error={Boolean(errors.sender_reply_to)}
hint={errors.sender_reply_to}
rightPlaceholder={`@${sendingDomain(config)}`}
title="Reply-to address"
value={replyToEmailUsername || ''}
onBlur={validate}
onChange={(e) => {
const username = e.target.value?.split('@')[0];
const newEmail = username ? `${username}@${sendingDomain(config)}` : '';
updateNewsletter({sender_reply_to: newEmail});
}}
onKeyDown={() => clearError('sender_reply_to')}
/>
);
} else {
return (
<TextField
error={Boolean(errors.sender_reply_to)}
hint={errors.sender_reply_to}
placeholder={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')}
/>
);
}
}
// Self-hosters, or legacy Pro users
if (!isManagedEmail(config)) {
return (
<Select
options={replyToEmails}
@ -231,6 +220,44 @@ const Sidebar: React.FC<{
onSelect={option => updateNewsletter({sender_reply_to: option?.value})}
/>
);
}
// Pro users with custom sending domains
if (hasSendingDomain(config)) {
const replyToEmail = ['newsletter', 'support'].includes(newsletter.sender_reply_to) ? '' : renderReplyToEmail(newsletter, config, supportEmailAddress, defaultEmailAddress);
const replyToEmailUsername = replyToEmail?.split('@')[0] || '';
return (
<TextField
error={Boolean(errors.sender_reply_to)}
hint={errors.sender_reply_to}
rightPlaceholder={`@${sendingDomain(config)}`}
title="Reply-to address"
value={replyToEmailUsername}
onBlur={validate}
onChange={(e) => {
const username = e.target.value?.split('@')[0];
const newEmail = username ? `${username}@${sendingDomain(config)}` : 'newsletter';
updateNewsletter({sender_reply_to: newEmail});
}}
onKeyDown={() => clearError('sender_reply_to')}
/>
);
}
// Pro users without custom sending domains
return (
<TextField
error={Boolean(errors.sender_reply_to)}
hint={errors.sender_reply_to}
placeholder={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[] = [
@ -535,7 +562,7 @@ const NewsletterDetailModalContent: React.FC<{newsletter: Newsletter; onlyOne: b
const {newsletters, meta} = await editNewsletter(formState);
if (meta?.sent_email_verification) {
if (meta?.sent_email_verification[0] === 'sender_email') {
const previousFrom = renderFrom(newsletters[0], config, defaultEmailAddress);
const previousFrom = renderSenderEmail(newsletters[0], config, defaultEmailAddress);
NiceModal.show(ConfirmationModal, {
title: 'Confirm newsletter email address',
@ -584,7 +611,7 @@ const NewsletterDetailModalContent: React.FC<{newsletter: Newsletter; onlyOne: b
newErrors.sender_email = 'Invalid email.';
}
if (isManagedEmail(config) && formState.sender_reply_to && (!validator.isEmail(formState.sender_reply_to))) {
if (formState.sender_reply_to && !validator.isEmail(formState.sender_reply_to) && !['newsletter', 'support'].includes(formState.sender_reply_to)) {
newErrors.sender_reply_to = 'Invalid email.';
}