/web-larek-frontend

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

Primary LanguageTypeScript

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

Макет

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

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

  • src/ — исходные файлы проекта
  • src/components/ — папка с JS компонентами
  • src/components/base/ — папка с базовым кодом + класс Presenter
  • src/components/models/ - папка с используемыми классами Model
  • src/components/views/ - папка с используемыми классами View

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

  • src/pages/index.html — HTML-файл главной страницы
  • src/types/index.ts — файл с типами
  • src/index.ts — точка входа приложения и реализация класса Presenter
  • 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

Архитектура

UML scheme

Приложение реализовано по MVP архитектуре и состоит из компонентов:

Компонент Описание Базовый класс Связанный класс
1 Model Модель данных Model
  • AppData
  • LotItem
  • Order
2 View Модель отображения Component
  • Page
  • Modal
  • Basket
  • Card
  • BasketItem
  • Form
  • ContactsForm
  • DeliveryForm
  • Success
3 Presenter Модель связи - Реализуется в файле index.ts

В приложении используется событийно-ориентированный подход. В качестве инструмента, который обеспечивает данных подход, выступает EventEmitter.

Базовый код

1. Класс Api

Базовый класс доступа к веб-серверу, который реализует 2 типа основных операций: безопасные (GET) и небезопасные (POST, DELETE)

2. Класс Components

Базовый класс для наследования модели отображения. Реализует базовые элементы работы с элементами, такие как переключение классов, установка текста у элемента и т.д.

3. Класс EventEmitter

Реализует паттерн «Наблюдатель» и позволяет подписываться на события и уведомлять подписчиков о наступлении события.

Класс имеет методы on, off, emit — для подписки на событие, отписки от события и уведомления подписчиков о наступлении события соответственно.

Дополнительно реализованы методы onAll и offAll — для подписки на все события и сброса всех подписчиков.

4. Класс Model

Базовый класс для компонентов модели данных. Позволяем связать переданный данные со свойствами объекта (реализуется в конструкторе) и инициализировать вызов именованных событий через метод emitChanges.

Компоненты модели данных (бизнес-логика)

1. Класс AppState

Класс данных всего приложения. Позволяет отслеживать состояние всего приложения. Содержит внутри себя свойство:

  • catalog - для отслеживания списка доступных лотов - установка данного свойства вызывает событие catalog:changed
  • basket - отслеживание лотов, которые находятся в корзине.
  • order - отслеживает состояние заказа
  • preview - отслеживает лот, который используется для подробного изучения в модальном окне

Также реализует дополнительные методы для доступа к методам перечисленных выше свойств

2. Класс LotItem

Класс данных отдельной карточки. Структура карточки определяется ответом от API - сервера с добавлением свойства и методов, реализующих логику взаимодействия с корзиной через вызов события lot:changed

3. Класс Order

Класс данных процесса оформления заказа. Содержит свойства, которые отображаются на полях соответствующих форм и реализует простейшую логику валидации свойств на наличие значений. Изменения в любом из свойств вызывают проверку всех полей и генерации события formErrors:changed

Компоненты представления

1. Класс Page

Класс представления всей страницы. Позволяет задать:

  • counter - элемент отображения количества товаров в корзине
  • galery - элемент отображения всех доступных карточек
  • wrapper - обёртка, позволяющая блокировать прокрутку страницы при открытии модального окна
  • basket - кнопка для отображения корзины. Клик по кнопке вызывает событие basket:open

2. Класс Modal

Класс представления модального окна. Позволяет задать

  • content - для отображения внутреннего содержания модального окна
  • closeButton - для отображения кнопки закрытия модального окна

Привязывает события закрытие модального окна (modal:close) к кликам по кнопке закрытия формы и по родительскому контейнеру модального окна

3. Класс Basket

Класс представления корзины. Позволяет задать:

  • list - список отображаемых элементов в корзине
  • total - общую ценность корзины
  • button - кнопку открытия формы оформления заказа. Вызывает событие order_payment:open

4. Класс Card

5. Класс BasketItem

Класс представления элементов корзины. Позволяет задать:

  • index - порядковый номер элемента в корзине
  • title - название элемента в корзине
  • price - стоимость элемента в корзине
  • deleteBtn - кнопка удаления элемента из корзины

