HM-105. Подтянуть загрузку данных пользователя. (#47)

This commit is contained in:
Nikolay
2020-08-02 12:18:54 +03:00
committed by GitHub
parent 93171aca68
commit 3a8bf0632b
8 changed files with 134 additions and 34 deletions

View File

@ -1,5 +1,6 @@
import LocalStorageAPI from './LocalStorageAPI'; import LocalStorageAPI from './LocalStorageAPI';
import {LOCAL_STORAGE_TYPE} from './consts'; import {LOCAL_STORAGE_TYPE} from './consts';
import userInfoService from '../services/UserInfoService';
const API_NAME = 'storageServiceUITokenApi'; const API_NAME = 'storageServiceUITokenApi';
@ -27,6 +28,7 @@ class TokenApi {
saveTokenPair = (tokens) => { saveTokenPair = (tokens) => {
this.localApi.createOrUpdate(tokens.refresh_token); this.localApi.createOrUpdate(tokens.refresh_token);
this.sessionApi.createOrUpdate(tokens.access_token); this.sessionApi.createOrUpdate(tokens.access_token);
userInfoService.setUserLogin();
} }
/** /**

View File

@ -13,19 +13,23 @@
<template id="main-menu"> <template id="main-menu">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid d-flex"> <div class="container-fluid d-flex">
<div class="Logo__box d-flex align-items-center"> <div class="MainMenu__logoBox d-flex align-items-center">
<img src="./img/logo.svg" alt="logo" class="Logo mr-2"> <img src="./img/logo.svg" alt="logo" class="MainMenu__logo mr-2">
<a class="h3 text-light navbar-brand text-wrap m-0">Storage Service</a> <a class="h3 text-light navbar-brand text-wrap m-0">Storage Service</a>
</div> </div>
<button class="navbar-toggler ml-auto" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" <button class="navbar-toggler ml-auto" type="button" data-toggle="collapse"
aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse ml-5" id="navbarNavDropdown"> <div class="collapse navbar-collapse ml-5" id="navbarNavDropdown">
<ul class="navbar-nav"></ul> <ul class="navbar-nav mr-auto"></ul>
<div>
<div class="MainMenu__avatar"></div>
</div>
<button type="button"
class="btn btn-outline-dark MainMenu__exitButton">Выйти</button>
</div> </div>
<div class="Avatar"></div>
<button type="submit" class="btn btn-outline-dark text-light ml-1">Выйти</button>
</nav> </nav>
</template> </template>

View File

@ -11,10 +11,15 @@ import RouterPagesContainer from './components/router-pages-container/index';
import LogsPage from './components/logs-page/index'; import LogsPage from './components/logs-page/index';
import LoginPage from './components/login-page'; import LoginPage from './components/login-page';
import authServiceApi from './api/AuthServiceAPI'; import authServiceApi from './api/AuthServiceAPI';
import userInfoService from './services/UserInfoService';
import {EVENTS} from './consts';
const initAppComponents = () => { const initAppComponents = () => {
const mainMenu = new MainMenu(); const mainMenu = new MainMenu();
mainMenu.render(); mainMenu.render();
userInfoService.subscribe(EVENTS.CHANGE_USER_INFO, ({avatar}) => {
mainMenu.setAvatar(avatar);
});
const routerPagesContainer = new RouterPagesContainer(mainMenu); const routerPagesContainer = new RouterPagesContainer(mainMenu);

View File

@ -1,40 +1,52 @@
.Logo { .MainMenu__logo {
width: 50px; width: 50px;
margin: 0 20px; margin: 0 20px;
} }
.Logo__box { .MainMenu__logoBox {
width: 170px; width: 170px;
cursor: pointer; cursor: pointer;
} }
.Buttons__container {
margin: 0 20px;
display: flex;
justify-content: center;
}
.NavButton {
margin: 5px 10px;
}
.nav-item { .nav-item {
cursor: pointer; cursor: pointer;
} }
@media (max-width: 900px){ .MainMenu__avatar {
.Buttons__container {
flex-direction: column;
align-items: center;
justify-content: center;
}
}
.Avatar {
border-radius: 50%; border-radius: 50%;
background-image: url('https://d5qmjlya0ygtg.cloudfront.net/569/c5295/f9ad/47c8/96a0/66a65609b38d/original/331698.jpg');
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
background-origin: border-box; background-origin: border-box;
width: 50px; width: 50px;
height: 50px; height: 50px;
background-size: cover; background-size: cover;
cursor: pointer;
}
.MainMenu__exitButton {
cursor: pointer;
color: hsla(0, 0%, 100%, 0.5);
}
.MainMenu__exitButton:hover {
color: #fff;
}
.MainMenu__profileButton {
display: none;
}
@media (max-width: 991px) {
.MainMenu__profileButton {
display: block;
}
.MainMenu__exitButton {
padding-left: 0;
margin-left: 0;
}
.MainMenu__avatar {
display: none;
}
} }

View File

@ -4,19 +4,25 @@ import routeService from '../../services/RouteService';
import './MainMenu.css'; import './MainMenu.css';
import {createElement} from '../../utils/elementUtils'; import {createElement} from '../../utils/elementUtils';
import {EVENTS} from '../../consts'; import {EVENTS} from '../../consts';
import tokenApi from '../../api/TokenAPI';
export const NAV_MENU = [ export const NAV_MENU = [
{ {
title: 'Главная', title: 'Главная',
url: '/' url: '/',
}, },
{ {
title: 'Список хранилищ', title: 'Список хранилищ',
url: '/api' url: '/api',
}, },
{ {
title: 'Журнал', title: 'Журнал',
url: '/logs' url: '/logs',
},
{
title: 'Личный кабинет',
url: '/profile',
className: 'MainMenu__profileButton'
}, },
]; ];
@ -27,12 +33,20 @@ class MainMenu extends Component {
super('#main-menu', document.body); super('#main-menu', document.body);
this.buttonsContainer = this.mainNode.querySelector('.navbar-nav'); this.buttonsContainer = this.mainNode.querySelector('.navbar-nav');
this.logoBox = this.mainNode.querySelector('.Logo__box'); this.logoBox = this.mainNode.querySelector('.MainMenu__logoBox');
this.avatar = this.mainNode.querySelector('.MainMenu__avatar');
this.exitButton = this.mainNode.querySelector('.MainMenu__exitButton');
this.addEventListener(this.exitButton, 'click', this.exitApp);
this.addEventListener(this.logoBox, 'click', () => { this.addEventListener(this.logoBox, 'click', () => {
routeService.goTo('/'); routeService.goTo('/');
}); });
this.addEventListener(this.avatar, 'click', () => {
routeService.goTo('/profile');
});
this.addSubscribe(routeService, EVENTS.ROUTE_CHANGE, (route) => { this.addSubscribe(routeService, EVENTS.ROUTE_CHANGE, (route) => {
this.menuItems.forEach(({url, link}) => { this.menuItems.forEach(({url, link}) => {
if (route.url === url) { if (route.url === url) {
@ -44,13 +58,22 @@ class MainMenu extends Component {
}); });
} }
exitApp = () => {
tokenApi.clearTokents();
location.reload();
}
setAvatar = (url) => {
this.avatar.style.backgroundImage = `url('${url}')`;
}
render = () => { render = () => {
this.menuItems = NAV_MENU.map(({url, title}) => { this.menuItems = NAV_MENU.map(({url, title, className = ''}) => {
const li = createElement({ const li = createElement({
tagName: 'li', tagName: 'li',
parentNode: this.buttonsContainer, parentNode: this.buttonsContainer,
options: { options: {
className: 'nav-item', className: `nav-item ${className}`,
}, },
}); });
const link = createElement({ const link = createElement({

View File

@ -35,6 +35,7 @@ export const EVENTS = {
ROUTE_SEARCH_CHANGE: 'routeSearchChange', ROUTE_SEARCH_CHANGE: 'routeSearchChange',
ROW_CLICK: 'rowClick', ROW_CLICK: 'rowClick',
ROW_DOUBLE_CLICK: 'rowDoubleClick', ROW_DOUBLE_CLICK: 'rowDoubleClick',
CHANGE_USER_INFO: 'changeUserInfo',
}; };
export const FORM_TYPES = { export const FORM_TYPES = {

View File

@ -0,0 +1,26 @@
import usersServiceApi from '../api/UsersServiceAPI';
import tokenApi from '../api/TokenAPI';
import {parseJwt} from '../utils/jwtDecode';
import {EVENTS} from '../consts';
import EmitService from './EmitService';
class UserInfoService extends EmitService {
constructor () {
super();
this.userInfo = {
login: 'not_user',
avatar: 'https://d5qmjlya0ygtg.cloudfront.net/569/c5295/f9ad/47c8/96a0/66a65609b38d/original/331698.jpg',
};
}
setUserLogin = async () => {
const {login} = parseJwt(tokenApi.getAccessToken());
this.userInfo = await usersServiceApi.find(login);
this.next(EVENTS.CHANGE_USER_INFO, {...this.userInfo});
}
}
const userInfoService = new UserInfoService();
export default userInfoService;

27
src/utils/jwtDecode.js Normal file
View File

@ -0,0 +1,27 @@
/**
* Функция для декодирования юникод текста
*/
export const base64DecodeUnicode = (string) => {
return decodeURIComponent(
Array.prototype.map
.call(atob(string), (c) => {
return `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`;
})
.join('')
);
};
/**
* Функция декодирования jwt токена для получения времени смерти
* accessToken'a
*/
export const parseJwt = (token) => {
return JSON.parse(
base64DecodeUnicode(
token
.split('.')[1]
.replace(/-/g, '+')
.replace(/_/g, '/')
)
);
};