local notification plumbing
This commit is contained in:
parent
43dcb39045
commit
deb3d5bdc3
15 changed files with 173 additions and 65 deletions
|
@ -1,7 +1,4 @@
|
|||
// @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 * as ICONS from 'constants/icons';
|
||||
import * as PAGES from 'constants/pages';
|
||||
|
@ -15,14 +12,11 @@ type HeaderMenuButtonProps = {
|
|||
authenticated: boolean,
|
||||
automaticDarkModeEnabled: boolean,
|
||||
currentTheme: string,
|
||||
user: ?User,
|
||||
handleThemeToggle: (boolean, string) => void,
|
||||
};
|
||||
|
||||
export default function HeaderMenuButtons(props: HeaderMenuButtonProps) {
|
||||
const { automaticDarkModeEnabled, currentTheme, user, handleThemeToggle } = props;
|
||||
|
||||
const notificationsEnabled = ENABLE_UI_NOTIFICATIONS || (user && user.experimental_ui);
|
||||
const { automaticDarkModeEnabled, currentTheme, handleThemeToggle } = props;
|
||||
|
||||
return (
|
||||
<div className="header__buttons">
|
||||
|
@ -39,7 +33,7 @@ export default function HeaderMenuButtons(props: HeaderMenuButtonProps) {
|
|||
</MenuList>
|
||||
</Menu>
|
||||
|
||||
{notificationsEnabled && <NotificationHeaderButton />}
|
||||
<NotificationHeaderButton />
|
||||
|
||||
<Menu>
|
||||
<Tooltip title={__('Settings')}>
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectUnseenNotificationCount } from 'redux/selectors/notifications';
|
||||
import { doLbryioSeeAllNotifications } from 'redux/actions/notifications';
|
||||
import { selectUnseenNotificationCount, selectUnseenLocalNotificationCount } from 'redux/selectors/notifications';
|
||||
import { doLbryioSeeAllNotifications, doLocalSeeAllNotifications } from 'redux/actions/notifications';
|
||||
import { selectUser } from 'redux/selectors/user';
|
||||
import NotificationHeaderButton from './view';
|
||||
|
||||
const select = (state) => ({
|
||||
unseenCount: selectUnseenNotificationCount(state),
|
||||
unseenLocalCount: selectUnseenLocalNotificationCount(state),
|
||||
user: selectUser(state),
|
||||
});
|
||||
|
||||
export default connect(select, {
|
||||
doLbryioSeeAllNotifications,
|
||||
doLocalSeeAllNotifications,
|
||||
})(NotificationHeaderButton);
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
// @flow
|
||||
// import 'scss/component/_header.scss'; // ody codesplits this; no. REMOVE THESE
|
||||
|
||||
import { ENABLE_UI_NOTIFICATIONS } from 'config';
|
||||
import { useHistory } from 'react-router';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as PAGES from 'constants/pages';
|
||||
|
@ -13,23 +10,22 @@ import Tooltip from 'component/common/tooltip';
|
|||
|
||||
type Props = {
|
||||
unseenCount: number,
|
||||
user: ?User,
|
||||
unseenLocalCount: number,
|
||||
doLbryioSeeAllNotifications: () => void,
|
||||
doLocalSeeAllNotifications: () => void,
|
||||
};
|
||||
|
||||
export default function NotificationHeaderButton(props: Props) {
|
||||
const { unseenCount, user, doLbryioSeeAllNotifications } = props;
|
||||
const { unseenCount, unseenLocalCount, doLbryioSeeAllNotifications, doLocalSeeAllNotifications } = props;
|
||||
|
||||
const { push } = useHistory();
|
||||
const notificationsEnabled = ENABLE_UI_NOTIFICATIONS || (user && user.experimental_ui);
|
||||
|
||||
function handleMenuClick() {
|
||||
if (unseenCount > 0) doLbryioSeeAllNotifications();
|
||||
if (unseenLocalCount > 0) doLocalSeeAllNotifications();
|
||||
push(`/$/${PAGES.NOTIFICATIONS}`);
|
||||
}
|
||||
|
||||
if (!notificationsEnabled) return null;
|
||||
|
||||
return (
|
||||
<Tooltip title={__('Notifications')}>
|
||||
<Button onClick={handleMenuClick} className="header__navigationItem--icon">
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doLbryioNotificationsMarkRead, doLbryioDeleteNotification } from 'redux/actions/notifications';
|
||||
import {
|
||||
doLbryioNotificationsMarkRead,
|
||||
doLbryioDeleteNotification,
|
||||
doLocalDeleteNotification,
|
||||
} from 'redux/actions/notifications';
|
||||
import Notification from './view';
|
||||
|
||||
const perform = (dispatch, ownProps) => ({
|
||||
readNotification: () => dispatch(doLbryioNotificationsMarkRead([ownProps.notification.id])),
|
||||
deleteNotification: () => dispatch(doLbryioDeleteNotification(ownProps.notification.id)),
|
||||
deleteLocalNotification: () => dispatch(doLocalDeleteNotification(ownProps.notification.id)),
|
||||
});
|
||||
|
||||
export default connect(null, perform)(Notification);
|
||||
|
|
|
@ -5,7 +5,6 @@ import { parseURI } from 'util/lbryURI';
|
|||
import Button from 'component/button';
|
||||
import useHover from 'effects/use-hover';
|
||||
import { useIsMobile } from 'effects/use-screensize';
|
||||
import { ENABLE_UI_NOTIFICATIONS } from 'config';
|
||||
|
||||
type SubscriptionArgs = {
|
||||
channelName: string,
|
||||
|
@ -34,7 +33,6 @@ export default function SubscribeButton(props: Props) {
|
|||
doToast,
|
||||
shrinkOnMobile = false,
|
||||
notificationsDisabled,
|
||||
user,
|
||||
uri,
|
||||
} = props;
|
||||
|
||||
|
@ -42,7 +40,6 @@ export default function SubscribeButton(props: Props) {
|
|||
const isMobile = useIsMobile();
|
||||
let isHovering = useHover(buttonRef);
|
||||
isHovering = isMobile ? true : isHovering;
|
||||
const uiNotificationsEnabled = (user && user.experimental_ui) || ENABLE_UI_NOTIFICATIONS;
|
||||
|
||||
const { channelName: rawChannelName } = parseURI(uri);
|
||||
|
||||
|
@ -119,7 +116,7 @@ export default function SubscribeButton(props: Props) {
|
|||
);
|
||||
}}
|
||||
/>
|
||||
{isSubscribed && uiNotificationsEnabled && (
|
||||
{isSubscribed && (
|
||||
<>
|
||||
<Button
|
||||
button="alt"
|
||||
|
|
|
@ -324,9 +324,6 @@ export const HAS_FETCHED_SUBSCRIPTIONS = 'HAS_FETCHED_SUBSCRIPTIONS';
|
|||
export const CHECK_SUBSCRIPTION_STARTED = 'CHECK_SUBSCRIPTION_STARTED';
|
||||
export const CHECK_SUBSCRIPTION_COMPLETED = 'CHECK_SUBSCRIPTION_COMPLETED';
|
||||
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';
|
||||
|
||||
// Publishing
|
||||
|
@ -357,6 +354,9 @@ export const LBRYIO_NOTIFICATION_SEEN_FAILED = 'LBRYIO_NOTIFICATION_SEEN_FAILED'
|
|||
export const LBRYIO_NOTIFICATION_DELETE_STARTED = 'LBRYIO_NOTIFICATION_DELETE_STARTED';
|
||||
export const LBRYIO_NOTIFICATION_DELETE_COMPLETED = 'LBRYIO_NOTIFICATION_DELETE_COMPLETED';
|
||||
export const LBRYIO_NOTIFICATION_DELETE_FAILED = 'LBRYIO_NOTIFICATION_DELETE_FAILED';
|
||||
export const LOCAL_NOTIFICATION_DELETE_COMPLETED = 'LBRYIO_NOTIFICATION_DELETE_COMPLETED';
|
||||
export const LOCAL_NOTIFICATION_SEEN_COMPLETED = 'LBRYIO_NOTIFICATION_DELETE_COMPLETED';
|
||||
|
||||
export const CREATE_TOAST = 'CREATE_TOAST';
|
||||
export const DISMISS_TOAST = 'DISMISS_TOAST';
|
||||
export const CREATE_ERROR = 'CREATE_ERROR';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import { parseURI } from 'util/lbryURI';
|
||||
import { YOUTUBE_STATUSES } from 'lbryinc';
|
||||
import Page from 'component/page';
|
||||
|
@ -26,6 +26,7 @@ import I18nMessage from 'component/i18nMessage';
|
|||
import TruncatedText from 'component/common/truncated-text';
|
||||
// $FlowFixMe cannot resolve ...
|
||||
import PlaceholderTx from 'static/img/placeholderTx.gif';
|
||||
import { FormField } from 'component/common/form-components/form-field';
|
||||
|
||||
export const PAGE_VIEW_QUERY = `view`;
|
||||
export const DISCUSSION_PAGE = `discussion`;
|
||||
|
@ -36,6 +37,7 @@ const PAGE = {
|
|||
ABOUT: 'about',
|
||||
DISCUSSION: DISCUSSION_PAGE,
|
||||
EDIT: 'edit',
|
||||
SUBSCRIPTION: 'subscription',
|
||||
};
|
||||
|
||||
type Props = {
|
||||
|
@ -159,6 +161,9 @@ function ChannelPage(props: Props) {
|
|||
case PAGE.DISCUSSION:
|
||||
tabIndex = 3;
|
||||
break;
|
||||
case PAGE.SUBSCRIPTION:
|
||||
tabIndex = 4;
|
||||
break;
|
||||
default:
|
||||
tabIndex = 0;
|
||||
break;
|
||||
|
@ -174,8 +179,10 @@ function ChannelPage(props: Props) {
|
|||
search += `${PAGE_VIEW_QUERY}=${PAGE.LISTS}`;
|
||||
} else if (newTabIndex === 2) {
|
||||
search += `${PAGE_VIEW_QUERY}=${PAGE.ABOUT}`;
|
||||
} else {
|
||||
} else if (newTabIndex === 3) {
|
||||
search += `${PAGE_VIEW_QUERY}=${PAGE.DISCUSSION}`;
|
||||
} else {
|
||||
search += `${PAGE_VIEW_QUERY}=${PAGE.SUBSCRIPTION}`;
|
||||
}
|
||||
|
||||
push(`${url}${search}`);
|
||||
|
@ -286,6 +293,7 @@ function ChannelPage(props: Props) {
|
|||
<Tab disabled={editing}>{__('Playlists')}</Tab>
|
||||
<Tab>{editing ? __('Editing Your Channel') : __('About --[tab title in Channel Page]--')}</Tab>
|
||||
<Tab disabled={editing}>{__('Community')}</Tab>
|
||||
<Tab disabled={editing}>{__('Subscription')}</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<TabPanel>
|
||||
|
@ -316,6 +324,27 @@ function ChannelPage(props: Props) {
|
|||
<TabPanel>
|
||||
{(discussionWasMounted || currentView === PAGE.DISCUSSION) && <ChannelDiscussion uri={uri} />}
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<div className="card">
|
||||
<section className="section card--section">
|
||||
<Fragment>
|
||||
<div className="media__info-text">
|
||||
<label>{__('New Content Notifications')}</label>
|
||||
<FormField name={'notify'} type={'checkbox'} checked />
|
||||
</div>
|
||||
|
||||
<div className="media__info-text">
|
||||
<label>{__('Download and Host new content')}</label>
|
||||
<FormField name={'host'} type={'checkbox'} checked />
|
||||
</div>
|
||||
<div className="media__info-text">
|
||||
<label>{__('Items to Host')}</label>
|
||||
<FormField name={'host_count'} type={'number'} value={3} />
|
||||
</div>
|
||||
</Fragment>
|
||||
</section>
|
||||
</div>
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
)}
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
doLbryioSeeAllNotifications,
|
||||
} from 'redux/actions/notifications';
|
||||
import NotificationsPage from './view';
|
||||
import { selectUser } from 'redux/selectors/user';
|
||||
|
||||
const select = (state) => ({
|
||||
notifications: selectNotifications(state),
|
||||
|
@ -24,6 +25,7 @@ const select = (state) => ({
|
|||
unreadCount: selectUnreadNotificationCount(state),
|
||||
unseenCount: selectUnseenNotificationCount(state),
|
||||
activeChannel: selectActiveChannelClaim(state),
|
||||
user: selectUser(state),
|
||||
});
|
||||
|
||||
export default connect(select, {
|
||||
|
|
|
@ -14,6 +14,7 @@ import { RULE } from 'constants/notifications';
|
|||
|
||||
type Props = {
|
||||
notifications: Array<Notification>,
|
||||
localNotifications: Array<Notification>,
|
||||
notificationsFiltered: Array<Notification>,
|
||||
notificationCategories: Array<NotificationCategory>,
|
||||
fetching: boolean,
|
||||
|
@ -24,12 +25,14 @@ type Props = {
|
|||
doLbryioNotificationList: (?Array<string>) => void,
|
||||
activeChannel: ?ChannelClaim,
|
||||
doCommentReactList: (Array<string>) => Promise<any>,
|
||||
user: User,
|
||||
};
|
||||
|
||||
export default function NotificationsPage(props: Props) {
|
||||
const {
|
||||
notifications,
|
||||
notificationsFiltered,
|
||||
localNotifications,
|
||||
fetching,
|
||||
unreadCount,
|
||||
unseenCount,
|
||||
|
@ -39,7 +42,10 @@ export default function NotificationsPage(props: Props) {
|
|||
notificationCategories,
|
||||
activeChannel,
|
||||
doCommentReactList,
|
||||
user,
|
||||
} = props;
|
||||
// const localCategories = [{ name: 'New Content', types: ['new_content'] }];
|
||||
const legacyNotificationsEnabled = user && user.experimental_ui;
|
||||
const initialFetchDone = useFetched(fetching);
|
||||
const [name, setName] = usePersistedState('notifications--rule', NOTIFICATIONS.NOTIFICATION_NAME_ALL);
|
||||
const isFiltered = name !== NOTIFICATIONS.NOTIFICATION_NAME_ALL;
|
||||
|
@ -113,7 +119,7 @@ export default function NotificationsPage(props: Props) {
|
|||
<div className="claim-list__alt-controls--wrap">
|
||||
{fetching && <Spinner type="small" />}
|
||||
|
||||
{unreadCount > 0 && (
|
||||
{legacyNotificationsEnabled && unreadCount > 0 && (
|
||||
<Button
|
||||
icon={ICONS.EYE}
|
||||
onClick={doLbryioNotificationsMarkRead}
|
||||
|
@ -121,7 +127,10 @@ export default function NotificationsPage(props: Props) {
|
|||
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
|
||||
className="notification__filter"
|
||||
type="select"
|
||||
|
@ -140,7 +149,7 @@ export default function NotificationsPage(props: Props) {
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
{list && list.length > 0 && !(isFiltered && fetching) ? (
|
||||
{legacyNotificationsEnabled && list && list.length > 0 && !(isFiltered && fetching) && (
|
||||
<div className="card">
|
||||
<div className="notification_list">
|
||||
{list.map((notification) => {
|
||||
|
@ -148,7 +157,17 @@ export default function NotificationsPage(props: Props) {
|
|||
})}
|
||||
</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">
|
||||
{!fetching && (
|
||||
<Yrbl
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Lbryio } from 'lbryinc';
|
|||
import { v4 as uuid } from 'uuid';
|
||||
import {
|
||||
selectNotifications,
|
||||
selectNotificationsLocal,
|
||||
selectNotificationsFiltered,
|
||||
selectNotificationCategories,
|
||||
} from 'redux/selectors/notifications';
|
||||
|
@ -184,3 +185,36 @@ export function doLbryioDeleteNotification(notificationId: number) {
|
|||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doLocalDeleteNotification(notificationId: number) {
|
||||
return (dispatch: Dispatch) => {
|
||||
dispatch({ type: ACTIONS.LOCAL_NOTIFICATION_DELETE_COMPLETED, data: { notificationId } });
|
||||
};
|
||||
}
|
||||
|
||||
export function doLocalSeeNotification(notificationIds: Array<string>) {
|
||||
return (dispatch: Dispatch) => {
|
||||
dispatch({
|
||||
type: ACTIONS.LOCAL_NOTIFICATION_SEEN_COMPLETED,
|
||||
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));
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { handleActions } from 'util/redux-utils';
|
|||
|
||||
const defaultState: NotificationState = {
|
||||
notifications: [],
|
||||
localNotifications: [],
|
||||
notificationsFiltered: [],
|
||||
notificationCategories: undefined,
|
||||
fetchingNotifications: false,
|
||||
|
@ -133,6 +134,39 @@ export default handleActions(
|
|||
};
|
||||
},
|
||||
|
||||
[ACTIONS.LOCAL_NOTIFICATION_DELETE_COMPLETED]: (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_SEEN_COMPLETED]: (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
|
||||
[ACTIONS.CREATE_ERROR]: (state: NotificationState, action: DoError) => {
|
||||
const error: ErrorNotification = action.data;
|
||||
|
|
|
@ -6,10 +6,17 @@ import { handleActions } from 'util/redux-utils';
|
|||
const defaultState: SubscriptionState = {
|
||||
subscriptions: [], // Deprecated
|
||||
following: [],
|
||||
autoDownloads: {},
|
||||
loading: false,
|
||||
firstRunCompleted: false,
|
||||
};
|
||||
|
||||
/*
|
||||
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(
|
||||
{
|
||||
[ACTIONS.CHANNEL_SUBSCRIBE]: (state: SubscriptionState, action): SubscriptionState => {
|
||||
|
@ -61,19 +68,6 @@ export default handleActions(
|
|||
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 => ({
|
||||
...state,
|
||||
viewMode: action.data,
|
||||
|
|
|
@ -3,6 +3,7 @@ import { createSelector } from 'reselect';
|
|||
export const 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);
|
||||
|
||||
|
@ -31,6 +32,14 @@ export const selectUnseenNotificationCount = createSelector(selectNotifications,
|
|||
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) => {
|
||||
if (state.toasts.length) {
|
||||
const { id, params } = state.toasts[0];
|
||||
|
|
|
@ -710,14 +710,11 @@ svg + .button__label {
|
|||
}
|
||||
}
|
||||
// bring back special button-following style later
|
||||
//.button-following {
|
||||
// color: var(--color-primary-contrast) !important;
|
||||
// //background-color: rgba(var(--color-primary-dynamic),0.5) !important;
|
||||
// background-color: rgba(125, 125, 125, 0.5) !important;
|
||||
// .icon {
|
||||
// stroke: var(--color-primary-contrast) !important;
|
||||
// }
|
||||
//}
|
||||
.button-following {
|
||||
.icon {
|
||||
stroke: var(--color-text) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.recommended-content__bubble {
|
||||
// margin-top: var(--spacing-xs);
|
||||
|
|
|
@ -11,18 +11,14 @@ $actions-z-index: 2;
|
|||
}
|
||||
}
|
||||
// bring back later
|
||||
//.button-following {
|
||||
// &.button--alt {
|
||||
// color: var(--color-text);
|
||||
// background-color: var(--color-button-alt-bg);
|
||||
// .icon {
|
||||
// stroke: var(--color-text);
|
||||
// }
|
||||
// &:hover {
|
||||
// color: var(--color-primary);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
.button-following {
|
||||
&.button--alt {
|
||||
color: var(--color-text);
|
||||
.icon {
|
||||
stroke: var(--color-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
.button-following:last-of-type {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue