Skip to content

Commit

Permalink
Implement SettingsCreatorPage
Browse files Browse the repository at this point in the history
  • Loading branch information
infinite-persistence committed Apr 29, 2021
1 parent fdb4ba7 commit 85e1642
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 4 deletions.
9 changes: 9 additions & 0 deletions static/app-strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -1863,6 +1863,15 @@
"Law URL": "Law URL",
"Clarification": "Clarification",
"Client name": "Client name",
"Creator settings": "Creator settings",
"Muted words": "Muted words",
"Add words": "Add words",
"Suggestions": "Suggestions",
"Add words to block": "Add words to block",
"Enabled comments for channel.": "Enabled comments for channel.",
"Minimum time gap for Slow Mode in livestream chat.": "Minimum time gap for Slow Mode in livestream chat.",
"Minimum tip amount for comments": "Minimum tip amount for comments",
"Minimum tip amount for hyperchats": "Minimum tip amount for hyperchats",
"We apologize for this inconvenience, but have added this additional step to prevent abuse. Users on VPN or shared connections will continue to see this message and are not eligible for Rewards.": "We apologize for this inconvenience, but have added this additional step to prevent abuse. Users on VPN or shared connections will continue to see this message and are not eligible for Rewards.",
"Help LBRY Save Crypto": "Help LBRY Save Crypto",
"The US government is attempting to destroy the cryptocurrency industry. Can you help?": "The US government is attempting to destroy the cryptocurrency industry. Can you help?",
Expand Down
26 changes: 24 additions & 2 deletions ui/page/settingsCreator/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
import { connect } from 'react-redux';
import SettingsCreatorPage from './view';
import {
doCommentBlockWords,
doCommentUnblockWords,
doFetchCreatorSettings,
doUpdateCreatorSettings,
} from 'redux/actions/comments';
import { selectActiveChannelClaim } from 'redux/selectors/app';
import {
selectSettingsByChannelId,
selectFetchingCreatorSettings,
selectFetchingBlockedWords,
} from 'redux/selectors/comments';

const select = (state) => ({});
const select = (state) => ({
activeChannelClaim: selectActiveChannelClaim(state),
settingsByChannelId: selectSettingsByChannelId(state),
fetchingCreatorSettings: selectFetchingCreatorSettings(state),
fetchingBlockedWords: selectFetchingBlockedWords(state),
});

const perform = (dispatch) => ({});
const perform = (dispatch) => ({
commentBlockWords: (channelClaim, words) => dispatch(doCommentBlockWords(channelClaim, words)),
commentUnblockWords: (channelClaim, words) => dispatch(doCommentUnblockWords(channelClaim, words)),
fetchCreatorSettings: () => dispatch(doFetchCreatorSettings()),
updateCreatorSettings: (channelClaim, settings) => dispatch(doUpdateCreatorSettings(channelClaim, settings)),
});

export default connect(select, perform)(SettingsCreatorPage);
200 changes: 198 additions & 2 deletions ui/page/settingsCreator/view.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,124 @@
// @flow
import * as React from 'react';
import Card from 'component/common/card';
import TagsSearch from 'component/tagsSearch';
import Page from 'component/page';
import ChannelSelector from 'component/channelSelector';
import Spinner from 'component/spinner';
import { FormField } from 'component/common/form-components/form-field';

const DEBOUNCE_REFRESH_MS = 1000;

type Props = {
activeChannelClaim: ChannelClaim,
settingsByChannelId: { [string]: PerChannelSettings },
fetchingCreatorSettings: boolean,
fetchingBlockedWords: boolean,
commentBlockWords: (ChannelClaim, Array<string>) => void,
commentUnblockWords: (ChannelClaim, Array<string>) => void,
fetchCreatorSettings: () => void,
updateCreatorSettings: (ChannelClaim, PerChannelSettings) => void,
};

