Skip to content

Commit

Permalink
refactor: rewrite header using handlebars
Browse files Browse the repository at this point in the history
  • Loading branch information
rasulov1337 committed Dec 20, 2024
1 parent 9454535 commit 9496f66
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 187 deletions.
2 changes: 1 addition & 1 deletion src/components/AuthPopup/AuthPopup.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class='overlay'>
<div class='overlay' id='overlay'>
<form novalidate method='POST' class='auth-modal' id='auth-form'>
<div class='close-cross'>
<a>
Expand Down
37 changes: 37 additions & 0 deletions src/components/Header/Header.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<header id='header' class='header-wrapper'>
<div class='header' id='header-inner'>
<div class='header__hrefs'>
{{#each menu}}
<a href='{{this.href}}' class='header__href'>{{this.text}}</a>
{{/each}}
</div>

<a class='header__logo-text-link' href='/'>
<img class='header__img2' src='/name.png' /></a>

<div class='header__signs'>
{{#each signs}}
<a class='header__sign' href='{{this.href}}'>
<img src='{{this.src}}' width='30' />
</a>
{{/each}}
</div>

{{#if isAuthorized}}
<div class='header__avatar-container' id='js-avatar-container'>
<img
src='{{sessionData.avatar}}'
id='js-header-avatar'
class='header__avatar-container__avatar'
width='50'
height='50'
/>
</div>
{{else}}
<button
class='header__button'
id='header-signin-button'
>Войти</button>
{{/if}}
</div>
</header>
6 changes: 3 additions & 3 deletions src/components/Header/Header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
padding: 0;
}

.header__hrefs__href {
.header__href {
color: #635b5b;
text-decoration: none;
font-size: 24px;
Expand All @@ -36,7 +36,7 @@
height: 100px;
}

.header__hrefs__href-active {
.header__href--active {
font-weight: bold;
position: relative;

Expand Down Expand Up @@ -216,6 +216,7 @@
}

.header__avatar-container {
display: none;
position: absolute;
right: 0;
margin: 0;
Expand All @@ -236,7 +237,6 @@
}

.header__img-logo,
.header__signs,
.header__hrefs {
display: none;
}
Expand Down
278 changes: 95 additions & 183 deletions src/components/Header/Header.ts
Original file line number Diff line number Diff line change
@@ -1,214 +1,126 @@
'use strict';

import ApiClient from '../../modules/ApiClient';
import globalStore from '../../modules/GlobalStore';
import AuthPopup from '../AuthPopup/AuthPopup';
import BaseComponent from '../BaseComponent/BaseComponent';
import PopupAlert from '../PopupAlert/PopupAlert';
import ProfilePopup from '../ProfilePopup/ProfilePopup';

interface HeaderCallbacks {
messagesPage: () => void;
favoritesPage: () => void;
notificationsPage: () => void;
signInPage: () => void;
interface SessionData {
avatar: string;
id: string;
}

class Header {
#config;
#isAuthorized;
#headerCallbacks;
#headerState;
#menuContainer;
#menuContainerWrapper;

constructor(headerCallbacks: HeaderCallbacks, isAuth: boolean) {
this.#headerCallbacks = headerCallbacks;
this.#menuContainerWrapper = document.createElement('header');
this.#menuContainerWrapper.id = 'header';
this.#menuContainerWrapper.classList.add('header-wrapper');
this.#menuContainer = document.createElement('div');
this.#menuContainer.classList.add('header');
this.#menuContainer.id = 'header-inner';

this.#isAuthorized = isAuth;

this.#config = {
menu: {
Main: {
href: '/',
text: 'Главная',
export default class Header extends BaseComponent {
constructor(parent: HTMLElement, sessionData?: SessionData) {
super({
parent: parent,
id: '',
templateName: 'Header',
templateData: {
isAuthorized: globalStore.auth.isAuthorized,
sessionData: sessionData,
menu: {
Main: {
href: '/',
text: 'Главная',
},
Map: {
href: '/map',
text: 'Карта',
},
},
Map: {
href: '/map',
text: 'Карта',
},
},

signs: {
Messages: {
src: '/svg/messages.svg',
href: '/chats',
callback: headerCallbacks.messagesPage,
},
Favorites: {
src: '/svg/favorites.svg',
href: '/favorites',
callback: headerCallbacks.favoritesPage,
},
Notifications: {
src: '/svg/notifications.svg',
href: '/notifications',
callback: headerCallbacks.notificationsPage,
signs: {
Messages: {
src: '/svg/messages.svg',
href: '/chats',
},
Favorites: {
src: '/svg/favorites.svg',
href: '/favorites',
},
Notifications: {
src: '/svg/notifications.svg',
href: '/notifications',
},
},
},
};

this.#headerState = {
activePageLink: null,
headerElements: {},
};
});
}

this.#render();
protected addEventListeners(): void {
this.addLinksEventListeners();
this.addAvatarEventListeners();
this.addSignsEventListeners();
this.addLoginButtonEventListenListener();
}

#renderMainText() {
const nameImg = document.createElement('img');
nameImg.classList.add('header__img2');
nameImg.src = '/name.png';
private addLinksEventListeners() {
const links = document.getElementsByClassName(
'header__href'
) as HTMLCollectionOf<HTMLAnchorElement>;

const link = document.createElement('a');
link.classList.add('header__logo-text-link');
link.href = '/';
[...links].forEach((elem: HTMLAnchorElement) => {
elem.onclick = () => {
document
.querySelector('.header__href--active')
?.classList.remove('header__href--active');

link.appendChild(nameImg);
elem.classList.add('header__href--active');
};

this.#menuContainer.appendChild(link);
if (elem.href === location.href) {
elem.classList.add('header__href--active');
}
});
}

#renderHrefs() {
const hrefs = document.createElement('div');
hrefs.classList.add('header__hrefs');
Object.entries(this.#config.menu).forEach(
([key, { href, text }], index) => {
const menuElement = document.createElement('a');
menuElement.href = href;
menuElement.text = text;
menuElement.addEventListener('click', (e) => {
e.preventDefault();

const elements = document.getElementsByClassName(
'header__hrefs__href'
);
[...elements].forEach((elem) =>
elem.classList.remove('header__hrefs__href-active')
);

menuElement.classList.add('header__hrefs__href-active');
});
menuElement.classList.add('header__hrefs__href');
private addAvatarEventListeners() {
const avatarContainer = document.getElementById('js-header-avatar');
if (!avatarContainer) return;

if (index === 0) {
menuElement.classList.add('header__hrefs__href-active');
this.#headerState.activePageLink = menuElement;
}
avatarContainer.onclick = function () {
const menu = new ProfilePopup();
menu.render(avatarContainer.parentElement!);
};
}

this.#headerState.headerElements[key] = menuElement;
hrefs.appendChild(menuElement);
}
private addSignsEventListeners() {
const signs = Array.from(
document.getElementsByClassName(
'header__sign'
) as HTMLCollectionOf<HTMLAnchorElement>
);
this.#menuContainer.appendChild(hrefs);
}

#renderSigns() {
const signsContainer = document.createElement('div');
signsContainer.classList.add('header__signs');
Object.entries(this.#config.signs).forEach(
([_, { href, src, callback }]) => {
const signElement = document.createElement('a');
if (this.#isAuthorized) signElement.href = href;
const img = document.createElement('img');
img.src = src;
img.width = 30;
signElement.appendChild(img);
signElement.addEventListener('click', (e: Event) => {
if (this.#isAuthorized) {
callback();
} else {
e.preventDefault();
this.#headerCallbacks.signInPage();
const errorMessage = PopupAlert(
'Необходимо зарегистрироваться'
);
document
.querySelector('.overlay')
?.appendChild(errorMessage);
}
});

signsContainer.appendChild(signElement);
signs.forEach((elem: HTMLAnchorElement) => {
if (!globalStore.auth.isAuthorized) {
elem.href = '';
}
);
this.#menuContainer.appendChild(signsContainer);
}

async #renderButtonOrAvatar() {
if (this.#isAuthorized) {
const avatarContainer = document.createElement('div');
avatarContainer.classList.add('header__avatar-container');
const avatar = document.createElement('img');

const uuid = await ApiClient.getSessionData();
const data = await ApiClient.getUser(uuid.id);
avatar.src = data.avatar;
avatar.width = 50;
avatar.height = 50;
avatar.classList.add('header__avatar-container__avatar');
avatar.classList.add('js-header-avatar');

avatar.onclick = () => {
const profileList = new ProfilePopup();
profileList.render(this.#menuContainer);
};
elem.onclick = () => {
if (!globalStore.auth.isAuthorized) {
const errorMessage = PopupAlert(
'Необходимо зарегистрироваться'
);
const authPopup = new AuthPopup();

avatarContainer.appendChild(avatar);

this.#menuContainer.appendChild(avatarContainer);
} else {
const entryButton = document.createElement('button');
entryButton.classList.add('header__button');
entryButton.textContent = 'Войти';
entryButton.addEventListener(
'click',
this.#headerCallbacks.signInPage
);
this.#menuContainer.appendChild(entryButton);
}
authPopup.render(document.body);
document
.getElementById('overlay')
?.appendChild(errorMessage);
}
};
});
}

async #render() {
// TODO: REWRITE TO HBS. IT IS TOO HARD TO MAINTAIN JS ONLY COMPONENT LIKE THIS

const menu = document.createElement('ul');
menu.classList.add('menu');
for (const menuSection in this.#config.menu) {
const data = this.#config.menu[menuSection];
const elem = document.createElement('a');
elem.classList.add('menu__element');
elem.textContent = data['text'];
elem.href = data['href'];
menu.appendChild(elem);
}
this.#menuContainer.appendChild(menu);

this.#menuContainerWrapper.appendChild(this.#menuContainer);

this.#renderHrefs();
this.#renderMainText();
this.#renderSigns();
await this.#renderButtonOrAvatar();
}
private addLoginButtonEventListenListener() {
const button = document.getElementById('header-signin-button');
if (!button) return;

getElement() {
return this.#menuContainerWrapper;
button.onclick = () => {
const authPopup = new AuthPopup();
authPopup.render(document.body);
};
}
}

export default Header;

0 comments on commit 9496f66

Please sign in to comment.