Skip to content

Commit

Permalink
feat(RSS-ECOMM-3_29): pages lazy loading (#210)
Browse files Browse the repository at this point in the history
* feat: implement lazy loading for pages

* fix: add a catch block
  • Loading branch information
stardustmeg authored May 9, 2024
1 parent a975cb7 commit 5f0b5c6
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 40 deletions.
60 changes: 44 additions & 16 deletions src/app/App/model/AppModel.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import type { Page } from '@/shared/types/common.ts';

import RouterModel from '@/app/Router/model/RouterModel.ts';
import LoginPageModel from '@/pages/LoginPage/model/LoginPageModel.ts';
import MainPageModel from '@/pages/MainPage/model/MainPageModel.ts';
import NotFoundPageModel from '@/pages/NotFoundPage/model/NotFoundPageModel.ts';
import RegistrationPageModel from '@/pages/RegistrationPage/model/RegistrationPageModel.ts';
import { PAGE_ID } from '@/shared/constants/pages.ts';
import FooterModel from '@/widgets/Footer/model/FooterModel.ts';
import HeaderModel from '@/widgets/Header/model/HeaderModel.ts';
Expand All @@ -17,22 +13,54 @@ class AppModel {
private router = new RouterModel();

constructor() {
this.initialize()
.then()
.catch(() => {
throw new Error('AppModel initialization error');
});
}

private createRoutes(): Promise<Map<string, () => Promise<Page>>> {
const routesMap = {
[PAGE_ID.DEFAULT_PAGE]: async (): Promise<Page> => {
const { default: MainPageModel } = await import('@/pages/MainPage/model/MainPageModel.ts');
return new MainPageModel(this.appView.getHTML());
},
[PAGE_ID.LOGIN_PAGE]: async (): Promise<Page> => {
const { default: LoginPageModel } = await import('@/pages/LoginPage/model/LoginPageModel.ts');
return new LoginPageModel(this.appView.getHTML(), this.router);
},
[PAGE_ID.MAIN_PAGE]: async (): Promise<Page> => {
const { default: MainPageModel } = await import('@/pages/MainPage/model/MainPageModel.ts');
return new MainPageModel(this.appView.getHTML());
},
[PAGE_ID.NOT_FOUND_PAGE]: async (): Promise<Page> => {
const { default: NotFoundPageModel } = await import('@/pages/NotFoundPage/model/NotFoundPageModel.ts');
return new NotFoundPageModel(this.appView.getHTML(), this.router);
},
[PAGE_ID.REGISTRATION_PAGE]: async (): Promise<Page> => {
const { default: RegistrationPageModel } = await import(
'@/pages/RegistrationPage/model/RegistrationPageModel.ts'
);
return new RegistrationPageModel(this.appView.getHTML(), this.router);
},
};

const routes = new Map<string, () => Promise<Page>>();
Object.entries(routesMap).forEach(([key, value]) => {
routes.set(key, value);
});

return Promise.resolve(routes);
}

private async initialize(): Promise<void> {
document.body.append(this.appView.getHTML());
this.appView.getHTML().insertAdjacentElement('beforebegin', new HeaderModel(this.router).getHTML());
this.appView.getHTML().insertAdjacentElement('afterend', new FooterModel(this.router).getHTML());
this.router.setRoutes(this.createRoutes());
}

private createRoutes(): Map<string, () => Page> {
return new Map(
Object.entries({
[PAGE_ID.DEFAULT_PAGE]: () => new MainPageModel(this.appView.getHTML()),
[PAGE_ID.LOGIN_PAGE]: () => new LoginPageModel(this.appView.getHTML(), this.router),
[PAGE_ID.MAIN_PAGE]: () => new MainPageModel(this.appView.getHTML()),
[PAGE_ID.NOT_FOUND_PAGE]: () => new NotFoundPageModel(this.appView.getHTML(), this.router),
[PAGE_ID.REGISTRATION_PAGE]: () => new RegistrationPageModel(this.appView.getHTML(), this.router),
}),
);
const routes = await this.createRoutes();
this.router.setRoutes(routes);
}

public start(): boolean {
Expand Down
14 changes: 7 additions & 7 deletions src/app/Router/model/RouterModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ const PATH_SEGMENTS_TO_KEEP = import.meta.env.VITE_APP_PATH_SEGMENTS_TO_KEEP;
const PROJECT_TITLE = import.meta.env.VITE_APP_PROJECT_TITLE;

class RouterModel {
private routes: Map<string, () => Page> = new Map();
private routes: Map<string, () => Promise<Page>> = new Map();

constructor() {
document.addEventListener('DOMContentLoaded', () => {
document.addEventListener('DOMContentLoaded', async () => {
const currentPath = window.location.pathname
.split(DEFAULT_SEGMENT)
.slice(PATH_SEGMENTS_TO_KEEP + NEXT_SEGMENT)
.join(DEFAULT_SEGMENT);
this.navigateTo(currentPath);
await this.navigateTo(currentPath);
});
}

Expand All @@ -25,7 +25,7 @@ class RouterModel {
document.title = title;
}

public navigateTo(path: string): void {
public async navigateTo(path: string): Promise<void> {
const pathnameApp = window.location.pathname
.split(DEFAULT_SEGMENT)
.slice(NEXT_SEGMENT, PATH_SEGMENTS_TO_KEEP + NEXT_SEGMENT)
Expand All @@ -38,14 +38,14 @@ class RouterModel {
this.changeAppTitle(pathParts[1], hasRoute);

if (!hasRoute) {
this.routes.get(PAGE_ID.NOT_FOUND_PAGE)?.();
await this.routes.get(PAGE_ID.NOT_FOUND_PAGE)?.();
return;
}

this.routes.get(pathParts[1])?.();
await this.routes.get(pathParts[1])?.();
}

public setRoutes(routes: Map<string, () => Page>): Map<string, () => Page> {
public setRoutes(routes: Map<string, () => Promise<Page>>): Map<string, () => Promise<Page>> {
this.routes = routes;
return this.routes;
}
Expand Down
10 changes: 8 additions & 2 deletions src/entities/Navigation/model/NavigationModel.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type RouterModel from '@/app/Router/model/RouterModel';

import serverMessageModel from '@/shared/ServerMessage/model/ServerMessageModel.ts';
import getStore from '@/shared/Store/Store.ts';
import observeStore, { selectCurrentPage, selectCurrentUser } from '@/shared/Store/observer.ts';
import { MESSAGE_STATUS, SERVER_MESSAGE } from '@/shared/constants/messages.ts';
import { PAGE_ID } from '@/shared/constants/pages.ts';

import NavigationView from '../view/NavigationView.ts';
Expand Down Expand Up @@ -43,9 +45,13 @@ class NavigationModel {
private setNavigationLinksHandlers(): boolean {
const navigationLinks = this.view.getNavigationLinks();
navigationLinks.forEach((link, route) => {
link.getHTML().addEventListener('click', (event) => {
link.getHTML().addEventListener('click', async (event) => {
event.preventDefault();
this.router.navigateTo(route);
try {
await this.router.navigateTo(route);
} catch {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
}
});
});

Expand Down
25 changes: 19 additions & 6 deletions src/pages/LoginPage/model/LoginPageModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import type RouterModel from '@/app/Router/model/RouterModel.ts';
import type { Page } from '@/shared/types/common.ts';
import type { User } from '@/shared/types/user.ts';

import serverMessageModel from '@/shared/ServerMessage/model/ServerMessageModel.ts';
import getStore from '@/shared/Store/Store.ts';
import { setCurrentPage } from '@/shared/Store/actions.ts';
import observeStore, { selectCurrentUser } from '@/shared/Store/observer.ts';
import { MESSAGE_STATUS, SERVER_MESSAGE } from '@/shared/constants/messages.ts';
import { PAGE_ID, PAGE_LINK_TEXT, PAGE_LINK_TEXT_KEYS } from '@/shared/constants/pages.ts';
import observeCurrentLanguage from '@/shared/utils/observeCurrentLanguage.ts';
import LoginFormModel from '@/widgets/LoginForm/model/LoginFormModel.ts';
Expand All @@ -24,30 +26,41 @@ class LoginPageModel implements Page {
this.init();
}

private checkAuthUser(): User | null {
private async checkAuthUser(): Promise<User | null> {
const { currentUser } = getStore().getState();

if (currentUser) {
this.router.navigateTo(PAGE_ID.MAIN_PAGE);
return currentUser;
try {
await this.router.navigateTo(PAGE_ID.MAIN_PAGE);
return currentUser;
} catch (error) {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
return null;
}
}

return null;
}

private init(): boolean {
getStore().dispatch(setCurrentPage(PAGE_ID.LOGIN_PAGE));
this.checkAuthUser();
this.checkAuthUser().catch(() => {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
});
this.view.getAuthWrapper().append(this.loginForm.getHTML());
this.loginForm.getFirstInputField().getView().getInput().getHTML().focus();
this.setRegisterLinkHandler();
observeStore(selectCurrentUser, () => this.checkAuthUser());
return true;
}

private registerLinkHandler(event: Event): void {
private async registerLinkHandler(event: Event): Promise<void> {
event.preventDefault();
this.router.navigateTo(PAGE_ID.REGISTRATION_PAGE);
try {
await this.router.navigateTo(PAGE_ID.REGISTRATION_PAGE);
} catch (error) {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
}
}

private setRegisterLinkHandler(): void {
Expand Down
10 changes: 8 additions & 2 deletions src/pages/RegistrationPage/model/RegistrationPageModel.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type RouterModel from '@/app/Router/model/RouterModel.ts';
import type { Page } from '@/shared/types/common.ts';

import serverMessageModel from '@/shared/ServerMessage/model/ServerMessageModel.ts';
import getStore from '@/shared/Store/Store.ts';
import { setCurrentPage } from '@/shared/Store/actions.ts';
import observeStore, { selectIsUserLoggedIn } from '@/shared/Store/observer.ts';
import { MESSAGE_STATUS, SERVER_MESSAGE } from '@/shared/constants/messages.ts';
import { PAGE_ID, PAGE_LINK_TEXT, PAGE_LINK_TEXT_KEYS } from '@/shared/constants/pages.ts';
import observeCurrentLanguage from '@/shared/utils/observeCurrentLanguage.ts';
import RegisterFormModel from '@/widgets/RegistrationForm/model/RegistrationFormModel.ts';
Expand Down Expand Up @@ -31,9 +33,13 @@ class RegistrationPageModel implements Page {
this.setLoginLinkHandler();
}

private loginLinkHandler(event: Event): void {
private async loginLinkHandler(event: Event): Promise<void> {
event.preventDefault();
this.router.navigateTo(PAGE_ID.LOGIN_PAGE);
try {
await this.router.navigateTo(PAGE_ID.LOGIN_PAGE);
} catch {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
}
}

private setLoginLinkHandler(): void {
Expand Down
28 changes: 21 additions & 7 deletions src/widgets/Header/model/HeaderModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import type RouterModel from '@/app/Router/model/RouterModel.ts';

import NavigationModel from '@/entities/Navigation/model/NavigationModel.ts';
import getCustomerModel from '@/shared/API/customer/model/CustomerModel.ts';
import serverMessageModel from '@/shared/ServerMessage/model/ServerMessageModel.ts';
import getStore from '@/shared/Store/Store.ts';
import { setCurrentUser } from '@/shared/Store/actions.ts';
import observeStore, { selectCurrentUser } from '@/shared/Store/observer.ts';
import { MESSAGE_STATUS, SERVER_MESSAGE } from '@/shared/constants/messages.ts';
// import { LANGUAGE_CHOICE } from '@/shared/constants/buttons.ts';
import { PAGE_ID } from '@/shared/constants/pages.ts';

Expand Down Expand Up @@ -44,11 +46,15 @@ class HeaderModel {
return true;
}

private logoutHandler(): boolean {
private async logoutHandler(): Promise<boolean> {
localStorage.clear();
getStore().dispatch(setCurrentUser(null));
getCustomerModel().logout();
this.router.navigateTo(PAGE_ID.LOGIN_PAGE);
try {
getCustomerModel().logout();
await this.router.navigateTo(PAGE_ID.LOGIN_PAGE);
} catch {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
}
return true;
}

Expand All @@ -72,17 +78,25 @@ class HeaderModel {

private setLogoHandler(): boolean {
const logo = this.view.getLinkLogo().getHTML();
logo.addEventListener('click', (event) => {
logo.addEventListener('click', async (event) => {
event.preventDefault();
this.router.navigateTo(PAGE_ID.DEFAULT_PAGE);
try {
await this.router.navigateTo(PAGE_ID.DEFAULT_PAGE);
} catch {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
}
});
return true;
}

private setLogoutButtonHandler(): boolean {
const logoutButton = this.view.getLogoutButton();
logoutButton.getHTML().addEventListener('click', () => {
this.logoutHandler();
logoutButton.getHTML().addEventListener('click', async () => {
try {
await this.logoutHandler();
} catch {
serverMessageModel.showServerMessage(SERVER_MESSAGE.BAD_REQUEST, MESSAGE_STATUS.ERROR);
}
logoutButton.setDisabled();
});
return true;
Expand Down

0 comments on commit 5f0b5c6

Please sign in to comment.