refactored comment flow
This commit is contained in:
parent
67ea0dc9b6
commit
e02f021b73
12 changed files with 125 additions and 84 deletions
|
@ -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(
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
|
12
ui/modal/modalCommentAcknowledgement/index.js
Normal file
12
ui/modal/modalCommentAcknowledgement/index.js
Normal 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);
|
43
ui/modal/modalCommentAcknowledgement/view.jsx
Normal file
43
ui/modal/modalCommentAcknowledgement/view.jsx
Normal 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;
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -95,6 +95,10 @@ fieldset-section {
|
|||
margin-top: var(--spacing-small);
|
||||
}
|
||||
}
|
||||
|
||||
+ fieldset-section {
|
||||
margin-top: var(--spacing-medium);
|
||||
}
|
||||
}
|
||||
|
||||
checkbox-element {
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
.markdown-preview {
|
||||
> *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
// Headers
|
||||
h1,
|
||||
h2,
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Add table
Reference in a new issue