mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Restored newsletter email verification flow (#18548)
refs https://github.com/TryGhost/Product/issues/3832 --- <!-- Leave the line below if you'd like GitHub Copilot to generate a summary from your commit --> <!-- copilot:summary --> ### <samp>🤖 Generated by Copilot at 8a40cbc</samp> This pull request adds a feature to verify the sender email address for a newsletter in the admin settings app. It implements a UI component, a custom hook, and a server-side service to handle the verification process. It also fixes a minor typo and a navigation issue in the newsletters module.
This commit is contained in:
parent
7f2dc6e5fa
commit
4b07de885a
4 changed files with 71 additions and 4 deletions
|
@ -97,3 +97,15 @@ export const useEditNewsletter = createMutation<NewslettersEditResponseType, New
|
|||
update: updateQueryCache('newsletters')
|
||||
}
|
||||
});
|
||||
|
||||
export const useVerifyNewsletterEmail = createMutation<NewslettersResponseType, {token: string}>({
|
||||
method: 'PUT',
|
||||
path: () => '/newsletters/verifications/',
|
||||
body: ({token}) => ({token}),
|
||||
defaultSearchParams: {include: 'count.active_members,count.posts'},
|
||||
updateQueries: {
|
||||
dataType,
|
||||
emberUpdateType: 'createOrUpdate',
|
||||
update: updateQueryCache('newsletters')
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,12 +1,27 @@
|
|||
import Button from '../../../admin-x-ds/global/Button';
|
||||
import ConfirmationModal from '../../../admin-x-ds/global/modal/ConfirmationModal';
|
||||
import NewslettersList from './newsletters/NewslettersList';
|
||||
import React, {useState} from 'react';
|
||||
import NiceModal, {useModal} from '@ebay/nice-modal-react';
|
||||
import React, {ReactNode, useEffect, useState} from 'react';
|
||||
import SettingGroup from '../../../admin-x-ds/settings/SettingGroup';
|
||||
import TabView from '../../../admin-x-ds/global/TabView';
|
||||
import useHandleError from '../../../utils/api/handleError';
|
||||
import useQueryParams from '../../../hooks/useQueryParams';
|
||||
import useRouting from '../../../hooks/useRouting';
|
||||
import {useBrowseNewsletters} from '../../../api/newsletters';
|
||||
import {APIError} from '../../../utils/errors';
|
||||
import {useBrowseNewsletters, useVerifyNewsletterEmail} from '../../../api/newsletters';
|
||||
import {withErrorBoundary} from '../../../admin-x-ds/global/ErrorBoundary';
|
||||
|
||||
const NavigateToNewsletter = ({id, children}: {id: string; children: ReactNode}) => {
|
||||
const modal = useModal();
|
||||
const {updateRoute} = useRouting();
|
||||
|
||||
return <button className="text-green" type="button" onClick={() => {
|
||||
updateRoute(`newsletters/${id}`);
|
||||
modal.remove();
|
||||
}}>{children}</button>;
|
||||
};
|
||||
|
||||
const Newsletters: React.FC<{ keywords: string[] }> = ({keywords}) => {
|
||||
const {updateRoute} = useRouting();
|
||||
const openNewsletterModal = () => {
|
||||
|
@ -15,6 +30,45 @@ const Newsletters: React.FC<{ keywords: string[] }> = ({keywords}) => {
|
|||
const [selectedTab, setSelectedTab] = useState('active-newsletters');
|
||||
const {data: {newsletters, meta, isEnd} = {}, fetchNextPage} = useBrowseNewsletters();
|
||||
|
||||
const verifyEmailToken = useQueryParams().getParam('verifyEmail');
|
||||
const {mutateAsync: verifyEmail} = useVerifyNewsletterEmail();
|
||||
const handleError = useHandleError();
|
||||
|
||||
useEffect(() => {
|
||||
if (!verifyEmailToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
const verify = async () => {
|
||||
try {
|
||||
const {newsletters: [updatedNewsletter]} = await verifyEmail({token: verifyEmailToken});
|
||||
|
||||
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></>,
|
||||
okLabel: 'Close',
|
||||
cancelLabel: '',
|
||||
onOk: confirmModal => confirmModal?.remove()
|
||||
});
|
||||
} catch (e) {
|
||||
let prompt = 'There was an error verifying your email address. Please try again.';
|
||||
|
||||
if (e instanceof APIError && e.message === 'Token expired') {
|
||||
prompt = 'The verification link has expired. Please try again.';
|
||||
}
|
||||
NiceModal.show(ConfirmationModal, {
|
||||
title: 'Error verifying email address',
|
||||
prompt: prompt,
|
||||
okLabel: 'Close',
|
||||
cancelLabel: '',
|
||||
onOk: confirmModal => confirmModal?.remove()
|
||||
});
|
||||
handleError(e, {withToast: false});
|
||||
}
|
||||
};
|
||||
verify();
|
||||
}, [verifyEmailToken, handleError, verifyEmail]);
|
||||
|
||||
const buttons = (
|
||||
<Button color='green' label='Add newsletter' link linkWithPadding onClick={() => {
|
||||
openNewsletterModal();
|
||||
|
|
|
@ -455,6 +455,7 @@ const NewsletterDetailModalContent: React.FC<{newsletter: Newsletter; onlyOne: b
|
|||
onOk: (confirmModal) => {
|
||||
confirmModal?.remove();
|
||||
modal.remove();
|
||||
updateRoute('newsletters');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ class NewslettersService {
|
|||
}
|
||||
|
||||
let updatedNewsletter;
|
||||
|
||||
|
||||
try {
|
||||
updatedNewsletter = await this.NewsletterModel.edit(cleanedAttrs, options);
|
||||
} catch (error) {
|
||||
|
@ -215,7 +215,7 @@ class NewslettersService {
|
|||
|
||||
// Load relations correctly in the response
|
||||
updatedNewsletter = await this.NewsletterModel.findOne({id: updatedNewsletter.id}, {...options, require: true});
|
||||
|
||||
|
||||
await this.respondWithEmailVerification(updatedNewsletter, emailsToVerify);
|
||||
return updatedNewsletter;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue