Compare commits
5 commits
master
...
feat-resto
Author | SHA1 | Date | |
---|---|---|---|
|
e7fca1b911 | ||
|
aba062ae43 | ||
|
deb3d5bdc3 | ||
|
43dcb39045 | ||
|
f532aa2566 |
25 changed files with 516 additions and 138 deletions
1
flow-typed/Claim.js
vendored
1
flow-typed/Claim.js
vendored
|
@ -67,6 +67,7 @@ declare type GenericMetadata = {
|
||||||
languages?: Array<string>,
|
languages?: Array<string>,
|
||||||
tags?: Array<string>,
|
tags?: Array<string>,
|
||||||
locations?: Array<Location>,
|
locations?: Array<Location>,
|
||||||
|
release_time?: number, // this shouldn't be here, but... fixme?
|
||||||
};
|
};
|
||||||
|
|
||||||
declare type ChannelMetadata = GenericMetadata & {
|
declare type ChannelMetadata = GenericMetadata & {
|
||||||
|
|
3
flow-typed/subscription.js
vendored
3
flow-typed/subscription.js
vendored
|
@ -16,4 +16,7 @@ declare type SubscriptionState = {
|
||||||
following: Array<Following>,
|
following: Array<Following>,
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
firstRunCompleted: boolean,
|
firstRunCompleted: boolean,
|
||||||
|
downloadEnabledByUrl: any,
|
||||||
|
downloadQueue: Array<string>,
|
||||||
|
lastReleaseBySubUrl: any,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2054,4 +2054,28 @@ export const icons = {
|
||||||
<path d="M12.5,23.24v-1A10.74,10.74,0,0,1,23.24,11.52" />
|
<path d="M12.5,23.24v-1A10.74,10.74,0,0,1,23.24,11.52" />
|
||||||
</g>
|
</g>
|
||||||
),
|
),
|
||||||
|
[ICONS.HOST]: buildIcon(
|
||||||
|
<g>
|
||||||
|
<path d="M9 22.5 12 9l3 13.5" />
|
||||||
|
<circle cx={12} cy={7.657} r={1.25} />
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M4 7.657c0-2.21.895-4.21 2.343-5.657l1.06 1.06A6.48 6.48 0 0 0 5.5 7.658a6.48 6.48 0 0 0 1.904 4.596l-1.06 1.06A7.975 7.975 0 0 1 4 7.658Zm13.657 5.657A7.975 7.975 0 0 0 20 7.657c0-2.21-.895-4.21-2.343-5.657l-1.06 1.06A6.48 6.48 0 0 1 18.5 7.658a6.48 6.48 0 0 1-1.904 4.596l1.06 1.06Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M7 7.657c0-1.38.56-2.63 1.464-3.536l1.061 1.061A3.49 3.49 0 0 0 8.5 7.657c0 .966.392 1.841 1.025 2.475l-1.06 1.06A4.984 4.984 0 0 1 7 7.657Zm8.536 3.535A4.984 4.984 0 0 0 17 7.657c0-1.38-.56-2.63-1.464-3.536l-1.061 1.061A3.49 3.49 0 0 1 15.5 7.657a3.49 3.49 0 0 1-1.025 2.475l1.06 1.06Z"
|
||||||
|
/>
|
||||||
|
<path d="M2 22h20" />
|
||||||
|
</g>
|
||||||
|
),
|
||||||
|
[ICONS.NO_HOST]: buildIcon(
|
||||||
|
<g>
|
||||||
|
<path d="M9 22.5 12 9l3 13.5" />
|
||||||
|
<circle cx={12} cy={7.657} r={1.25} />
|
||||||
|
<path d="M2 22h20" />
|
||||||
|
</g>
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
// @flow
|
// @flow
|
||||||
// import 'scss/component/_header.scss'; // ody codesplits this; no.
|
|
||||||
|
|
||||||
import { ENABLE_UI_NOTIFICATIONS } from 'config';
|
|
||||||
import { Menu, MenuList, MenuButton, MenuItem } from '@reach/menu-button';
|
import { Menu, MenuList, MenuButton, MenuItem } from '@reach/menu-button';
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import * as PAGES from 'constants/pages';
|
import * as PAGES from 'constants/pages';
|
||||||
|
@ -15,14 +12,11 @@ type HeaderMenuButtonProps = {
|
||||||
authenticated: boolean,
|
authenticated: boolean,
|
||||||
automaticDarkModeEnabled: boolean,
|
automaticDarkModeEnabled: boolean,
|
||||||
currentTheme: string,
|
currentTheme: string,
|
||||||
user: ?User,
|
|
||||||
handleThemeToggle: (boolean, string) => void,
|
handleThemeToggle: (boolean, string) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function HeaderMenuButtons(props: HeaderMenuButtonProps) {
|
export default function HeaderMenuButtons(props: HeaderMenuButtonProps) {
|
||||||
const { automaticDarkModeEnabled, currentTheme, user, handleThemeToggle } = props;
|
const { automaticDarkModeEnabled, currentTheme, handleThemeToggle } = props;
|
||||||
|
|
||||||
const notificationsEnabled = ENABLE_UI_NOTIFICATIONS || (user && user.experimental_ui);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="header__buttons">
|
<div className="header__buttons">
|
||||||
|
@ -39,7 +33,7 @@ export default function HeaderMenuButtons(props: HeaderMenuButtonProps) {
|
||||||
</MenuList>
|
</MenuList>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
{notificationsEnabled && <NotificationHeaderButton />}
|
<NotificationHeaderButton />
|
||||||
|
|
||||||
<Menu>
|
<Menu>
|
||||||
<Tooltip title={__('Settings')}>
|
<Tooltip title={__('Settings')}>
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectUnseenNotificationCount } from 'redux/selectors/notifications';
|
import { selectUnseenNotificationCount, selectUnseenLocalNotificationCount } from 'redux/selectors/notifications';
|
||||||
import { doSeeAllNotifications } from 'redux/actions/notifications';
|
import { doLbryioSeeAllNotifications, doLocalSeeAllNotifications } from 'redux/actions/notifications';
|
||||||
import { selectUser } from 'redux/selectors/user';
|
import { selectUser } from 'redux/selectors/user';
|
||||||
import NotificationHeaderButton from './view';
|
import NotificationHeaderButton from './view';
|
||||||
|
|
||||||
const select = (state) => ({
|
const select = (state) => ({
|
||||||
unseenCount: selectUnseenNotificationCount(state),
|
unseenCount: selectUnseenNotificationCount(state),
|
||||||
|
unseenLocalCount: selectUnseenLocalNotificationCount(state),
|
||||||
user: selectUser(state),
|
user: selectUser(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, {
|
export default connect(select, {
|
||||||
doSeeAllNotifications,
|
doLbryioSeeAllNotifications,
|
||||||
|
doLocalSeeAllNotifications,
|
||||||
})(NotificationHeaderButton);
|
})(NotificationHeaderButton);
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
// @flow
|
// @flow
|
||||||
// import 'scss/component/_header.scss'; // ody codesplits this; no. REMOVE THESE
|
|
||||||
|
|
||||||
import { ENABLE_UI_NOTIFICATIONS } from 'config';
|
|
||||||
import { useHistory } from 'react-router';
|
import { useHistory } from 'react-router';
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import * as PAGES from 'constants/pages';
|
import * as PAGES from 'constants/pages';
|
||||||
|
@ -13,23 +10,22 @@ import Tooltip from 'component/common/tooltip';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
unseenCount: number,
|
unseenCount: number,
|
||||||
user: ?User,
|
unseenLocalCount: number,
|
||||||
doSeeAllNotifications: () => void,
|
doLbryioSeeAllNotifications: () => void,
|
||||||
|
doLocalSeeAllNotifications: () => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function NotificationHeaderButton(props: Props) {
|
export default function NotificationHeaderButton(props: Props) {
|
||||||
const { unseenCount, user, doSeeAllNotifications } = props;
|
const { unseenCount, unseenLocalCount, doLbryioSeeAllNotifications, doLocalSeeAllNotifications } = props;
|
||||||
|
|
||||||
const { push } = useHistory();
|
const { push } = useHistory();
|
||||||
const notificationsEnabled = ENABLE_UI_NOTIFICATIONS || (user && user.experimental_ui);
|
|
||||||
|
|
||||||
function handleMenuClick() {
|
function handleMenuClick() {
|
||||||
if (unseenCount > 0) doSeeAllNotifications();
|
if (unseenCount > 0) doLbryioSeeAllNotifications();
|
||||||
|
if (unseenLocalCount > 0) doLocalSeeAllNotifications();
|
||||||
push(`/$/${PAGES.NOTIFICATIONS}`);
|
push(`/$/${PAGES.NOTIFICATIONS}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!notificationsEnabled) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip title={__('Notifications')}>
|
<Tooltip title={__('Notifications')}>
|
||||||
<Button onClick={handleMenuClick} className="header__navigationItem--icon">
|
<Button onClick={handleMenuClick} className="header__navigationItem--icon">
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doReadNotifications, doDeleteNotification } from 'redux/actions/notifications';
|
import {
|
||||||
|
doLbryioNotificationsMarkRead,
|
||||||
|
doLbryioDeleteNotification,
|
||||||
|
doLocalDeleteNotification,
|
||||||
|
} from 'redux/actions/notifications';
|
||||||
import Notification from './view';
|
import Notification from './view';
|
||||||
|
|
||||||
const perform = (dispatch, ownProps) => ({
|
const perform = (dispatch, ownProps) => ({
|
||||||
readNotification: () => dispatch(doReadNotifications([ownProps.notification.id])),
|
readNotification: () => dispatch(doLbryioNotificationsMarkRead([ownProps.notification.id])),
|
||||||
deleteNotification: () => dispatch(doDeleteNotification(ownProps.notification.id)),
|
deleteNotification: () => dispatch(doLbryioDeleteNotification(ownProps.notification.id)),
|
||||||
|
deleteLocalNotification: () => dispatch(doLocalDeleteNotification(ownProps.notification.id)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(null, perform)(Notification);
|
export default connect(null, perform)(Notification);
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { parseURI } from 'util/lbryURI';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import useHover from 'effects/use-hover';
|
import useHover from 'effects/use-hover';
|
||||||
import { useIsMobile } from 'effects/use-screensize';
|
import { useIsMobile } from 'effects/use-screensize';
|
||||||
import { ENABLE_UI_NOTIFICATIONS } from 'config';
|
|
||||||
|
|
||||||
type SubscriptionArgs = {
|
type SubscriptionArgs = {
|
||||||
channelName: string,
|
channelName: string,
|
||||||
|
@ -34,7 +33,6 @@ export default function SubscribeButton(props: Props) {
|
||||||
doToast,
|
doToast,
|
||||||
shrinkOnMobile = false,
|
shrinkOnMobile = false,
|
||||||
notificationsDisabled,
|
notificationsDisabled,
|
||||||
user,
|
|
||||||
uri,
|
uri,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
@ -42,7 +40,6 @@ export default function SubscribeButton(props: Props) {
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
let isHovering = useHover(buttonRef);
|
let isHovering = useHover(buttonRef);
|
||||||
isHovering = isMobile ? true : isHovering;
|
isHovering = isMobile ? true : isHovering;
|
||||||
const uiNotificationsEnabled = (user && user.experimental_ui) || ENABLE_UI_NOTIFICATIONS;
|
|
||||||
|
|
||||||
const { channelName: rawChannelName } = parseURI(uri);
|
const { channelName: rawChannelName } = parseURI(uri);
|
||||||
|
|
||||||
|
@ -119,7 +116,7 @@ export default function SubscribeButton(props: Props) {
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{isSubscribed && uiNotificationsEnabled && (
|
{isSubscribed && (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
button="alt"
|
button="alt"
|
||||||
|
|
|
@ -324,10 +324,11 @@ export const HAS_FETCHED_SUBSCRIPTIONS = 'HAS_FETCHED_SUBSCRIPTIONS';
|
||||||
export const CHECK_SUBSCRIPTION_STARTED = 'CHECK_SUBSCRIPTION_STARTED';
|
export const CHECK_SUBSCRIPTION_STARTED = 'CHECK_SUBSCRIPTION_STARTED';
|
||||||
export const CHECK_SUBSCRIPTION_COMPLETED = 'CHECK_SUBSCRIPTION_COMPLETED';
|
export const CHECK_SUBSCRIPTION_COMPLETED = 'CHECK_SUBSCRIPTION_COMPLETED';
|
||||||
export const CHECK_SUBSCRIPTIONS_SUBSCRIBE = 'CHECK_SUBSCRIPTIONS_SUBSCRIBE';
|
export const CHECK_SUBSCRIPTIONS_SUBSCRIBE = 'CHECK_SUBSCRIPTIONS_SUBSCRIBE';
|
||||||
export const FETCH_SUBSCRIPTIONS_START = 'FETCH_SUBSCRIPTIONS_START';
|
|
||||||
export const FETCH_SUBSCRIPTIONS_FAIL = 'FETCH_SUBSCRIPTIONS_FAIL';
|
|
||||||
export const FETCH_SUBSCRIPTIONS_SUCCESS = 'FETCH_SUBSCRIPTIONS_SUCCESS';
|
|
||||||
export const SET_VIEW_MODE = 'SET_VIEW_MODE';
|
export const SET_VIEW_MODE = 'SET_VIEW_MODE';
|
||||||
|
export const SUBSCRIPTION_DOWNLOAD_ADD = 'SUBSCRIPTION_DOWNLOAD_ADD';
|
||||||
|
export const SUBSCRIPTION_DOWNLOAD_REMOVE = 'SUBSCRIPTION_DOWNLOAD_REMOVE';
|
||||||
|
export const SUBSCRIPTION_RELEASE_UPDATE = 'SUBSCRIPTION_RELEASE_UPDATE';
|
||||||
|
export const SUBSCRIPTION_DOWNLOAD_TOGGLE = 'SUBSCRIPTION_DOWNLOAD_TOGGLE';
|
||||||
|
|
||||||
// Publishing
|
// Publishing
|
||||||
export const CLEAR_PUBLISH = 'CLEAR_PUBLISH';
|
export const CLEAR_PUBLISH = 'CLEAR_PUBLISH';
|
||||||
|
@ -344,19 +345,23 @@ export const MEDIA_PLAY = 'MEDIA_PLAY';
|
||||||
export const MEDIA_PAUSE = 'MEDIA_PAUSE';
|
export const MEDIA_PAUSE = 'MEDIA_PAUSE';
|
||||||
|
|
||||||
// Notifications
|
// Notifications
|
||||||
export const NOTIFICATION_LIST_STARTED = 'NOTIFICATION_LIST_STARTED';
|
export const LBRYIO_NOTIFICATION_LIST_STARTED = 'NOTIFICATION_LIST_STARTED';
|
||||||
export const NOTIFICATION_LIST_COMPLETED = 'NOTIFICATION_LIST_COMPLETED';
|
export const LBRYIO_NOTIFICATION_LIST_COMPLETED = 'NOTIFICATION_LIST_COMPLETED';
|
||||||
export const NOTIFICATION_LIST_FAILED = 'NOTIFICATION_LIST_FAILED';
|
export const LBRYIO_NOTIFICATION_LIST_FAILED = 'NOTIFICATION_LIST_FAILED';
|
||||||
export const NOTIFICATION_CATEGORIES_COMPLETED = 'NOTIFICATION_CATEGORIES_COMPLETED';
|
export const LBRYIO_NOTIFICATION_CATEGORIES_COMPLETED = 'LBRYIO_NOTIFICATION_CATEGORIES_COMPLETED';
|
||||||
export const NOTIFICATION_READ_STARTED = 'NOTIFICATION_READ_STARTED';
|
export const LBRYIO_NOTIFICATION_READ_STARTED = 'LBRYIO_NOTIFICATION_READ_STARTED';
|
||||||
export const NOTIFICATION_READ_COMPLETED = 'NOTIFICATION_READ_COMPLETED';
|
export const LBRYIO_NOTIFICATION_READ_COMPLETED = 'LBRYIO_NOTIFICATION_READ_COMPLETED';
|
||||||
export const NOTIFICATION_READ_FAILED = 'NOTIFICATION_READ_FAILED';
|
export const LBRYIO_NOTIFICATION_READ_FAILED = 'LBRYIO_NOTIFICATION_READ_FAILED';
|
||||||
export const NOTIFICATION_SEEN_STARTED = 'NOTIFICATION_SEEN_STARTED';
|
export const LBRYIO_NOTIFICATION_SEEN_STARTED = 'LBRYIO_NOTIFICATION_SEEN_STARTED';
|
||||||
export const NOTIFICATION_SEEN_COMPLETED = 'NOTIFICATION_SEEN_COMPLETED';
|
export const LBRYIO_NOTIFICATION_SEEN_COMPLETED = 'LBRYIO_NOTIFICATION_SEEN_COMPLETED';
|
||||||
export const NOTIFICATION_SEEN_FAILED = 'NOTIFICATION_SEEN_FAILED';
|
export const LBRYIO_NOTIFICATION_SEEN_FAILED = 'LBRYIO_NOTIFICATION_SEEN_FAILED';
|
||||||
export const NOTIFICATION_DELETE_STARTED = 'NOTIFICATION_DELETE_STARTED';
|
export const LBRYIO_NOTIFICATION_DELETE_STARTED = 'LBRYIO_NOTIFICATION_DELETE_STARTED';
|
||||||
export const NOTIFICATION_DELETE_COMPLETED = 'NOTIFICATION_DELETE_COMPLETED';
|
export const LBRYIO_NOTIFICATION_DELETE_COMPLETED = 'LBRYIO_NOTIFICATION_DELETE_COMPLETED';
|
||||||
export const NOTIFICATION_DELETE_FAILED = 'NOTIFICATION_DELETE_FAILED';
|
export const LBRYIO_NOTIFICATION_DELETE_FAILED = 'LBRYIO_NOTIFICATION_DELETE_FAILED';
|
||||||
|
export const LOCAL_NOTIFICATION_DELETE = 'LBRYIO_NOTIFICATION_DELETE';
|
||||||
|
export const LOCAL_NOTIFICATION_ADD = 'LBRYIO_NOTIFICATION_ADD';
|
||||||
|
export const LOCAL_NOTIFICATION_SEEN = 'LBRYIO_NOTIFICATION_SEEN';
|
||||||
|
|
||||||
export const CREATE_TOAST = 'CREATE_TOAST';
|
export const CREATE_TOAST = 'CREATE_TOAST';
|
||||||
export const DISMISS_TOAST = 'DISMISS_TOAST';
|
export const DISMISS_TOAST = 'DISMISS_TOAST';
|
||||||
export const CREATE_ERROR = 'CREATE_ERROR';
|
export const CREATE_ERROR = 'CREATE_ERROR';
|
||||||
|
|
|
@ -186,3 +186,5 @@ export const MYSTERIES = 'Mysteries';
|
||||||
export const TECHNOLOGY = 'Technology';
|
export const TECHNOLOGY = 'Technology';
|
||||||
export const EMOJI = 'Emoji';
|
export const EMOJI = 'Emoji';
|
||||||
export const STICKER = 'Sticker';
|
export const STICKER = 'Sticker';
|
||||||
|
export const HOST = 'Host';
|
||||||
|
export const NO_HOST = 'NoHost';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import * as PAGES from 'constants/pages';
|
import * as PAGES from 'constants/pages';
|
||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import { parseURI } from 'util/lbryURI';
|
import { parseURI } from 'util/lbryURI';
|
||||||
import { YOUTUBE_STATUSES } from 'lbryinc';
|
import { YOUTUBE_STATUSES } from 'lbryinc';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
|
@ -36,6 +36,7 @@ const PAGE = {
|
||||||
ABOUT: 'about',
|
ABOUT: 'about',
|
||||||
DISCUSSION: DISCUSSION_PAGE,
|
DISCUSSION: DISCUSSION_PAGE,
|
||||||
EDIT: 'edit',
|
EDIT: 'edit',
|
||||||
|
SUBSCRIPTION: 'subscription',
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -159,6 +160,9 @@ function ChannelPage(props: Props) {
|
||||||
case PAGE.DISCUSSION:
|
case PAGE.DISCUSSION:
|
||||||
tabIndex = 3;
|
tabIndex = 3;
|
||||||
break;
|
break;
|
||||||
|
case PAGE.SUBSCRIPTION:
|
||||||
|
tabIndex = 4;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
tabIndex = 0;
|
tabIndex = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -174,8 +178,10 @@ function ChannelPage(props: Props) {
|
||||||
search += `${PAGE_VIEW_QUERY}=${PAGE.LISTS}`;
|
search += `${PAGE_VIEW_QUERY}=${PAGE.LISTS}`;
|
||||||
} else if (newTabIndex === 2) {
|
} else if (newTabIndex === 2) {
|
||||||
search += `${PAGE_VIEW_QUERY}=${PAGE.ABOUT}`;
|
search += `${PAGE_VIEW_QUERY}=${PAGE.ABOUT}`;
|
||||||
} else {
|
} else if (newTabIndex === 3) {
|
||||||
search += `${PAGE_VIEW_QUERY}=${PAGE.DISCUSSION}`;
|
search += `${PAGE_VIEW_QUERY}=${PAGE.DISCUSSION}`;
|
||||||
|
} else {
|
||||||
|
search += `${PAGE_VIEW_QUERY}=${PAGE.SUBSCRIPTION}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
push(`${url}${search}`);
|
push(`${url}${search}`);
|
||||||
|
|
|
@ -9,8 +9,13 @@ import {
|
||||||
} from 'redux/selectors/notifications';
|
} from 'redux/selectors/notifications';
|
||||||
import { doCommentReactList } from 'redux/actions/comments';
|
import { doCommentReactList } from 'redux/actions/comments';
|
||||||
import { selectActiveChannelClaim } from 'redux/selectors/app';
|
import { selectActiveChannelClaim } from 'redux/selectors/app';
|
||||||
import { doReadNotifications, doNotificationList, doSeeAllNotifications } from 'redux/actions/notifications';
|
import {
|
||||||
|
doLbryioNotificationsMarkRead,
|
||||||
|
doLbryioNotificationList,
|
||||||
|
doLbryioSeeAllNotifications,
|
||||||
|
} from 'redux/actions/notifications';
|
||||||
import NotificationsPage from './view';
|
import NotificationsPage from './view';
|
||||||
|
import { selectUser } from 'redux/selectors/user';
|
||||||
|
|
||||||
const select = (state) => ({
|
const select = (state) => ({
|
||||||
notifications: selectNotifications(state),
|
notifications: selectNotifications(state),
|
||||||
|
@ -20,11 +25,12 @@ const select = (state) => ({
|
||||||
unreadCount: selectUnreadNotificationCount(state),
|
unreadCount: selectUnreadNotificationCount(state),
|
||||||
unseenCount: selectUnseenNotificationCount(state),
|
unseenCount: selectUnseenNotificationCount(state),
|
||||||
activeChannel: selectActiveChannelClaim(state),
|
activeChannel: selectActiveChannelClaim(state),
|
||||||
|
user: selectUser(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, {
|
export default connect(select, {
|
||||||
doReadNotifications,
|
doLbryioNotificationsMarkRead,
|
||||||
doNotificationList,
|
doLbryioNotificationList,
|
||||||
doSeeAllNotifications,
|
doLbryioSeeAllNotifications,
|
||||||
doCommentReactList,
|
doCommentReactList,
|
||||||
})(NotificationsPage);
|
})(NotificationsPage);
|
||||||
|
|
|
@ -14,32 +14,38 @@ import { RULE } from 'constants/notifications';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
notifications: Array<Notification>,
|
notifications: Array<Notification>,
|
||||||
|
localNotifications: Array<Notification>,
|
||||||
notificationsFiltered: Array<Notification>,
|
notificationsFiltered: Array<Notification>,
|
||||||
notificationCategories: Array<NotificationCategory>,
|
notificationCategories: Array<NotificationCategory>,
|
||||||
fetching: boolean,
|
fetching: boolean,
|
||||||
unreadCount: number,
|
unreadCount: number,
|
||||||
unseenCount: number,
|
unseenCount: number,
|
||||||
doSeeAllNotifications: () => void,
|
doLbryioSeeAllNotifications: () => void,
|
||||||
doReadNotifications: () => void,
|
doLbryioNotificationsMarkRead: () => void,
|
||||||
doNotificationList: (?Array<string>) => void,
|
doLbryioNotificationList: (?Array<string>) => void,
|
||||||
activeChannel: ?ChannelClaim,
|
activeChannel: ?ChannelClaim,
|
||||||
doCommentReactList: (Array<string>) => Promise<any>,
|
doCommentReactList: (Array<string>) => Promise<any>,
|
||||||
|
user: User,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function NotificationsPage(props: Props) {
|
export default function NotificationsPage(props: Props) {
|
||||||
const {
|
const {
|
||||||
notifications,
|
notifications,
|
||||||
notificationsFiltered,
|
notificationsFiltered,
|
||||||
|
localNotifications,
|
||||||
fetching,
|
fetching,
|
||||||
unreadCount,
|
unreadCount,
|
||||||
unseenCount,
|
unseenCount,
|
||||||
doSeeAllNotifications,
|
doLbryioSeeAllNotifications,
|
||||||
doReadNotifications,
|
doLbryioNotificationsMarkRead,
|
||||||
doNotificationList,
|
doLbryioNotificationList,
|
||||||
notificationCategories,
|
notificationCategories,
|
||||||
activeChannel,
|
activeChannel,
|
||||||
doCommentReactList,
|
doCommentReactList,
|
||||||
|
user,
|
||||||
} = props;
|
} = props;
|
||||||
|
// const localCategories = [{ name: 'New Content', types: ['new_content'] }];
|
||||||
|
const legacyNotificationsEnabled = user && user.experimental_ui;
|
||||||
const initialFetchDone = useFetched(fetching);
|
const initialFetchDone = useFetched(fetching);
|
||||||
const [name, setName] = usePersistedState('notifications--rule', NOTIFICATIONS.NOTIFICATION_NAME_ALL);
|
const [name, setName] = usePersistedState('notifications--rule', NOTIFICATIONS.NOTIFICATION_NAME_ALL);
|
||||||
const isFiltered = name !== NOTIFICATIONS.NOTIFICATION_NAME_ALL;
|
const isFiltered = name !== NOTIFICATIONS.NOTIFICATION_NAME_ALL;
|
||||||
|
@ -81,9 +87,9 @@ export default function NotificationsPage(props: Props) {
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (unseenCount > 0) {
|
if (unseenCount > 0) {
|
||||||
doSeeAllNotifications();
|
doLbryioSeeAllNotifications();
|
||||||
}
|
}
|
||||||
}, [unseenCount, doSeeAllNotifications]);
|
}, [unseenCount, doLbryioSeeAllNotifications]);
|
||||||
|
|
||||||
const stringifiedNotificationCategories = JSON.stringify(notificationCategories);
|
const stringifiedNotificationCategories = JSON.stringify(notificationCategories);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -97,7 +103,7 @@ export default function NotificationsPage(props: Props) {
|
||||||
try {
|
try {
|
||||||
const matchingCategory = arrayNotificationCategories.find((category) => category.name === name);
|
const matchingCategory = arrayNotificationCategories.find((category) => category.name === name);
|
||||||
if (matchingCategory) {
|
if (matchingCategory) {
|
||||||
doNotificationList(matchingCategory.types);
|
doLbryioNotificationList(matchingCategory.types);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
@ -113,10 +119,18 @@ export default function NotificationsPage(props: Props) {
|
||||||
<div className="claim-list__alt-controls--wrap">
|
<div className="claim-list__alt-controls--wrap">
|
||||||
{fetching && <Spinner type="small" />}
|
{fetching && <Spinner type="small" />}
|
||||||
|
|
||||||
{unreadCount > 0 && (
|
{legacyNotificationsEnabled && unreadCount > 0 && (
|
||||||
<Button icon={ICONS.EYE} onClick={doReadNotifications} button="secondary" label={__('Mark all as read')} />
|
<Button
|
||||||
|
icon={ICONS.EYE}
|
||||||
|
onClick={doLbryioNotificationsMarkRead}
|
||||||
|
button="secondary"
|
||||||
|
label={__('Mark all as read')}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{notificationCategories && (
|
{!legacyNotificationsEnabled && unreadCount > 0 && (
|
||||||
|
<Button icon={ICONS.EYE} onClick={() => alert('clear')} button="secondary" label={__('Mark all as read')} />
|
||||||
|
)}
|
||||||
|
{legacyNotificationsEnabled && notificationCategories && (
|
||||||
<FormField
|
<FormField
|
||||||
className="notification__filter"
|
className="notification__filter"
|
||||||
type="select"
|
type="select"
|
||||||
|
@ -135,7 +149,7 @@ export default function NotificationsPage(props: Props) {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{list && list.length > 0 && !(isFiltered && fetching) ? (
|
{legacyNotificationsEnabled && list && list.length > 0 && !(isFiltered && fetching) && (
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="notification_list">
|
<div className="notification_list">
|
||||||
{list.map((notification) => {
|
{list.map((notification) => {
|
||||||
|
@ -143,7 +157,17 @@ export default function NotificationsPage(props: Props) {
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
)}
|
||||||
|
{!legacyNotificationsEnabled && localNotifications && localNotifications.length > 0 && (
|
||||||
|
<div className="card">
|
||||||
|
<div className="notification_list">
|
||||||
|
{localNotifications.map((notification) => {
|
||||||
|
return <Notification key={notification.id} notification={notification} local />;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!(legacyNotificationsEnabled && list && list.length > 0 && !(isFiltered && fetching)) && (
|
||||||
<div className="main--empty">
|
<div className="main--empty">
|
||||||
{!fetching && (
|
{!fetching && (
|
||||||
<Yrbl
|
<Yrbl
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { doClearSupport, doBalanceSubscribe } from 'redux/actions/wallet';
|
||||||
import { doClearPublish } from 'redux/actions/publish';
|
import { doClearPublish } from 'redux/actions/publish';
|
||||||
import { Lbryio } from 'lbryinc';
|
import { Lbryio } from 'lbryinc';
|
||||||
import { selectFollowedTagsList } from 'redux/selectors/tags';
|
import { selectFollowedTagsList } from 'redux/selectors/tags';
|
||||||
import { doToast, doError, doNotificationList } from 'redux/actions/notifications';
|
import { doToast, doError, doLbryioNotificationList } from 'redux/actions/notifications';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
doFetchDaemonSettings,
|
doFetchDaemonSettings,
|
||||||
|
@ -509,7 +509,7 @@ export function doSignIn() {
|
||||||
dispatch(doNotificationSocketConnect(notificationsEnabled));
|
dispatch(doNotificationSocketConnect(notificationsEnabled));
|
||||||
|
|
||||||
if (notificationsEnabled) {
|
if (notificationsEnabled) {
|
||||||
dispatch(doNotificationList());
|
dispatch(doLbryioNotificationList());
|
||||||
}
|
}
|
||||||
dispatch(doCheckPendingClaims());
|
dispatch(doCheckPendingClaims());
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import Lbry from 'lbry';
|
||||||
import { parseURI, buildURI, isURIEqual } from 'util/lbryURI';
|
import { parseURI, buildURI, isURIEqual } from 'util/lbryURI';
|
||||||
import { selectClaimsByUri, selectMyChannelClaims } from 'redux/selectors/claims';
|
import { selectClaimsByUri, selectMyChannelClaims } from 'redux/selectors/claims';
|
||||||
import { doClaimSearch } from 'redux/actions/claims';
|
import { doClaimSearch } from 'redux/actions/claims';
|
||||||
import { doToast, doSeeNotifications } from 'redux/actions/notifications';
|
import { doToast, doLbryioNotificationsMarkSeen } from 'redux/actions/notifications';
|
||||||
import {
|
import {
|
||||||
selectMyReactsForComment,
|
selectMyReactsForComment,
|
||||||
selectOthersReactsForComment,
|
selectOthersReactsForComment,
|
||||||
|
@ -452,7 +452,7 @@ export function doCommentReact(commentId: string, type: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notification && !notification.is_seen) {
|
if (notification && !notification.is_seen) {
|
||||||
dispatch(doSeeNotifications([notification.id]));
|
dispatch(doLbryioNotificationsMarkSeen([notification.id]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const exclusiveTypes = {
|
const exclusiveTypes = {
|
||||||
|
@ -593,7 +593,7 @@ export function doCommentCreate(
|
||||||
|
|
||||||
// send a notification
|
// send a notification
|
||||||
const notification = parent_id && makeSelectNotificationForCommentId(parent_id)(state);
|
const notification = parent_id && makeSelectNotificationForCommentId(parent_id)(state);
|
||||||
if (notification && !notification.is_seen) dispatch(doSeeNotifications([notification.id]));
|
if (notification && !notification.is_seen) dispatch(doLbryioNotificationsMarkSeen([notification.id]));
|
||||||
|
|
||||||
if (!signatureData) {
|
if (!signatureData) {
|
||||||
return dispatch(doToast({ isError: true, message: __('Unable to verify your channel. Please try again.') }));
|
return dispatch(doToast({ isError: true, message: __('Unable to verify your channel. Please try again.') }));
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { Lbryio } from 'lbryinc';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import {
|
import {
|
||||||
selectNotifications,
|
selectNotifications,
|
||||||
|
selectNotificationsLocal,
|
||||||
selectNotificationsFiltered,
|
selectNotificationsFiltered,
|
||||||
selectNotificationCategories,
|
selectNotificationCategories,
|
||||||
} from 'redux/selectors/notifications';
|
} from 'redux/selectors/notifications';
|
||||||
|
@ -45,12 +46,12 @@ export function doDismissError() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doNotificationList(types?: Array<string>) {
|
export function doLbryioNotificationList(types?: Array<string>) {
|
||||||
return async (dispatch: Dispatch, getState: GetState) => {
|
return async (dispatch: Dispatch, getState: GetState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const notificationTypes = selectNotificationCategories(state);
|
const notificationTypes = selectNotificationCategories(state);
|
||||||
|
|
||||||
dispatch({ type: ACTIONS.NOTIFICATION_LIST_STARTED });
|
dispatch({ type: ACTIONS.LBRYIO_NOTIFICATION_LIST_STARTED });
|
||||||
|
|
||||||
let params: any = { is_app_readable: true };
|
let params: any = { is_app_readable: true };
|
||||||
if (types) {
|
if (types) {
|
||||||
|
@ -62,7 +63,7 @@ export function doNotificationList(types?: Array<string>) {
|
||||||
const notificationCategories = await Lbryio.call('notification', 'categories');
|
const notificationCategories = await Lbryio.call('notification', 'categories');
|
||||||
if (notificationCategories) {
|
if (notificationCategories) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.NOTIFICATION_CATEGORIES_COMPLETED,
|
type: ACTIONS.LBRYIO_NOTIFICATION_CATEGORIES_COMPLETED,
|
||||||
data: {
|
data: {
|
||||||
notificationCategories: notificationCategories.reverse(),
|
notificationCategories: notificationCategories.reverse(),
|
||||||
},
|
},
|
||||||
|
@ -94,7 +95,7 @@ export function doNotificationList(types?: Array<string>) {
|
||||||
|
|
||||||
dispatch(doResolveUris(channelsToResolve));
|
dispatch(doResolveUris(channelsToResolve));
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.NOTIFICATION_LIST_COMPLETED,
|
type: ACTIONS.LBRYIO_NOTIFICATION_LIST_COMPLETED,
|
||||||
data: {
|
data: {
|
||||||
newNotifications: notifications,
|
newNotifications: notifications,
|
||||||
filterRule: Boolean(types),
|
filterRule: Boolean(types),
|
||||||
|
@ -102,12 +103,12 @@ export function doNotificationList(types?: Array<string>) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
dispatch({ type: ACTIONS.NOTIFICATION_LIST_FAILED, data: { error } });
|
dispatch({ type: ACTIONS.LBRYIO_NOTIFICATION_LIST_FAILED, data: { error } });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doReadNotifications(notificationsIds: Array<number>) {
|
export function doLbryioNotificationsMarkRead(notificationsIds: Array<number>) {
|
||||||
return (dispatch: Dispatch, getState: GetState) => {
|
return (dispatch: Dispatch, getState: GetState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const notifications = selectNotifications(state);
|
const notifications = selectNotifications(state);
|
||||||
|
@ -127,36 +128,36 @@ export function doReadNotifications(notificationsIds: Array<number>) {
|
||||||
ids = Array.from(new Set([...getUnreadIds(notifications), ...getUnreadIds(notificationsFiltered)]));
|
ids = Array.from(new Set([...getUnreadIds(notifications), ...getUnreadIds(notificationsFiltered)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({ type: ACTIONS.NOTIFICATION_READ_STARTED });
|
dispatch({ type: ACTIONS.LBRYIO_NOTIFICATION_READ_STARTED });
|
||||||
return Lbryio.call('notification', 'edit', { notification_ids: ids.join(','), is_read: true })
|
return Lbryio.call('notification', 'edit', { notification_ids: ids.join(','), is_read: true })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch({ type: ACTIONS.NOTIFICATION_READ_COMPLETED, data: { notificationIds: ids } });
|
dispatch({ type: ACTIONS.LBRYIO_NOTIFICATION_READ_COMPLETED, data: { notificationIds: ids } });
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
dispatch({ type: ACTIONS.NOTIFICATION_READ_FAILED, data: { error } });
|
dispatch({ type: ACTIONS.LBRYIO_NOTIFICATION_READ_FAILED, data: { error } });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doSeeNotifications(notificationIds: Array<string>) {
|
export function doLbryioNotificationsMarkSeen(notificationIds: Array<string>) {
|
||||||
return (dispatch: Dispatch) => {
|
return (dispatch: Dispatch) => {
|
||||||
dispatch({ type: ACTIONS.NOTIFICATION_SEEN_STARTED });
|
dispatch({ type: ACTIONS.LBRYIO_NOTIFICATION_SEEN_STARTED });
|
||||||
return Lbryio.call('notification', 'edit', { notification_ids: notificationIds.join(','), is_seen: true })
|
return Lbryio.call('notification', 'edit', { notification_ids: notificationIds.join(','), is_seen: true })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.NOTIFICATION_SEEN_COMPLETED,
|
type: ACTIONS.LBRYIO_NOTIFICATION_SEEN_COMPLETED,
|
||||||
data: {
|
data: {
|
||||||
notificationIds,
|
notificationIds,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
dispatch({ type: ACTIONS.NOTIFICATION_SEEN_FAILED, data: { error } });
|
dispatch({ type: ACTIONS.LBRYIO_NOTIFICATION_SEEN_FAILED, data: { error } });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doSeeAllNotifications() {
|
export function doLbryioSeeAllNotifications() {
|
||||||
return (dispatch: Dispatch, getState: GetState) => {
|
return (dispatch: Dispatch, getState: GetState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const notifications = selectNotifications(state);
|
const notifications = selectNotifications(state);
|
||||||
|
@ -169,18 +170,57 @@ export function doSeeAllNotifications() {
|
||||||
const getUnseenIds = (list) => list.filter((n) => !n.is_seen).map((n) => n.id);
|
const getUnseenIds = (list) => list.filter((n) => !n.is_seen).map((n) => n.id);
|
||||||
const unseenIds = Array.from(new Set([...getUnseenIds(notifications), ...getUnseenIds(notificationsFiltered)]));
|
const unseenIds = Array.from(new Set([...getUnseenIds(notifications), ...getUnseenIds(notificationsFiltered)]));
|
||||||
|
|
||||||
dispatch(doSeeNotifications(unseenIds));
|
dispatch(doLbryioNotificationsMarkSeen(unseenIds));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doDeleteNotification(notificationId: number) {
|
export function doLbryioDeleteNotification(notificationId: number) {
|
||||||
return (dispatch: Dispatch) => {
|
return (dispatch: Dispatch) => {
|
||||||
Lbryio.call('notification', 'delete', { notification_ids: notificationId })
|
Lbryio.call('notification', 'delete', { notification_ids: notificationId })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch({ type: ACTIONS.NOTIFICATION_DELETE_COMPLETED, data: { notificationId } });
|
dispatch({ type: ACTIONS.LBRYIO_NOTIFICATION_DELETE_COMPLETED, data: { notificationId } });
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
dispatch(doToast({ isError: true, message: __('Unable to delete this right now. Please try again later.') }));
|
dispatch(doToast({ isError: true, message: __('Unable to delete this right now. Please try again later.') }));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doLocalAddNotification(notifications: Array<any>) {
|
||||||
|
return (dispatch: Dispatch) => {
|
||||||
|
dispatch({ type: ACTIONS.LOCAL_NOTIFICATION_ADD, data: { notifications } });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doLocalDeleteNotification(notificationId: number) {
|
||||||
|
return (dispatch: Dispatch) => {
|
||||||
|
dispatch({ type: ACTIONS.LOCAL_NOTIFICATION_DELETE, data: { notificationId } });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doLocalSeeNotification(notificationIds: Array<string>) {
|
||||||
|
return (dispatch: Dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.LOCAL_NOTIFICATION_SEEN,
|
||||||
|
data: {
|
||||||
|
notificationIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doLocalSeeAllNotifications() {
|
||||||
|
return (dispatch: Dispatch, getState: GetState) => {
|
||||||
|
const state = getState();
|
||||||
|
const notifications = selectNotificationsLocal(state);
|
||||||
|
|
||||||
|
if (!notifications) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUnseenIds = (list) => list.filter((n) => !n.is_seen).map((n) => n.id);
|
||||||
|
const unseenIds = Array.from(new Set([...getUnseenIds(notifications)]));
|
||||||
|
|
||||||
|
dispatch(doLbryioNotificationsMarkSeen(unseenIds));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,17 @@ import { Lbryio } from 'lbryinc';
|
||||||
import { doClaimRewardType } from 'redux/actions/rewards';
|
import { doClaimRewardType } from 'redux/actions/rewards';
|
||||||
import { parseURI } from 'util/lbryURI';
|
import { parseURI } from 'util/lbryURI';
|
||||||
import { doAlertWaitingForSync } from 'redux/actions/app';
|
import { doAlertWaitingForSync } from 'redux/actions/app';
|
||||||
import { doToast } from 'redux/actions/notifications';
|
import { doLocalAddNotification, doToast } from 'redux/actions/notifications';
|
||||||
|
import { setUnion } from 'util/set-operations';
|
||||||
|
import { getNotificationFromClaim } from 'util/notifications';
|
||||||
|
|
||||||
|
import {
|
||||||
|
makeSelectNotificationsDisabled,
|
||||||
|
selectDownloadEnabledUrls,
|
||||||
|
makeSelectLastReleaseForUri,
|
||||||
|
selectSubscriptionUris,
|
||||||
|
} from 'redux/selectors/subscriptions';
|
||||||
|
import Lbry from '../../lbry';
|
||||||
|
|
||||||
type SubscriptionArgs = {
|
type SubscriptionArgs = {
|
||||||
channelName: string,
|
channelName: string,
|
||||||
|
@ -85,3 +95,110 @@ export function doChannelUnsubscribe(subscription: SubscriptionArgs, followToast
|
||||||
return dispatch(doToggleSubscription(subscription, followToast, true));
|
return dispatch(doToggleSubscription(subscription, followToast, true));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doAddUriToDownloadQueue(uri: string) {
|
||||||
|
return (dispatch: Dispatch) => {
|
||||||
|
return dispatch(doAddUrisToDownloadQueue([uri]));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doAddUrisToDownloadQueue(uris: Array<string>) {
|
||||||
|
return (dispatch: Dispatch) => {
|
||||||
|
return dispatch({
|
||||||
|
type: ACTIONS.SUBSCRIPTION_DOWNLOAD_ADD,
|
||||||
|
data: uris,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doRemoveUriFromDownloadQueue(uri: string) {
|
||||||
|
return (dispatch: Dispatch) => {
|
||||||
|
return dispatch({
|
||||||
|
type: ACTIONS.SUBSCRIPTION_DOWNLOAD_REMOVE,
|
||||||
|
data: uri,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doUpdateLastReleasesForUri(entries: { [string]: number }) {
|
||||||
|
return (dispatch: Dispatch) => {
|
||||||
|
return dispatch({
|
||||||
|
type: ACTIONS.SUBSCRIPTION_RELEASE_UPDATE,
|
||||||
|
// data: entries = { [uri]: timestamp } >
|
||||||
|
data: entries,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doSubscriptionDownloadEnableForUri(uri: string, enable: boolean) {
|
||||||
|
return (dispatch: Dispatch) => {
|
||||||
|
return dispatch({
|
||||||
|
type: ACTIONS.SUBSCRIPTION_DOWNLOAD_TOGGLE,
|
||||||
|
data: { uri, enable },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doCheckChannelPublishes() {
|
||||||
|
// finish this
|
||||||
|
return async (dispatch: Dispatch, getState: GetState) => {
|
||||||
|
const state = getState();
|
||||||
|
// for sub in subs, if notify+ or download+, getnewpublishes()
|
||||||
|
const subs = new Set(selectSubscriptionUris(state));
|
||||||
|
const dls = new Set(selectDownloadEnabledUrls(state));
|
||||||
|
const channels = Array.from(setUnion(subs, dls));
|
||||||
|
|
||||||
|
for (const channelUri of channels) {
|
||||||
|
// $FlowFixMe
|
||||||
|
const hasNotify = !makeSelectNotificationsDisabled(channelUri)(state); // eslint-disable-line
|
||||||
|
const hasDownload = dls.has(channelUri);
|
||||||
|
const lastRelease = makeSelectLastReleaseForUri(channelUri)(state);
|
||||||
|
if (hasNotify || hasDownload) {
|
||||||
|
// getNewPublishes since ???
|
||||||
|
let lastTime = Math.floor(Date.now() / 1000);
|
||||||
|
const results = await Lbry.claim_search({
|
||||||
|
channel: channelUri,
|
||||||
|
release_time: `>${lastRelease}`,
|
||||||
|
order_by: ['release_time'],
|
||||||
|
});
|
||||||
|
const latest = results.items;
|
||||||
|
if (latest.length && latest[0].value && latest[0].value.release_time) {
|
||||||
|
lastTime = latest[0].value.release_time;
|
||||||
|
}
|
||||||
|
// dispatch release time update()
|
||||||
|
const notifications = [];
|
||||||
|
const downloads = [];
|
||||||
|
const releaseEntries = {}; // refactor to {} maybe
|
||||||
|
for (const claim of latest) {
|
||||||
|
if (hasNotify) {
|
||||||
|
const notification = getNotificationFromClaim(claim);
|
||||||
|
notifications.push(notification);
|
||||||
|
}
|
||||||
|
if (hasDownload) {
|
||||||
|
downloads.push(claim.permanent_url);
|
||||||
|
}
|
||||||
|
releaseEntries[channelUri] = lastTime;
|
||||||
|
}
|
||||||
|
dispatch(doLocalAddNotification(notifications));
|
||||||
|
dispatch(doAddUrisToDownloadQueue(downloads));
|
||||||
|
// dispatch last check for channelUri
|
||||||
|
dispatch(doUpdateLastReleasesForUri(releaseEntries));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// do download
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doCheckChannelsSubscribe() {
|
||||||
|
return (dispatch: Dispatch) => {
|
||||||
|
dispatch(doCheckChannelPublishes());
|
||||||
|
setInterval(() => dispatch(doCheckChannelPublishes()), 10000);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDownloadQueue() {
|
||||||
|
return (dispatch: Dispatch) => {
|
||||||
|
// for each download, trigger download,
|
||||||
|
// if downloading, back off
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import { getAuthToken } from 'util/saved-passwords';
|
import { getAuthToken } from 'util/saved-passwords';
|
||||||
import { doNotificationList } from 'redux/actions/notifications';
|
import { doLbryioNotificationList } from 'redux/actions/notifications';
|
||||||
import { SOCKETY_SERVER_API } from 'config';
|
import { SOCKETY_SERVER_API } from 'config';
|
||||||
|
|
||||||
const NOTIFICATION_WS_URL = `${SOCKETY_SERVER_API}/internal?id=`;
|
const NOTIFICATION_WS_URL = `${SOCKETY_SERVER_API}/internal?id=`;
|
||||||
|
@ -79,7 +79,7 @@ export const doNotificationSocketConnect = (enableNotifications) => (dispatch) =
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case 'pending_notification':
|
case 'pending_notification':
|
||||||
if (enableNotifications) {
|
if (enableNotifications) {
|
||||||
dispatch(doNotificationList());
|
dispatch(doLbryioNotificationList());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'swap-status':
|
case 'swap-status':
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { handleActions } from 'util/redux-utils';
|
||||||
|
|
||||||
const defaultState: NotificationState = {
|
const defaultState: NotificationState = {
|
||||||
notifications: [],
|
notifications: [],
|
||||||
|
localNotifications: [],
|
||||||
notificationsFiltered: [],
|
notificationsFiltered: [],
|
||||||
notificationCategories: undefined,
|
notificationCategories: undefined,
|
||||||
fetchingNotifications: false,
|
fetchingNotifications: false,
|
||||||
|
@ -35,13 +36,13 @@ export default handleActions(
|
||||||
},
|
},
|
||||||
|
|
||||||
// Notifications
|
// Notifications
|
||||||
[ACTIONS.NOTIFICATION_LIST_STARTED]: (state, action) => {
|
[ACTIONS.LBRYIO_NOTIFICATION_LIST_STARTED]: (state) => {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
fetchingNotifications: true,
|
fetchingNotifications: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[ACTIONS.NOTIFICATION_LIST_COMPLETED]: (state, action) => {
|
[ACTIONS.LBRYIO_NOTIFICATION_LIST_COMPLETED]: (state, action) => {
|
||||||
const { filterRule, newNotifications } = action.data;
|
const { filterRule, newNotifications } = action.data;
|
||||||
if (filterRule) {
|
if (filterRule) {
|
||||||
return {
|
return {
|
||||||
|
@ -57,13 +58,13 @@ export default handleActions(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ACTIONS.NOTIFICATION_LIST_FAILED]: (state, action) => {
|
[ACTIONS.LBRYIO_NOTIFICATION_LIST_FAILED]: (state) => {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
fetchingNotifications: false,
|
fetchingNotifications: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[ACTIONS.NOTIFICATION_CATEGORIES_COMPLETED]: (state, action) => {
|
[ACTIONS.LBRYIO_NOTIFICATION_CATEGORIES_COMPLETED]: (state, action) => {
|
||||||
const { notificationCategories } = action.data;
|
const { notificationCategories } = action.data;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -71,7 +72,7 @@ export default handleActions(
|
||||||
notificationCategories,
|
notificationCategories,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[ACTIONS.NOTIFICATION_READ_COMPLETED]: (state, action) => {
|
[ACTIONS.LBRYIO_NOTIFICATION_READ_COMPLETED]: (state, action) => {
|
||||||
const { notifications, notificationsFiltered } = state;
|
const { notifications, notificationsFiltered } = state;
|
||||||
const { notificationIds } = action.data;
|
const { notificationIds } = action.data;
|
||||||
|
|
||||||
|
@ -94,12 +95,12 @@ export default handleActions(
|
||||||
notificationsFiltered: markIdsAsRead(notificationsFiltered, notificationIds),
|
notificationsFiltered: markIdsAsRead(notificationsFiltered, notificationIds),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[ACTIONS.NOTIFICATION_READ_FAILED]: (state, action) => {
|
[ACTIONS.LBRYIO_NOTIFICATION_READ_FAILED]: (state, action) => {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[ACTIONS.NOTIFICATION_SEEN_COMPLETED]: (state, action) => {
|
[ACTIONS.LBRYIO_NOTIFICATION_SEEN_COMPLETED]: (state, action) => {
|
||||||
const { notifications, notificationsFiltered } = state;
|
const { notifications, notificationsFiltered } = state;
|
||||||
const { notificationIds } = action.data;
|
const { notificationIds } = action.data;
|
||||||
|
|
||||||
|
@ -118,7 +119,7 @@ export default handleActions(
|
||||||
notificationsFiltered: markIdsAsSeen(notificationsFiltered, notificationIds),
|
notificationsFiltered: markIdsAsSeen(notificationsFiltered, notificationIds),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[ACTIONS.NOTIFICATION_DELETE_COMPLETED]: (state, action) => {
|
[ACTIONS.LBRYIO_NOTIFICATION_DELETE_COMPLETED]: (state, action) => {
|
||||||
const { notifications, notificationsFiltered } = state;
|
const { notifications, notificationsFiltered } = state;
|
||||||
const { notificationId } = action.data;
|
const { notificationId } = action.data;
|
||||||
|
|
||||||
|
@ -133,6 +134,43 @@ export default handleActions(
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[ACTIONS.LOCAL_NOTIFICATION_DELETE]: (state, action) => {
|
||||||
|
const { localNotifications } = state;
|
||||||
|
const { notificationId } = action.data;
|
||||||
|
|
||||||
|
const deleteId = (list, id) => {
|
||||||
|
return localNotifications.filter((n) => n.id !== id);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
localNotifications: deleteId(localNotifications, notificationId),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ACTIONS.LOCAL_NOTIFICATION_ADD]: (state, action) => {
|
||||||
|
const { localNotifications } = state;
|
||||||
|
const { notifications } = action.data;
|
||||||
|
return localNotifications.concat(notifications);
|
||||||
|
},
|
||||||
|
[ACTIONS.LOCAL_NOTIFICATION_SEEN]: (state, action) => {
|
||||||
|
const { localNotifications } = state;
|
||||||
|
const { notificationIds } = action.data;
|
||||||
|
|
||||||
|
const markIdsAsSeen = (list, ids) => {
|
||||||
|
return list.map((n) => {
|
||||||
|
if (ids.includes(n.id)) {
|
||||||
|
return { ...n, is_seen: true };
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
localNotifications: markIdsAsSeen(localNotifications, notificationIds),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
[ACTIONS.CREATE_ERROR]: (state: NotificationState, action: DoError) => {
|
[ACTIONS.CREATE_ERROR]: (state: NotificationState, action: DoError) => {
|
||||||
const error: ErrorNotification = action.data;
|
const error: ErrorNotification = action.data;
|
||||||
|
|
|
@ -8,8 +8,17 @@ const defaultState: SubscriptionState = {
|
||||||
following: [],
|
following: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
firstRunCompleted: false,
|
firstRunCompleted: false,
|
||||||
|
downloadEnabledByUrl: {},
|
||||||
|
downloadQueue: [],
|
||||||
|
lastReleaseBySubUrl: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
For each channel, track number to keep downloaded (number), downloads (Array<{id, releaseTime}>)
|
||||||
|
AutoDownloadById
|
||||||
|
{ channel_id: { count: n, downloads: [ { claimId: xyz, releaseTime: 123 ], ... } }
|
||||||
|
*/
|
||||||
|
|
||||||
export default handleActions(
|
export default handleActions(
|
||||||
{
|
{
|
||||||
[ACTIONS.CHANNEL_SUBSCRIBE]: (state: SubscriptionState, action): SubscriptionState => {
|
[ACTIONS.CHANNEL_SUBSCRIBE]: (state: SubscriptionState, action): SubscriptionState => {
|
||||||
|
@ -61,23 +70,47 @@ export default handleActions(
|
||||||
following: newFollowing,
|
following: newFollowing,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[ACTIONS.FETCH_SUBSCRIPTIONS_START]: (state: SubscriptionState): SubscriptionState => ({
|
|
||||||
...state,
|
|
||||||
loading: true,
|
|
||||||
}),
|
|
||||||
[ACTIONS.FETCH_SUBSCRIPTIONS_FAIL]: (state: SubscriptionState): SubscriptionState => ({
|
|
||||||
...state,
|
|
||||||
loading: false,
|
|
||||||
}),
|
|
||||||
[ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS]: (state: SubscriptionState, action): SubscriptionState => ({
|
|
||||||
...state,
|
|
||||||
loading: false,
|
|
||||||
subscriptions: action.data,
|
|
||||||
}),
|
|
||||||
[ACTIONS.SET_VIEW_MODE]: (state: SubscriptionState, action): SubscriptionState => ({
|
[ACTIONS.SET_VIEW_MODE]: (state: SubscriptionState, action): SubscriptionState => ({
|
||||||
...state,
|
...state,
|
||||||
viewMode: action.data,
|
viewMode: action.data,
|
||||||
}),
|
}),
|
||||||
|
[ACTIONS.SUBSCRIPTION_DOWNLOAD_ADD]: (state: SubscriptionState, action): SubscriptionState => {
|
||||||
|
const { downloadQueue } = state;
|
||||||
|
const uri = action.data;
|
||||||
|
const newDownloadQueue = downloadQueue.concat(uri);
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
downloadUrisQueued: newDownloadQueue,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ACTIONS.SUBSCRIPTION_DOWNLOAD_REMOVE]: (state: SubscriptionState, action): SubscriptionState => {
|
||||||
|
const { downloadQueue } = state;
|
||||||
|
const uri = action.data;
|
||||||
|
const newDownloadQueue = downloadQueue.filter((f) => f !== uri);
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
downloadUrisQueued: newDownloadQueue,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ACTIONS.SUBSCRIPTION_RELEASE_UPDATE]: (state: SubscriptionState, action): SubscriptionState => {
|
||||||
|
const { lastReleaseBySubUrl } = state;
|
||||||
|
const entries = action.data;
|
||||||
|
|
||||||
|
Object.entries(entries).forEach(([uri, timestamp]) => {
|
||||||
|
lastReleaseBySubUrl[uri] = timestamp;
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
lastReleaseBySubUrl,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ACTIONS.SUBSCRIPTION_DOWNLOAD_TOGGLE]: (state: SubscriptionState, action): SubscriptionState => {
|
||||||
|
const { downloadEnabledByUrl } = state;
|
||||||
|
const { uri, enable } = action.data;
|
||||||
|
|
||||||
|
downloadEnabledByUrl[uri] = enable;
|
||||||
|
return Object.assign({}, state, { downloadEnabledByUrl });
|
||||||
|
},
|
||||||
[ACTIONS.SYNC_STATE_POPULATE]: (
|
[ACTIONS.SYNC_STATE_POPULATE]: (
|
||||||
state: SubscriptionState,
|
state: SubscriptionState,
|
||||||
action: { data: { subscriptions: ?Array<string>, following: ?Array<Subscription> } }
|
action: { data: { subscriptions: ?Array<string>, following: ?Array<Subscription> } }
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { createSelector } from 'reselect';
|
||||||
export const selectState = (state) => state.notifications || {};
|
export const selectState = (state) => state.notifications || {};
|
||||||
|
|
||||||
export const selectNotifications = createSelector(selectState, (state) => state.notifications);
|
export const selectNotifications = createSelector(selectState, (state) => state.notifications);
|
||||||
|
export const selectNotificationsLocal = createSelector(selectState, (state) => state.localNotifications);
|
||||||
|
|
||||||
export const selectNotificationsFiltered = createSelector(selectState, (state) => state.notificationsFiltered);
|
export const selectNotificationsFiltered = createSelector(selectState, (state) => state.notificationsFiltered);
|
||||||
|
|
||||||
|
@ -31,6 +32,14 @@ export const selectUnseenNotificationCount = createSelector(selectNotifications,
|
||||||
return notifications ? notifications.filter((notification) => !notification.is_seen).length : 0;
|
return notifications ? notifications.filter((notification) => !notification.is_seen).length : 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const selectUnseenLocalNotificationCount = createSelector(selectNotificationsLocal, (notifications) => {
|
||||||
|
return notifications ? notifications.filter((notification) => !notification.is_seen).length : 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const selectUnreadLocalNotificationCount = createSelector(selectNotificationsLocal, (notifications) => {
|
||||||
|
return notifications ? notifications.filter((notification) => !notification.is_read).length : 0;
|
||||||
|
});
|
||||||
|
|
||||||
export const selectToast = createSelector(selectState, (state) => {
|
export const selectToast = createSelector(selectState, (state) => {
|
||||||
if (state.toasts.length) {
|
if (state.toasts.length) {
|
||||||
const { id, params } = state.toasts[0];
|
const { id, params } = state.toasts[0];
|
||||||
|
|
|
@ -30,6 +30,12 @@ export const selectFollowing = createSelector(selectState, (state) => state.foll
|
||||||
// Fetching list of users subscriptions
|
// Fetching list of users subscriptions
|
||||||
export const selectIsFetchingSubscriptions = createSelector(selectState, (state) => state.loading);
|
export const selectIsFetchingSubscriptions = createSelector(selectState, (state) => state.loading);
|
||||||
|
|
||||||
|
export const selectDownloadEnabledByUrl = createSelector(selectState, (state) => state.downloadEnabledByUrl);
|
||||||
|
export const selectLastReleasesByUrl = createSelector(selectState, (state) => state.lastReleaseBySubUrl);
|
||||||
|
export const selectDownloadEnabledUrls = createSelector(selectDownloadEnabledByUrl, (enabledByUrl) =>
|
||||||
|
Object.keys(enabledByUrl)
|
||||||
|
);
|
||||||
|
|
||||||
// The current view mode on the subscriptions page
|
// The current view mode on the subscriptions page
|
||||||
export const selectViewMode = createSelector(selectState, (state) => state.viewMode);
|
export const selectViewMode = createSelector(selectState, (state) => state.viewMode);
|
||||||
|
|
||||||
|
@ -147,10 +153,19 @@ export const makeSelectNotificationsDisabled = (uri) =>
|
||||||
const disabled = following.some((sub) => {
|
const disabled = following.some((sub) => {
|
||||||
return sub.uri === uri && sub.notificationsDisabled === true;
|
return sub.uri === uri && sub.notificationsDisabled === true;
|
||||||
});
|
});
|
||||||
|
|
||||||
return disabled;
|
return disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const makeSelectDownloadEnabled = (uri) =>
|
||||||
|
createSelector(selectDownloadEnabledByUrl, (downloadEnabledByUrl) => {
|
||||||
|
return downloadEnabledByUrl[uri] || false;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const makeSelectLastReleaseForUri = (uri) =>
|
||||||
|
createSelector(selectLastReleasesByUrl, (last) => {
|
||||||
|
return last[uri] || Math.floor(Date.now() / 1000) - 604800; // fall back to a week ago
|
||||||
|
});
|
||||||
|
|
|
@ -663,16 +663,18 @@ svg + .button__label {
|
||||||
.button:first-child:not(:only-child) {
|
.button:first-child:not(:only-child) {
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
margin-right: 1px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:nth-child(2) {
|
.button:not(:first-child):not(:last-child) {
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:last-child:not(:only-child) {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
margin-left: 1px;
|
|
||||||
&:hover {
|
|
||||||
fill: var(--color-text) !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.button--file-action {
|
.button--file-action {
|
||||||
|
@ -710,14 +712,11 @@ svg + .button__label {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// bring back special button-following style later
|
// bring back special button-following style later
|
||||||
//.button-following {
|
.button-following {
|
||||||
// color: var(--color-primary-contrast) !important;
|
.icon {
|
||||||
// //background-color: rgba(var(--color-primary-dynamic),0.5) !important;
|
stroke: var(--color-text) !important;
|
||||||
// background-color: rgba(125, 125, 125, 0.5) !important;
|
}
|
||||||
// .icon {
|
}
|
||||||
// stroke: var(--color-primary-contrast) !important;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
.recommended-content__bubble {
|
.recommended-content__bubble {
|
||||||
// margin-top: var(--spacing-xs);
|
// margin-top: var(--spacing-xs);
|
||||||
|
|
|
@ -11,19 +11,15 @@ $actions-z-index: 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// bring back later
|
// bring back later
|
||||||
//.button-following {
|
.button-following {
|
||||||
// &.button--alt {
|
&.button--alt {
|
||||||
// color: var(--color-text);
|
color: var(--color-text);
|
||||||
// background-color: var(--color-button-alt-bg);
|
.icon {
|
||||||
// .icon {
|
stroke: var(--color-text);
|
||||||
// stroke: var(--color-text);
|
}
|
||||||
// }
|
}
|
||||||
// &:hover {
|
}
|
||||||
// color: var(--color-primary);
|
.button-following:not(first-of-type) {
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
.button-following:last-of-type {
|
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
66
ui/util/notifications.js
Normal file
66
ui/util/notifications.js
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
export const getNotificationFromClaim = (claim) => {
|
||||||
|
// create a notification object from claim
|
||||||
|
const claimName = claim.name;
|
||||||
|
const claimTitle = claim.title;
|
||||||
|
|
||||||
|
const signingChannel = claim.signing_channel;
|
||||||
|
const channelUrl = signingChannel && signingChannel.permanent_url;
|
||||||
|
const claimThumbnail = claim.value.thumbnail;
|
||||||
|
const channelThumbnail = signingChannel.value.thumbnail;
|
||||||
|
|
||||||
|
const dynamic = {};
|
||||||
|
dynamic.claim_name = claimName;
|
||||||
|
dynamic.channel_url = channelUrl;
|
||||||
|
dynamic.claim_title = claimTitle;
|
||||||
|
dynamic.claim_thumbnail = claimThumbnail;
|
||||||
|
dynamic.channel_thumbnail = channelThumbnail;
|
||||||
|
|
||||||
|
const target = `lbry://${claimName}#${claim.claim_id}`;
|
||||||
|
const device = { target };
|
||||||
|
|
||||||
|
const notificationParams = {};
|
||||||
|
notificationParams.dynamic = dynamic;
|
||||||
|
notificationParams.device = device;
|
||||||
|
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
const notification = {};
|
||||||
|
notification.notification_rule = 'new_content';
|
||||||
|
notification.notification_params = notificationParams;
|
||||||
|
notification.is_seen = false;
|
||||||
|
notification.is_read = false;
|
||||||
|
notification.active_at = timestamp;
|
||||||
|
notification.created_at = timestamp;
|
||||||
|
notification.updated_at = timestamp;
|
||||||
|
notification.id = claim.claim_id;
|
||||||
|
|
||||||
|
return notification;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
id(pin):1063634811
|
||||||
|
user_id(pin):1006101
|
||||||
|
type(pin):"new_content"
|
||||||
|
notification_rule(pin):"new_content"
|
||||||
|
is_app_readable(pin):true
|
||||||
|
is_read(pin):false
|
||||||
|
is_emailed(pin):true
|
||||||
|
is_device_notified(pin):true
|
||||||
|
active_at(pin):"2022-05-07T21:47:28Z"
|
||||||
|
created_at(pin):"2022-05-07T21:47:28Z"
|
||||||
|
updated_at(pin):"2022-05-07T21:48:41Z"
|
||||||
|
is_seen(pin):false
|
||||||
|
is_deleted(pin):false
|
||||||
|
dynamic: {
|
||||||
|
claim_name(pin):"macbook-logic-board-repair-livestream-3"
|
||||||
|
channel_url(pin):"lbry://@rossmanngroup#aa5544b6778d3620d57d8dcd3229c6c59354857a"
|
||||||
|
claim_title(pin):"Macbook logic board repair livestream with Louis Rossmann"
|
||||||
|
claim_thumbnail(pin):"https://thumbnails.lbry.com/3zuzWlc8jsg"
|
||||||
|
channel_thumbnail(pin):"https://thumbnails.lbry.com/UCl2mFZoRqjw_ELax4Yisf6w"
|
||||||
|
}
|
||||||
|
|
||||||
|
notification_rule
|
||||||
|
notificatoin_parameters { dynamic: { claim_name:, channel_url:, claim_title:, claim_thumbnail:, channel_thumbnail:, }
|
||||||
|
is_read
|
||||||
|
is_seen
|
||||||
|
|
||||||
|
*/
|
Loading…
Reference in a new issue