refactored comment flow

This commit is contained in:
Jeremy Kauffman 2019-11-14 15:02:15 -05:00 committed by Sean Yesmunt
parent 67ea0dc9b6
commit e02f021b73
12 changed files with 125 additions and 84 deletions

View file

@ -1,14 +1,17 @@
import { connect } from 'react-redux';
import { doCommentCreate, makeSelectClaimForUri } from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app';
import { CommentCreate } from './view';
import { selectUserVerifiedEmail } from 'lbryinc';
const select = (state, props) => ({
commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true,
claim: makeSelectClaimForUri(props.uri)(state),
});
const perform = dispatch => ({
createComment: (comment, claimId, channel) => dispatch(doCommentCreate(comment, claimId, channel)),
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
});
export default connect(

View file

@ -5,15 +5,19 @@ import { FormField, Form } from 'component/common/form';
import Button from 'component/button';
import ChannelSection from 'component/selectChannel';
import usePersistedState from 'effects/use-persisted-state';
import * as MODALS from 'constants/modal_types';
import I18nMessage from '../i18nMessage/view';
type Props = {
commentingEnabled: boolean,
uri: string,
claim: StreamClaim,
openModal: (id: string, { onCommentAcknowledge: () => void }) => void,
createComment: (string, string, string) => void,
};
export function CommentCreate(props: Props) {
const { createComment, claim } = props;
const { commentingEnabled, createComment, claim, openModal } = props;
const { claim_id: claimId } = claim;
const [commentValue, setCommentValue] = usePersistedState(`comment-${claimId}`, '');
const [commentAck, setCommentAck] = usePersistedState('comment-acknowledge', false);
@ -28,10 +32,16 @@ export function CommentCreate(props: Props) {
setChannel(channel);
}
function handleCommentAck(event) {
function handleCommentAck() {
setCommentAck(true);
}
function onTextareaFocus() {
if (!commentAck) {
openModal(MODALS.COMMENT_ACKNOWEDGEMENT, { onCommentAcknowledge: handleCommentAck });
}
}
function handleSubmit() {
if (channel !== CHANNEL_NEW && commentValue.length) createComment(commentValue, claimId, channel);
setCommentValue('');
@ -39,58 +49,35 @@ export function CommentCreate(props: Props) {
useEffect(() => setCharCount(commentValue.length), [commentValue]);
if (!commentingEnabled) {
return (
<I18nMessage tokens={{ sign_in_link: <Button button="link" requiresAuth label={__('sign in')} /> }}>
Please %sign_in_link% to comment.
</I18nMessage>
);
}
return (
<section>
{commentAck !== true && (
<div>
<p>{__('A few things to know before participating in the comment alpha:')}</p>
<ul>
<li>
{__('During the alpha, all comments are sent to a LBRY, Inc. server, not the LBRY network itself.')}
</li>
<li>
{__(
'During the alpha, comments are not decentralized or censorship resistant (but we repeat ourselves).'
)}
</li>
<li>
{__(
'For the initial release, deleting or editing comments is not possible. Please be mindful of this when posting.'
)}
</li>
<li>
{__(
'When the alpha ends, we will attempt to transition comments, but do not promise to do so. Any transition will likely involve publishing previous comments under a single archive handle.'
)}
</li>
</ul>
<Button button="primary" onClick={handleCommentAck} label={__('Got it!')} />
</div>
)}
{commentAck === true && (
<Form onSubmit={handleSubmit}>
<ChannelSection channel={channel} onChannelChange={handleChannelChange} />
<FormField
disabled={channel === CHANNEL_NEW}
type="textarea"
name="content_description"
label={__('Comment')}
placeholder={__('Your comment')}
value={commentValue}
charCount={charCount}
onChange={handleCommentChange}
/>
<div className="card__actions">
<Button
button="primary"
disabled={channel === CHANNEL_NEW || !commentValue.length}
type="submit"
label={__('Post')}
requiresAuth={IS_WEB}
/>
</div>
</Form>
)}
</section>
<Form onSubmit={handleSubmit}>
<ChannelSection channel={channel} onChannelChange={handleChannelChange} />
<FormField
disabled={channel === CHANNEL_NEW}
type="textarea"
name="content_description"
label={__('Comment')}
onFocus={onTextareaFocus}
placeholder={__('Say something about this...')}
value={commentValue}
charCount={charCount}
onChange={handleCommentChange}
/>
<Button
button="primary"
disabled={channel === CHANNEL_NEW || !commentValue.length}
type="submit"
label={__('Post')}
requiresAuth={IS_WEB}
/>
</Form>
);
}

View file

@ -1,5 +1,6 @@
export const CONFIRM_FILE_REMOVE = 'confirm_file_remove';
export const CONFIRM_EXTERNAL_RESOURCE = 'confirm_external_resource';
export const COMMENT_ACKNOWEDGEMENT = 'comment_acknowlegement';
export const INCOMPATIBLE_DAEMON = 'incompatible_daemon';
export const FILE_TIMEOUT = 'file_timeout';
export const DOWNLOADING = 'downloading';

View file

@ -0,0 +1,12 @@
import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app';
import ModalCommentAcknowledgement from './view';
const perform = dispatch => ({
closeModal: () => dispatch(doHideModal()),
});
export default connect(
null,
perform
)(ModalCommentAcknowledgement);

View file

@ -0,0 +1,43 @@
// @flow
import React from 'react';
import { Modal } from 'modal/modal';
type Props = {
onCommentAcknowledge: () => void,
closeModal: () => void,
};
class ModalCommentAcknowledgement extends React.PureComponent<Props> {
render() {
const { closeModal, onCommentAcknowledge } = this.props;
function onAbortedOrConfirmed() {
onCommentAcknowledge();
closeModal();
}
return (
<Modal
isOpen
onAborted={onAbortedOrConfirmed}
title={__('Comment Acknowledgement')}
onConfirmed={onAbortedOrConfirmed}
>
<p>{__('A few things to know before making your comment:')}</p>
<ul>
<li>
{__(
'Commenting is in alpha. During the alpha, all comments are sent to a LBRY, Inc. server, not the LBRY network itself.'
)}
</li>
<li>
{__('Deleting or editing comments is not currently possible. Please be mindful of this when posting.')}
</li>
<li>{__('When the alpha ends, we will attempt to transition comments, but do not promise to do so.')}</li>
</ul>
</Modal>
);
}
}
export default ModalCommentAcknowledgement;

View file

@ -26,6 +26,7 @@ import ModalWalletDecrypt from 'modal/modalWalletDecrypt';
import ModalWalletUnlock from 'modal/modalWalletUnlock';
import ModalRewardCode from 'modal/modalRewardCode';
import ModalPasswordUnsave from 'modal/modalPasswordUnsave';
import ModalCommentAcknowledgement from 'modal/modalCommentAcknowledgement';
type Props = {
modal: { id: string, modalProps: {} },
@ -96,6 +97,8 @@ function ModalRouter(props: Props) {
return <ModalPasswordUnsave {...modalProps} />;
case MODALS.REWARD_GENERATED_CODE:
return <ModalRewardCode {...modalProps} />;
case MODALS.COMMENT_ACKNOWEDGEMENT:
return <ModalCommentAcknowledgement {...modalProps} />;
default:
return null;
}

View file

@ -223,13 +223,14 @@ class FilePage extends React.Component<Props> {
<div className="media__info--large">
<FileDetails uri={uri} />
<ClaimTags uri={uri} type="large" />
<div className="media__info-title">
{__('Comments')} <span className="badge badge--alert">ALPHA</span>
</div>
<CommentCreate uri={uri} />
<CommentsList uri={uri} />
</div>
<div className="media__info-title">{__('Comments')}</div>
<section className="section">
<CommentCreate uri={uri} />
</section>
<section className="section">
<CommentsList uri={uri} />
</section>
</div>
<div className="grid-area--related">
<div className="media__actions media__actions--between media__actions--nowrap">

View file

@ -31,7 +31,6 @@
@import 'component/menu-button';
@import 'component/modal';
@import 'component/navigation';
@import 'component/notice';
@import 'component/pagination';
@import 'component/placeholder';
@import 'component/search';

View file

@ -1,14 +1,16 @@
.comments {
@extend .ul--no-style;
margin-top: var(--spacing-large);
}
.comment {
display: flex;
flex-direction: column;
padding: 0;
font-size: var(--font-multiplier-small);
padding: var(--spacing-small) 0;
padding: var(--spacing-small) 0 var(--spacing-small);
&:first-of-type {
padding-top: 0;
}
&:not(:last-of-type) {
border-bottom: 1px solid var(--lbry-gray-1);
@ -23,6 +25,7 @@
text-overflow: ellipsis;
display: flex;
justify-content: space-between;
margin-bottom: var(--spacing-small);
time {
opacity: 0.3;
@ -34,7 +37,6 @@
}
.comment__author {
margin-bottom: 1rem;
text-overflow: ellipsis; // This is where the magic happens
flex-basis: 400px;
flex-shrink: 1;

View file

@ -95,6 +95,10 @@ fieldset-section {
margin-top: var(--spacing-small);
}
}
+ fieldset-section {
margin-top: var(--spacing-medium);
}
}
checkbox-element {

View file

@ -1,4 +1,8 @@
.markdown-preview {
> *:last-child {
margin-bottom: 0;
}
// Headers
h1,
h2,

View file

@ -1,18 +0,0 @@
.notice {
border: 1px solid;
border-radius: 5px;
padding: var(--spacing-medium) var(--spacing-large);
text-shadow: 0 1px 0 rgba($lbry-white, 0.5);
&:not(.notice--error) {
background-color: $lbry-green-1;
border-color: $lbry-green-2;
color: $lbry-green-3;
}
}
.notice--error {
background-color: $lbry-red-1;
border-color: $lbry-red-2;
color: $lbry-red-3;
}