diff --git a/ui/page/settingsCreator/index.js b/ui/page/settingsCreator/index.js index 8420dc985..0a5813069 100644 --- a/ui/page/settingsCreator/index.js +++ b/ui/page/settingsCreator/index.js @@ -16,7 +16,6 @@ import { selectFetchingBlockedWords, selectModerationDelegatesById, } from 'redux/selectors/comments'; -import { doToast } from 'redux/actions/notifications'; const select = (state) => ({ activeChannelClaim: selectActiveChannelClaim(state), @@ -36,7 +35,6 @@ const perform = (dispatch) => ({ commentModRemoveDelegate: (modChanId, modChanName, creatorChannelClaim) => dispatch(doCommentModRemoveDelegate(modChanId, modChanName, creatorChannelClaim)), commentModListDelegates: (creatorChannelClaim) => dispatch(doCommentModListDelegates(creatorChannelClaim)), - doToast: (options) => dispatch(doToast(options)), }); export default connect(select, perform)(SettingsCreatorPage); diff --git a/ui/page/settingsCreator/view.jsx b/ui/page/settingsCreator/view.jsx index 92bb24b9c..dd8c5b2ff 100644 --- a/ui/page/settingsCreator/view.jsx +++ b/ui/page/settingsCreator/view.jsx @@ -1,21 +1,17 @@ // @flow -import * as ICONS from 'constants/icons'; import * as React from 'react'; import Card from 'component/common/card'; import TagsSearch from 'component/tagsSearch'; import Page from 'component/page'; -import Button from 'component/button'; import ChannelSelector from 'component/channelSelector'; +import SearchChannelField from 'component/searchChannelField'; import SettingsRow from 'component/settingsRow'; import Spinner from 'component/spinner'; import { FormField } from 'component/common/form-components/form-field'; -import Icon from 'component/common/icon'; import LbcSymbol from 'component/common/lbc-symbol'; import I18nMessage from 'component/i18nMessage'; -import { isNameValid, parseURI } from 'lbry-redux'; -import ClaimPreview from 'component/claimPreview'; +import { parseURI } from 'lbry-redux'; import debounce from 'util/debounce'; -import { getUriForSearchTerm } from 'util/search'; const DEBOUNCE_REFRESH_MS = 1000; @@ -54,23 +50,19 @@ export default function SettingsCreatorPage(props: Props) { commentModListDelegates, fetchCreatorSettings, updateCreatorSettings, - doToast, } = props; const [commentsEnabled, setCommentsEnabled] = React.useState(true); const [mutedWordTags, setMutedWordTags] = React.useState([]); - const [moderatorTags, setModeratorTags] = React.useState([]); - const [moderatorSearchTerm, setModeratorSearchTerm] = React.useState(''); - const [moderatorSearchError, setModeratorSearchError] = React.useState(''); - const [moderatorSearchClaimUri, setModeratorSearchClaimUri] = React.useState(''); + const [moderatorUris, setModeratorUris] = React.useState([]); const [minTip, setMinTip] = React.useState(0); const [minSuper, setMinSuper] = React.useState(0); const [slowModeMin, setSlowModeMin] = React.useState(0); const [lastUpdated, setLastUpdated] = React.useState(1); - const pushSlowModeMinDebounced = React.useMemo(() => debounce(pushSlowModeMin, 1000), []); - const pushMinTipDebounced = React.useMemo(() => debounce(pushMinTip, 1000), []); - const pushMinSuperDebounced = React.useMemo(() => debounce(pushMinSuper, 1000), []); + const pushSlowModeMinDebounced = React.useMemo(() => debounce(pushSlowModeMin, 1000), []); // eslint-disable-line react-hooks/exhaustive-deps + const pushMinTipDebounced = React.useMemo(() => debounce(pushMinTip, 1000), []); // eslint-disable-line react-hooks/exhaustive-deps + const pushMinSuperDebounced = React.useMemo(() => debounce(pushMinSuper, 1000), []); // eslint-disable-line react-hooks/exhaustive-deps // ************************************************************************** // ************************************************************************** @@ -79,8 +71,8 @@ export default function SettingsCreatorPage(props: Props) { * Updates corresponding GUI states with the given PerChannelSettings values. * * @param settings - * @param fullSync If true, update all states and consider 'undefined' settings as "cleared/false"; - * if false, only update defined settings. + * @param fullSync If true, update all states and consider 'undefined' + * settings as "cleared/false"; if false, only update defined settings. */ function settingsToStates(settings: PerChannelSettings, fullSync: boolean) { const doSetMutedWordTags = (words: Array) => { @@ -137,6 +129,31 @@ export default function SettingsCreatorPage(props: Props) { updateCreatorSettings(activeChannelClaim, { min_tip_amount_super_chat: value }); } + function parseModUri(uri) { + try { + return parseURI(uri); + } catch (e) {} + return undefined; + } + + function handleModeratorAdded(channelUri: string) { + setModeratorUris([...moderatorUris, channelUri]); + const parsedUri = parseModUri(channelUri); + if (parsedUri && parsedUri.claimId && parsedUri.claimName) { + commentModAddDelegate(parsedUri.claimId, parsedUri.claimName, activeChannelClaim); + setLastUpdated(Date.now()); + } + } + + function handleModeratorRemoved(channelUri: string) { + setModeratorUris(moderatorUris.filter((x) => x !== channelUri)); + const parsedUri = parseModUri(channelUri); + if (parsedUri && parsedUri.claimId && parsedUri.claimName) { + commentModRemoveDelegate(parsedUri.claimId, parsedUri.claimName, activeChannelClaim); + setLastUpdated(Date.now()); + } + } + function addMutedWords(newTags: Array) { const validatedNewTags = []; newTags.forEach((newTag) => { @@ -162,74 +179,9 @@ export default function SettingsCreatorPage(props: Props) { setLastUpdated(Date.now()); } - function addModerator(newTags: Array) { - // Ignoring multiple entries for now, although supports it. - let modUri; - try { - modUri = parseURI(newTags[0].name); - } catch (e) {} - - if (modUri && modUri.isChannel && modUri.claimName && modUri.claimId) { - if (!moderatorTags.some((modTag) => modTag.name === newTags[0].name)) { - setModeratorTags([...moderatorTags, newTags[0]]); - commentModAddDelegate(modUri.claimId, modUri.claimName, activeChannelClaim); - setLastUpdated(Date.now()); - } - } else { - doToast({ message: __('Invalid channel URL "%url%"', { url: newTags[0].name }), isError: true }); - } - } - - function removeModerator(tagToRemove: Tag) { - let modUri; - try { - modUri = parseURI(tagToRemove.name); - } catch (e) {} - - if (modUri && modUri.isChannel && modUri.claimName && modUri.claimId) { - const newModeratorTags = moderatorTags.slice().filter((t) => t.name !== tagToRemove.name); - setModeratorTags(newModeratorTags); - commentModRemoveDelegate(modUri.claimId, modUri.claimName, activeChannelClaim); - setLastUpdated(Date.now()); - } - } - - function handleChannelSearchSelect(claim) { - if (claim && claim.name && claim.claim_id) { - addModerator([{ name: claim.name + '#' + claim.claim_id }]); - } - } - // ************************************************************************** // ************************************************************************** - // 'moderatorSearchTerm' to 'moderatorSearchClaimUri' - React.useEffect(() => { - if (!moderatorSearchTerm) { - setModeratorSearchError(''); - setModeratorSearchClaimUri(''); - } else { - const [searchUri, error] = getUriForSearchTerm(moderatorSearchTerm); - setModeratorSearchError(error ? __('Something not quite right..') : ''); - - try { - const { streamName, channelName, isChannel } = parseURI(searchUri); - - if (!isChannel && streamName && isNameValid(streamName)) { - setModeratorSearchError(__('Not a channel (prefix with "@", or enter the channel URL)')); - setModeratorSearchClaimUri(''); - } else if (isChannel && channelName && isNameValid(channelName)) { - setModeratorSearchClaimUri(searchUri); - } - } catch (e) { - if (moderatorSearchTerm !== '@') { - setModeratorSearchError(''); - } - setModeratorSearchClaimUri(''); - } - } - }, [moderatorSearchTerm, setModeratorSearchError]); - // Update local moderator states with data from API. React.useEffect(() => { commentModListDelegates(activeChannelClaim); @@ -239,15 +191,9 @@ export default function SettingsCreatorPage(props: Props) { if (activeChannelClaim) { const delegates = moderationDelegatesById[activeChannelClaim.claim_id]; if (delegates) { - setModeratorTags( - delegates.map((d) => { - return { - name: d.channelName + '#' + d.channelId, - }; - }) - ); + setModeratorUris(delegates.map((d) => `${d.channelName}#${d.channelId}`)); } else { - setModeratorTags([]); + setModeratorUris([]); } } }, [activeChannelClaim, moderationDelegatesById]); @@ -401,64 +347,14 @@ export default function SettingsCreatorPage(props: Props) { -
- - - {__('Search channel')} - - - } - placeholder={__('Enter a @username or URL')} - value={moderatorSearchTerm} - onChange={(e) => setModeratorSearchTerm(e.target.value)} - error={moderatorSearchError} - /> - {moderatorSearchClaimUri && ( -
- { - return ( -
- )} -
+
diff --git a/ui/scss/component/section.scss b/ui/scss/component/section.scss index a45b88a7e..9d77d8a8c 100644 --- a/ui/scss/component/section.scss +++ b/ui/scss/component/section.scss @@ -230,10 +230,6 @@ .settings__row--value { width: 100%; - fieldset-section:not(:only-child) { - margin-top: var(--spacing-s); - } - fieldset-section.radio { margin-top: var(--spacing-s); } @@ -242,10 +238,6 @@ margin-top: var(--spacing-m); } - .tags--remove { - margin-bottom: 0; - } - .tags__input-wrapper { .tag__input { height: unset;