Skip to content

oskalfi/web-larek-frontend

Repository files navigation

Проектная работа "Веб-ларек"

Стек: HTML, SCSS, TS, Webpack

Структура проекта:

  • src/ — исходные файлы проекта
  • src/components/ — папка с JS компонентами
  • src/components/base/ — папка с базовым кодом

Важные файлы:

  • src/pages/index.html — HTML-файл главной страницы
  • src/types/index.ts — файл с типами
  • src/index.ts — точка входа приложения
  • src/scss/styles.scss — корневой файл стилей
  • src/utils/constants.ts — файл с константами
  • src/utils/utils.ts — файл с утилитами

Установка и запуск

Для установки и запуска проекта необходимо выполнить команды

npm install
npm run start

или

yarn
yarn start

Сборка

npm run build

или

yarn build

Архитектура

Архитектурный паттерн: Model-View-Presenter. Код приложения разделён на:

  • слой данных (model), отвечает за хранение и изменение данных;
  • слой отображения (view), отвечает за отображение данных на странице;
  • презентер, отвечает за связь между отображением и слоем данных.

Типы данных, используемые в приложении

Модель для работы с массивом товаров:

interface IAppModel {
	products: ICard[];
	preview: string | null;
	isBlocked: boolean;
	setItems(items: ICard[]): void;
	setPreview(id: string): void;
	getItem(cardId: string): ICard;
	getItems(): ICard[];
}

Товар:

interface ICard {
	id: string;
	description: string;
	image: string;
	title: string;
	category: string;
	price: number| null;
}

Корзина:

interface IBasketModel {
	products: ICard[];
	counter: number;
	addItem(cardId: string): number;
	removeItem(cardId: string): void;
	getTotalPrice(): number;
	isBasketProduct(id: string): boolean;
	getCounter(): number;
}

Данные покупателя:

interface IUserData {
	payment: string;
	email: string;
	phone: string;
	address: string;
}

Данные заказа:

interface IOrder extends IUserData {
	total: number;
	items: string[]; // массив с идентификаторами товаров
}

Типы ответа сервера после отправки заказа:

type TSuccessOrderResponse = {
	id: string;
	total: number;
}
type TFailOrderResponse = {
	error: string;
}

Данные для обработчика события выбора метода оплаты:

export interface IPaymentPickEvent {
	event: Event;
	allButtons: Record<string, HTMLButtonElement>;
}

Данные для обработчика события добавления товара в корзину:

export type AddToBasketEvent = {
	records: ICard;
	card: Card;
};

Базовый код

Класс Component<T>

Абстрактный класс, наследуемый классами слоя отображения. Реализует методы создания элемента с помощью шаблона,
его обновления и перерисовки, а также удаления из разметки. Конструктор класса принимает объект типа T,
для определения и последующего использования его данных при заполнении и рендеринге элемента.

Конструктор:

constructor(template: HTMLTemplateElement, events: IEvents) {
	this.template = template;
	this.events = events;
}

Поля:

  • protected template: HTMLTemplateElement — ссылка на шаблон элемента;
  • protected element: HTMLElement | HTMLButtonElement — ссылка на разметку элемента;
  • protected events: IEvents — экземпляр EventEmitter;

Методы:

  • abstract fillElement(data: T): void — заполняет элемент данными, переданными в параметре;
  • render(): HTMLElement - возвращает разметку элемента;
  • remove(): void — удаляет элемент из разметки;

Класс API

Содержит базовую логику отправки запросов. В конструктор передаётся адрес сервера и опционально — объект с заголовками запроса.

Методы:

  • get — выполнит GET-запрос на переданный в параметрах эндпоинт и вернёт Promise с ответом сервера;
  • post — принимает объект с данными, которые будут переданы в формате JSON в теле запроса, и отправляет эти данные на эндпоинт — второй параметр метода. Метод POST-запроса может быть переопределён путём задания третьего параметра, по-умолчанию выполняется POST.

Класс EventEmitter

Брокер событий позволяет отправлять события и подписываться на события, происходящие в системе. Класс используется в презентере для обработки событий и в слоях приложения для генерации событий. Основные методы, реализуемые классом описаны интерфейсом. Класс имеет следующие методы:

  • on — устанавливает обработчик на событие;
  • off — снимает обработчик с события;
  • emit — воспроизводит событие;
  • trigger — возвращает функцию, которая при вызове инициализирует событие, переданное в параметрах метода. Таким образом, помимо обработчиков события может содержать дополнительную обработку.
  • onAll — вызвать все события;
  • offAll — удалить все события.

Слой данных

Класс AppModel

Класс необходим для работы с массивом карточек. Конструктор класса принимает экземпляр класса EventEmitter.\

Поля:

  • products: ICard[] — массив карточек;
  • isBlocked: boolean — заблокирована ли страница, если сервер вернул ошибку;
  • events: IEvents — экземпляр класса EventEmitter для инициализации событий при изменении данных;

Методы:

  • setItems(items: ICard[]): void — записывает полученный от сервера массив данных;
  • getItem(cardId: string): ICard — возвращает отдельно взятую карточку;
  • getItems(): ICard[] — возвращает массив карточек;
  • blockThePage(): void — управляет свойством isBlocked и инициирует событие «page:block»;

Класс UserData

Класс необходим для работы с данными пользователя.
Конструктор класса принимает инстант брокера событий.\

Поля:

  • protected data: IUserData — объект с данными пользователя;
  • protected events: IEvents — экземпляр класса EventEmitter для инициализации событий при изменении данных;
  • public errors: Record<string, string> — объект, хранящий сообщения ошибок, привязаных полям, где ключ — имя поля, а значение — текст ошибки;

Методы: геттеры и сеттеры для сохранения/получения данных пользователя, а также:

  • setError(data: {fieldName: string, errorMessage: string}): void — добавляет ошибку в поле errors;
  • validate(value: string): boolean — валидация данных пользователя;
  • clear(): void — очистит данные пользователя;

Класс BasketModel

Предназначен для работы с данными корзины. Реализует методы добавления товара, подсчёта количества и общей стоиомости
всех товаров в корзине.Конструктор класса принимает инстант брокера событий.\

Поля:

  • _products: ICard[] — массив карточек;
  • events: IEvents — экземпляр класса EventEmitter для инициализации событий при изменении данных;

Методы:

  • addItem(product: ICard): void — добавит в корзину товар;
  • removeItem(cardId: string): void — удалит товар из корзины и вызовет событие изменения корзины;
  • getTotalPrice(): number — вернёт сумму всех товаров в корзине;
  • isBasketProduct(id: string): boolean — есть ли в корзине товар с таким id;
  • isEmpty(): boolean — возвращает true если корзина пуста;
  • getCounter(): number — вернёт количество товаров в корзине;
  • get products(): ICard[] — вернёт массив товаров, добавленных в корзину;
  • clear(): void — очищает корзину от добавленных товаров;

Слой отображения

Отвечают за отображение и взаимодействие с пользователем.

Класс Page

Предназначен для работы с контейнером карточек на главной странице. Конструктор принимает экземпляр брокера событий.

Поля:

  • protected main: HTMLElement - контейнер с карточками;
  • protected basket: HTMLButtonElement — кнопка корзины;
  • protected basketCounter: HTMLElement - элемент счётчика товаров;
  • protected events: IEvents — экземпляр EventEmitter;

Методы:

  • showProducts(items: HTMLElement[]): void {} — вставит массив карточек на страницу;

  • showBasketAmount(items: number): void — отобразит в иконке корзины количество добавленных товаров;

Класс Modal

Необходим для реализации модального окна.
Содержит методы для открытия и закрытия модального окна, вставки в него контента, устанавливает слушатели на клавишу ESC (закрытие мод.окна при нажатии), на оверлей и кнопку-крестик (закрытие при клике).\

Поля:

  • protected container: HTMLElement — контейнер модального окна;
  • content: HTMLElement; — содержимое модального окна (контент);
  • closeButton: HTMLButtonElement — кнопка закрытия;
  • submitButton?: HTMLButtonElement — кнопка подтверждения действия;
  • isOpened: boolean — значение указывает, открыто ли модальное окно;
  • events: IEvents — экземпляр класса EventEmitter для инициализации событий при изменении данных;

Методы:

  • open(element: HTMLElement): void - вставляет контент в модальное окно и открывает его;
  • close(): void — закрывает модальное окно, очищая контент;
  • setContent(content: HTMLElement): void — вставляет элемент в контейнер модального окна;
  • clear(): void — очищает модальное окно от контента;

Класс Form

Предназначен для реализации отображения формы. При сабмите инициирует событие, в которое передаёт объект с данными из полей ввода. При изменении данных в поле ввода также инициирует событие изменения данных. Управляет активностью кнопки подтверждения.

Поля:

  • element: HTMLFormElement — элемент формы;
  • formName: string — название формы;
  • submitButton: HTMLButtonElement — кнопка подтверждения;
  • events: IEvents — экземпляр брокера событий;
  • inputs: NodeListOf<HTMLInputElement> — инпуты формы;
  • inputsErrors: NodeListOf<HTMLElement> - элементы ошибок инпутов;
  • paymentButtons?: Record<'card' | 'cash', HTMLButtonElement> — радио-кнопки в форме с методом оплаты;

Методы:

  • toggleButtonState(): void — включает/отключает кнопку подтверждения;
  • clear(): void — очищает поля ввода и деактивирует кнопку сохранения;
  • showInputError(fieldName: string, errorMessage: string): void — отображает текст ошибки;
  • hideInputError(fieldName: string) — скрывает текст ошибки под указанным полем ввода;
  • get form(): HTMLFormElement — геттер для получения элемента формы;

Класс Card

Наследует класс Component<T>. Отвечает за отображение компонента карточки и его взаимодействие с пользователем.
Конструктор принимает объект данных товара ICard, шаблон разметки и экземпляр брокера событий. Далее по шаблону производится поиск всех\ возможных элементов компонента. При наличии таковых в шаблоне, они заполняются данными из объекта ICard, после чего на интерактивные элементы добавляются слушатели событий.

Поля:

  • _id: string — идентификатор товара;
  • public element: HTMLElement — элемент карточки;
  • description?: HTMLElement — описание товара;
  • image?: HTMLImageElement — изображение товара;
  • title?: HTMLElement — название товара;
  • category?: HTMLElement — категория товара;
  • price?: HTMLElement — цена товара;
  • addToBasketButton?: HTMLButtonElement — кнопка «добавить в корзину»;
  • removeFromBasket?: HTMLButtonElement — кнопка удаления из корзины;
  • public basketItemIndex?: HTMLElement — элемент-индекс товара в корзине;

Методы:

  • fillElement(data: ICard): void — заполняет данными элементы, имеющиеся у компонента товара;
  • toggleButtonState(cardId): void — отключает/включает кнопку «В корзину», если товар уже был добавлен в корзину;
  • get id(): string — возвращает _id карточки;

Класс Basket

Предназначен для отображения модального окна корзины. Конструктор класса принимает инстант брокера событий и элемент разметки корзины.

Поля:

  • element: HTMLElement — элемент открытой корзины;
  • list: HTMLElement — контейнер списка товаров;
  • totalAmount: HTMLElement — элемент разметки, отображающий общую стоимость товаров;
  • orderButton: HTMLButtonElement — кнопка «Оформить»;
  • events: IEvents — инстант брокера событий;

Методы:

  • displayProducts(products: Card[]): void — отобразит товары корзины;
  • displayTotalAmount(value: number): void — отобразит сумму всех товаров корзины;
  • buttonState(value: boolean): void — управляет активностью кнопки «Оформить»;

Класс SuccessOrder

Предназначен для отображения модального окна успешной покупки. Конструктор класса принимает инстант брокера событий и элемент-контейнер с разметкой содержимого для модального окна.

Поля:

  • _element: HTMLElement — содержимое модального окна;
  • orderDescription: HTMLElement — элемент, отображающий сумму заказа;
  • submitButton: HTMLButtonElement — кнопка сабмита;
  • events: IEvents — инстант брокера событий;

Методы:

  • get element(): HTMLElement — геттер поля _element;
  • showOrderAmount(amount: number): void — устанавливает сумму заказа в поле orderDescription;

Класс FailOrder extends SuccessOrder

Предназначен для реализации модального окна неудачной покупки. Расширяет конструктор родительского класса.

Слой коммуникации

Класс AppAPI

Класс предоставляет методы взаимодействия с бэкендом. Конструктор принимает инстант класса API.

Слой презентера

Роль презентера будет выполнять код, распологающийся в файле ./src/index.ts. Он описывает взаимодействие отображения и данных.
Сначала создаются все необходимые экземпляры классов, а затем настраивается работа событий.
События, генерируемые брокером событий вызывают обработчики, за счёт которых и осуществляется взаимодействие.\

Список событий

События изменения данных

Создаются классами моделей.

  • page:block — содержит обработку ошибки в случае, если данные с сервера не были получены;
  • basketModel:changed - изменение количества товаров корзины;
  • userData:changed - изменение данных пользователя;

События взаимодействия с интерфейсом

Создаются классами отображения.

  • modal:close - закрытие модального окна;

  • basket:open - открытие корзины;

  • basket:submit - нажатие кнопки «оформить» в корзине;

  • item:open - нажатие на карточку;

  • item:addToBasket - нажатие на кнопку «в корзину» в модальном окне карточки;

  • item:removeFromBasket - удаление товара из корзины;

  • payment-method:changed - выбор метода оплаты;

  • address:changed - изменение данных в поле с адресом;

  • modal-address:submit - нажатие на кнопку «далее» в модальном окне с адресом доставки;

  • email:changed - изменение данных в поле с почтой;

  • phone-number:changed - изменение данных в поле с номером телефона;

  • modal-contacts:submit - нажатие на кнопку «далее» в модальном окне с почтой и телефоном;

  • modal-success:submit — нажатие на кнопку подтверждения в модальном окне успешной покупки.

Пример взаимодействия

Взаимодействия классов на примере добавления товара в корзину:

  1. Слой отображения. В классе Card навешивается слушатель события клика по кнопке «Добавить в корзину».
  2. Слой презентера. Клик вызывает обработчик события «item:selected» из слоя презентера. В обработчике события вызывается метод модели BasketModel.addItem(cardId).
  3. Слой данных. Модель записывает новые данные, после чего происходит событие «basket:changed».
  4. Слой презентера. В обработчике «basket:changed» вызывается функция слоя отображения Basket.render(products).
  5. Слой отображения. Метод render() отобразит карточки из массива BasketModel.products.

About

Фронтенд проекта "Веб Ларёк"

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published