mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-04 02:01:58 -05:00
Wired mailgun and analytics settings in admin-x
refs https://github.com/TryGhost/Team/issues/3151 - updates textfield to have password type - updates wiring for mailgun settings - updates wiring for analytics settings - fixes local value read or useSettingGroup
This commit is contained in:
parent
ec56572764
commit
a3e39ce61e
5 changed files with 133 additions and 55 deletions
|
@ -45,6 +45,15 @@ export const WithHint: Story = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const PasswordType: Story = {
|
||||||
|
args: {
|
||||||
|
title: 'Password',
|
||||||
|
type: 'password',
|
||||||
|
placeholder: 'Enter something',
|
||||||
|
hint: 'Here\'s some hint'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const Error: Story = {
|
export const Error: Story = {
|
||||||
args: {
|
args: {
|
||||||
title: 'Title',
|
title: 'Title',
|
||||||
|
|
|
@ -3,9 +3,12 @@ import React from 'react';
|
||||||
import Heading from './Heading';
|
import Heading from './Heading';
|
||||||
import Hint from './Hint';
|
import Hint from './Hint';
|
||||||
|
|
||||||
|
type InputFieldType = 'text' | 'number' | 'email' | 'password' | 'checkbox' | 'radio' | 'file' | 'date' | 'time' | 'range' | 'search';
|
||||||
|
|
||||||
interface ITextField {
|
interface ITextField {
|
||||||
inputRef?: React.RefObject<HTMLInputElement>;
|
inputRef?: React.RefObject<HTMLInputElement>;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
type?: InputFieldType;
|
||||||
value?: string;
|
value?: string;
|
||||||
error?: boolean;
|
error?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
@ -13,7 +16,9 @@ interface ITextField {
|
||||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TextField: React.FC<ITextField> = ({inputRef, title, value, error, placeholder, hint, onChange, ...props}) => {
|
const TextField: React.FC<ITextField> = ({
|
||||||
|
type = 'text', inputRef, title, value, error, placeholder, hint, onChange, ...props
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col'>
|
<div className='flex flex-col'>
|
||||||
{title && <Heading useLabelTag={true}>{title}</Heading>}
|
{title && <Heading useLabelTag={true}>{title}</Heading>}
|
||||||
|
@ -22,7 +27,7 @@ const TextField: React.FC<ITextField> = ({inputRef, title, value, error, placeho
|
||||||
className={`-mx-1 -mt-0.5 h-10 border-b ${error ? `border-red` : `border-grey-500 hover:border-grey-600 focus:border-grey-900`} px-1 py-2 ${title && `mt-0`}`}
|
className={`-mx-1 -mt-0.5 h-10 border-b ${error ? `border-red` : `border-grey-500 hover:border-grey-600 focus:border-grey-900`} px-1 py-2 ${title && `mt-0`}`}
|
||||||
defaultValue={value}
|
defaultValue={value}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
type='text'
|
type={type}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
{...props} />
|
{...props} />
|
||||||
{hint && <Hint color={error ? 'red' : ''}>{hint}</Hint>}
|
{hint && <Hint color={error ? 'red' : ''}>{hint}</Hint>}
|
||||||
|
|
|
@ -1,61 +1,111 @@
|
||||||
import Dropdown from '../../../admin-x-ds/global/Dropdown';
|
import Dropdown from '../../../admin-x-ds/global/Dropdown';
|
||||||
import Link from '../../../admin-x-ds/global/Link';
|
import Link from '../../../admin-x-ds/global/Link';
|
||||||
import React, {useState} from 'react';
|
import React from 'react';
|
||||||
import SettingGroup from '../../../admin-x-ds/settings/SettingGroup';
|
import SettingGroup from '../../../admin-x-ds/settings/SettingGroup';
|
||||||
import SettingGroupContent from '../../../admin-x-ds/settings/SettingGroupContent';
|
import SettingGroupContent from '../../../admin-x-ds/settings/SettingGroupContent';
|
||||||
import TextField from '../../../admin-x-ds/global/TextField';
|
import TextField from '../../../admin-x-ds/global/TextField';
|
||||||
import {TSettingGroupStates} from '../../../admin-x-ds/settings/SettingGroup';
|
import useSettingGroup from '../../../hooks/useSettingGroup';
|
||||||
|
|
||||||
|
const MAILGUN_REGIONS = [
|
||||||
|
{label: '🇺🇸 US', value: 'https://api.mailgun.net/v3'},
|
||||||
|
{label: '🇪🇺 EU', value: 'https://api.eu.mailgun.net/v3'}
|
||||||
|
];
|
||||||
|
|
||||||
const MailGun: React.FC = () => {
|
const MailGun: React.FC = () => {
|
||||||
const [currentState, setCurrentState] = useState<TSettingGroupStates>('view');
|
const {
|
||||||
|
currentState,
|
||||||
|
handleSave,
|
||||||
|
handleCancel,
|
||||||
|
updateSetting,
|
||||||
|
getSettingValues,
|
||||||
|
handleStateChange
|
||||||
|
} = useSettingGroup();
|
||||||
|
|
||||||
const handleStateChange = (newState: TSettingGroupStates) => {
|
const [mailgunRegion, mailgunDomain, mailgunApiKey] = getSettingValues([
|
||||||
setCurrentState(newState);
|
'mailgun_base_url', 'mailgun_domain', 'mailgun_api_key'
|
||||||
};
|
]) as string[];
|
||||||
|
|
||||||
|
const isMailgunSetup = mailgunRegion && mailgunDomain && mailgunApiKey;
|
||||||
|
|
||||||
|
const data = isMailgunSetup ? [
|
||||||
|
{
|
||||||
|
heading: 'Mailgun region',
|
||||||
|
key: 'mailgun-region',
|
||||||
|
value: mailgunRegion
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: 'Mailgun domain',
|
||||||
|
key: 'mailgun-domain',
|
||||||
|
value: mailgunDomain
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: 'Mailgun private API key',
|
||||||
|
key: 'commenting',
|
||||||
|
value: mailgunApiKey
|
||||||
|
}
|
||||||
|
] : [
|
||||||
|
{
|
||||||
|
heading: 'Status',
|
||||||
|
key: 'status',
|
||||||
|
value: 'Mailgun is not set up'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const values = (
|
const values = (
|
||||||
<SettingGroupContent
|
<SettingGroupContent
|
||||||
columns={2}
|
columns={1}
|
||||||
values={[
|
values={data}
|
||||||
{
|
|
||||||
heading: 'Status',
|
|
||||||
key: 'status',
|
|
||||||
value: 'Mailgun is not set up'
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const apiKeysHint = (
|
||||||
|
<>Find your Mailgun API keys <Link href="https://app.mailgun.com/app/account/security/api_keys" rel="noopener noreferrer" target="_blank">here</Link></>
|
||||||
|
);
|
||||||
|
|
||||||
const inputs = (
|
const inputs = (
|
||||||
<SettingGroupContent>
|
<SettingGroupContent>
|
||||||
<div className='grid grid-cols-[0.25fr_0.75fr] gap-6'>
|
<div className='grid grid-cols-[0.25fr_0.75fr] gap-6'>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
defaultSelectedOption='option-1'
|
defaultSelectedOption={mailgunRegion}
|
||||||
options={[
|
options={MAILGUN_REGIONS}
|
||||||
{value: 'option-1', label: 'US'},
|
|
||||||
{value: 'option-2', label: 'EU'}
|
|
||||||
]}
|
|
||||||
title="Mailgun region"
|
title="Mailgun region"
|
||||||
onSelect={() => {}}
|
onSelect={(value) => {
|
||||||
|
updateSetting('mailgun_base_url', value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
title='Mailgun domain'
|
title='Mailgun domain'
|
||||||
|
value={mailgunDomain}
|
||||||
|
onChange={(e) => {
|
||||||
|
updateSetting('mailgun_domain', e.target.value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<div className='col-span-2'>
|
<div className='col-span-2'>
|
||||||
<TextField
|
<TextField
|
||||||
hint={<>Find your Mailgun API keys <Link href="https://app.mailgun.com/app/account/security/api_keys" rel="noopener noreferrer" target="_blank">here</Link></>}
|
hint={apiKeysHint}
|
||||||
title='Mailgun private API key'
|
title='Mailgun private API key'
|
||||||
|
type='password'
|
||||||
|
value={mailgunApiKey}
|
||||||
|
onChange={(e) => {
|
||||||
|
updateSetting('mailgun_api_key', e.target.value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SettingGroupContent>
|
</SettingGroupContent>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const groupDescription = (
|
||||||
|
<>The Mailgun API is used for bulk email newsletter delivery. <Link href='https://ghost.org/docs/faq/mailgun-newsletters/' target='_blank'>Why is this required?</Link></>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingGroup
|
<SettingGroup
|
||||||
description={<>The Mailgun API is used for bulk email newsletter delivery. <Link href='https://ghost.org/docs/faq/mailgun-newsletters/' target='_blank'>Why is this required?</Link></>}
|
description={groupDescription}
|
||||||
state={currentState}
|
state={currentState}
|
||||||
title='Mailgun'
|
title='Mailgun'
|
||||||
|
onCancel={handleCancel}
|
||||||
|
onSave={handleSave}
|
||||||
onStateChange={handleStateChange}
|
onStateChange={handleStateChange}
|
||||||
>
|
>
|
||||||
{currentState === 'view' ? values : inputs}
|
{currentState === 'view' ? values : inputs}
|
||||||
|
|
|
@ -1,67 +1,81 @@
|
||||||
import Button from '../../../admin-x-ds/global/Button';
|
import Button from '../../../admin-x-ds/global/Button';
|
||||||
import ButtonGroup from '../../../admin-x-ds/global/ButtonGroup';
|
import React from 'react';
|
||||||
import React, {useState} from 'react';
|
|
||||||
import SettingGroup from '../../../admin-x-ds/settings/SettingGroup';
|
import SettingGroup from '../../../admin-x-ds/settings/SettingGroup';
|
||||||
import SettingGroupContent from '../../../admin-x-ds/settings/SettingGroupContent';
|
import SettingGroupContent from '../../../admin-x-ds/settings/SettingGroupContent';
|
||||||
import Toggle from '../../../admin-x-ds/global/Toggle';
|
import Toggle from '../../../admin-x-ds/global/Toggle';
|
||||||
import {TSettingGroupStates} from '../../../admin-x-ds/settings/SettingGroup';
|
import useSettingGroup from '../../../hooks/useSettingGroup';
|
||||||
|
|
||||||
const Analytics: React.FC = () => {
|
const Analytics: React.FC = () => {
|
||||||
const [currentState, setCurrentState] = useState<TSettingGroupStates>('view');
|
const {
|
||||||
|
currentState,
|
||||||
|
handleSave,
|
||||||
|
handleCancel,
|
||||||
|
updateSetting,
|
||||||
|
getSettingValues,
|
||||||
|
handleStateChange
|
||||||
|
} = useSettingGroup();
|
||||||
|
|
||||||
const handleStateChange = () => {
|
const [trackEmailOpens, trackEmailClicks, trackMemberSources, outboundLinkTagging] = getSettingValues([
|
||||||
setCurrentState('unsaved');
|
'email_track_opens', 'email_track_clicks', 'members_track_sources', 'outbound_link_tagging'
|
||||||
|
]) as boolean[];
|
||||||
|
|
||||||
|
const handleToggleChange = (key: string, e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
updateSetting(key, e.target.checked);
|
||||||
};
|
};
|
||||||
|
|
||||||
const inputs = (
|
const inputs = (
|
||||||
<SettingGroupContent columns={2}>
|
<SettingGroupContent columns={2}>
|
||||||
<Toggle
|
<Toggle
|
||||||
// direction='rtl'
|
// direction='rtl'
|
||||||
|
checked={trackEmailOpens}
|
||||||
hint='Record when a member opens an email'
|
hint='Record when a member opens an email'
|
||||||
id='newsletter-opens'
|
id='newsletter-opens'
|
||||||
label='Newsletter opens'
|
label='Newsletter opens'
|
||||||
onChange={handleStateChange}
|
onChange={(e) => {
|
||||||
|
handleToggleChange('email_track_opens', e);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Toggle
|
<Toggle
|
||||||
// direction='rtl'
|
// direction='rtl'
|
||||||
|
checked={trackEmailClicks}
|
||||||
hint='Record when a member clicks on any link in an email'
|
hint='Record when a member clicks on any link in an email'
|
||||||
id='newsletter-clicks'
|
id='newsletter-clicks'
|
||||||
label='Newsletter clicks'
|
label='Newsletter clicks'
|
||||||
onChange={handleStateChange}
|
onChange={(e) => {
|
||||||
|
handleToggleChange('email_track_clicks', e);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Toggle
|
<Toggle
|
||||||
// direction='rtl'
|
// direction='rtl'
|
||||||
|
checked={trackMemberSources}
|
||||||
hint='Track the traffic sources and posts that drive the most member growth'
|
hint='Track the traffic sources and posts that drive the most member growth'
|
||||||
id='member-sources'
|
id='member-sources'
|
||||||
label='Member sources'
|
label='Member sources'
|
||||||
onChange={handleStateChange}
|
onChange={(e) => {
|
||||||
|
handleToggleChange('members_track_sources', e);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Toggle
|
<Toggle
|
||||||
// direction='rtl'
|
// direction='rtl'
|
||||||
|
checked={outboundLinkTagging}
|
||||||
hint='Make it easier for other sites to track the traffic you send them in their analytics'
|
hint='Make it easier for other sites to track the traffic you send them in their analytics'
|
||||||
id='outbound-links'
|
id='outbound-links'
|
||||||
label='Outbound link tagging'
|
label='Outbound link tagging'
|
||||||
onChange={handleStateChange}
|
onChange={(e) => {
|
||||||
|
handleToggleChange('outbound_link_tagging', e);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</SettingGroupContent>
|
</SettingGroupContent>
|
||||||
);
|
);
|
||||||
|
|
||||||
const buttons = <ButtonGroup buttons={[
|
|
||||||
{
|
|
||||||
label: 'Cancel'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Save',
|
|
||||||
color: 'green'
|
|
||||||
}
|
|
||||||
]} link={true} />;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingGroup
|
<SettingGroup
|
||||||
customButtons={currentState === 'unsaved' ? buttons : <></>}
|
|
||||||
description='Decide what data you collect from your members'
|
description='Decide what data you collect from your members'
|
||||||
state={currentState}
|
state={currentState}
|
||||||
title='Analytics'
|
title='Analytics'
|
||||||
|
onCancel={handleCancel}
|
||||||
|
onSave={handleSave}
|
||||||
|
onStateChange={handleStateChange}
|
||||||
>
|
>
|
||||||
{inputs}
|
{inputs}
|
||||||
<div className='mt-1'>
|
<div className='mt-1'>
|
||||||
|
|
|
@ -115,7 +115,7 @@ const useSettingGroup = (): SettingGroupHook => {
|
||||||
// function to get the values of the settings
|
// function to get the values of the settings
|
||||||
const getSettingValues = (keys: string[]) => {
|
const getSettingValues = (keys: string[]) => {
|
||||||
return keys.map((key) => {
|
return keys.map((key) => {
|
||||||
return settings?.find(setting => setting.key === key)?.value;
|
return localSettings?.find(setting => setting.key === key)?.value;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue