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

boris notificatins

This commit is contained in:
Fedor Katurov 2020-04-14 12:40:16 +07:00
parent bfa61d3987
commit abcdcfa09f
6 changed files with 75 additions and 20 deletions

View file

@ -1,11 +1,11 @@
import React, { FC, useCallback, memo, useState, useEffect } from 'react';
import React, { FC, useCallback, memo, useState, useEffect, useMemo } from 'react';
import { connect } from 'react-redux';
import { push as historyPush } from 'connected-react-router';
import { Link } from 'react-router-dom';
import { Logo } from '~/components/main/Logo';
import { Filler } from '~/components/containers/Filler';
import { selectUser } from '~/redux/auth/selectors';
import { selectUser, selectAuthUpdates } from '~/redux/auth/selectors';
import { Group } from '~/components/containers/Group';
import { DIALOGS } from '~/redux/modal/constants';
import pick from 'ramda/es/pick';
@ -19,9 +19,12 @@ import classNames from 'classnames';
import * as style from './style.scss';
import * as MODAL_ACTIONS from '~/redux/modal/actions';
import * as AUTH_ACTIONS from '~/redux/auth/actions';
import { IState } from '~/redux/store';
import isBefore from 'date-fns/isBefore';
const mapStateToProps = state => ({
user: pick(['username', 'is_user', 'photo'])(selectUser(state)),
const mapStateToProps = (state: IState) => ({
user: pick(['username', 'is_user', 'photo', 'last_seen_boris'])(selectUser(state)),
updates: pick(['boris_commented_at'])(selectAuthUpdates(state)),
pathname: path(['router', 'location', 'pathname'], state),
});
@ -35,7 +38,15 @@ const mapDispatchToProps = {
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
const HeaderUnconnected: FC<IProps> = memo(
({ user, user: { is_user }, showDialog, pathname, authLogout, authOpenProfile }) => {
({
user,
user: { is_user, last_seen_boris },
showDialog,
pathname,
updates: { boris_commented_at },
authLogout,
authOpenProfile,
}) => {
const [is_scrolled, setIsScrolled] = useState(false);
const onLogin = useCallback(() => showDialog(DIALOGS.LOGIN), [showDialog]);
@ -55,6 +66,13 @@ const HeaderUnconnected: FC<IProps> = memo(
return () => window.removeEventListener('scroll', onScroll);
}, [onScroll]);
const hasBorisUpdates = useMemo(
() =>
boris_commented_at &&
(!last_seen_boris || isBefore(new Date(last_seen_boris), new Date(boris_commented_at))),
[boris_commented_at, last_seen_boris]
);
return createPortal(
<div className={classNames(style.wrap, { [style.is_scrolled]: is_scrolled })}>
<div className={style.container}>
@ -71,7 +89,10 @@ const HeaderUnconnected: FC<IProps> = memo(
</Link>
<Link
className={classNames(style.item, { [style.is_active]: pathname === URLS.BORIS })}
className={classNames(style.item, {
[style.is_active]: pathname === URLS.BORIS,
[style.has_dot]: hasBorisUpdates,
})}
to={URLS.BORIS}
>
БОРИС

View file

@ -90,6 +90,26 @@
transition: transform 0.5s, opacity 0.25s;
}
&::after {
content: ' ';
position: absolute;
width: 8px;
height: 8px;
border-radius: 4px;
background: $red;
left: 50%;
bottom: -2px;
transform: translate(-50%, 0);
transition: opacity 0.5s;
opacity: 0;
}
&.has_dot {
&::after {
opacity: 1;
}
}
@include tablet {
padding: $gap;

View file

@ -1,6 +1,6 @@
import { api, errorMiddleware, resultMiddleware, configWithToken } from '~/utils/api';
import { API } from '~/constants/api';
import { IResultWithStatus, IMessage } from '~/redux/types';
import { IResultWithStatus, IMessage, INotification } from '~/redux/types';
import { userLoginTransform } from '~/redux/auth/transforms';
import { IUser } from './types';
@ -55,7 +55,9 @@ export const apiAuthGetUpdates = ({
access,
exclude_dialogs,
last,
}): Promise<IResultWithStatus<{ message: IMessage }>> =>
}): Promise<
IResultWithStatus<{ notifications: INotification[]; boris: { commented_at: string } }>
> =>
api
.get(API.USER.GET_UPDATES, configWithToken(access, { params: { exclude_dialogs, last } }))
.then(resultMiddleware)

View file

@ -14,6 +14,7 @@ const INITIAL_STATE: IAuthState = {
updates: {
last: null,
notifications: [],
boris_commented_at: null,
},
login: {

View file

@ -40,7 +40,7 @@ import {
selectAuthUpdates,
selectAuthRestore,
} from './selectors';
import { IResultWithStatus, INotification, IMessageNotification } from '../types';
import { IResultWithStatus, INotification, IMessageNotification, Unwrap } from '../types';
import { IUser, IAuthState } from './types';
import { REHYDRATE, RehydrateAction } from 'redux-persist';
import { selectModal } from '~/redux/modal/selectors';
@ -244,32 +244,42 @@ function* sendMessage({ message, onSuccess }: ReturnType<typeof authSendMessage>
}
function* getUpdates() {
const user = yield select(selectAuthUser);
const user: ReturnType<typeof selectAuthUser> = yield select(selectAuthUser);
if (!user || !user.is_user || user.role === USER_ROLES.GUEST || !user.id) return;
const modal: IModalState = yield select(selectModal);
const profile: IAuthState['profile'] = yield select(selectAuthProfile);
const { last }: IAuthState['updates'] = yield select(selectAuthUpdates);
const { last, boris_commented_at }: IAuthState['updates'] = yield select(selectAuthUpdates);
const exclude_dialogs =
modal.is_shown && modal.dialog === DIALOGS.PROFILE && profile.user.id ? profile.user.id : null;
const { error, data }: IResultWithStatus<{ notifications: INotification[] }> = yield call(
const { error, data }: Unwrap<ReturnType<typeof apiAuthGetUpdates>> = yield call(
reqWrapper,
apiAuthGetUpdates,
{ exclude_dialogs, last: last || user.last_seen_messages }
);
if (error || !data || !data.notifications || !data.notifications.length) return;
if (error || !data) {
return;
}
const { notifications } = data;
if (data.notifications && data.notifications.length) {
yield put(
authSetUpdates({
last: data.notifications[0].created_at,
notifications: data.notifications,
})
);
}
yield put(
authSetUpdates({
last: notifications[0].created_at,
notifications,
})
);
if (data.boris && data.boris.commented_at && boris_commented_at !== data.boris.commented_at) {
yield put(
authSetUpdates({
boris_commented_at: data.boris.commented_at,
})
);
}
}
function* startPollingSaga() {

View file

@ -31,6 +31,7 @@ export type IAuthState = Readonly<{
updates: {
last: string;
notifications: INotification[];
boris_commented_at: string;
};
login: {