group comment notifications and clean up notification style
This commit is contained in:
parent
9fc3d10d4b
commit
9acbdf9825
6 changed files with 99 additions and 13 deletions
|
@ -1,5 +1,6 @@
|
||||||
[ignore]
|
[ignore]
|
||||||
.*\.typeface\.json
|
.*\.typeface\.json
|
||||||
|
.*/node_modules/findup/.*
|
||||||
|
|
||||||
[include]
|
[include]
|
||||||
|
|
||||||
|
|
3
flow-typed/notification.js
vendored
3
flow-typed/notification.js
vendored
|
@ -21,6 +21,8 @@ declare type WebNotification = {
|
||||||
},
|
},
|
||||||
dynamic: {
|
dynamic: {
|
||||||
comment_author: string,
|
comment_author: string,
|
||||||
|
hash: string,
|
||||||
|
claim_title: string,
|
||||||
},
|
},
|
||||||
email: {},
|
email: {},
|
||||||
},
|
},
|
||||||
|
@ -28,4 +30,5 @@ declare type WebNotification = {
|
||||||
type: string,
|
type: string,
|
||||||
updated_at: string,
|
updated_at: string,
|
||||||
user_id: number,
|
user_id: number,
|
||||||
|
group_count?: number,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import { NOTIFICATION_CREATOR_SUBSCRIBER, NOTIFICATION_COMMENT } from 'constants/notifications';
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
|
@ -14,14 +16,14 @@ type Props = {
|
||||||
children: any,
|
children: any,
|
||||||
};
|
};
|
||||||
|
|
||||||
const NOTIFICATION_CREATOR_SUBSCRIBER = 'creator_subscriber';
|
|
||||||
const NOTIFICATION_COMMENT = 'comment';
|
|
||||||
|
|
||||||
export default function Notification(props: Props) {
|
export default function Notification(props: Props) {
|
||||||
const { notification, menuButton = false } = props;
|
const { notification, menuButton = false } = props;
|
||||||
const notificationTarget = notification && notification.notification_parameters.device.target;
|
|
||||||
const notificationLink = formatLbryUrlForWeb(notificationTarget);
|
|
||||||
const { push } = useHistory();
|
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;
|
let icon;
|
||||||
switch (notification.notification_rule) {
|
switch (notification.notification_rule) {
|
||||||
|
@ -29,7 +31,7 @@ export default function Notification(props: Props) {
|
||||||
icon = <Icon icon={ICONS.SUBSCRIBE} sectionIcon className="notification__icon" />;
|
icon = <Icon icon={ICONS.SUBSCRIBE} sectionIcon className="notification__icon" />;
|
||||||
break;
|
break;
|
||||||
case NOTIFICATION_COMMENT:
|
case NOTIFICATION_COMMENT:
|
||||||
icon = <ChannelThumbnail uri={notification.notification_parameters.dynamic.comment_author} />;
|
icon = <ChannelThumbnail small uri={notification.notification_parameters.dynamic.comment_author} />;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
icon = <Icon icon={ICONS.NOTIFICATION} sectionIcon className="notification__icon" />;
|
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__wrapper">
|
||||||
<div className="notification__icon">{icon}</div>
|
<div className="notification__icon">{icon}</div>
|
||||||
<div className="notification__content">
|
<div className="notification__content">
|
||||||
<div className="notification__title">{notification.notification_parameters.device.title}</div>
|
<div>
|
||||||
<div className="notification__text">{notification.notification_parameters.device.text}</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.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">
|
<div className="notification__time">
|
||||||
<DateTime timeAgo date={notification.created_at} />
|
<DateTime timeAgo date={notification.created_at} />
|
||||||
</div>
|
</div>
|
||||||
|
|
2
ui/constants/notifications.js
Normal file
2
ui/constants/notifications.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export const NOTIFICATION_CREATOR_SUBSCRIBER = 'creator_subscriber';
|
||||||
|
export const NOTIFICATION_COMMENT = 'comment';
|
|
@ -1,4 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
import { NOTIFICATION_COMMENT } from 'constants/notifications';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import Card from 'component/common/card';
|
import Card from 'component/common/card';
|
||||||
|
@ -13,6 +14,51 @@ type Props = {
|
||||||
export default function NotificationsPage(props: Props) {
|
export default function NotificationsPage(props: Props) {
|
||||||
const { notifications, fetching } = 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 (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
{fetching && (
|
{fetching && (
|
||||||
|
@ -20,13 +66,17 @@ export default function NotificationsPage(props: Props) {
|
||||||
<Spinner delayed />
|
<Spinner delayed />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{notifications && notifications.length > 0 ? (
|
{groupedNotifications && groupedNotifications.length > 0 ? (
|
||||||
<Card
|
<Card
|
||||||
isBodyList
|
isBodyList
|
||||||
title={__('Notifications')}
|
title={__('Notifications')}
|
||||||
body={
|
body={
|
||||||
<div className="notification_list">
|
<div className="notification_list">
|
||||||
{notifications.map((notification, index) => {
|
{groupedNotifications.map((notification, index) => {
|
||||||
|
if (!notification) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return <Notification key={notification.id} notification={notification} />;
|
return <Notification key={notification.id} notification={notification} />;
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,25 +13,41 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notification__icon {
|
||||||
|
.icon__wrapper {
|
||||||
|
margin-right: var(--spacing-m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.notification__wrapper {
|
.notification__wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
.channel-thumbnail {
|
||||||
|
@include handleChannelGif(3rem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification__content {
|
.notification__content {
|
||||||
margin-left: var(--spacing-m);
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification__title {
|
.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 {
|
.notification__text {
|
||||||
font-size: var(--font-body);
|
font-size: var(--font-body);
|
||||||
margin-top: var(--spacing-s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification__time {
|
.notification__time {
|
||||||
@extend .help;
|
@extend .help;
|
||||||
|
margin-bottom: 0;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue