Skip to content

Commit

Permalink
Add direct reacting from notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
saltrafael committed Aug 23, 2021
1 parent 53ff9cb commit 124a41e
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 45 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add confirmation on comment removal _community pr!_ ([#6563](https://github.com/lbryio/lbry-desktop/pull/6563))
- Show on content page if a file is part of a playlist already _community pr!_([#6393](https://github.com/lbryio/lbry-desktop/pull/6393))
- Add filtering to playlists ([#6905](https://github.com/lbryio/lbry-desktop/pull/6905))
- Added direct replying to notifications _community pr!_ ([#6935](https://github.com/lbryio/lbry-desktop/pull/6935))

### Changed
- Use Canonical Url for copy link ([#6500](https://github.com/lbryio/lbry-desktop/pull/6500))
Expand Down
9 changes: 9 additions & 0 deletions ui/component/comment/view.jsx
Expand Up @@ -63,6 +63,9 @@ type Props = {
isModerator: boolean,
isGlobalMod: boolean,
isFiat: boolean,
supportDisabled: boolean,
setQuickReply: (any) => void,
quickReply: any,
};

const LENGTH_TO_COLLAPSE = 300;
Expand Down Expand Up @@ -98,6 +101,9 @@ function Comment(props: Props) {
isModerator,
isGlobalMod,
isFiat,
supportDisabled,
setQuickReply,
quickReply,
} = props;

const {
Expand Down Expand Up @@ -183,6 +189,7 @@ function Comment(props: Props) {

function handleSubmit() {
updateComment(commentId, editedMessage);
if (setQuickReply) setQuickReply({ ...quickReply, comment_id: commentId, comment: editedMessage });
setEditing(false);
}

Expand Down Expand Up @@ -292,6 +299,7 @@ function Comment(props: Props) {
commentIsMine={commentIsMine}
handleEditComment={handleEditComment}
supportAmount={supportAmount}
setQuickReply={setQuickReply}
/>
</Menu>
</div>
Expand Down Expand Up @@ -401,6 +409,7 @@ function Comment(props: Props) {
onCancelReplying={() => {
setReplying(false);
}}
supportDisabled={supportDisabled}
/>
)}
</>
Expand Down
59 changes: 33 additions & 26 deletions ui/component/commentCreate/view.jsx
Expand Up @@ -47,8 +47,10 @@ type Props = {
claimIsMine: boolean,
sendTip: ({}, (any) => void, (any) => void) => void,
doToast: ({ message: string }) => void,
supportDisabled: boolean,
doFetchCreatorSettings: (channelId: string) => Promise<any>,
settingsByChannelId: { [channelId: string]: PerChannelSettings },
setQuickReply: (any) => void,
};

export function CommentCreate(props: Props) {
Expand All @@ -71,6 +73,8 @@ export function CommentCreate(props: Props) {
doToast,
doFetchCreatorSettings,
settingsByChannelId,
supportDisabled,
setQuickReply,
} = props;
const buttonRef: ElementRef<any> = React.useRef();
const {
Expand All @@ -80,7 +84,7 @@ export function CommentCreate(props: Props) {
const [isSubmitting, setIsSubmitting] = React.useState(false);
const [commentFailure, setCommentFailure] = React.useState(false);
const [successTip, setSuccessTip] = React.useState({ txid: undefined, tipAmount: undefined });
const { claim_id: claimId } = claim;
const claimId = claim && claim.claim_id;
const [isSupportComment, setIsSupportComment] = React.useState();
const [isReviewingSupportComment, setIsReviewingSupportComment] = React.useState();
const [tipAmount, setTipAmount] = React.useState(1);
Expand Down Expand Up @@ -322,6 +326,7 @@ export function CommentCreate(props: Props) {
createComment(commentValue, claimId, parentId, txid, payment_intent_id, environment)
.then((res) => {
setIsSubmitting(false);
if (setQuickReply) setQuickReply(res);

if (res && res.signature) {
setCommentValue('');
Expand Down Expand Up @@ -517,32 +522,34 @@ export function CommentCreate(props: Props) {
requiresAuth={IS_WEB}
/>
)}
{!claimIsMine && (
<Button
disabled={disabled}
button="alt"
className="thatButton"
icon={ICONS.LBC}
onClick={() => {
setIsSupportComment(true);
setActiveTab(TAB_LBC);
}}
/>
)}
{/* @if TARGET='web' */}
{!claimIsMine && stripeEnvironment && (
<Button
disabled={disabled}
button="alt"
className="thisButton"
icon={ICONS.FINANCE}
onClick={() => {
setIsSupportComment(true);
setActiveTab(TAB_FIAT);
}}
/>
{!supportDisabled && !claimIsMine && (
<>
<Button
disabled={disabled}
button="alt"
className="thatButton"
icon={ICONS.LBC}
onClick={() => {
setIsSupportComment(true);
setActiveTab(TAB_LBC);
}}
/>
{/* @if TARGET='web' */}
{stripeEnvironment && (
<Button
disabled={disabled}
button="alt"
className="thisButton"
icon={ICONS.FINANCE}
onClick={() => {
setIsSupportComment(true);
setActiveTab(TAB_FIAT);
}}
/>
)}
{/* @endif */}
</>
)}
{/* @endif */}
{isReply && !minTip && (
<Button
button="link"
Expand Down
10 changes: 9 additions & 1 deletion ui/component/commentMenuList/view.jsx
Expand Up @@ -30,6 +30,7 @@ type Props = {
moderationDelegatorsById: { [string]: { global: boolean, delegators: { name: string, claimId: string } } },
openModal: (id: string, {}) => void,
supportAmount?: any,
setQuickReply: (any) => void,
};

function CommentMenuList(props: Props) {
Expand All @@ -56,6 +57,7 @@ function CommentMenuList(props: Props) {
moderationDelegatorsById,
openModal,
supportAmount,
setQuickReply,
} = props;

const contentChannelClaim = !claim
Expand Down Expand Up @@ -83,7 +85,13 @@ function CommentMenuList(props: Props) {
if (playingUri && playingUri.source === 'comment') {
clearPlayingUri();
}
openModal(MODALS.CONFIRM_REMOVE_COMMENT, { commentId, commentIsMine, contentChannelPermanentUrl, supportAmount });
openModal(MODALS.CONFIRM_REMOVE_COMMENT, {
commentId,
commentIsMine,
contentChannelPermanentUrl,
supportAmount,
setQuickReply,
});
}

function handleCommentBlock() {
Expand Down
8 changes: 7 additions & 1 deletion ui/component/notification/index.js
@@ -1,8 +1,14 @@
import { connect } from 'react-redux';
import { doReadNotifications, doDeleteNotification } from 'redux/actions/notifications';
import { doResolveUri, selectMyChannelClaims } from 'lbry-redux';
import Notification from './view';

export default connect(null, {
const select = (state) => ({
myChannels: selectMyChannelClaims(state),
});

export default connect(select, {
doReadNotifications,
doDeleteNotification,
doResolveUri,
})(Notification);
96 changes: 87 additions & 9 deletions ui/component/notification/view.jsx
Expand Up @@ -18,19 +18,45 @@ import NotificationContentChannelMenu from 'component/notificationContentChannel
import LbcMessage from 'component/common/lbc-message';
import UriIndicator from 'component/uriIndicator';
import { NavLink } from 'react-router-dom';
import CommentReactions from 'component/commentReactions';
import CommentCreate from 'component/commentCreate';
import CommentView from 'component/comment';
import { ENABLE_CREATOR_REACTIONS } from 'config';

type Props = {
notification: WebNotification,
menuButton: boolean,
children: any,
doReadNotifications: ([number]) => void,
doDeleteNotification: (number) => void,
doResolveUri: (string) => void,
myChannels: ?Array<ChannelClaim>,
};

export default function Notification(props: Props) {
const { notification, menuButton = false, doReadNotifications, doDeleteNotification } = props;
const {
notification,
menuButton = false,
doReadNotifications,
doDeleteNotification,
doResolveUri,
myChannels,
} = props;
const { push } = useHistory();
const { notification_rule, notification_parameters, is_read, id } = notification;
const [isReplying, setReplying] = React.useState(false);
const [quickReply, setQuickReply] = React.useState();

const isMyComment = (channelId: string): boolean => {
if (myChannels != null && channelId != null) {
for (let i = 0; i < myChannels.length; i++) {
if (myChannels[i].claim_id === channelId) {
return true;
}
}
}
return false;
};

const isCommentNotification =
notification_rule === RULE.COMMENT ||
Expand All @@ -52,6 +78,12 @@ export default function Notification(props: Props) {
notificationTarget = notification_parameters.device.target;
}

React.useEffect(() => {
if ((ENABLE_CREATOR_REACTIONS && isCommentNotification) || (isReplying && notificationTarget)) {
doResolveUri(notificationTarget);
}
}, [doResolveUri, isCommentNotification, isReplying, notificationTarget]);

const creatorIcon = (channelUrl) => {
return (
<UriIndicator uri={channelUrl} link>
Expand Down Expand Up @@ -152,6 +184,10 @@ export default function Notification(props: Props) {
doReadNotifications([id]);
}

function handleQuickReply() {
setReplying(!isReplying);
}

const Wrapper = menuButton
? (props: { children: any }) => (
<MenuItem className="menu__link--notification" onSelect={handleNotificationClick}>
Expand All @@ -176,12 +212,12 @@ export default function Notification(props: Props) {
);

return (
<Wrapper>
<div
className={classnames('notification__wrapper', {
'notification__wrapper--unread': !is_read,
})}
>
<div
className={classnames('notification__wrapper', {
'notification__wrapper--unread': !is_read,
})}
>
<Wrapper>
<div className="notification__icon">{icon}</div>

<div className="notification__content-wrapper">
Expand Down Expand Up @@ -249,7 +285,49 @@ export default function Notification(props: Props) {
</MenuList>
</Menu>
</div>
</div>
</Wrapper>
</Wrapper>

{isCommentNotification && (
<div>
<div className="notification__reactions">
<Button label={__('Reply')} className="comment__action" onClick={handleQuickReply} icon={ICONS.REPLY} />
<CommentReactions uri={notificationTarget} commentId={notification_parameters.dynamic.hash} />
</div>

{isReplying && (
<CommentCreate
isReply
uri={notificationTarget}
parentId={notification_parameters.dynamic.hash}
onDoneReplying={() => setReplying(false)}
onCancelReplying={() => setReplying(false)}
setQuickReply={setQuickReply}
supportDisabled
/>
)}

{quickReply && (
<CommentView
key={quickReply.comment_id}
uri={notificationTarget}
authorUri={quickReply.channel_url}
author={quickReply.channel_name}
claimId={quickReply.claim_id}
commentId={quickReply.comment_id}
message={quickReply.comment}
timePosted={quickReply.timestamp * 1000}
commentIsMine={quickReply.channel_id && isMyComment(quickReply.channel_id)}
isPinned={quickReply.is_pinned}
supportAmount={quickReply.support_amount}
numDirectReplies={quickReply.replies}
isFiat={quickReply.is_fiat}
setQuickReply={setQuickReply}
quickReply={quickReply}
supportDisabled
/>
)}
</div>
)}
</div>
);
}
18 changes: 15 additions & 3 deletions ui/modal/modalRemoveComment/view.jsx
Expand Up @@ -11,10 +11,19 @@ type Props = {
closeModal: () => void,
deleteComment: (string, ?string) => void,
supportAmount?: any,
setQuickReply: (any) => void,
};

function ModalRemoveComment(props: Props) {
const { commentId, commentIsMine, contentChannelPermanentUrl, closeModal, deleteComment, supportAmount } = props;
const {
commentId,
commentIsMine,
contentChannelPermanentUrl,
closeModal,
deleteComment,
supportAmount,
setQuickReply,
} = props;

return (
<Modal isOpen contentLabel={__('Confirm Comment Deletion')} type="card" onAborted={closeModal}>
Expand All @@ -24,7 +33,9 @@ function ModalRemoveComment(props: Props) {
<React.Fragment>
<p>{__('Are you sure you want to remove this comment?')}</p>
{Boolean(supportAmount) && (
<p className="help error__text"> {__('This comment has a tip associated with it which cannot be reverted.')}</p>
<p className="help error__text">
{__('This comment has a tip associated with it which cannot be reverted.')}
</p>
)}
</React.Fragment>
}
Expand All @@ -35,8 +46,9 @@ function ModalRemoveComment(props: Props) {
button="primary"
label={__('Remove')}
onClick={() => {
deleteComment(commentId, commentIsMine ? undefined : contentChannelPermanentUrl);
closeModal();
deleteComment(commentId, commentIsMine ? undefined : contentChannelPermanentUrl);
if (setQuickReply) setQuickReply(undefined);
}}
/>
<Button button="link" label={__('Cancel')} onClick={closeModal} />
Expand Down

0 comments on commit 124a41e

Please sign in to comment.