diff --git a/app/javascript/flavours/glitch/components/form_fields/index.ts b/app/javascript/flavours/glitch/components/form_fields/index.ts index b44ceb63f8..97fb90cf56 100644 --- a/app/javascript/flavours/glitch/components/form_fields/index.ts +++ b/app/javascript/flavours/glitch/components/form_fields/index.ts @@ -10,6 +10,7 @@ export { type ComboboxItemState, } from './combobox_field'; export { CopyLinkField } from './copy_link_field'; +export { EmojiTextInputField, EmojiTextAreaField } from './emoji_text_field'; export { RadioButtonField, RadioButton } from './radio_button_field'; export { ToggleField, Toggle } from './toggle_field'; export { SelectField, Select } from './select_field'; diff --git a/app/javascript/flavours/glitch/features/account_edit/components/char_counter.tsx b/app/javascript/flavours/glitch/features/account_edit/components/char_counter.tsx deleted file mode 100644 index a1e242b519..0000000000 --- a/app/javascript/flavours/glitch/features/account_edit/components/char_counter.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { FormattedMessage } from 'react-intl'; - -import classNames from 'classnames'; - -import { polymorphicForwardRef } from '@/types/polymorphic'; - -import classes from '../styles.module.scss'; - -export const CharCounter = polymorphicForwardRef< - 'p', - { currentLength: number; maxLength: number } ->(({ currentLength, maxLength, as: Component = 'p' }, ref) => ( - maxLength && classes.counterError, - )} - > - - -)); -CharCounter.displayName = 'CharCounter'; diff --git a/app/javascript/flavours/glitch/features/account_edit/components/emoji_picker.tsx b/app/javascript/flavours/glitch/features/account_edit/components/emoji_picker.tsx deleted file mode 100644 index e69b9e8b9d..0000000000 --- a/app/javascript/flavours/glitch/features/account_edit/components/emoji_picker.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useCallback } from 'react'; -import type { FC } from 'react'; - -import { isPlainObject } from '@reduxjs/toolkit'; - -import EmojiPickerDropdown from '../../compose/containers/emoji_picker_dropdown_container'; - -export const EmojiPicker: FC<{ onPick: (emoji: string) => void }> = ({ - onPick, -}) => { - const handlePick = useCallback( - (emoji: unknown) => { - if (isPlainObject(emoji)) { - if ('native' in emoji && typeof emoji.native === 'string') { - onPick(emoji.native); - } else if ( - 'shortcode' in emoji && - typeof emoji.shortcode === 'string' - ) { - onPick(`:${emoji.shortcode}:`); - } - } - }, - [onPick], - ); - return ; -}; diff --git a/app/javascript/flavours/glitch/features/account_edit/components/field_actions.tsx b/app/javascript/flavours/glitch/features/account_edit/components/field_actions.tsx new file mode 100644 index 0000000000..4a1ee57d9c --- /dev/null +++ b/app/javascript/flavours/glitch/features/account_edit/components/field_actions.tsx @@ -0,0 +1,37 @@ +import type { FC } from 'react'; +import { useCallback } from 'react'; + +import { openModal } from '@/flavours/glitch/actions/modal'; +import { useAppDispatch } from '@/flavours/glitch/store'; + +import { EditButton, DeleteIconButton } from './edit_button'; + +export const AccountFieldActions: FC<{ item: string; id: string }> = ({ + item, + id, +}) => { + const dispatch = useAppDispatch(); + const handleEdit = useCallback(() => { + dispatch( + openModal({ + modalType: 'ACCOUNT_EDIT_FIELD_EDIT', + modalProps: { fieldKey: id }, + }), + ); + }, [dispatch, id]); + const handleDelete = useCallback(() => { + dispatch( + openModal({ + modalType: 'ACCOUNT_EDIT_FIELD_DELETE', + modalProps: { fieldKey: id }, + }), + ); + }, [dispatch, id]); + + return ( + <> + + + + ); +}; diff --git a/app/javascript/flavours/glitch/features/account_edit/index.tsx b/app/javascript/flavours/glitch/features/account_edit/index.tsx index ac5066a5da..8729d6fa35 100644 --- a/app/javascript/flavours/glitch/features/account_edit/index.tsx +++ b/app/javascript/flavours/glitch/features/account_edit/index.tsx @@ -9,6 +9,7 @@ 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 { DismissibleCallout } from '@/flavours/glitch/components/callout/dismissible'; 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'; @@ -20,6 +21,7 @@ import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store'; import { AccountEditColumn, AccountEditEmptyColumn } from './components/column'; import { EditButton } from './components/edit_button'; +import { AccountFieldActions } from './components/field_actions'; import { AccountEditSection } from './components/section'; import classes from './styles.module.scss'; @@ -54,6 +56,14 @@ export const messages = defineMessages({ defaultMessage: 'Add your pronouns, external links, or anything else you’d like to share.', }, + customFieldsName: { + id: 'account_edit.custom_fields.name', + defaultMessage: 'field', + }, + customFieldsTipTitle: { + id: 'account_edit.custom_fields.tip_title', + defaultMessage: 'Tip: Adding verified links', + }, featuredHashtagsTitle: { id: 'account_edit.featured_hashtags.title', defaultMessage: 'Featured hashtags', @@ -101,6 +111,9 @@ export const AccountEdit: FC = () => { const handleBioEdit = useCallback(() => { handleOpenModal('ACCOUNT_EDIT_BIO'); }, [handleOpenModal]); + const handleCustomFieldsVerifiedHelp = useCallback(() => { + handleOpenModal('ACCOUNT_EDIT_VERIFY_LINKS'); + }, [handleOpenModal]); const handleProfileDisplayEdit = useCallback(() => { handleOpenModal('ACCOUNT_EDIT_PROFILE_DISPLAY'); }, [handleOpenModal]); @@ -123,6 +136,7 @@ export const AccountEdit: FC = () => { const headerSrc = autoPlayGif ? profile.header : profile.headerStatic; const hasName = !!profile.displayName; const hasBio = !!profile.bio; + const hasFields = profile.fields.length > 0; const hasTags = profile.featuredTags.length > 0; return ( @@ -171,8 +185,48 @@ export const AccountEdit: FC = () => { + showDescription={!hasFields} + > +
    + {profile.fields.map((field) => ( +
  1. +
    + + +
    + +
  2. + ))} +
+ + {!hasFields && ( + + + + )} +
= ({ onClose }) => { const intl = useIntl(); const titleId = useId(); - const counterId = useId(); - const textAreaRef = useRef(null); const { profile: { bio } = {}, isPending } = useAppSelector( (state) => state.profileEdit, ); const [newBio, setNewBio] = useState(bio ?? ''); - const handleChange: ChangeEventHandler = useCallback( - (event) => { - setNewBio(event.currentTarget.value); - }, - [], + const maxLength = useAppSelector( + (state) => + state.server.getIn([ + 'server', + 'configuration', + 'accounts', + 'max_note_length', + ]) as number | undefined, ); - const handlePickEmoji = useCallback((emoji: string) => { - setNewBio((prev) => { - const position = textAreaRef.current?.selectionStart ?? prev.length; - return insertEmojiAtPosition(prev, emoji, position); - }); - }, []); const dispatch = useAppDispatch(); const handleSave = useCallback(() => { @@ -70,27 +57,18 @@ export const BioModal: FC = ({ onClose }) => { onConfirm={handleSave} onClose={onClose} updating={isPending} - disabled={newBio.length > MAX_BIO_LENGTH} + disabled={!!maxLength && newBio.length > maxLength} noFocusButton > -
-