[Glitch] Profile editing: Tab display controls
Port d69d7c0507 to glitch-soc
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import type { ChangeEventHandler, FC } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { Callout } from '@/flavours/glitch/components/callout';
|
||||
import { ToggleField } from '@/flavours/glitch/components/form_fields';
|
||||
import { LoadingIndicator } from '@/flavours/glitch/components/loading_indicator';
|
||||
import { patchProfile } from '@/flavours/glitch/reducers/slices/profile_edit';
|
||||
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
|
||||
|
||||
import type { DialogModalProps } from '../../ui/components/dialog_modal';
|
||||
import { DialogModal } from '../../ui/components/dialog_modal';
|
||||
import { messages } from '../index';
|
||||
import classes from '../styles.module.scss';
|
||||
|
||||
export const ProfileDisplayModal: FC<DialogModalProps> = ({ onClose }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const { profile, isPending } = useAppSelector((state) => state.profileEdit);
|
||||
const serverName = useAppSelector(
|
||||
(state) => state.meta.get('domain') as string,
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const handleToggleChange: ChangeEventHandler<HTMLInputElement> = useCallback(
|
||||
(event) => {
|
||||
const { name, checked } = event.target;
|
||||
void dispatch(patchProfile({ [name]: checked }));
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
if (!profile) {
|
||||
return <LoadingIndicator />;
|
||||
}
|
||||
|
||||
return (
|
||||
<DialogModal
|
||||
onClose={onClose}
|
||||
title={intl.formatMessage(messages.profileTabTitle)}
|
||||
noCancelButton
|
||||
>
|
||||
<div className={classes.toggleInputWrapper}>
|
||||
<ToggleField
|
||||
checked={profile.showMedia}
|
||||
onChange={handleToggleChange}
|
||||
disabled={isPending}
|
||||
name='show_media'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='account_edit.profile_tab.show_media.title'
|
||||
defaultMessage='Show ‘Media’ tab'
|
||||
/>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='account_edit.profile_tab.show_media.description'
|
||||
defaultMessage='‘Media’ is an optional tab that shows your posts containing images or videos.'
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<ToggleField
|
||||
checked={profile.showMediaReplies}
|
||||
onChange={handleToggleChange}
|
||||
disabled={!profile.showMedia || isPending}
|
||||
name='show_media_replies'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='account_edit.profile_tab.show_media_replies.title'
|
||||
defaultMessage='Include replies on ‘Media’ tab'
|
||||
/>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='account_edit.profile_tab.show_media_replies.description'
|
||||
defaultMessage='When enabled, Media tab shows both your posts and replies to other people’s posts.'
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<ToggleField
|
||||
checked={profile.showFeatured}
|
||||
onChange={handleToggleChange}
|
||||
disabled={isPending}
|
||||
name='show_featured'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='account_edit.profile_tab.show_featured.title'
|
||||
defaultMessage='Show ‘Featured’ tab'
|
||||
/>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='account_edit.profile_tab.show_featured.description'
|
||||
defaultMessage='‘Featured’ is an optional tab where you can showcase other accounts.'
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Callout
|
||||
title={
|
||||
<FormattedMessage
|
||||
id='account_edit.profile_tab.hint.title'
|
||||
defaultMessage='Displays still vary'
|
||||
/>
|
||||
}
|
||||
icon={false}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='account_edit.profile_tab.hint.description'
|
||||
defaultMessage='These settings customize what users see on {server} in the official apps, but they may not apply to users on other servers and 3rd party apps.'
|
||||
values={{
|
||||
server: serverName,
|
||||
}}
|
||||
/>
|
||||
</Callout>
|
||||
</DialogModal>
|
||||
);
|
||||
};
|
||||
@@ -1,13 +1,14 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import type { ModalType } from '@/flavours/glitch/actions/modal';
|
||||
import { openModal } from '@/flavours/glitch/actions/modal';
|
||||
import { Avatar } from '@/flavours/glitch/components/avatar';
|
||||
import { Button } from '@/flavours/glitch/components/button';
|
||||
import { CustomEmojiProvider } from '@/flavours/glitch/components/emoji/context';
|
||||
import { EmojiHTML } from '@/flavours/glitch/components/emoji/html';
|
||||
import { useElementHandledLink } from '@/flavours/glitch/components/status/handled_link';
|
||||
@@ -25,7 +26,7 @@ import { EditButton } from './components/edit_button';
|
||||
import { AccountEditSection } from './components/section';
|
||||
import classes from './styles.module.scss';
|
||||
|
||||
const messages = defineMessages({
|
||||
export const messages = defineMessages({
|
||||
columnTitle: {
|
||||
id: 'account_edit.column_title',
|
||||
defaultMessage: 'Edit Profile',
|
||||
@@ -104,6 +105,9 @@ export const AccountEdit: FC = () => {
|
||||
const handleBioEdit = useCallback(() => {
|
||||
handleOpenModal('ACCOUNT_EDIT_BIO');
|
||||
}, [handleOpenModal]);
|
||||
const handleProfileDisplayEdit = useCallback(() => {
|
||||
handleOpenModal('ACCOUNT_EDIT_PROFILE_DISPLAY');
|
||||
}, [handleOpenModal]);
|
||||
|
||||
const history = useHistory();
|
||||
const handleFeaturedTagsEdit = useCallback(() => {
|
||||
@@ -193,6 +197,17 @@ export const AccountEdit: FC = () => {
|
||||
title={messages.profileTabTitle}
|
||||
description={messages.profileTabSubtitle}
|
||||
showDescription
|
||||
buttons={
|
||||
<Button
|
||||
className={classes.editButton}
|
||||
onClick={handleProfileDisplayEdit}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='account_edit.profile_tab.button_label'
|
||||
defaultMessage='Customize'
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</CustomEmojiProvider>
|
||||
</AccountEditColumn>
|
||||
|
||||
@@ -90,6 +90,16 @@ textarea.inputText {
|
||||
}
|
||||
}
|
||||
|
||||
.toggleInputWrapper {
|
||||
> div {
|
||||
padding: 12px 0;
|
||||
|
||||
&:not(:first-child) {
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Column component
|
||||
|
||||
.column {
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import type { FC, ReactNode } from 'react';
|
||||
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Button } from '@/flavours/glitch/components/button';
|
||||
import { IconButton } from '@/flavours/glitch/components/icon_button';
|
||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||
|
||||
export type { BaseConfirmationModalProps as DialogModalProps } from './confirmation_modals/confirmation_modal';
|
||||
|
||||
interface DialogModalProps {
|
||||
className?: string;
|
||||
title: ReactNode;
|
||||
onClose: () => void;
|
||||
description?: ReactNode;
|
||||
formClassName?: string;
|
||||
children?: ReactNode;
|
||||
noCancelButton?: boolean;
|
||||
onSave?: () => void;
|
||||
saveLabel?: ReactNode;
|
||||
}
|
||||
|
||||
export const DialogModal: FC<DialogModalProps> = ({
|
||||
className,
|
||||
title,
|
||||
onClose,
|
||||
description,
|
||||
formClassName,
|
||||
children,
|
||||
noCancelButton = false,
|
||||
onSave,
|
||||
saveLabel,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const showButtons = !noCancelButton || onSave;
|
||||
|
||||
return (
|
||||
<div className={classNames('modal-root__modal dialog-modal', className)}>
|
||||
<div className='dialog-modal__header'>
|
||||
<IconButton
|
||||
className='dialog-modal__header__close'
|
||||
title={intl.formatMessage({
|
||||
id: 'lightbox.close',
|
||||
defaultMessage: 'Close',
|
||||
})}
|
||||
icon='close'
|
||||
iconComponent={CloseIcon}
|
||||
onClick={onClose}
|
||||
/>
|
||||
|
||||
<h1 className='dialog-modal__header__title'>{title}</h1>
|
||||
</div>
|
||||
|
||||
<div className='dialog-modal__content'>
|
||||
{description && (
|
||||
<div className='dialog-modal__content__description'>
|
||||
{description}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={classNames('dialog-modal__content__form', formClassName)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showButtons && (
|
||||
<div className='dialog-modal__content__actions'>
|
||||
{!noCancelButton && (
|
||||
<Button onClick={onClose} secondary>
|
||||
<FormattedMessage
|
||||
id='confirmation_modal.cancel'
|
||||
defaultMessage='Cancel'
|
||||
/>
|
||||
</Button>
|
||||
)}
|
||||
{onSave && (
|
||||
<Button onClick={onClose}>
|
||||
{saveLabel ?? (
|
||||
<FormattedMessage
|
||||
id='confirmation_modal.cancel'
|
||||
defaultMessage='Cancel'
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -105,6 +105,7 @@ export const MODAL_COMPONENTS = {
|
||||
'ACCOUNT_FIELD_OVERFLOW': () => import('@/flavours/glitch/features/account_timeline/modals/field_modal').then(module => ({ default: module.AccountFieldModal })),
|
||||
'ACCOUNT_EDIT_NAME': () => import('@/flavours/glitch/features/account_edit/components/name_modal').then(module => ({ default: module.NameModal })),
|
||||
'ACCOUNT_EDIT_BIO': () => import('@/flavours/glitch/features/account_edit/components/bio_modal').then(module => ({ default: module.BioModal })),
|
||||
'ACCOUNT_EDIT_PROFILE_DISPLAY': () => import('@/flavours/glitch/features/account_edit/components/profile_display_modal').then(module => ({ default: module.ProfileDisplayModal })),
|
||||
};
|
||||
|
||||
export default class ModalRoot extends PureComponent {
|
||||
|
||||
Reference in New Issue
Block a user