2
1
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2023-12-13 21:00:40 +01:00

Added confirmation modal after setting portal email address (#17231)

refs https://github.com/TryGhost/Product/issues/3545
This commit is contained in:
Jono M 2023-07-07 14:05:14 +12:00 committed by GitHub
parent e397368393
commit 4ffdab3c82
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 42 additions and 21 deletions

View file

@ -1,11 +1,12 @@
import React, {createContext, useCallback, useContext, useEffect, useState} from 'react';
import {Config, Setting, SiteData} from '../../types/api';
import {ServicesContext} from './ServiceProvider';
import {SettingsResponseType} from '../../utils/api';
// Define the Settings Context
interface SettingsContextProps {
settings: Setting[] | null;
saveSettings: (updatedSettings: Setting[]) => Promise<Setting[]>;
saveSettings: (updatedSettings: Setting[]) => Promise<SettingsResponseType>;
siteData: SiteData | null;
config: Config | null;
settingsLoaded: boolean;
@ -20,7 +21,7 @@ const SettingsContext = createContext<SettingsContextProps>({
siteData: null,
config: null,
settingsLoaded: false,
saveSettings: async () => []
saveSettings: async () => ({settings: []})
});
function serialiseSettingsData(settings: Setting[]): Setting[] {
@ -121,10 +122,13 @@ const SettingsProvider: React.FC<SettingsProviderProps> = ({children}) => {
setSettings(newSettings);
return newSettings;
return {
settings: newSettings,
meta: data.meta
};
} catch (error) {
// Log error in settings API
return [];
return {settings: []};
}
}, [api]);
@ -139,3 +143,4 @@ const SettingsProvider: React.FC<SettingsProviderProps> = ({children}) => {
};
export {SettingsContext, SettingsProvider};

View file

@ -1,4 +1,5 @@
import AccountPage from './portal/AccountPage';
import ConfirmationModal from '../../../admin-x-ds/global/modal/ConfirmationModal';
import LookAndFeel from './portal/LookAndFeel';
import NiceModal, {useModal} from '@ebay/nice-modal-react';
import PortalPreview from './portal/PortalPreview';
@ -9,6 +10,7 @@ import useForm, {Dirtyable} from '../../../hooks/useForm';
import {PreviewModalContent} from '../../../admin-x-ds/global/modal/PreviewModal';
import {Setting, SettingValue, Tier} from '../../../types/api';
import {SettingsContext} from '../../providers/SettingsProvider';
import {fullEmailAddress} from '../../../utils/helpers';
import {useTiers} from '../../providers/ServiceProvider';
const Sidebar: React.FC<{
@ -61,7 +63,7 @@ const PortalModal: React.FC = () => {
const modal = useModal();
const [selectedPreviewTab, setSelectedPreviewTab] = useState('signup');
const {settings, saveSettings} = useContext(SettingsContext);
const {settings, saveSettings, siteData} = useContext(SettingsContext);
const {data: tiers, update: updateTiers} = useTiers();
const {formState, saveState, handleSave, updateForm} = useForm({
@ -72,7 +74,23 @@ const PortalModal: React.FC = () => {
onSave: async () => {
await updateTiers(formState.tiers.filter(tier => tier.dirty));
await saveSettings(formState.settings.filter(setting => setting.dirty));
const {meta, settings: currentSettings} = await saveSettings(formState.settings.filter(setting => setting.dirty));
if (meta?.sent_email_verification) {
const newEmail = formState.settings.find(setting => setting.key === 'members_support_address')?.value;
const currentEmail = currentSettings.find(setting => setting.key === 'members_support_address')?.value;
NiceModal.show(ConfirmationModal, {
title: 'Confirm email address',
prompt: <>
We've sent a confirmation email to <strong>{newEmail}</strong>.
Until verified, your support address will remain {fullEmailAddress(currentEmail?.toString() || 'noreply', siteData!)}.
</>,
okLabel: 'Close',
cancelLabel: '',
onOk: confirmModal => confirmModal?.remove()
});
}
}
});

View file

@ -3,7 +3,7 @@ import React, {FocusEventHandler, useContext, useState} from 'react';
import TextField from '../../../../admin-x-ds/global/form/TextField';
import {Setting, SettingValue} from '../../../../types/api';
import {SettingsContext} from '../../../providers/SettingsProvider';
import {getEmailDomain, getSettingValues} from '../../../../utils/helpers';
import {fullEmailAddress, getEmailDomain, getSettingValues} from '../../../../utils/helpers';
const AccountPage: React.FC<{
localSettings: Setting[]
@ -14,16 +14,7 @@ const AccountPage: React.FC<{
const {siteData} = useContext(SettingsContext) || {};
const emailDomain = getEmailDomain(siteData!);
const parseEmailAddress = (value?: string) => {
let emailAddress = value || 'noreply';
// Adds default domain as site domain
if (emailAddress.indexOf('@') < 0 && emailDomain) {
emailAddress = `${emailAddress}@${emailDomain}`;
}
return emailAddress;
};
const [value, setValue] = useState(parseEmailAddress(membersSupportAddress?.toString()));
const [value, setValue] = useState(fullEmailAddress(membersSupportAddress?.toString() || '', siteData!));
const updateSupportAddress: FocusEventHandler<HTMLInputElement> = (e) => {
let supportAddress = e.target.value;
@ -31,7 +22,7 @@ const AccountPage: React.FC<{
let settingValue = emailDomain && supportAddress === `noreply@${emailDomain}` ? 'noreply' : supportAddress;
updateSetting('members_support_address', settingValue);
setValue(parseEmailAddress(settingValue));
setValue(fullEmailAddress(settingValue, siteData!));
};
return <Form marginTop>

View file

@ -110,7 +110,7 @@ const DesignModal: React.FC = () => {
}
if (formState.settings.some(setting => setting.dirty)) {
const newSettings = await saveSettings(formState.settings.filter(setting => setting.dirty));
const {settings: newSettings} = await saveSettings(formState.settings.filter(setting => setting.dirty));
updateForm(state => ({...state, settings: newSettings}));
}
}

View file

@ -1,7 +1,7 @@
import {Config, CustomThemeSetting, InstalledTheme, Label, Offer, Post, Setting, SiteData, Theme, Tier, User, UserRole} from '../types/api';
import {getGhostPaths} from './helpers';
interface Meta {
export interface Meta {
pagination: {
page: number;
limit: number;
@ -12,8 +12,10 @@ interface Meta {
}
}
export type SettingsResponseMeta = Meta & { sent_email_verification?: boolean }
export interface SettingsResponseType {
meta: Meta;
meta?: SettingsResponseMeta;
settings: Setting[];
}

View file

@ -108,6 +108,11 @@ export function getEmailDomain(siteData: SiteData): string {
return domain;
}
export function fullEmailAddress(value: 'noreply' | string, siteData: SiteData) {
const emailDomain = getEmailDomain(siteData);
return value === 'noreply' ? `noreply@${emailDomain}` : value;
}
export function checkStripeEnabled(settings: Setting[], config: Config) {
const hasSetting = (key: string) => settings.some(setting => setting.key === key && setting.value);