6. Класс Form

Класс представления базовой формы. Позволяет задать:

  • submit - кнопку отправки формы
  • errors - блок отображения ошибок в форме

В данном классе на весь контейнер отображение привязываем событие отслеживание input, для вызова событий вида container.field:change и событие container:submit

6. Класс DeliveryForm

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

  • payment - способ оплаты
  • address - адрес доставки

7. Класс ContactsForm

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

  • email - почта для связи
  • phone - телефон для связи

8. Класс Success

Класс представления, определяющий отображение основной информации об оформленном заказе:

  • total - общая сумма заказа (забираем из ответа сервера)

Внешние связи

1. LarekAPI

Класс взаимодействия с конкретным API-сервером. Реализует такие методы, как:

  • getLotItem - для чтения информации по конкретному лоту
  • getLotList - для чтения информации по всем доступным лотам
  • postOrderLots - оформления заказа через соответствующий запрос на сервер

Ключевые типы данных

// Модель лота
interface ILot {
	id: string; // идентификатор лота
	title: string; // заголовок лота
	description: string; // описание лота
	image: string; // полный путь до файла картинки лота
	category: ILotCategory; // категория лота
	price: number; // цена лота
	isOrdered: boolean; // признак включения в заказ
	placeInBasket: () => void; // добавляем лот в корзину
	removeFromBasket: () => void; // удаляем лот из корзины
}

// Модель заказа
interface IOrder {  // Модель заказа
	payment: IPaymentType; // способ оплаты
	address: string; // адрес доставки
	email: string; // почта для связи
	phone: string; // телефон для связи
	items: ILot[]; // объекты лотов в корзине
    formErrors: IFormErrors;  // массив ошибок у формы
	validateOrder(): void; // проверка полей формы
	clearOrder(): void; // обнуляем поля заказа
	validatePayment(): void; // проверяем способ оплаты
	validateAddress(): void; // проверяем адрес доставки
	validateEmail(): void; // проверяем почту
	validatePhone(): void; // проверяем телефон
	postOrder(): void; // завершаем заказ
}

interface IAppState {  // Модель приложения
    catalog: ILot[]; // доступные лоты
	basket: ILot[]; // лоты в корзине
	order: IOrder; // заказ
	preview: ILot; // лот для модального окна
	isLotInBasket(item: ILot): boolean; // проверка находится ли лот в корзине
	clearBasket(): void; // очищаем корзину
	getTotalAmount(): number; // получить стоимость корзины
	getBasketIds(): number; // получить список индексов в корзине
	getBasketLength(): number; // получить количество товаров в корзине
	initOrder(): IOrder; // инициализируем объект заказа}

// Все события в ларьке
enum Events {
	LOAD_LOTS = 'catalog:changed', // подгружаем доступные лоты
	OPEN_LOT = 'card:open', // открываем карточку лота для просмотра
	OPEN_BASKET = 'basket:open', // открываем корзину
	CHANGE_LOT_IN_BASKET = 'lot:changed', // добавляем/удаляем лот из корзины
	VALIDATE_ORDER = 'formErrors:changed', // проверяем форму отправки
	OPEN_FIRST_ORDER_PART = 'order_payment:open', // начинаем оформление заказа
	FINISH_FIRST_ORDER_PART = 'order:submit', // заполнили первую форму
	OPEN_SECOND_ORDER_PART = 'order_contacts:open', // продолжаем оформление заказа
	FINISH_SECOND_ORDER_PART = 'contacts:submit', // заполнили первую форму
	PLACE_ORDER = 'order:post', // завершаем заказ
	SELECT_PAYMENT = 'payment:changed', // выбираем способ оплаты
	INPUT_ORDER_ADDRESS = 'order.address:change', // изменили адрес доставки
	INPUT_ORDER_EMAIL = 'contacts.email:change', // изменили почту для связи
	INPUT_ORDER_PHONE = 'contacts.phone:change', // изменили телефон для связи
	OPEN_MODAL = 'modal:open', // блокировка при открытии модального окна
	CLOSE_MODAL = 'modal:close', // снятие блокировки при закрытии модального окна
}