Стек: 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
Товар
export interface IProduct {
id: string;
description: string;
image: string;
title: string;
category: string;
price: number | null;
}
Данные для оформления заказа
export interface IOrder {
payment: string;
email: string;
phone: string;
address: string;
total: number;
items: string[];
}
Данные, хранящиеся в модели
export interface IModel {
catalog: IProduct[];
preview: string | null;
basket: Map<string, number>;
order: IOrder;
}
Данные карточки, отображающейся в корзине
export type TBasketCard = Pick<IProduct, 'id' | 'title' | 'price'>
Данные для заказа, приходящие от пользователя
export type TOrderData = Pick<IOrder, 'payment' | 'address' | 'email' | 'phone'>;
Сообщения об ошибках в формах
export type FormErrors = Partial<Record<keyof IOrder, string>>;
Данные, возвращаемые сервером после успешного оформления заказа
export interface IOrderResult {
id: string;
total: number;
}
Код приложения разделен на слои согласно парадигме MVP:
- слой данных (Model), отвечает за хранение и изменение данных
- слой представления (View), отвечает за отображение данных на странице
- презентер (Presenter), отвечает за связь представления и данных.
Содержит в себе базовую логику отправки запросов. В конструктор передается базовый адрес сервера и опциональный объект с заголовками запросов.
- constructor(baseUrl: string, options: RequestInit = {})
Методы:
get
- выполняетGET
запрос на переданный в параметрах ендпоинт и возвращает промис с объектом, которым ответил серверpost
- принимает объект с данными, которые будут переданы в JSON в теле запроса, и отправляет эти данные на ендпоинт, переданный как параметр при вызове метода. По умолчанию выполняетсяPOST
запрос, но метод запроса может быть переопределен заданием третьего параметра при вызове.
Брокер событий позволяет отправлять события и подписываться на события, происходящие в системе. Класс используется в презентере для обработки событий и в слоях приложения для генерации событий. Конструктор не принимает никаких параметров.
Основные методы, реализуемые классом, описаны интерфейсом IEvents
:
on
- подписка на событиеemit
- инициализация событияtrigger
- возвращает функцию, при вызове которой инициализируется требуемое в параметрах событие
Базовая модель, которая позволяет установить исходные данные в класс и отличить ее от простых объектов с данными.
Конструктор принимает объект, в котором все свойства заданного типа являются необязательными, и инстант брокера событий.
- constructor(data: Partial, protected events: IEvents)
Методы:
- emitChanges(event: string, payload?: object) - сообщает всем, что модель изменилась
Базовый компонент, который позволяет работать с DOM-элементами.
Конструктор принимает контейнер с разметкой.
- constructor(protected readonly container: HTMLElement)
Методы:
- toggleClass(element: HTMLElement, className: string, force?: boolean) - переключает класс
- setDisabled(element: HTMLElement, state: boolean) - меняет статус блокировки
- render(data?: Partial): HTMLElement - возвращает корневой DOM-элементами
Класс наследуется от Model c типом IModel, отвечает за хранение и логику работы с данными приложения.\
В полях класса хранятся следующие данные:
- catalog: IProduct[] - массив объектов карточек
- preview: string - id карточки, выбранной для просмотра в модальном окне
- basket: Map<string, number> - словарь с товарами, добавленными в корзину, где ключом является id товара, а значением - цена
- order: IOrder - объект, содержащий данные, необходимые для оформления заказа
- orderFormErrors: FormErrors - ошибки, возникающие в форме заказа
- contactsFormErrors: FormErrors - ошибки, возникающие в форме контактов
Так же класс предоставляет набор методов для взаимодействия с этими данными:
- setCatalog(items: IProduct[]): void - устанавливает набор карточек в каталог
- setPreview(item: Product): void - устанавливает id текущей выбранной карточки
- toggleProductState(id: string, price: number | null): void - переключает состояние товара в корзине
- isProductInBasket(id: string): boolean - проверяет, есть ли товар в корзине
- getBasketCounter(): number - возвращает количество товаров в корзине
- getBasketItems(): TBasketCard[] - возвращает состав корзины
- getTotal(): number - возвращает итоговую сумму корзины
- clearBasket(): void - очищает корзину
- setOrderItems(): void - переносит товары из корзины в заказ
- setOrderTotal(): void - переносит в заказ итоговую сумму
- setOrderField(field: keyof TOrderData, value: string): void - устанавливает значение полей в заказ
- validateOrder(): boolean - валидирует форму заказа
- validateContacts(): boolean - валидирует форму контактов
Класс наследуется от Model с типом IProduct, отвечает за хранения данных товара.
В полях класса хранятся следующие данные:
- id: string - идентификатор товара
- description: string - описание товара
- image: string - изображение товара
- title: string - название товара
- category: string - категория товара
- price: number | null - цена товара
Класс наследуется от Model с типом IOrder, отвечает за хранения данных заказа.
В полях класса хранятся следующие данные:
- payment: 'card' | 'cash' - способ оплаты (онлайн или при получении)
- email: string - адрес электронной почты
- phone: string - номер телефона
- address: string - адрес доставки
- total: number - итоговая сумма заказа
- items: string[] - состав заказа (выбранные товары)
Все классы представления отвечают за отображение внутри контейнера (DOM-элемент) передаваемых в них данных.
Класс наследуется от Component с типом IPage и реализует страницу сайта. Конструктор принимает контейнер модального окна и экземпляр класса EventEmitter
для возможности инициации событий.
- constructor(container: HTMLElement, protected events: IEvents)
Поля класса:
- counter: HTMLElement - счетчик товаров в корзине
- catalog: HTMLElement - каталог
- wrapper: HTMLElement - обертка страницы
- basket: HTMLElement - корзина
Методы:
- сеттеры для полей класса
Класс наследуется от Component с типом IModalData и реализует модальное окно. Предоставляет методы open
и close
для управления отображением модального окна, а также метод render
для отрисовки окна. Устанавливает слушатели на клик в оверлей и кнопку-крестик для закрытия попапа. Конструктор принимает контейнер модального окна и экземпляр класса EventEmitter
для возможности инициации событий.
- constructor(container: HTMLElement, protected events: IEvents)
Поля класса:
- closeButton: HTMLButtonElement - кнопка закрытия
- content: HTMLElement - область с контентом модального окна
Класс наследуется от Component с типом IFormState и реализует элемент формы. Предоставляет метод onInputChange
, имитирующий события при изменении полей формы, метод render
для установки значений и получения контейнера, а также сеттеры полей класса.
Конструктор принимает контейнер с разметкой формы и экземпляр класса EventEmitter
для возможности инициации событий.
- constructor(protected container: HTMLFormElement, protected events: IEvents)
Поля класса:
- submit: HTMLButtonElement - кнопка отправки формы
- errors: HTMLElement - ошибки валидации полей формы
Класс наследуется от Component с типом IBasketView и реализует корзину. Предоставляет сеттеры для полей items и total и геттер для поля button. Конструктор принимает контейнер с разметкой корзины и экземпляр класса EventEmitter
.
- constructor(container: HTMLElement, protected events: EventEmitter)
Поля класса:
- list: HTMLElement - список товаров
- total: HTMLElement - итоговая сумма
- button: HTMLButtonElement - кнопка оформления
Класс наследуется от Component с типом ISuccess и реализует окно с сообщением об успешном оформлении заказа. Устанавливает слушатель на кнопку внутри окна, при нажатии на которую можно продолжить покупки. Предоставляет сеттер для поля total. Конструктор принимает контейнер в разметкой окна и функцию-обработчик для кнопки.
- constructor(container: HTMLElement, actions: ISuccessActions)
Поля класса:
- close: HTMLElement - кнопка закрытия
- total: HTMLElement - итоговая сумма покупок
Класс наследуется от Component с типом IProduct
Отвечает за отображение карточки, задавая в карточке данные названия, цены товара, которые присутсвуют во всех представлениях карточек. Класс используется как базовый для более специализированных отображений. В конструктор класса передается DOM элемент темплейта, что позволяет при необходимости формировать карточки разных вариантов верстки. В классе устанавливаются слушатель на кнопку добавления товара в корзину или на клик по контейнеру, если кнопки в представлении нет.
Поля класса содержат элементы разметки элементов карточки. Конструктор, кроме темплейта принимает экземпляр EventEmitter
для инициации событий и имя блока.\
- constructor(blockName: string, container: HTMLElement, actions?: ICardActions)
Методы:
- геттеры и сеттеры для полей класса
Класс наследуется от Card и отвечает за отображение карточки в каталоге, задавая также категорию и изображение. В конструктор передается контейнер с разметкой и функция-обработчик.
- constructor(container: HTMLElement, actions?: ICardActions)
Методы:
- геттеры и сеттеры для полей класса
Расширяет класс CatalogItem, добавляя поле с описанием товара, которое используется в отображении превью карточки.
Класс наследуется от Card и отвечает за отображение карточки в корзине. В конструктор передается контейнер с разметкой и функция-обработчик.
- constructor(container: HTMLElement, actions?: ICardActions)
Методы:
- геттер для поля index
Класс наследуется от Form с типом IOrder
Отвечает за блок сайта с информацией о заказе, содержит поля для хранения данных о заказе. Принимает в конструктор контейнер с разметкой, экземпляр EventEmitter
и функцию-обработчик.
- constructor(container: HTMLFormElement, events: IEvents, actions?: IOrderActions)
Поля класса:
- card: HTMLButtonElement - кнопка для выбора оплаты онлайн
- cash: HTMLButtonElement - кнопка для выбора оплаты при получении
Методы:
- switchPayment(): void - переключает состояние кнопок для выбора способа оплаты
- геттеры и сеттеры для полей класса
Класс наследуется от Form с типом IOrder
Содержит поля для хранения контактов клиента. Принимает в конструктор контейнер с разметкой формы и экземпляр EventEmitter
.
- constructor(container: HTMLFormElement, events: IEvents)
Методы:
- сеттеры для полей класса
Расширяет класс Api и реализует интерфейс IAppApi и предоставляет методы реализующие взаимодействие с бэкендом сервиса.
Принимает в конструктор cdn, базовый url и заголовки.
- constructor(cdn: string, baseUrl: string, options?: RequestInit)
Код, описывающий взаимодействие представления и данных между собой находится в файле index.ts
, выполняющем роль презентера.
Взаимодействие осуществляется за счет событий генерируемых с помощью брокера событий и обработчиков этих событий, описанных в index.ts
В index.ts
сначала создаются экземпляры всех необходимых классов, а затем настраивается обработка событий.
Список всех событий, которые могут генерироваться в системе:
События изменения данных (генерируются классами моделями данных)
items:changed
- установка каталогаpreview:changed
- изменение id выбранной для просмотра карточкиbasket:changed
- изменение состава корзиныorder:ready
- готовность заказаorderFormErrors:changed
- изменение набора ошибок в форме заказаcontactsFormErrors:changed
- изменение набора ошибок в форме контактов
События, возникающие при взаимодействии пользователя с интерфейсом (генерируются классами, отвечающими за представление)
card:select
- выбор карточки для отображения в модальном окнеbasket:open
- открытие модального окна с корзинойorder:open
- открытие модального окна с формой для заполнения данных о заказеorder:changed
- изменение полей в форме заказаorder:submit
- отправка формы с информацией о заказеcontacts:changed
- изменение полей в форме контактовcontacts:submit
- отправка формы с информацией о контактахsuccess:open
- открытие модального окна с информацией об успешном оформлении заказаmodal:open
- открытие модального окнаmodal:close
- закрытие модального окна