export default function SettingsCreatorPage(props: Props) {
const {
activeChannelClaim,
settingsByChannelId,
commentBlockWords,
commentUnblockWords,
fetchCreatorSettings,
updateCreatorSettings,
} = props;

const [commentsEnabled, setCommentsEnabled] = React.useState(true);
const [mutedWordTags, setMutedWordTags] = React.useState([]);
const [minTipAmountComment, setMinTipAmountComment] = React.useState(0);
const [minTipAmountSuperChat, setMinTipAmountSuperChat] = React.useState(0);
const [slowModeMinGap, setSlowModeMinGap] = React.useState(0);
const [lastUpdated, setLastUpdated] = React.useState(1);

function settingsToStates(settings: PerChannelSettings) {
if (settings.comments_enabled !== undefined) {
setCommentsEnabled(settings.comments_enabled);
}
if (settings.min_tip_amount_comment !== undefined) {
setMinTipAmountComment(settings.min_tip_amount_comment);
}
if (settings.min_tip_amount_super_chat !== undefined) {
setMinTipAmountSuperChat(settings.min_tip_amount_super_chat);
}
if (settings.slow_mode_min_gap !== undefined) {
setSlowModeMinGap(settings.slow_mode_min_gap);
}
}

function setSettings(newSettings: PerChannelSettings) {
settingsToStates(newSettings);
updateCreatorSettings(activeChannelClaim, newSettings);
setLastUpdated(Date.now());
}

function addMutedWords(newTags: Array<Tag>) {
const validatedNewTags = [];
newTags.forEach((newTag) => {
if (!mutedWordTags.some((tag) => tag.name === newTag.name)) {
validatedNewTags.push(newTag);
}
});

if (validatedNewTags.length !== 0) {
setMutedWordTags([...mutedWordTags, ...validatedNewTags]);
commentBlockWords(
activeChannelClaim,
validatedNewTags.map((x) => x.name)
);
setLastUpdated(Date.now());
}
}

function removeMutedWord(tagToRemove: Tag) {
const newMutedWordTags = mutedWordTags.slice().filter((t) => t.name !== tagToRemove.name);
setMutedWordTags(newMutedWordTags);
commentUnblockWords(activeChannelClaim, ['', tagToRemove.name]);
setLastUpdated(Date.now());
}

// Update local states with data from API data.
React.useEffect(() => {
if (lastUpdated !== 0 && Date.now() - lastUpdated < DEBOUNCE_REFRESH_MS) {
// Still debouncing. Skip update.
return;
}

if (activeChannelClaim && settingsByChannelId && settingsByChannelId[activeChannelClaim.claim_id]) {
const channelSettings = settingsByChannelId[activeChannelClaim.claim_id];

settingsToStates(channelSettings);
if (channelSettings.words) {
const tagArray = Array.from(new Set(channelSettings.words));
setMutedWordTags(
tagArray
.filter((t) => t !== '')
.map((x) => {
return { name: x };
})
);
}
}
}, [activeChannelClaim, settingsByChannelId, lastUpdated]);

// Re-sync list, mainly to correct any invalid settings.
React.useEffect(() => {
if (lastUpdated) {
const timer = setTimeout(() => {
fetchCreatorSettings();
}, DEBOUNCE_REFRESH_MS);
return () => clearTimeout(timer);
}
}, [lastUpdated, fetchCreatorSettings]);

const isBusy = !activeChannelClaim || !settingsByChannelId || !settingsByChannelId[activeChannelClaim.claim_id];

export default function SettingsCreatorPage(/* props: Props */) {
return (
<Page
noFooter
Expand All @@ -13,7 +129,87 @@ export default function SettingsCreatorPage(/* props: Props */) {
}}
className="card-stack"
>
Blah
<ChannelSelector hideAnon />
{isBusy && (
<div className="main--empty">
<Spinner />
</div>
)}
{!isBusy && (
<>
<Card
title={__('General')}
actions={
<>
<FormField
type="checkbox"
name="comments_enabled"
label={__('Enabled comments for channel.')}
checked={commentsEnabled}
onChange={() => setSettings({ comments_enabled: !commentsEnabled })}
/>
<FormField
name="slow_mode_min_gap"
label={__('Minimum time gap for Slow Mode in livestream chat.')}
min={0}
step={1}
type="number"
placeholder="1"
value={slowModeMinGap}
onChange={(e) => setSettings({ slow_mode_min_gap: e.target.value })}
/>
</>
}
/>
<Card
title={__('Filter')}
actions={
<div className="tag--blocked-words">
<TagsSearch
label={__('Muted words')}
labelAddNew={__('Add words')}
labelSuggestions={__('Suggestions')}
onRemove={removeMutedWord}
onSelect={addMutedWords}
disableAutoFocus
tagsPassedIn={mutedWordTags}
placeholder={__('Add words to block')}
hideSuggestions
/>
</div>
}
/>
<Card
title={__('Tip')}
actions={
<>
<FormField
name="min_tip_amount_comment"
label={__('Minimum tip amount for comments')}
className="form-field--price-amount"
min={0}
step={1}
type="number"
placeholder="1"
value={minTipAmountComment}
onChange={(e) => setSettings({ min_tip_amount_comment: e.target.value })}
/>
<FormField
name="min_tip_amount_super_chat"
label={__('Minimum tip amount for hyperchats')}
className="form-field--price-amount"
min={0}
step={1}
type="number"
placeholder="1"
value={minTipAmountSuperChat}
onChange={(e) => setSettings({ min_tip_amount_super_chat: e.target.value })}
/>
</>
}
/>
</>
)}
</Page>
);
}
12 changes: 12 additions & 0 deletions ui/scss/component/_tags.scss
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,15 @@
margin: calc(2rem / 10) calc(2rem / 10);
max-width: 20rem;
}

.tag--blocked-words {
.tag {
color: var(--color-tag-words);
background-color: var(--color-tag-words-bg);

&:hover {
color: var(--color-tag-words-hover);
background-color: var(--color-tag-words-bg-hover);
}
}
}
6 changes: 6 additions & 0 deletions ui/scss/themes/dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@
--color-tag-hover: var(--color-white);
--color-tag-bg-hover: var(--color-primary-alt-2);

// Tags (words)
--color-tag-words: var(--color-text);
--color-tag-words-bg: var(--color-gray-5);
--color-tag-words-hover: var(--color-white);
--color-tag-words-bg-hover: var(--color-gray-4);

// Snack
--color-snack-bg: var(--color-secondary);

Expand Down
6 changes: 6 additions & 0 deletions ui/scss/themes/light.scss
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@
--color-snack-bg-error: var(--color-danger);
--color-snack-upgrade: var(--color-tertiary);

// Tags (words)
--color-tag-words: var(--color-gray-5);
--color-tag-words-bg: var(--color-button-alt-bg);
--color-tag-words-hover: var(--color-button-alt-text);
--color-tag-words-bg-hover: var(--color-button-alt-bg-hover);

// Editor
--color-editor-cursor: var(--color-text);
--color-editor-quote: #707070;
Expand Down

0 comments on commit 85e1642

Please sign in to comment.