From 8a37fa1f1b5c5f24843f7d18e835c13efa10a7f3 Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Tue, 5 Nov 2019 17:14:47 +0700 Subject: [PATCH] user menu --- src/components/main/Header/index.tsx | 53 ++++++++--------- src/components/main/Header/style.scss | 36 +----------- src/components/main/UserButton/index.tsx | 28 +++++++++ src/components/main/UserButton/styles.scss | 68 ++++++++++++++++++++++ src/redux/auth/actions.ts | 4 ++ src/redux/auth/constants.ts | 2 + src/redux/auth/sagas.ts | 6 ++ 7 files changed, 135 insertions(+), 62 deletions(-) create mode 100644 src/components/main/UserButton/index.tsx create mode 100644 src/components/main/UserButton/styles.scss diff --git a/src/components/main/Header/index.tsx b/src/components/main/Header/index.tsx index e1fd0e24..5fe17874 100644 --- a/src/components/main/Header/index.tsx +++ b/src/components/main/Header/index.tsx @@ -9,11 +9,10 @@ import { Filler } from '~/components/containers/Filler'; import { selectUser } from '~/redux/auth/selectors'; import { Group } from '~/components/containers/Group'; import * as MODAL_ACTIONS from '~/redux/modal/actions'; +import * as AUTH_ACTIONS from '~/redux/auth/actions'; import { DIALOGS } from '~/redux/modal/constants'; import { pick } from 'ramda'; -import { Icon } from '~/components/input/Icon'; -import { getURL } from '~/utils/dom'; -import { API } from '~/constants/api'; +import { UserButton } from '../UserButton'; const mapStateToProps = state => ({ user: pick(['username', 'is_user', 'photo'])(selectUser(state)), @@ -22,40 +21,36 @@ const mapStateToProps = state => ({ const mapDispatchToProps = { push: historyPush, showDialog: MODAL_ACTIONS.modalShowDialog, + authLogout: AUTH_ACTIONS.authLogout, }; type IProps = ReturnType & typeof mapDispatchToProps & {}; -const HeaderUnconnected: FC = memo(({ user: { username, is_user, photo }, showDialog }) => { - const onLogin = useCallback(() => showDialog(DIALOGS.LOGIN), [showDialog]); +const HeaderUnconnected: FC = memo( + ({ user, user: { username, is_user, photo }, showDialog, authLogout }) => { + const onLogin = useCallback(() => showDialog(DIALOGS.LOGIN), [showDialog]); - return ( -
- + return ( +
+ - + -
- flow +
+ flow +
+ + {is_user && } + + {!is_user && ( + +
ВДОХ
+
+ )}
- - {is_user && ( - -
{username}
-
- {(!photo || !photo.id) && } -
-
- )} - - {!is_user && ( - -
ВДОХ
-
- )} -
- ); -}); + ); + } +); const Header = connect( mapStateToProps, diff --git a/src/components/main/Header/style.scss b/src/components/main/Header/style.scss index 5191d6f4..e8fa4337 100644 --- a/src/components/main/Header/style.scss +++ b/src/components/main/Header/style.scss @@ -4,6 +4,7 @@ justify-content: flex-end; font-weight: 500; height: 120px; + z-index: 5; } .spacer { @@ -63,38 +64,7 @@ } .user_button { - align-items: center; - border-radius: $input_radius; - font: $font_16_semibold; - text-transform: uppercase; - flex: 0 !important; + flex: 0; + padding-left: $gap / 2; cursor: pointer; - margin-left: $gap; - white-space: nowrap; - box-shadow: inset transparentize($content_bg, 0.8) 0 0 0 1px; - background: transparentize($content_bg, 0.1); - padding: 0 0 0 $gap; -} - -.user_avatar { - @include outer_shadow(); - - flex: 0 0 32px; - width: 32px; - height: 32px; - background: white; - border-radius: $radius; - margin-left: ($gap + 2px) !important; - background: 50% 50% no-repeat $wisegreen; - display: flex; - align-items: center; - justify-content: center; - background-size: cover; - - svg { - fill: #222222; - stroke: #222222; - width: 24px; - height: 24px; - } } diff --git a/src/components/main/UserButton/index.tsx b/src/components/main/UserButton/index.tsx new file mode 100644 index 00000000..0ee80dd0 --- /dev/null +++ b/src/components/main/UserButton/index.tsx @@ -0,0 +1,28 @@ +import React, { FC } from 'react'; +import { Group } from '~/components/containers/Group'; +import styles from './styles.scss'; +import { getURL } from '~/utils/dom'; +import { Icon } from '~/components/input/Icon'; +import { IUser } from '~/redux/auth/types'; + +interface IProps { + user: Partial; + onLogout: () => void; +} + +const UserButton: FC = ({ user: { username, photo }, onLogout }) => ( +
+ +
{username}
+
+ {(!photo || !photo.id) && } +
+
+ +
+
Выдох
+
+
+); + +export { UserButton }; diff --git a/src/components/main/UserButton/styles.scss b/src/components/main/UserButton/styles.scss new file mode 100644 index 00000000..895685f9 --- /dev/null +++ b/src/components/main/UserButton/styles.scss @@ -0,0 +1,68 @@ +.wrap { + position: relative; + z-index: 2; + + &:hover .menu { + display: flex; + } +} + +.menu { + position: absolute; + right: 0; + top: 100%; + padding: $gap; + background: $content_bg; + border-radius: 0 0 $radius $radius; + display: none; + z-index: 1; + background: $content_bg; + min-width: 100%; + + & > div { + padding: $gap $gap * 2; + cursor: pointer; + opacity: 0.5; + } + + &:hover > div { + opacity: 1; + } +} + +.user_button { + align-items: center; + border-radius: $input_radius; + font: $font_16_semibold; + text-transform: uppercase; + flex: 0 !important; + cursor: pointer; + margin-left: $gap; + white-space: nowrap; + box-shadow: inset transparentize($content_bg, 0.8) 0 0 0 1px; + background: transparentize($content_bg, 0.1); + padding: 0 0 0 $gap; +} + +.user_avatar { + @include outer_shadow(); + + flex: 0 0 32px; + width: 32px; + height: 32px; + background: white; + border-radius: $radius; + margin-left: ($gap + 2px) !important; + background: 50% 50% no-repeat $wisegreen; + display: flex; + align-items: center; + justify-content: center; + background-size: cover; + + svg { + fill: #222222; + stroke: #222222; + width: 24px; + height: 24px; + } +} diff --git a/src/redux/auth/actions.ts b/src/redux/auth/actions.ts index 98602c6f..c09619ae 100644 --- a/src/redux/auth/actions.ts +++ b/src/redux/auth/actions.ts @@ -28,3 +28,7 @@ export const authSetUser = (profile: Partial) => ({ type: AUTH_USER_ACTIONS.SET_USER, profile, }); + +export const authLogout = () => ({ + type: AUTH_USER_ACTIONS.LOGOUT, +}); diff --git a/src/redux/auth/constants.ts b/src/redux/auth/constants.ts index 6cfae639..e8ca97a1 100644 --- a/src/redux/auth/constants.ts +++ b/src/redux/auth/constants.ts @@ -6,6 +6,8 @@ export const AUTH_USER_ACTIONS = { SET_USER: 'SET_USER', SET_TOKEN: 'SET_TOKEN', + LOGOUT: 'LOGOUT', + GOT_POST_MESSAGE: 'GOT_POST_MESSAGE', }; diff --git a/src/redux/auth/sagas.ts b/src/redux/auth/sagas.ts index 59502bbe..140d940f 100644 --- a/src/redux/auth/sagas.ts +++ b/src/redux/auth/sagas.ts @@ -85,8 +85,14 @@ function* gotPostMessageSaga({ token }: ReturnType) { if (is_shown && dialog === DIALOGS.LOGIN) yield put(modalSetShown(false)); } +function* logoutSaga() { + yield put(authSetToken(null)); + yield put(authSetUser({ ...EMPTY_USER })); +} + function* authSaga() { yield takeLatest(REHYDRATE, checkUserSaga); + yield takeLatest(AUTH_USER_ACTIONS.LOGOUT, logoutSaga); yield takeLatest(AUTH_USER_ACTIONS.SEND_LOGIN_REQUEST, sendLoginRequestSaga); yield takeLatest(AUTH_USER_ACTIONS.GOT_POST_MESSAGE, gotPostMessageSaga); }