1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-25 12:56:41 +07:00

notification menu

This commit is contained in:
Fedor Katurov 2019-11-13 12:11:47 +07:00
parent 6c1f8967e8
commit 9b0c3dd1fb
20 changed files with 371 additions and 39 deletions

View file

@ -13,6 +13,8 @@ import * as AUTH_ACTIONS from '~/redux/auth/actions';
import { DIALOGS } from '~/redux/modal/constants';
import { pick } from 'ramda';
import { UserButton } from '../UserButton';
import { Icon } from '~/components/input/Icon';
import { Notifications } from '../Notifications';
const mapStateToProps = state => ({
user: pick(['username', 'is_user', 'photo'])(selectUser(state)),
@ -39,8 +41,7 @@ const HeaderUnconnected: FC<IProps> = memo(
<Filler />
<div className={style.plugs}>
<Link to="/boris">((( boris )))</Link>
<Link to="/">flow</Link>
<Notifications />
</div>
{is_user && (

View file

@ -14,11 +14,24 @@
.plugs {
display: flex;
user-select: none;
font: $font_16_medium;
text-transform: uppercase;
align-items: center;
> a,
> div {
&::after {
content: ' ';
margin-left: $spc;
background: white;
width: 4px;
height: $gap;
display: block;
opacity: 0.2;
border-radius: 4px;
margin-right: 10px;
}
& > a.item,
& > div.item {
font: $font_16_medium;
display: flex;
align-items: center;
position: relative;
@ -33,17 +46,6 @@
color: $red;
}
&::after {
content: ' ';
margin-left: $spc;
background: white;
width: 4px;
height: $gap;
display: block;
opacity: 0.2;
border-radius: 4px;
}
&:first-child {
padding-left: $spc + $gap;
}

View file

@ -1,8 +1,9 @@
import * as React from 'react';
import * as styles from './style.scss';
import React from 'react';
import styles from './style.scss';
import { Link } from 'react-router-dom';
export const Logo = () => (
<div className={styles.logo}>
<Link className={styles.logo} to="/">
VAULT
</div>
</Link>
);

View file

@ -1,9 +1,7 @@
.logo {
// font-family: Raleway;
//font-size: $text_sign;
//font-weight: 800;
font: $font_24_bold;
//font-family: Raleway;
display: flex;
user-select: none;
color: white;
text-decoration: none;
}

View file

@ -0,0 +1,62 @@
import React, { FC, useMemo, useState, useCallback, useEffect } from 'react';
import { Icon } from '~/components/input/Icon';
import styles from './styles.scss';
import { connect } from 'react-redux';
import { selectAuthUpdates, selectAuthUser } from '~/redux/auth/selectors';
import pick from 'ramda/es/pick';
import classNames from 'classnames';
import * as AUTH_ACTIONS from '~/redux/auth/actions';
import { NotificationBubble } from '../../notifications/NotificationBubble';
const mapStateToProps = state => ({
user: pick(['last_seen_messages'], selectAuthUser(state)),
updates: selectAuthUpdates(state),
});
const mapDispatchToProps = {
authSetLastSeenMessages: AUTH_ACTIONS.authSetLastSeenMessages,
};
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
const NotificationsUnconnected: FC<IProps> = ({
updates: { last, notifications },
user: { last_seen_messages },
authSetLastSeenMessages,
}) => {
const [visible, setVisible] = useState(true);
const has_new = useMemo(
() =>
notifications.length &&
last &&
Date.parse(last) &&
(!last_seen_messages ||
(Date.parse(last_seen_messages) && Date.parse(last) > Date.parse(last_seen_messages))),
[last, last_seen_messages, notifications]
);
useEffect(() => {
if (!visible || !has_new) return;
authSetLastSeenMessages(new Date().toISOString());
}, [visible]);
const showList = useCallback(() => setVisible(true), [setVisible]);
const hideList = useCallback(() => setVisible(false), [setVisible]);
return (
<div className={classNames(styles.wrap, { [styles.is_new]: has_new })}>
<div className={styles.icon} onFocus={showList} onBlur={hideList} tabIndex={-1}>
{has_new ? <Icon icon="bell_ring" size={24} /> : <Icon icon="bell" size={24} />}
</div>
{visible && <NotificationBubble notifications={notifications} />}
</div>
);
};
const Notifications = connect(
mapStateToProps,
mapDispatchToProps
)(NotificationsUnconnected);
export { Notifications };

View file

@ -0,0 +1,38 @@
@keyframes ring {
0% {
transform: rotate(-10deg);
}
20% {
transform: rotate(10deg);
}
40% {
transform: rotate(-10deg);
}
100% {
transform: rotate(0);
}
}
.wrap {
fill: white;
position: relative;
outline: none;
&.is_new {
.icon {
animation: ring 1s infinite alternate;
svg {
fill: $red;
}
}
}
}
.icon {
outline: none;
cursor: pointer;
}