769b1cdabb
## Ticket "1742 Notification popup: incorrect target" Commentron uses old links for some of the notification types. ## Change Factored out the code that determines the new target and use it both Notifications Page and Popup Menu.
234 lines
7.9 KiB
JavaScript
234 lines
7.9 KiB
JavaScript
// @flow
|
|
import 'scss/component/_header.scss';
|
|
|
|
import { ENABLE_UI_NOTIFICATIONS } from 'config';
|
|
import { useHistory } from 'react-router';
|
|
import * as ICONS from 'constants/icons';
|
|
import * as PAGES from 'constants/pages';
|
|
import Icon from 'component/common/icon';
|
|
import NotificationBubble from 'component/notificationBubble';
|
|
import React from 'react';
|
|
import Tooltip from 'component/common/tooltip';
|
|
import Notification from 'component/notification';
|
|
import DateTime from 'component/dateTime';
|
|
import ChannelThumbnail from 'component/channelThumbnail';
|
|
import { Menu as MuiMenu } from '@mui/material';
|
|
import Button from 'component/button';
|
|
import ClickAwayListener from '@mui/material/ClickAwayListener';
|
|
import { RULE } from 'constants/notifications';
|
|
import UriIndicator from 'component/uriIndicator';
|
|
import { getNotificationLink } from '../notification/helpers/target';
|
|
import { generateNotificationTitle } from '../notification/helpers/title';
|
|
import { generateNotificationText } from '../notification/helpers/text';
|
|
import { parseURI } from 'util/lbryURI';
|
|
import { NavLink } from 'react-router-dom';
|
|
|
|
type Props = {
|
|
notifications: Array<Notification>,
|
|
unseenCount: number,
|
|
user: ?User,
|
|
authenticated: boolean,
|
|
readNotification: (Array<number>) => void,
|
|
seeNotification: (Array<number>) => void,
|
|
deleteNotification: (number) => void,
|
|
doSeeAllNotifications: () => void,
|
|
};
|
|
|
|
export default function NotificationHeaderButton(props: Props) {
|
|
const {
|
|
notifications,
|
|
unseenCount,
|
|
user,
|
|
authenticated,
|
|
readNotification,
|
|
seeNotification,
|
|
deleteNotification,
|
|
doSeeAllNotifications,
|
|
} = props;
|
|
const list = notifications.slice(0, 20);
|
|
const { push } = useHistory();
|
|
const notificationsEnabled = authenticated && (ENABLE_UI_NOTIFICATIONS || (user && user.experimental_ui));
|
|
|
|
const [anchorEl, setAnchorEl] = React.useState(null);
|
|
const [clicked, setClicked] = React.useState(false);
|
|
const open = Boolean(anchorEl);
|
|
const handleClick = (event) => {
|
|
doSeeAllNotifications();
|
|
if (unseenCount > 0) doSeeAllNotifications();
|
|
setAnchorEl(!anchorEl ? event.currentTarget : null);
|
|
};
|
|
const handleClose = () => setAnchorEl(null);
|
|
|
|
const menuProps = {
|
|
id: 'notification-menu',
|
|
anchorEl,
|
|
open,
|
|
onClose: handleClose,
|
|
MenuListProps: {
|
|
'aria-labelledby': 'basic-button',
|
|
sx: { padding: 'var(--spacing-xs)' },
|
|
},
|
|
className: 'menu__list--header menu__list--notifications',
|
|
sx: { 'z-index': 2 },
|
|
PaperProps: { className: 'MuiMenu-list--paper' },
|
|
disableScrollLock: true,
|
|
};
|
|
|
|
const handleClickAway = () => {
|
|
if (!clicked) {
|
|
if (open) setClicked(true);
|
|
} else {
|
|
setAnchorEl(null);
|
|
setClicked(false);
|
|
}
|
|
};
|
|
|
|
const creatorIcon = (channelUrl, channelThumbnail) => (
|
|
<UriIndicator uri={channelUrl} link showAtSign channelInfo={{ uri: channelUrl, name: '' }}>
|
|
<ChannelThumbnail small thumbnailPreview={channelThumbnail} uri={channelThumbnail ? undefined : channelUrl} />
|
|
</UriIndicator>
|
|
);
|
|
|
|
function handleMenuClick() {
|
|
push(`/$/${PAGES.NOTIFICATIONS}`);
|
|
}
|
|
|
|
function handleNotificationDelete(e, id) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
deleteNotification(id);
|
|
}
|
|
|
|
React.useEffect(() => {
|
|
if (!open) setClicked(false);
|
|
}, [open]);
|
|
|
|
if (!notificationsEnabled) return null;
|
|
|
|
function handleNotificationClick(notification) {
|
|
const { id, is_read } = notification;
|
|
|
|
if (!is_read) {
|
|
seeNotification([id]);
|
|
readNotification([id]);
|
|
}
|
|
|
|
push(getNotificationLink(notification));
|
|
}
|
|
|
|
function getWebUri(notification) {
|
|
return getNotificationLink(notification);
|
|
}
|
|
|
|
function menuEntry(notification) {
|
|
const { id, active_at, notification_rule, notification_parameters, is_read, type } = notification;
|
|
|
|
let channelUrl;
|
|
let icon;
|
|
switch (notification_rule) {
|
|
case RULE.CREATOR_SUBSCRIBER:
|
|
icon = <Icon icon={ICONS.SUBSCRIBE} sectionIcon />;
|
|
break;
|
|
case RULE.COMMENT:
|
|
case RULE.CREATOR_COMMENT:
|
|
channelUrl = notification_parameters.dynamic.comment_author;
|
|
icon = creatorIcon(channelUrl, notification_parameters?.dynamic?.comment_author_thumbnail);
|
|
break;
|
|
case RULE.COMMENT_REPLY:
|
|
channelUrl = notification_parameters.dynamic.reply_author;
|
|
icon = creatorIcon(channelUrl, notification_parameters?.dynamic?.comment_author_thumbnail);
|
|
break;
|
|
case RULE.NEW_CONTENT:
|
|
channelUrl = notification_parameters.dynamic.channel_url;
|
|
icon = creatorIcon(channelUrl, notification_parameters?.dynamic?.channel_thumbnail);
|
|
break;
|
|
case RULE.NEW_LIVESTREAM:
|
|
channelUrl = notification_parameters.dynamic.channel_url;
|
|
icon = creatorIcon(channelUrl, notification_parameters?.dynamic?.channel_thumbnail);
|
|
break;
|
|
case RULE.WEEKLY_WATCH_REMINDER:
|
|
case RULE.DAILY_WATCH_AVAILABLE:
|
|
case RULE.DAILY_WATCH_REMIND:
|
|
case RULE.MISSED_OUT:
|
|
case RULE.REWARDS_APPROVAL_PROMPT:
|
|
icon = <Icon icon={ICONS.LBC} sectionIcon />;
|
|
break;
|
|
case RULE.FIAT_TIP:
|
|
icon = <Icon icon={ICONS.FINANCE} sectionIcon />;
|
|
break;
|
|
default:
|
|
icon = <Icon icon={ICONS.NOTIFICATION} sectionIcon />;
|
|
}
|
|
|
|
let channelName;
|
|
if (channelUrl) {
|
|
try {
|
|
({ claimName: channelName } = parseURI(channelUrl));
|
|
} catch (e) {}
|
|
}
|
|
|
|
return (
|
|
<NavLink onClick={() => handleNotificationClick(notification)} key={id} to={getWebUri(notification)}>
|
|
<div
|
|
className={is_read ? 'menu__list--notification' : 'menu__list--notification menu__list--notification-unread'}
|
|
key={id}
|
|
>
|
|
<div className="notification__icon">{icon}</div>
|
|
<div className="menu__list--notification-info">
|
|
<div className="menu__list--notification-type">
|
|
{generateNotificationTitle(notification_rule, notification_parameters, channelName)}
|
|
</div>
|
|
<div
|
|
className={
|
|
type === 'comments' ? 'menu__list--notification-title blockquote' : 'menu__list--notification-title'
|
|
}
|
|
>
|
|
{generateNotificationText(notification_rule, notification_parameters)}
|
|
</div>
|
|
{!is_read && <span className="dot">•</span>}
|
|
<DateTime timeAgo date={active_at} />
|
|
</div>
|
|
<div className="delete-notification" onClick={(e) => handleNotificationDelete(e, id)}>
|
|
<Icon icon={ICONS.DELETE} sectionIcon />
|
|
</div>
|
|
</div>
|
|
</NavLink>
|
|
);
|
|
}
|
|
|
|
return (
|
|
notificationsEnabled && (
|
|
<>
|
|
<Tooltip title={__('Notifications')}>
|
|
<Button className="header__navigationItem--icon" onClick={handleClick}>
|
|
<Icon size={18} icon={ICONS.NOTIFICATION} aria-hidden />
|
|
<NotificationBubble />
|
|
</Button>
|
|
</Tooltip>
|
|
|
|
<ClickAwayListener onClickAway={handleClickAway}>
|
|
<MuiMenu {...menuProps}>
|
|
<div className="menu__list--notifications-header" />
|
|
<div className="menu__list--notifications-list">
|
|
{list.map((notification) => {
|
|
return menuEntry(notification);
|
|
})}
|
|
{list.length === 0 && (
|
|
<div className="menu__list--notification-empty">
|
|
<div className="menu__list--notification-empty-title">{__('No notifications')}</div>
|
|
<div className="menu__list--notification-empty-text">
|
|
{__("You don't have any notifications yet, but they will be here when you do!")}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<NavLink onClick={handleMenuClick} to={`/$/${PAGES.NOTIFICATIONS}`}>
|
|
<div className="menu__list--notifications-more">{__('View all')}</div>
|
|
</NavLink>
|
|
</MuiMenu>
|
|
</ClickAwayListener>
|
|
</>
|
|
)
|
|
);
|
|
}
|