make notifications deleteable + unsub from the bell on notifications page
This commit is contained in:
parent
a836467714
commit
485a734c9b
11 changed files with 140 additions and 9 deletions
|
@ -1464,7 +1464,7 @@
|
|||
"Your other content language": "Your other content language",
|
||||
"Search only in this language by default": "Search only in this language by default",
|
||||
"This link leads to an external website.": "This link leads to an external website.",
|
||||
"Hold on, we are setting up your account": "Hold on, we are setting up your account",
|
||||
"Please wait a bit, we are still getting your account ready. on, we are setting up your account": "Hold on, we are setting up your account",
|
||||
"No Content Found": "No Content Found",
|
||||
"Publish Something": "Publish Something",
|
||||
"Watch on lbry.tv": "Watch on lbry.tv",
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doSeeNotifications } from 'redux/actions/notifications';
|
||||
import { doSeeNotifications, doDeleteNotification } from 'redux/actions/notifications';
|
||||
import Notification from './view';
|
||||
|
||||
export default connect(null, {
|
||||
doSeeNotifications,
|
||||
doDeleteNotification,
|
||||
})(Notification);
|
||||
|
|
|
@ -9,27 +9,31 @@ import Icon from 'component/common/icon';
|
|||
import DateTime from 'component/dateTime';
|
||||
import Button from 'component/button';
|
||||
import ChannelThumbnail from 'component/channelThumbnail';
|
||||
import { MenuItem } from '@reach/menu-button';
|
||||
import { formatLbryUrlForWeb } from 'util/url';
|
||||
import { useHistory } from 'react-router';
|
||||
import { parseURI } from 'lbry-redux';
|
||||
import { PAGE_VIEW_QUERY, DISCUSSION_PAGE } from 'page/channel/view';
|
||||
import FileThumbnail from 'component/fileThumbnail';
|
||||
import { Menu, MenuList, MenuButton, MenuItem } from '@reach/menu-button';
|
||||
import NotificationContentChannelMenu from 'component/notificationContentChannelMenu';
|
||||
|
||||
type Props = {
|
||||
notification: WebNotification,
|
||||
menuButton: boolean,
|
||||
children: any,
|
||||
doSeeNotifications: ([number]) => void,
|
||||
doDeleteNotification: number => void,
|
||||
};
|
||||
|
||||
export default function Notification(props: Props) {
|
||||
const { notification, menuButton = false, doSeeNotifications } = props;
|
||||
const { notification, menuButton = false, doSeeNotifications, doDeleteNotification } = props;
|
||||
const { push } = useHistory();
|
||||
const { notification_rule, notification_parameters, is_seen, id } = notification;
|
||||
const isCommentNotification =
|
||||
notification_rule === NOTIFICATIONS.NOTIFICATION_COMMENT || notification_rule === NOTIFICATIONS.NOTIFICATION_REPLY;
|
||||
const commentText = isCommentNotification && notification_parameters.dynamic.comment;
|
||||
const channelUrl =
|
||||
(notification_rule === NOTIFICATIONS.NEW_CONTENT && notification.notification_parameters.dynamic.channel_url) || '';
|
||||
|
||||
let notificationTarget;
|
||||
switch (notification_rule) {
|
||||
|
@ -153,12 +157,29 @@ export default function Notification(props: Props) {
|
|||
</div>
|
||||
|
||||
<div className="notification__extra">
|
||||
{!is_seen && <Button className="notification__mark-seen" onClick={handleSeeNotification} />}
|
||||
<div className="notification__time">
|
||||
<DateTime timeAgo date={notification.active_at} />
|
||||
</div>
|
||||
{!is_seen && <Button className="notification__mark-seen" onClick={handleSeeNotification} />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="notification__menu">
|
||||
<Menu>
|
||||
<MenuButton onClick={e => e.stopPropagation()}>
|
||||
<Icon size={18} icon={ICONS.MORE_VERTICAL} />
|
||||
</MenuButton>
|
||||
<MenuList className="menu__list--comments">
|
||||
<MenuItem className="menu__link" onSelect={() => doDeleteNotification(id)}>
|
||||
<Icon aria-hidden icon={ICONS.DELETE} />
|
||||
{__('Delete')}
|
||||
</MenuItem>
|
||||
{notification_rule === NOTIFICATIONS.NEW_CONTENT && channelUrl ? (
|
||||
<NotificationContentChannelMenu uri={channelUrl} />
|
||||
) : null}
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</div>
|
||||
</div>
|
||||
</Wrapper>
|
||||
);
|
||||
|
|
14
ui/component/notificationContentChannelMenu/index.js
Normal file
14
ui/component/notificationContentChannelMenu/index.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doChannelSubscribe } from 'redux/actions/subscriptions';
|
||||
import { doToast } from 'redux/actions/notifications';
|
||||
import { makeSelectNotificationsDisabled } from 'redux/selectors/subscriptions';
|
||||
import SubscribeButton from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
notificationsDisabled: makeSelectNotificationsDisabled(props.uri)(state),
|
||||
});
|
||||
|
||||
export default connect(select, {
|
||||
doChannelSubscribe,
|
||||
doToast,
|
||||
})(SubscribeButton);
|
42
ui/component/notificationContentChannelMenu/view.jsx
Normal file
42
ui/component/notificationContentChannelMenu/view.jsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import React from 'react';
|
||||
import { MenuItem } from '@reach/menu-button';
|
||||
import { parseURI } from 'lbry-redux';
|
||||
import Icon from 'component/common/icon';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
notificationsDisabled: boolean,
|
||||
doToast: ({ message: string }) => void,
|
||||
doChannelSubscribe: Subscription => void,
|
||||
};
|
||||
|
||||
export default function NotificationContentChannelMenu(props: Props) {
|
||||
const { uri, notificationsDisabled, doToast, doChannelSubscribe } = props;
|
||||
const { claimName } = parseURI(uri);
|
||||
|
||||
function handleClick() {
|
||||
doChannelSubscribe({
|
||||
uri,
|
||||
channelName: claimName,
|
||||
notificationsDisabled: !notificationsDisabled,
|
||||
});
|
||||
|
||||
doToast({
|
||||
message: !notificationsDisabled
|
||||
? __('Notifications turned off for %channel%.', { channel: claimName })
|
||||
: __('Notifications turned on for %channel%.', { channel: claimName }),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuItem onSelect={handleClick}>
|
||||
<div className="menu__link">
|
||||
<Icon aria-hidden icon={notificationsDisabled ? ICONS.BELL : ICONS.BELL_ON} />
|
||||
{notificationsDisabled ? __('Turn Back On') : __('Turn Off')}
|
||||
</div>
|
||||
<span className="menu__link-help">{claimName}</span>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
|
@ -94,7 +94,7 @@ export default function SubscribeButton(props: Props) {
|
|||
});
|
||||
|
||||
if (newNotificationsDisabled === false) {
|
||||
doToast({ message: __('Notifications enabled for %channel%!', { channel: claimName }) });
|
||||
doToast({ message: __('Notifications turned on for %channel%!', { channel: claimName }) });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -238,6 +238,9 @@ export const NOTIFICATION_READ_FAILED = 'NOTIFICATION_READ_FAILED';
|
|||
export const NOTIFICATION_SEEN_STARTED = 'NOTIFICATION_SEEN_STARTED';
|
||||
export const NOTIFICATION_SEEN_COMPLETED = 'NOTIFICATION_SEEN_COMPLETED';
|
||||
export const NOTIFICATION_SEEN_FAILED = 'NOTIFICATION_SEEN_FAILED';
|
||||
export const NOTIFICATION_DELETE_STARTED = 'NOTIFICATION_DELETE_STARTED';
|
||||
export const NOTIFICATION_DELETE_COMPLETED = 'NOTIFICATION_DELETE_COMPLETED';
|
||||
export const NOTIFICATION_DELETE_FAILED = 'NOTIFICATION_DELETE_FAILED';
|
||||
export const CREATE_TOAST = 'CREATE_TOAST';
|
||||
export const DISMISS_TOAST = 'DISMISS_TOAST';
|
||||
export const CREATE_ERROR = 'CREATE_ERROR';
|
||||
|
|
|
@ -338,7 +338,7 @@ export function doAlertWaitingForSync() {
|
|||
return dispatch =>
|
||||
dispatch(
|
||||
doToast({
|
||||
message: __('Hold on, we are setting up your account'),
|
||||
message: __('Please wait a bit, we are still getting your account ready.'),
|
||||
isError: false,
|
||||
})
|
||||
);
|
||||
|
|
|
@ -126,3 +126,15 @@ export function doSeeAllNotifications() {
|
|||
dispatch(doSeeNotifications(unSeenNotifications));
|
||||
};
|
||||
}
|
||||
|
||||
export function doDeleteNotification(notificationId: number) {
|
||||
return (dispatch: Dispatch<*>) => {
|
||||
Lbryio.call('notification', 'delete', { notification_ids: notificationId })
|
||||
.then(() => {
|
||||
dispatch({ type: ACTIONS.NOTIFICATION_DELETE_COMPLETED, data: { notificationId } });
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(doToast({ isError: true, message: __('Unable to delete this right now. Please try again later.') }));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -82,6 +82,18 @@ export default handleActions(
|
|||
notifications: newNotifications,
|
||||
};
|
||||
},
|
||||
[ACTIONS.NOTIFICATION_DELETE_COMPLETED]: (state, action) => {
|
||||
const { notifications } = state;
|
||||
const { notificationId } = action.data;
|
||||
const newNotifications = notifications.filter(notification => {
|
||||
return notification.id !== notificationId;
|
||||
});
|
||||
|
||||
return {
|
||||
...state,
|
||||
notifications: newNotifications,
|
||||
};
|
||||
},
|
||||
|
||||
// Errors
|
||||
[ACTIONS.CREATE_ERROR]: (state: NotificationState, action: DoError) => {
|
||||
|
|
|
@ -34,13 +34,14 @@ $contentMaxWidth: 35rem;
|
|||
|
||||
@media (min-width: $breakpoint-small) {
|
||||
align-items: center;
|
||||
margin-left: var(--spacing-m);
|
||||
}
|
||||
}
|
||||
|
||||
.notification__wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
padding: var(--spacing-m);
|
||||
padding: var(--spacing-m) 0;
|
||||
|
||||
.channel-thumbnail {
|
||||
@include handleChannelGif(3rem);
|
||||
|
@ -111,7 +112,7 @@ $contentMaxWidth: 35rem;
|
|||
}
|
||||
|
||||
.notification__text-wrapper {
|
||||
max-width: calc(#{$contentMaxWidth} - (#{$thumbnailWidth} * 16 / 9) - var(--spacing-m)); //25rem;
|
||||
max-width: calc(#{$contentMaxWidth} - (#{$thumbnailWidth} * 16 / 9) - var(--spacing-m));
|
||||
}
|
||||
|
||||
.notification__title {
|
||||
|
@ -179,6 +180,15 @@ $contentMaxWidth: 35rem;
|
|||
.notification__extra {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-right: var(--spacing-m);
|
||||
flex-direction: row-reverse;
|
||||
|
||||
@media (min-width: $breakpoint-small) {
|
||||
margin-left: var(--spacing-s);
|
||||
margin-top: 0;
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.notification__mark-seen {
|
||||
|
@ -193,3 +203,19 @@ $contentMaxWidth: 35rem;
|
|||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.notification__menu {
|
||||
margin-right: var(--spacing-m);
|
||||
|
||||
.icon {
|
||||
stroke: var(--color-text-help);
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: var(--border-radius);
|
||||
|
||||
&:focus {
|
||||
@include linkFocus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue