Skip to content

Commit

Permalink
feat: implement cooperation page
Browse files Browse the repository at this point in the history
  • Loading branch information
Kleostro committed Jun 5, 2024
1 parent 5ae7cde commit 35ff086
Show file tree
Hide file tree
Showing 10 changed files with 340 additions and 3 deletions.
4 changes: 4 additions & 0 deletions src/app/App/model/AppModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class AppModel {
const { default: CatalogPageModel } = await import('@/pages/CatalogPage/model/CatalogPageModel.ts');
return new CatalogPageModel(this.appView.getHTML());
},
[PAGE_ID.COOPERATION_PAGE]: async (): Promise<Page> => {
const { default: CooperationPageModel } = await import('@/pages/CooperationPage/model/CooperationPageModel.ts');
return new CooperationPageModel(this.appView.getHTML());
},
[PAGE_ID.DEFAULT_PAGE]: async (): Promise<Page> => {
const { default: MainPageModel } = await import('@/pages/MainPage/model/MainPageModel.ts');
return new MainPageModel(this.appView.getHTML());
Expand Down
4 changes: 2 additions & 2 deletions src/app/styles/variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
--bold-font: 700 1rem 'Cerapro', sans-serif; // 16px
--medium-bold-font: 700 1.125rem 'Cerapro', sans-serif; // 18px
--extra-bold-font: 700 2.1875rem 'Cerapro', sans-serif; // 35px
--black-font: 900 2rem 'Cerapro', sans-serif; // 32px
--extra-black-font: 900 3.5rem 'Cerapro', sans-serif; // 70px
--black-font: 900 2.1875rem 'Cerapro', sans-serif; // 35px
--extra-black-font: 900 2.5rem 'Cerapro', sans-serif; // 40px

body.light {
// colors
Expand Down
1 change: 1 addition & 0 deletions src/pages/CartPage/view/cartPageView.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ $color: var(--steam-green-800);
width: max-content;
height: max-content;
text-transform: none;
cursor: pointer;

&::after {
bottom: var(--five);
Expand Down
44 changes: 44 additions & 0 deletions src/pages/CooperationPage/model/CooperationPageModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { CooperationData } from '@/shared/types/validation/cooperationData.ts';

import getStore from '@/shared/Store/Store.ts';
import { setCurrentPage } from '@/shared/Store/actions.ts';
import observeStore, { selectCurrentLanguage } from '@/shared/Store/observer.ts';
import { PAGE_ID } from '@/shared/constants/pages.ts';
import isCooperationData from '@/shared/types/validation/cooperationData.ts';
import getCooperationData from '@/shared/utils/getCooperationData.ts';
import showErrorMessage from '@/shared/utils/userMessage.ts';

import CooperationPageView from '../view/CooperationPageView.ts';

class CooperationPageModel {
private view: CooperationPageView;

constructor(parent: HTMLDivElement) {
this.view = new CooperationPageView(parent);
this.init();
}

private init(): void {
getCooperationData()
.then((data) => {
if (isCooperationData(data)) {
this.view.drawCooperationInfo(data);
this.observeState(data);
}
})
.catch(showErrorMessage);
getStore().dispatch(setCurrentPage(PAGE_ID.COOPERATION_PAGE));
}

private observeState(data: CooperationData[]): void {
observeStore(selectCurrentLanguage, () => {
this.view.redrawCooperationInfo(data);
});
}

public getHTML(): HTMLDivElement {
return this.view.getHTML();
}
}

export default CooperationPageModel;
136 changes: 136 additions & 0 deletions src/pages/CooperationPage/view/CooperationPageView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import type { CooperationData } from '@/shared/types/validation/cooperationData';

import getStore from '@/shared/Store/Store.ts';
import createBaseElement from '@/shared/utils/createBaseElement.ts';

import styles from './cooperationPageView.module.scss';

class CooperationPageView {
private page: HTMLDivElement;

private parent: HTMLDivElement;

private wrapper: HTMLDivElement;

constructor(parent: HTMLDivElement) {
this.parent = parent;
this.parent.innerHTML = '';
this.wrapper = this.createCooperationWrapper();
this.page = this.createHTML();
window.scrollTo(0, 0);
}

private createCooperationWrapper(): HTMLDivElement {
this.wrapper = createBaseElement({
cssClasses: [styles.cooperationWrapper],
tag: 'div',
});

return this.wrapper;
}

private createDescription(description: string): HTMLParagraphElement {
const descriptionElement = createBaseElement({
cssClasses: [styles.cooperationDescription],
tag: 'p',
});
descriptionElement.textContent = description;
return descriptionElement;
}

private createHTML(): HTMLDivElement {
this.page = createBaseElement({
cssClasses: [styles.cooperationPage],
tag: 'div',
});

this.page.append(this.wrapper);
this.parent.append(this.page);

return this.page;
}

private createItem(text: string): HTMLLIElement {
const listItem = createBaseElement({
cssClasses: [styles.cooperationListItem],
innerContent: text,
tag: 'li',
});
return listItem;
}

private createItemList(): HTMLUListElement {
const itemList = createBaseElement({
cssClasses: [styles.cooperationItemList],
tag: 'ul',
});
return itemList;
}

private createSubtitle(subtitle: string): HTMLHeadingElement {
const subtitleElement = createBaseElement({
cssClasses: [styles.cooperationSubtitle],
tag: 'h2',
});
subtitleElement.textContent = subtitle;
return subtitleElement;
}

private createTitle(title: string): HTMLHeadingElement {
const titleElement = createBaseElement({
cssClasses: [styles.cooperationTitle],
tag: 'h2',
});
titleElement.textContent = title;
return titleElement;
}

public drawCooperationInfo(data: CooperationData[]): void {
data.forEach((item) => {
const section = createBaseElement({
cssClasses: [styles.cooperationSection],
tag: 'div',
});
const currentTitle = item[getStore().getState().currentLanguage].title;
const currentDescription = item[getStore().getState().currentLanguage].description;
const currentSubtitle = item[getStore().getState().currentLanguage].subtitle;
const currentItems = item[getStore().getState().currentLanguage].items;
if (currentTitle) {
const title = this.createTitle(currentTitle);
section.append(title);
}

if (currentDescription) {
const title = this.createDescription(currentDescription);
section.append(title);
}

if (currentSubtitle) {
const title = this.createSubtitle(currentSubtitle);
section.append(title);
}

if (currentItems) {
const createItemList = this.createItemList();
currentItems.forEach((item) => {
const listItem = this.createItem(item.text);
createItemList.append(listItem);
});
section.append(createItemList);
}

this.wrapper.append(section);
});
}

public getHTML(): HTMLDivElement {
return this.page;
}

public redrawCooperationInfo(data: CooperationData[]): void {
this.wrapper.innerHTML = '';
this.drawCooperationInfo(data);
}
}

export default CooperationPageView;
79 changes: 79 additions & 0 deletions src/pages/CooperationPage/view/cooperationPageView.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
.cooperationPage {
position: relative;
display: block;
padding: 0 var(--small-offset);
animation: show 0.2s ease-out forwards;
}

@keyframes show {
0% {
opacity: 0;
}

100% {
display: block;
opacity: 1;
}
}

.cooperationWrapper {
display: flex;
flex-direction: column;
margin: 0 auto;
max-width: 80%;
gap: var(--extra-small-offset);

@media (max-width: 768px) {
max-width: 100%;
}
}

.cooperationSection {
display: flex;
flex-direction: column;
border-radius: var(--medium-br);
padding: var(--small-offset);
background-color: var(--steam-green-1000);
gap: var(--extra-small-offset);
}

.cooperationTitle {
font: var(--medium-font);
letter-spacing: var(--one);
color: var(--steam-green-800);
}

.cooperationSubtitle {
font: var(--medium-bold-font);
letter-spacing: var(--one);
color: var(--noble-gray-1000);
}

.cooperationDescription {
font: var(--regular-font);
line-height: 170%;
letter-spacing: var(--one);
color: var(--noble-gray-800);
}

.cooperationItemList {
display: flex;
flex-direction: column;
gap: var(--tiny-offset);
}

.cooperationListItem {
position: relative;
margin-left: var(--extra-small-offset);
font: var(--regular-font);
letter-spacing: var(--one);
color: var(--noble-gray-700);

&::after {
content: '';
position: absolute;
left: -1.7rem;
top: 0;
padding: 0.15rem 0.3rem;
}
}
3 changes: 3 additions & 0 deletions src/shared/constants/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const PAGE_TITLE: Record<LanguageChoiceType, Record<string, string>> = {
blog: 'Blog',
cart: 'Cart',
catalog: 'Catalog',
cooperation: 'Cooperation',
login: 'Login',
main: 'Main',
product: 'Product',
Expand All @@ -22,6 +23,7 @@ export const PAGE_TITLE: Record<LanguageChoiceType, Record<string, string>> = {
blog: 'Блог',
cart: 'Корзина',
catalog: 'Каталог',
cooperation: 'Сотрудничество',
login: 'Вход',
main: 'Главная',
product: 'Товар',
Expand Down Expand Up @@ -125,6 +127,7 @@ export const PAGE_ID = {
BLOG: 'blog',
CART_PAGE: 'cart',
CATALOG_PAGE: 'catalog',
COOPERATION_PAGE: 'cooperation',
DEFAULT_PAGE: '',
LOGIN_PAGE: 'login',
MAIN_PAGE: 'main',
Expand Down
61 changes: 61 additions & 0 deletions src/shared/types/validation/cooperationData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
interface CooperationListItem {
text: string;
}

interface CooperationItem {
description?: string;
items?: CooperationListItem[];
subtitle?: string;
title?: string;
}

export interface CooperationData {
en: CooperationItem;
ru: CooperationItem;
}

const isCooperationItem = (data: unknown): data is CooperationItem => {
let result = true;
if (data === null || typeof data !== 'object') {
result = false;
return result;
}

if ('description' in data && typeof data.description === 'string') {
result = true;
}

if ('title' in data && typeof data.title === 'string') {
result = true;
}

if ('subtitle' in data && typeof data.subtitle === 'string') {
result = true;
}

if ('items' in data && Array.isArray(data.items)) {
data.items.forEach((item: CooperationListItem) => {
result = 'text' in item && typeof item.text === 'string';
});
}

return result;
};

const isCooperationData = (data: unknown): data is CooperationData[] => {
let result = true;
if (!Array.isArray(data)) {
return false;
}
data.forEach((item: CooperationData) => {
if ('en' in item && 'ru' in item) {
result = isCooperationItem(item.en) && isCooperationItem(item.ru);
} else {
result = false;
}
});

return result;
};

export default isCooperationData;
2 changes: 1 addition & 1 deletion src/shared/utils/calcUserBirthDayRange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const calcUserBirthDayRange = (birthDay: string): { end: string; start: string }
const birthDate = new Date(birthDay);

const start = new Date(birthDate.getFullYear(), birthDate.getMonth(), birthDate.getDate() - 3);
const end = new Date(birthDate.getFullYear(), birthDate.getMonth(), birthDate.getDate() + 4);
const end = new Date(birthDate.getFullYear(), birthDate.getMonth(), birthDate.getDate() + 3);

if (start.getDate() < 1) {
start.setMonth(start.getMonth() - 1);
Expand Down
9 changes: 9 additions & 0 deletions src/shared/utils/getCooperationData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const COOPERATION_URL = 'https://raw.githubusercontent.com/stardustmeg/greenshop-db/main/cooperation/cooperation.json';

const getCooperationData = async (): Promise<unknown> => {
const response = await fetch(COOPERATION_URL);
const data: unknown = await response.json();
return data;
};

export default getCooperationData;

0 comments on commit 35ff086

Please sign in to comment.