wip with channel prompts on comments
This commit is contained in:
parent
5beb219ff6
commit
a5107f075c
9 changed files with 101 additions and 37 deletions
|
@ -2,6 +2,7 @@
|
|||
import * as MODALS from 'constants/modal_types';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { FormField } from 'component/common/form';
|
||||
import Button from 'component/button';
|
||||
import TagsSearch from 'component/tagsSearch';
|
||||
|
@ -70,6 +71,7 @@ function ChannelForm(props: Props) {
|
|||
createError,
|
||||
clearChannelErrors,
|
||||
openModal,
|
||||
disabled,
|
||||
} = props;
|
||||
const [nameError, setNameError] = React.useState(undefined);
|
||||
const [bidError, setBidError] = React.useState('');
|
||||
|
@ -180,7 +182,7 @@ function ChannelForm(props: Props) {
|
|||
// TODO clear and bail after submit
|
||||
return (
|
||||
<>
|
||||
<div className="main--contained">
|
||||
<div className={classnames('main--contained', { 'card--disabled': disabled })}>
|
||||
<header className="channel-cover">
|
||||
<div className="channel__quick-actions">
|
||||
<Button
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
// @flow
|
||||
import { SIMPLE_SITE, SITE_NAME } from 'config';
|
||||
import * as MODALS from 'constants/modal_types';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import { CHANNEL_NEW } from 'constants/claim';
|
||||
import { SIMPLE_SITE } from 'config';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { FormField, Form } from 'component/common/form';
|
||||
import Button from 'component/button';
|
||||
import ChannelSelection from 'component/selectChannel';
|
||||
import usePersistedState from 'effects/use-persisted-state';
|
||||
import * as MODALS from 'constants/modal_types';
|
||||
import I18nMessage from 'component/i18nMessage';
|
||||
import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field';
|
||||
|
||||
|
@ -43,6 +44,7 @@ export function CommentCreate(props: Props) {
|
|||
const [channel, setChannel] = usePersistedState('comment-channel', '');
|
||||
const [charCount, setCharCount] = useState(commentValue.length);
|
||||
const [advancedEditor, setAdvancedEditor] = usePersistedState('comment-editor-mode', false);
|
||||
const hasChannels = channels && channels.length;
|
||||
|
||||
const topChannel =
|
||||
channels &&
|
||||
|
@ -104,6 +106,18 @@ export function CommentCreate(props: Props) {
|
|||
);
|
||||
}
|
||||
|
||||
if (!hasChannels) {
|
||||
return (
|
||||
<div className="notice-message">
|
||||
<h3 className="section__title">{__('Join the discussion')}</h3>
|
||||
<p className="section__subtitle">{__('A channel is required to comment on %SITE_NAME%.', { SITE_NAME })}</p>
|
||||
<div className="section__actions">
|
||||
<Button button="primary" label={__('Create a channel')} navigate={`/$/${PAGES.CHANNEL_NEW}`} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Form
|
||||
onSubmit={handleSubmit}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { makeSelectClaimIsMine, selectMyChannelClaims } from 'lbry-redux';
|
||||
import { makeSelectRepliesForParentId } from 'redux/selectors/comments';
|
||||
|
||||
import CommentsReplies from './view';
|
||||
import { doToast } from 'redux/actions/notifications';
|
||||
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||
import CommentsReplies from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
myChannels: selectMyChannelClaims(state),
|
||||
|
@ -12,4 +12,6 @@ const select = (state, props) => ({
|
|||
commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true,
|
||||
});
|
||||
|
||||
export default connect(select, null)(CommentsReplies);
|
||||
export default connect(select, {
|
||||
doToast,
|
||||
})(CommentsReplies);
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
// @flow
|
||||
import { SITE_NAME } from 'config';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import React from 'react';
|
||||
import Comment from 'component/comment';
|
||||
import Button from 'component/button';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import CommentCreate from 'component/commentCreate';
|
||||
import { useHistory } from 'react-router';
|
||||
|
||||
type Props = {
|
||||
comments: Array<any>,
|
||||
|
@ -13,31 +16,35 @@ type Props = {
|
|||
linkedComment?: Comment,
|
||||
parentId: string,
|
||||
commentingEnabled: boolean,
|
||||
doToast: ({ message: string }) => void,
|
||||
};
|
||||
|
||||
function CommentsReplies(props: Props) {
|
||||
const { uri, comments, claimIsMine, myChannels, linkedComment, parentId, commentingEnabled } = props;
|
||||
const { uri, comments, claimIsMine, myChannels, linkedComment, parentId, commentingEnabled, doToast } = props;
|
||||
const {
|
||||
push,
|
||||
location: { pathname },
|
||||
} = useHistory();
|
||||
const [isReplying, setReplying] = React.useState(false);
|
||||
const [isExpanded, setExpanded] = React.useState(false);
|
||||
const [start, setStart] = React.useState(0);
|
||||
const [end, setEnd] = React.useState(9);
|
||||
const sortedComments = comments ? [...comments].reverse() : [];
|
||||
const numberOfComments = comments ? comments.length : 0;
|
||||
const linkedCommentId = linkedComment ? linkedComment.comment_id : '';
|
||||
const commentsIndexOfLInked = comments && sortedComments.findIndex(e => e.comment_id === linkedCommentId);
|
||||
const hasChannels = myChannels && myChannels.length > 0;
|
||||
|
||||
const showMore = () => {
|
||||
function showMore() {
|
||||
if (start > 0) {
|
||||
setStart(0);
|
||||
} else {
|
||||
setEnd(numberOfComments);
|
||||
}
|
||||
};
|
||||
|
||||
const linkedCommentId = linkedComment ? linkedComment.comment_id : '';
|
||||
|
||||
const commentsIndexOfLInked = comments && sortedComments.findIndex(e => e.comment_id === linkedCommentId);
|
||||
}
|
||||
|
||||
// todo: implement comment_list --mine in SDK so redux can grab with selectCommentIsMine
|
||||
const isMyComment = (channelId: string) => {
|
||||
function isMyComment(channelId: string) {
|
||||
if (myChannels != null && channelId != null) {
|
||||
for (let i = 0; i < myChannels.length; i++) {
|
||||
if (myChannels[i].claim_id === channelId) {
|
||||
|
@ -46,16 +53,25 @@ function CommentsReplies(props: Props) {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
const handleCommentDone = () => {
|
||||
function handleCommentDone() {
|
||||
if (!isExpanded) {
|
||||
setExpanded(true);
|
||||
setStart(numberOfComments || 0);
|
||||
}
|
||||
setEnd(numberOfComments + 1);
|
||||
setReplying(false);
|
||||
};
|
||||
}
|
||||
|
||||
function handleCommentReply() {
|
||||
if (!hasChannels) {
|
||||
push(`/$/${PAGES.CHANNEL_NEW}?redirect=${pathname}`);
|
||||
doToast({ message: __('A channel is required to comment on %SITE_NAME%', { SITE_NAME }) });
|
||||
} else {
|
||||
setReplying(!isReplying);
|
||||
}
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
if (
|
||||
|
@ -75,13 +91,13 @@ function CommentsReplies(props: Props) {
|
|||
const displayedComments = sortedComments.slice(start, end);
|
||||
|
||||
return (
|
||||
<li className={'comment__replies-container'}>
|
||||
<li className="comment__replies-container">
|
||||
<div className="comment__actions">
|
||||
<Button
|
||||
requiresAuth={IS_WEB}
|
||||
label={commentingEnabled ? __('Reply') : __('Log in to reply')}
|
||||
className="comment__action"
|
||||
onClick={() => setReplying(!isReplying)}
|
||||
onClick={handleCommentReply}
|
||||
icon={ICONS.REPLY}
|
||||
/>
|
||||
{!isExpanded && Boolean(numberOfComments) && (
|
||||
|
@ -124,7 +140,7 @@ function CommentsReplies(props: Props) {
|
|||
requiresAuth={IS_WEB}
|
||||
label={commentingEnabled ? __('Reply') : __('Log in to reply')}
|
||||
className="comment__action--nested"
|
||||
onClick={() => setReplying(!isReplying)}
|
||||
onClick={handleCommentReply}
|
||||
icon={ICONS.REPLY}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -20,6 +20,7 @@ type Props = {
|
|||
|
||||
function InviteNew(props: Props) {
|
||||
const { inviteNew, errorMessage, isPending, referralCode = '', channels } = props;
|
||||
const noChannels = !channels || !(channels.length > 0);
|
||||
|
||||
// Email
|
||||
const [email, setEmail] = useState('');
|
||||
|
@ -77,6 +78,7 @@ function InviteNew(props: Props) {
|
|||
actions={
|
||||
<React.Fragment>
|
||||
<CopyableText label={__('Your invite link')} copyable={referral} />
|
||||
{!noChannels && (
|
||||
<SelectChannel
|
||||
channel={referralSource}
|
||||
onChannelChange={channel => handleReferralChange(channel)}
|
||||
|
@ -84,6 +86,7 @@ function InviteNew(props: Props) {
|
|||
hideAnon
|
||||
injected={[referralCode]}
|
||||
/>
|
||||
)}
|
||||
|
||||
<p className="help">
|
||||
<I18nMessage
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectBalance } from 'lbry-redux';
|
||||
import ChannelNew from './view';
|
||||
|
||||
const select = () => ({});
|
||||
const perform = () => ({});
|
||||
const select = state => ({
|
||||
balance: selectBalance(state),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(ChannelNew);
|
||||
export default connect(select)(ChannelNew);
|
||||
|
|
|
@ -2,20 +2,39 @@
|
|||
import React from 'react';
|
||||
import ChannelEdit from 'component/channelEdit';
|
||||
import Page from 'component/page';
|
||||
import { withRouter } from 'react-router';
|
||||
import Button from 'component/button';
|
||||
import { useHistory } from 'react-router';
|
||||
import * as PAGES from 'constants/pages';
|
||||
|
||||
type Props = {
|
||||
history: { push: string => void, goBack: () => void },
|
||||
balance: number,
|
||||
};
|
||||
|
||||
function ChannelNew(props: Props) {
|
||||
const { history } = props;
|
||||
const { balance } = props;
|
||||
const { push, location } = useHistory();
|
||||
const urlSearchParams = new URLSearchParams(location.search);
|
||||
const redirectUrl = urlSearchParams.get('redirect');
|
||||
const emptyBalance = balance === 0;
|
||||
|
||||
return (
|
||||
<Page noSideNavigation authPage backout={{ title: __('Create Channel') }}>
|
||||
<ChannelEdit onDone={() => history.push(`/$/${PAGES.CHANNELS}`)} />
|
||||
<Page noSideNavigation noFooter backout={{ title: __('Create A Channel'), backLabel: __('Cancel') }}>
|
||||
{emptyBalance && (
|
||||
<div className="main--contained">
|
||||
<div className="notice-message--above-content">
|
||||
<h1 className="section__title">You need LBC for this</h1>
|
||||
<h1 className="section__subtitle">Get sum coinz</h1>
|
||||
<div className="section__actions">
|
||||
<Button button="primary" label={__('Earn Rewards')} navigate={`/$/${PAGES.REWARDS}`} />
|
||||
<Button button="primary" label={__('Purchase LBC')} navigate={`/$/${PAGES.BUY}`} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ChannelEdit disabled={emptyBalance} onDone={() => push(redirectUrl || `/$/${PAGES.CHANNELS}`)} />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
export default withRouter(ChannelNew);
|
||||
export default ChannelNew;
|
||||
|
|
|
@ -4,6 +4,7 @@ $thumbnailWidthSmall: 2rem;
|
|||
.comments {
|
||||
list-style-type: none;
|
||||
font-size: var(--font-small);
|
||||
margin-top: var(--spacing-l);
|
||||
}
|
||||
|
||||
.comments--replies {
|
||||
|
|
|
@ -301,6 +301,11 @@ textarea {
|
|||
background-color: var(--color-primary-alt);
|
||||
}
|
||||
|
||||
.notice-message--above-content {
|
||||
@extend .notice-message;
|
||||
margin-bottom: var(--spacing-l);
|
||||
}
|
||||
|
||||
.privacy-img {
|
||||
height: 10rem;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue