group comment notifications and clean up notification style

This commit is contained in:
Sean Yesmunt 2020-07-30 16:14:12 -04:00
parent 9fc3d10d4b
commit 9acbdf9825
6 changed files with 99 additions and 13 deletions

View file

@ -1,5 +1,6 @@
[ignore]
.*\.typeface\.json
.*/node_modules/findup/.*
[include]

View file

@ -21,6 +21,8 @@ declare type WebNotification = {
},
dynamic: {
comment_author: string,
hash: string,
claim_title: string,
},
email: {},
},
@ -28,4 +30,5 @@ declare type WebNotification = {
type: string,
updated_at: string,
user_id: number,
group_count?: number,
};

View file

@ -1,4 +1,6 @@
// @flow
import { NOTIFICATION_CREATOR_SUBSCRIBER, NOTIFICATION_COMMENT } from 'constants/notifications';
import * as ICONS from 'constants/icons';
import React from 'react';
import Icon from 'component/common/icon';
@ -14,14 +16,14 @@ type Props = {
children: any,
};
const NOTIFICATION_CREATOR_SUBSCRIBER = 'creator_subscriber';
const NOTIFICATION_COMMENT = 'comment';
export default function Notification(props: Props) {
const { notification, menuButton = false } = props;
const notificationTarget = notification && notification.notification_parameters.device.target;
const notificationLink = formatLbryUrlForWeb(notificationTarget);
const { push } = useHistory();
const notificationTarget = notification && notification.notification_parameters.device.target;
let notificationLink = formatLbryUrlForWeb(notificationTarget);
if (notification.notification_rule === NOTIFICATION_COMMENT && notification.notification_parameters.dynamic.hash) {
notificationLink += `?lc=${notification.notification_parameters.dynamic.hash}`;
}
let icon;
switch (notification.notification_rule) {
@ -29,7 +31,7 @@ export default function Notification(props: Props) {
icon = <Icon icon={ICONS.SUBSCRIBE} sectionIcon className="notification__icon" />;
break;
case NOTIFICATION_COMMENT:
icon = <ChannelThumbnail uri={notification.notification_parameters.dynamic.comment_author} />;
icon = <ChannelThumbnail small uri={notification.notification_parameters.dynamic.comment_author} />;
break;
default:
icon = <Icon icon={ICONS.NOTIFICATION} sectionIcon className="notification__icon" />;
@ -52,8 +54,20 @@ export default function Notification(props: Props) {
<div className="notification__wrapper">
<div className="notification__icon">{icon}</div>
<div className="notification__content">
<div>
{notification.notification_rule !== NOTIFICATION_COMMENT && (
<div className="notification__title">{notification.notification_parameters.device.title}</div>
<div className="notification__text">{notification.notification_parameters.device.text}</div>
)}
<div className="notification__text">
{notification.notification_parameters.device.text.replace(
// This is terrible and will be replaced when I make the comment channel clickable
'commented on',
notification.group_count ? `left ${notification.group_count} comments on` : 'commented on'
)}
</div>
</div>
<div className="notification__time">
<DateTime timeAgo date={notification.created_at} />
</div>

View file

@ -0,0 +1,2 @@
export const NOTIFICATION_CREATOR_SUBSCRIBER = 'creator_subscriber';
export const NOTIFICATION_COMMENT = 'comment';

View file

@ -1,4 +1,5 @@
// @flow
import { NOTIFICATION_COMMENT } from 'constants/notifications';
import React from 'react';
import Page from 'component/page';
import Card from 'component/common/card';
@ -13,6 +14,51 @@ type Props = {
export default function NotificationsPage(props: Props) {
const { notifications, fetching } = props;
// Group sequential comment notifications if they are by the same author
let groupedCount = 1;
const groupedNotifications =
notifications &&
notifications.reduce((list, notification, index) => {
if (index === 0) {
return [notification];
}
const previousNotification = notifications[index - 1];
const isCommentNotification = notification.notification_rule === NOTIFICATION_COMMENT;
const previousIsCommentNotification = previousNotification.notification_rule === NOTIFICATION_COMMENT;
if (isCommentNotification && previousIsCommentNotification) {
const notificationTarget = notification.notification_parameters.device.target;
const previousTarget = previousNotification && previousNotification.notification_parameters.device.target;
const author = notification.notification_parameters.dynamic.comment_author;
const previousAuthor = previousNotification.notification_parameters.dynamic.comment_author;
if (author === previousAuthor && notificationTarget === previousTarget) {
const newList = [...list];
newList.pop();
groupedCount += 1;
const newNotification = {
...previousNotification,
group_count: groupedCount,
};
newList[index - groupedCount] = newNotification;
return newList;
} else {
if (groupedCount > 1) {
groupedCount = 1;
}
return [...list, notification];
}
} else {
if (groupedCount > 1) {
groupedCount = 1;
}
return [...list, notification];
}
}, []);
return (
<Page>
{fetching && (
@ -20,13 +66,17 @@ export default function NotificationsPage(props: Props) {
<Spinner delayed />
</div>
)}
{notifications && notifications.length > 0 ? (
{groupedNotifications && groupedNotifications.length > 0 ? (
<Card
isBodyList
title={__('Notifications')}
body={
<div className="notification_list">
{notifications.map((notification, index) => {
{groupedNotifications.map((notification, index) => {
if (!notification) {
return null;
}
return <Notification key={notification.id} notification={notification} />;
})}
</div>

View file

@ -13,25 +13,41 @@
}
}
.notification__icon {
.icon__wrapper {
margin-right: var(--spacing-m);
}
}
.notification__wrapper {
width: 100%;
display: flex;
.channel-thumbnail {
@include handleChannelGif(3rem);
}
}
.notification__content {
margin-left: var(--spacing-m);
display: flex;
flex: 1;
justify-content: space-between;
align-items: center;
}
.notification__title {
font-size: var(--font-large);
font-size: var(--font-small);
font-weight: bold;
color: var(--color-text);
margin-bottom: var(--spacing-s);
}
.notification__text {
font-size: var(--font-body);
margin-top: var(--spacing-s);
}
.notification__time {
@extend .help;
margin-bottom: 0;
margin-top: 0;
}