HM-105. Подтянуть загрузку данных пользователя. (#47)
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
import LocalStorageAPI from './LocalStorageAPI';
|
||||
import {LOCAL_STORAGE_TYPE} from './consts';
|
||||
import userInfoService from '../services/UserInfoService';
|
||||
|
||||
const API_NAME = 'storageServiceUITokenApi';
|
||||
|
||||
@ -27,6 +28,7 @@ class TokenApi {
|
||||
saveTokenPair = (tokens) => {
|
||||
this.localApi.createOrUpdate(tokens.refresh_token);
|
||||
this.sessionApi.createOrUpdate(tokens.access_token);
|
||||
userInfoService.setUserLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
18
src/app.html
18
src/app.html
@ -13,19 +13,23 @@
|
||||
<template id="main-menu">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container-fluid d-flex">
|
||||
<div class="Logo__box d-flex align-items-center">
|
||||
<img src="./img/logo.svg" alt="logo" class="Logo mr-2">
|
||||
<div class="MainMenu__logoBox d-flex align-items-center">
|
||||
<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>
|
||||
</div>
|
||||
<button class="navbar-toggler ml-auto" type="button" data-toggle="collapse" data-target="#navbarNavDropdown"
|
||||
aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<button class="navbar-toggler ml-auto" type="button" data-toggle="collapse"
|
||||
data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false"
|
||||
aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<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 class="Avatar"></div>
|
||||
<button type="submit" class="btn btn-outline-dark text-light ml-1">Выйти</button>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
|
||||
@ -11,10 +11,15 @@ import RouterPagesContainer from './components/router-pages-container/index';
|
||||
import LogsPage from './components/logs-page/index';
|
||||
import LoginPage from './components/login-page';
|
||||
import authServiceApi from './api/AuthServiceAPI';
|
||||
import userInfoService from './services/UserInfoService';
|
||||
import {EVENTS} from './consts';
|
||||
|
||||
const initAppComponents = () => {
|
||||
const mainMenu = new MainMenu();
|
||||
mainMenu.render();
|
||||
userInfoService.subscribe(EVENTS.CHANGE_USER_INFO, ({avatar}) => {
|
||||
mainMenu.setAvatar(avatar);
|
||||
});
|
||||
|
||||
const routerPagesContainer = new RouterPagesContainer(mainMenu);
|
||||
|
||||
|
||||
@ -1,40 +1,52 @@
|
||||
.Logo {
|
||||
.MainMenu__logo {
|
||||
width: 50px;
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.Logo__box {
|
||||
.MainMenu__logoBox {
|
||||
width: 170px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Buttons__container {
|
||||
margin: 0 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.NavButton {
|
||||
margin: 5px 10px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (max-width: 900px){
|
||||
.Buttons__container {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
.Avatar {
|
||||
.MainMenu__avatar {
|
||||
border-radius: 50%;
|
||||
background-image: url('https://d5qmjlya0ygtg.cloudfront.net/569/c5295/f9ad/47c8/96a0/66a65609b38d/original/331698.jpg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-origin: border-box;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,19 +4,25 @@ import routeService from '../../services/RouteService';
|
||||
import './MainMenu.css';
|
||||
import {createElement} from '../../utils/elementUtils';
|
||||
import {EVENTS} from '../../consts';
|
||||
import tokenApi from '../../api/TokenAPI';
|
||||
|
||||
export const NAV_MENU = [
|
||||
{
|
||||
title: 'Главная',
|
||||
url: '/'
|
||||
url: '/',
|
||||
},
|
||||
{
|
||||
title: 'Список хранилищ',
|
||||
url: '/api'
|
||||
url: '/api',
|
||||
},
|
||||
{
|
||||
title: 'Журнал',
|
||||
url: '/logs'
|
||||
url: '/logs',
|
||||
},
|
||||
{
|
||||
title: 'Личный кабинет',
|
||||
url: '/profile',
|
||||
className: 'MainMenu__profileButton'
|
||||
},
|
||||
];
|
||||
|
||||
@ -27,12 +33,20 @@ class MainMenu extends Component {
|
||||
super('#main-menu', document.body);
|
||||
|
||||
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', () => {
|
||||
routeService.goTo('/');
|
||||
});
|
||||
|
||||
this.addEventListener(this.avatar, 'click', () => {
|
||||
routeService.goTo('/profile');
|
||||
});
|
||||
|
||||
this.addSubscribe(routeService, EVENTS.ROUTE_CHANGE, (route) => {
|
||||
this.menuItems.forEach(({url, link}) => {
|
||||
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 = () => {
|
||||
this.menuItems = NAV_MENU.map(({url, title}) => {
|
||||
this.menuItems = NAV_MENU.map(({url, title, className = ''}) => {
|
||||
const li = createElement({
|
||||
tagName: 'li',
|
||||
parentNode: this.buttonsContainer,
|
||||
options: {
|
||||
className: 'nav-item',
|
||||
className: `nav-item ${className}`,
|
||||
},
|
||||
});
|
||||
const link = createElement({
|
||||
|
||||
@ -35,6 +35,7 @@ export const EVENTS = {
|
||||
ROUTE_SEARCH_CHANGE: 'routeSearchChange',
|
||||
ROW_CLICK: 'rowClick',
|
||||
ROW_DOUBLE_CLICK: 'rowDoubleClick',
|
||||
CHANGE_USER_INFO: 'changeUserInfo',
|
||||
};
|
||||
|
||||
export const FORM_TYPES = {
|
||||
|
||||
26
src/services/UserInfoService.js
Normal file
26
src/services/UserInfoService.js
Normal 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
27
src/utils/jwtDecode.js
Normal 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, '/')
|
||||
)
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user