Merge branch 'edit-profile-checkboxes' into 'develop'
EditProfile: use Toggle instead of Checkbox, other Toggle refactors See merge request soapbox-pub/soapbox-fe!1323
This commit is contained in:
commit
45a7dc5bcf
|
@ -30,5 +30,6 @@ export { default as Stack } from './stack/stack';
|
||||||
export { default as Tabs } from './tabs/tabs';
|
export { default as Tabs } from './tabs/tabs';
|
||||||
export { default as Text } from './text/text';
|
export { default as Text } from './text/text';
|
||||||
export { default as Textarea } from './textarea/textarea';
|
export { default as Textarea } from './textarea/textarea';
|
||||||
|
export { default as Toggle } from './toggle/toggle';
|
||||||
export { default as Tooltip } from './tooltip/tooltip';
|
export { default as Tooltip } from './tooltip/tooltip';
|
||||||
export { default as Widget } from './widget/widget';
|
export { default as Widget } from './widget/widget';
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactToggle, { ToggleProps } from 'react-toggle';
|
||||||
|
|
||||||
|
/** A glorified checkbox. Wrapper around react-toggle. */
|
||||||
|
const Toggle: React.FC<ToggleProps> = ({ icons = false, ...rest }) => {
|
||||||
|
return (
|
||||||
|
<ReactToggle
|
||||||
|
icons={icons}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Toggle;
|
|
@ -4,16 +4,12 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||||
import { updateNotificationSettings } from 'soapbox/actions/accounts';
|
import { updateNotificationSettings } from 'soapbox/actions/accounts';
|
||||||
import { patchMe } from 'soapbox/actions/me';
|
import { patchMe } from 'soapbox/actions/me';
|
||||||
import snackbar from 'soapbox/actions/snackbar';
|
import snackbar from 'soapbox/actions/snackbar';
|
||||||
import {
|
import List, { ListItem } from 'soapbox/components/list';
|
||||||
Checkbox,
|
|
||||||
} from 'soapbox/features/forms';
|
|
||||||
import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures } from 'soapbox/hooks';
|
import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures } from 'soapbox/hooks';
|
||||||
import { normalizeAccount } from 'soapbox/normalizers';
|
import { normalizeAccount } from 'soapbox/normalizers';
|
||||||
import resizeImage from 'soapbox/utils/resize_image';
|
import resizeImage from 'soapbox/utils/resize_image';
|
||||||
|
|
||||||
import { Button, Column, Form, FormActions, FormGroup, Input, Textarea } from '../../components/ui';
|
import { Button, Column, Form, FormActions, FormGroup, Input, Textarea, HStack, Toggle } from '../../components/ui';
|
||||||
import HStack from '../../components/ui/hstack/hstack';
|
|
||||||
import Stack from '../../components/ui/stack/stack';
|
|
||||||
import Streamfield, { StreamfieldComponent } from '../../components/ui/streamfield/streamfield';
|
import Streamfield, { StreamfieldComponent } from '../../components/ui/streamfield/streamfield';
|
||||||
|
|
||||||
import ProfilePreview from './components/profile-preview';
|
import ProfilePreview from './components/profile-preview';
|
||||||
|
@ -394,63 +390,79 @@ const EditProfile: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* HACK: wrap these checkboxes in a .simple_form container so they get styled (for now) */}
|
<List>
|
||||||
{/* Need a either move, replace, or refactor these checkboxes. */}
|
|
||||||
<Stack space={2} className='simple_form'>
|
|
||||||
{features.followRequests && (
|
{features.followRequests && (
|
||||||
<Checkbox
|
<ListItem
|
||||||
label={<FormattedMessage id='edit_profile.fields.locked_label' defaultMessage='Lock account' />}
|
label={<FormattedMessage id='edit_profile.fields.locked_label' defaultMessage='Lock account' />}
|
||||||
hint={<FormattedMessage id='edit_profile.hints.locked' defaultMessage='Requires you to manually approve followers' />}
|
hint={<FormattedMessage id='edit_profile.hints.locked' defaultMessage='Requires you to manually approve followers' />}
|
||||||
checked={data.locked}
|
>
|
||||||
onChange={handleCheckboxChange('locked')}
|
<Toggle
|
||||||
/>
|
checked={data.locked}
|
||||||
|
onChange={handleCheckboxChange('locked')}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{features.hideNetwork && (
|
{features.hideNetwork && (
|
||||||
<Checkbox
|
<ListItem
|
||||||
label={<FormattedMessage id='edit_profile.fields.hide_network_label' defaultMessage='Hide network' />}
|
label={<FormattedMessage id='edit_profile.fields.hide_network_label' defaultMessage='Hide network' />}
|
||||||
hint={<FormattedMessage id='edit_profile.hints.hide_network' defaultMessage='Who you follow and who follows you will not be shown on your profile' />}
|
hint={<FormattedMessage id='edit_profile.hints.hide_network' defaultMessage='Who you follow and who follows you will not be shown on your profile' />}
|
||||||
checked={account ? hidesNetwork(account): false}
|
>
|
||||||
onChange={handleHideNetworkChange}
|
<Toggle
|
||||||
/>
|
checked={account ? hidesNetwork(account): false}
|
||||||
|
onChange={handleHideNetworkChange}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{features.bots && (
|
{features.bots && (
|
||||||
<Checkbox
|
<ListItem
|
||||||
label={<FormattedMessage id='edit_profile.fields.bot_label' defaultMessage='This is a bot account' />}
|
label={<FormattedMessage id='edit_profile.fields.bot_label' defaultMessage='This is a bot account' />}
|
||||||
hint={<FormattedMessage id='edit_profile.hints.bot' defaultMessage='This account mainly performs automated actions and might not be monitored' />}
|
hint={<FormattedMessage id='edit_profile.hints.bot' defaultMessage='This account mainly performs automated actions and might not be monitored' />}
|
||||||
checked={data.bot}
|
>
|
||||||
onChange={handleCheckboxChange('bot')}
|
<Toggle
|
||||||
/>
|
checked={data.bot}
|
||||||
|
onChange={handleCheckboxChange('bot')}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{features.muteStrangers && (
|
{features.muteStrangers && (
|
||||||
<Checkbox
|
<ListItem
|
||||||
label={<FormattedMessage id='edit_profile.fields.stranger_notifications_label' defaultMessage='Block notifications from strangers' />}
|
label={<FormattedMessage id='edit_profile.fields.stranger_notifications_label' defaultMessage='Block notifications from strangers' />}
|
||||||
hint={<FormattedMessage id='edit_profile.hints.stranger_notifications' defaultMessage='Only show notifications from people you follow' />}
|
hint={<FormattedMessage id='edit_profile.hints.stranger_notifications' defaultMessage='Only show notifications from people you follow' />}
|
||||||
checked={muteStrangers}
|
>
|
||||||
onChange={(e) => setMuteStrangers(e.target.checked)}
|
<Toggle
|
||||||
/>
|
checked={muteStrangers}
|
||||||
|
onChange={(e) => setMuteStrangers(e.target.checked)}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{features.profileDirectory && (
|
{features.profileDirectory && (
|
||||||
<Checkbox
|
<ListItem
|
||||||
label={<FormattedMessage id='edit_profile.fields.discoverable_label' defaultMessage='Allow account discovery' />}
|
label={<FormattedMessage id='edit_profile.fields.discoverable_label' defaultMessage='Allow account discovery' />}
|
||||||
hint={<FormattedMessage id='edit_profile.hints.discoverable' defaultMessage='Display account in profile directory and allow indexing by external services' />}
|
hint={<FormattedMessage id='edit_profile.hints.discoverable' defaultMessage='Display account in profile directory and allow indexing by external services' />}
|
||||||
checked={data.discoverable}
|
>
|
||||||
onChange={handleCheckboxChange('discoverable')}
|
<Toggle
|
||||||
/>
|
checked={data.discoverable}
|
||||||
|
onChange={handleCheckboxChange('discoverable')}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{features.emailList && (
|
{features.emailList && (
|
||||||
<Checkbox
|
<ListItem
|
||||||
label={<FormattedMessage id='edit_profile.fields.accepts_email_list_label' defaultMessage='Subscribe to newsletter' />}
|
label={<FormattedMessage id='edit_profile.fields.accepts_email_list_label' defaultMessage='Subscribe to newsletter' />}
|
||||||
hint={<FormattedMessage id='edit_profile.hints.accepts_email_list' defaultMessage='Opt-in to news and marketing updates.' />}
|
hint={<FormattedMessage id='edit_profile.hints.accepts_email_list' defaultMessage='Opt-in to news and marketing updates.' />}
|
||||||
checked={data.accepts_email_list}
|
>
|
||||||
onChange={handleCheckboxChange('accepts_email_list')}
|
<Toggle
|
||||||
/>
|
checked={data.accepts_email_list}
|
||||||
|
onChange={handleCheckboxChange('accepts_email_list')}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</List>
|
||||||
|
|
||||||
{features.profileFields && (
|
{features.profileFields && (
|
||||||
<Streamfield
|
<Streamfield
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
import Toggle from 'react-toggle';
|
|
||||||
|
|
||||||
export default class SettingToggle extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
id: PropTypes.string,
|
|
||||||
prefix: PropTypes.string,
|
|
||||||
settings: ImmutablePropTypes.map.isRequired,
|
|
||||||
settingPath: PropTypes.array.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange = ({ target }) => {
|
|
||||||
this.props.onChange(this.props.settingPath, target.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { id, settings, settingPath } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Toggle
|
|
||||||
id={id}
|
|
||||||
checked={settings.getIn(settingPath)}
|
|
||||||
onChange={this.onChange}
|
|
||||||
icons={false}
|
|
||||||
onKeyDown={this.onKeyDown}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { Toggle } from 'soapbox/components/ui';
|
||||||
|
|
||||||
|
import type { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
|
interface ISettingToggle {
|
||||||
|
/** Unique identifier for the Toggle. */
|
||||||
|
id?: string,
|
||||||
|
/** The full user settings map. */
|
||||||
|
settings: ImmutableMap<string, any>,
|
||||||
|
/** Array of key names leading into the setting map. */
|
||||||
|
settingPath: string[],
|
||||||
|
/** Callback when the setting is toggled. */
|
||||||
|
onChange: (settingPath: string[], checked: boolean) => void,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stateful toggle to change user settings. */
|
||||||
|
const SettingToggle: React.FC<ISettingToggle> = ({ id, settings, settingPath, onChange }) => {
|
||||||
|
|
||||||
|
const handleChange: React.ChangeEventHandler<HTMLInputElement> = ({ target }) => {
|
||||||
|
onChange(settingPath, target.checked);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Toggle
|
||||||
|
id={id}
|
||||||
|
checked={!!settings.getIn(settingPath)}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SettingToggle;
|
|
@ -101,7 +101,7 @@ const Preferences = () => {
|
||||||
// dispatch(changeSetting(['defaultContentType'], event.target.value));
|
// dispatch(changeSetting(['defaultContentType'], event.target.value));
|
||||||
// };
|
// };
|
||||||
|
|
||||||
const onToggleChange = (key: string, checked: boolean) => {
|
const onToggleChange = (key: string[], checked: boolean) => {
|
||||||
dispatch(changeSetting(key, checked, intl));
|
dispatch(changeSetting(key, checked, intl));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
|
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
|
||||||
import React, { useState, useEffect, useMemo } from 'react';
|
import React, { useState, useEffect, useMemo } from 'react';
|
||||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||||
import Toggle from 'react-toggle';
|
|
||||||
|
|
||||||
import { updateConfig } from 'soapbox/actions/admin';
|
import { updateConfig } from 'soapbox/actions/admin';
|
||||||
import { uploadMedia } from 'soapbox/actions/media';
|
import { uploadMedia } from 'soapbox/actions/media';
|
||||||
|
@ -17,6 +16,7 @@ import {
|
||||||
Input,
|
Input,
|
||||||
Textarea,
|
Textarea,
|
||||||
Button,
|
Button,
|
||||||
|
Toggle,
|
||||||
} from 'soapbox/components/ui';
|
} from 'soapbox/components/ui';
|
||||||
import Streamfield from 'soapbox/components/ui/streamfield/streamfield';
|
import Streamfield from 'soapbox/components/ui/streamfield/streamfield';
|
||||||
import ThemeSelector from 'soapbox/features/ui/components/theme-selector';
|
import ThemeSelector from 'soapbox/features/ui/components/theme-selector';
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-toggle-track {
|
.react-toggle-track {
|
||||||
@apply bg-gray-200 w-[50px] p-0 rounded-full transition-colors;
|
@apply bg-gray-300 dark:bg-slate-700 w-[50px] p-0 rounded-full transition-colors;
|
||||||
height: var(--input-height);
|
height: var(--input-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue