Refactor NIP-05 warnings
This commit is contained in:
parent
819711a4f1
commit
29bdd54dd1
|
@ -1,8 +1,8 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { CLEAR_EDITOR_COMMAND, TextNode, type LexicalEditor, $getRoot } from 'lexical';
|
import { CLEAR_EDITOR_COMMAND, TextNode, type LexicalEditor, $getRoot } from 'lexical';
|
||||||
import React, { Suspense, useCallback, useEffect, useRef, useState } from 'react';
|
import React, { Suspense, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import { Link, useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -17,7 +17,7 @@ import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest
|
||||||
import { Button, HStack, Stack } from 'soapbox/components/ui';
|
import { Button, HStack, Stack } from 'soapbox/components/ui';
|
||||||
import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container';
|
import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container';
|
||||||
import { ComposeEditor } from 'soapbox/features/ui/util/async-components';
|
import { ComposeEditor } from 'soapbox/features/ui/util/async-components';
|
||||||
import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, useOwnAccount, usePrevious } from 'soapbox/hooks';
|
import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, usePrevious } from 'soapbox/hooks';
|
||||||
|
|
||||||
import QuotedStatusContainer from '../containers/quoted-status-container';
|
import QuotedStatusContainer from '../containers/quoted-status-container';
|
||||||
import ReplyIndicatorContainer from '../containers/reply-indicator-container';
|
import ReplyIndicatorContainer from '../containers/reply-indicator-container';
|
||||||
|
@ -39,7 +39,6 @@ import SpoilerInput from './spoiler-input';
|
||||||
import TextCharacterCounter from './text-character-counter';
|
import TextCharacterCounter from './text-character-counter';
|
||||||
import UploadForm from './upload-form';
|
import UploadForm from './upload-form';
|
||||||
import VisualCharacterCounter from './visual-character-counter';
|
import VisualCharacterCounter from './visual-character-counter';
|
||||||
import Warning from './warning';
|
|
||||||
|
|
||||||
import type { Emoji } from 'soapbox/features/emoji';
|
import type { Emoji } from 'soapbox/features/emoji';
|
||||||
|
|
||||||
|
@ -68,13 +67,11 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { account } = useOwnAccount();
|
|
||||||
const { instance } = useInstance();
|
const { instance } = useInstance();
|
||||||
|
|
||||||
const compose = useCompose(id);
|
const compose = useCompose(id);
|
||||||
const showSearch = useAppSelector((state) => state.search.submitted && !state.search.hidden);
|
const showSearch = useAppSelector((state) => state.search.submitted && !state.search.hidden);
|
||||||
const maxTootChars = instance.configuration.statuses.max_characters;
|
const maxTootChars = instance.configuration.statuses.max_characters;
|
||||||
const scheduledStatusCount = useAppSelector((state) => state.scheduled_statuses.size);
|
|
||||||
const features = useFeatures();
|
const features = useFeatures();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -109,7 +106,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
const isEmpty = !(fulltext.trim() || anyMedia);
|
const isEmpty = !(fulltext.trim() || anyMedia);
|
||||||
const condensed = shouldCondense && !isDraggedOver && !composeFocused && isEmpty && !isUploading;
|
const condensed = shouldCondense && !isDraggedOver && !composeFocused && isEmpty && !isUploading;
|
||||||
const shouldAutoFocus = autoFocus && !showSearch;
|
const shouldAutoFocus = autoFocus && !showSearch;
|
||||||
const canSubmit = !!editorRef.current && !isSubmitting && !isUploading && !isChangingUpload && !isEmpty && length(fulltext) <= maxTootChars && account?.source?.nostr?.nip05 !== undefined;
|
const canSubmit = !!editorRef.current && !isSubmitting && !isUploading && !isChangingUpload && !isEmpty && length(fulltext) <= maxTootChars;
|
||||||
|
|
||||||
const getClickableArea = () => {
|
const getClickableArea = () => {
|
||||||
return clickableAreaRef ? clickableAreaRef.current : formRef.current;
|
return clickableAreaRef ? clickableAreaRef.current : formRef.current;
|
||||||
|
@ -247,25 +244,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack className='w-full' space={4} ref={formRef} onClick={handleClick} element='form' onSubmit={handleSubmit}>
|
<Stack className='w-full' space={4} ref={formRef} onClick={handleClick} element='form' onSubmit={handleSubmit}>
|
||||||
{scheduledStatusCount > 0 && !event && !group && (
|
|
||||||
<Warning
|
|
||||||
message={(
|
|
||||||
<FormattedMessage
|
|
||||||
id='compose_form.scheduled_statuses.message'
|
|
||||||
defaultMessage='You have scheduled posts. {click_here} to see them.'
|
|
||||||
values={{ click_here: (
|
|
||||||
<Link to='/scheduled_statuses'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='compose_form.scheduled_statuses.click_here'
|
|
||||||
defaultMessage='Click here'
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
) }}
|
|
||||||
/>)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<WarningContainer composeId={id} />
|
<WarningContainer composeId={id} />
|
||||||
|
|
||||||
{!shouldCondense && !event && !group && groupId && <ReplyGroupIndicator composeId={id} />}
|
{!shouldCondense && !event && !group && groupId && <ReplyGroupIndicator composeId={id} />}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { useAppSelector, useCompose } from 'soapbox/hooks';
|
import { useAppSelector, useCompose, useOwnAccount, useSettingsNotifications } from 'soapbox/hooks';
|
||||||
import { selectOwnAccount } from 'soapbox/selectors';
|
import { selectOwnAccount } from 'soapbox/selectors';
|
||||||
|
|
||||||
import Warning from '../components/warning';
|
import Warning from '../components/warning';
|
||||||
|
@ -15,11 +15,60 @@ interface IWarningWrapper {
|
||||||
|
|
||||||
const WarningWrapper: React.FC<IWarningWrapper> = ({ composeId }) => {
|
const WarningWrapper: React.FC<IWarningWrapper> = ({ composeId }) => {
|
||||||
const compose = useCompose(composeId);
|
const compose = useCompose(composeId);
|
||||||
|
const scheduledStatusCount = useAppSelector((state) => state.scheduled_statuses.size);
|
||||||
|
const { account } = useOwnAccount();
|
||||||
|
const settingsNotifications = useSettingsNotifications();
|
||||||
|
|
||||||
const needsLockWarning = useAppSelector((state) => compose.privacy === 'private' && !selectOwnAccount(state)!.locked);
|
const needsLockWarning = useAppSelector((state) => compose.privacy === 'private' && !selectOwnAccount(state)!.locked);
|
||||||
const hashtagWarning = (compose.privacy !== 'public' && compose.privacy !== 'group') && APPROX_HASHTAG_RE.test(compose.text);
|
const hashtagWarning = (compose.privacy !== 'public' && compose.privacy !== 'group') && APPROX_HASHTAG_RE.test(compose.text);
|
||||||
const directMessageWarning = compose.privacy === 'direct';
|
const directMessageWarning = compose.privacy === 'direct';
|
||||||
|
|
||||||
|
if (scheduledStatusCount > 0) {
|
||||||
|
return (
|
||||||
|
<Warning
|
||||||
|
message={(
|
||||||
|
<FormattedMessage
|
||||||
|
id='compose_form.scheduled_statuses.message'
|
||||||
|
defaultMessage='You have scheduled posts. {click_here} to see them.'
|
||||||
|
values={{ click_here: (
|
||||||
|
<Link to='/scheduled_statuses'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='compose_form.scheduled_statuses.click_here'
|
||||||
|
defaultMessage='Click here'
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
) }}
|
||||||
|
/>)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (account?.source?.nostr?.nip05 === undefined) {
|
||||||
|
if (settingsNotifications.has('needsNip05')) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='compose_form.nip05.warning'
|
||||||
|
defaultMessage={'You don\'t have a username configured. {click} to set one up.'}
|
||||||
|
values={{
|
||||||
|
click: (
|
||||||
|
<Link to='/settings/identity'>
|
||||||
|
<FormattedMessage id='compose_form.nip05.warning.click' defaultMessage='Click here' />
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='compose_form.nip05.pending'
|
||||||
|
defaultMessage='Your username request is under review.'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (needsLockWarning) {
|
if (needsLockWarning) {
|
||||||
return (
|
return (
|
||||||
<Warning
|
<Warning
|
||||||
|
|
|
@ -18,8 +18,7 @@ import { $createParagraphNode, $createTextNode, $getRoot, type LexicalEditor } f
|
||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import Warning from 'soapbox/features/compose/components/warning';
|
import { useAppDispatch } from 'soapbox/hooks';
|
||||||
import { useAppDispatch, useOwnAccount, useSettingsNotifications } from 'soapbox/hooks';
|
|
||||||
|
|
||||||
import { useNodes } from './nodes';
|
import { useNodes } from './nodes';
|
||||||
import AutosuggestPlugin from './plugins/autosuggest-plugin';
|
import AutosuggestPlugin from './plugins/autosuggest-plugin';
|
||||||
|
@ -85,8 +84,6 @@ const ComposeEditor = React.forwardRef<LexicalEditor, IComposeEditor>(({
|
||||||
}, ref) => {
|
}, ref) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const nodes = useNodes();
|
const nodes = useNodes();
|
||||||
const { account } = useOwnAccount();
|
|
||||||
const settingsNotifications = useSettingsNotifications();
|
|
||||||
|
|
||||||
const [suggestionsHidden, setSuggestionsHidden] = useState(true);
|
const [suggestionsHidden, setSuggestionsHidden] = useState(true);
|
||||||
|
|
||||||
|
@ -135,9 +132,6 @@ const ComposeEditor = React.forwardRef<LexicalEditor, IComposeEditor>(({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LexicalComposer initialConfig={initialConfig}>
|
<LexicalComposer initialConfig={initialConfig}>
|
||||||
{ account?.source?.nostr?.nip05 === undefined ?
|
|
||||||
<Warning message={settingsNotifications.has('needsNip05') ? <FormattedMessage id='compose_form.warning' defaultMessage={'Warning: To post, you need a valid username. Please configure your username in \'Settings > Identity\' before continuing.'} /> : <FormattedMessage id='compose_form.warning_waiting' defaultMessage='Warning: To post, you need a valid username. Your username request is pending validation. Please wait until your username is validated.' />} /> : null
|
|
||||||
}
|
|
||||||
<div className={clsx('relative', className)}>
|
<div className={clsx('relative', className)}>
|
||||||
<PlainTextPlugin
|
<PlainTextPlugin
|
||||||
contentEditable={
|
contentEditable={
|
||||||
|
|
|
@ -479,6 +479,9 @@
|
||||||
"compose_form.markdown.marked": "Post markdown enabled",
|
"compose_form.markdown.marked": "Post markdown enabled",
|
||||||
"compose_form.markdown.unmarked": "Post markdown disabled",
|
"compose_form.markdown.unmarked": "Post markdown disabled",
|
||||||
"compose_form.message": "Message",
|
"compose_form.message": "Message",
|
||||||
|
"compose_form.nip05.pending": "Your username request is under review.",
|
||||||
|
"compose_form.nip05.warning": "You don't have a username configured. {click} to set one up.",
|
||||||
|
"compose_form.nip05.warning.click": "Click here",
|
||||||
"compose_form.placeholder": "What's on your mind?",
|
"compose_form.placeholder": "What's on your mind?",
|
||||||
"compose_form.poll.add_option": "Add an answer",
|
"compose_form.poll.add_option": "Add an answer",
|
||||||
"compose_form.poll.duration": "Poll duration",
|
"compose_form.poll.duration": "Poll duration",
|
||||||
|
@ -501,8 +504,6 @@
|
||||||
"compose_form.spoiler_placeholder": "Write your warning here (optional)",
|
"compose_form.spoiler_placeholder": "Write your warning here (optional)",
|
||||||
"compose_form.spoiler_remove": "Remove sensitive",
|
"compose_form.spoiler_remove": "Remove sensitive",
|
||||||
"compose_form.spoiler_title": "Sensitive content",
|
"compose_form.spoiler_title": "Sensitive content",
|
||||||
"compose_form.warning": "Warning: To post, you need a valid username. Please configure your username in 'Settings > Identity' before continuing.",
|
|
||||||
"compose_form.warning_waiting": "Warning: To post, you need a valid username. Your username request is pending validation. Please wait until your username is validated.",
|
|
||||||
"compose_group.share_to_followers": "Share with my followers",
|
"compose_group.share_to_followers": "Share with my followers",
|
||||||
"confirmation_modal.cancel": "Cancel",
|
"confirmation_modal.cancel": "Cancel",
|
||||||
"confirmations.admin.deactivate_user.confirm": "Deactivate @{name}",
|
"confirmations.admin.deactivate_user.confirm": "Deactivate @{name}",
|
||||||
|
|
Loading…
Reference in New Issue