Приложение "Веб-ларёк" — это учебный проект по итогам модуля ООП и TypeScript (спринты 8-9) курса Фронтенд-разработчик от Яндекс Практикум. Функционал приложения позволяет посмотреть каталог товаров, добавить их в корзину, оформить заказ.
Стек: 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
Код приложения разделен на слои согласно парадигме MVP (Model-View-Presenter):
- слой данных, отвечает за хранение и изменение данных
- слой представления, отвечает за отображение данных на странице
- презентер, отвечает за связь представления и данных
Содержит в себе базовую логику отправки запросов.
В конструктор передается базовый адрес сервера и глобальные опции для всех запросов(опционально): constructor(baseUrl: string, options: RequestInit = {}).
Методы:
get- выполняет GET запрос на переданный в параметрах ендпоинт и возвращает промис с объектом, которым ответил серверpost- принимает объект с данными, которые будут переданы в JSON в теле запроса, и отправляет эти данные на ендпоинт переданный как параметр при вызове метода. По умолчанию выполняетсяPOSTзапрос, но метод запроса может быть переопределен заданием третьего параметра при вызовеhandleResponse- обрабатывает HTTP-ответ и возвращает данные в зависимости от результата выполнения запроса
Брокер событий позволяет отправлять события и подписываться на события, происходящие в системе.
Класс используется в презентере для обработки событий и в слоях приложения для генерации событий.
В конструктор передается карта для хранения событий и подписок: constructor() { this._events = new Map<EventName, Set<Subscriber>>(); }.
Основные методы, реализуемые классом описаны интерфейсом IEvents:
on- подписка на событиеoff- отписка от событияemit- инициализация событияtrigger- возвращает функцию, при вызове которой инициализируется требуемое в параметрах событиеonAll- подписка на все событияoffAll- отписка от всех событий
type TProductCategory = 'хард-скил' | 'софт-скил' | 'кнопка' | 'другое' | 'дополнительное';
type TFormErrors = Partial<Record<keyof IOrder, string>>;
type TCategoryMapping = {[Key in TProductCategory]: string;};
id: string;- уникальный IDtitle: string;- название товараdescription: string;- описание товараprice: number | null;- цена товара выражается числом либо nullcategory: CategoryType;- категория товараimage: string;- ссылка на картинкуisSelected: boolean;- наличие товара в корзине
Интерфейс состояния приложения IAppState, который используется для хранения и работы с карточками и корзиной:
catalog: ProductItem[];- массив карточек товараbasket: ProductItem[];- корзина с товарамиorder: IOrder;- информация о заказе при оформлении покупкиformErrors: TFormErrors;- ошибки при заполнении формsetCatalog(items: IProduct[]): void;- метод для преобразования данных, полученных с сервера, в тип данных приложенияaddToBasket(value: ProductItem): void;- метод для добавления товара в корзинуremoveFromBasket(id: string): void;- метод для удаления товара из корзиныgetBasketAmount(): number;- метод для подсчёта количества товаров, добавленных в корзинуgetTotalPrice(): number;- метод для суммирования цен товаров, добавленных в корзинуclearBasket(): void;- метод для очистки корзиныsetItemsID(): void;- метод для добавления ID товара в корзинеsetPayment(method: PaymentMethod): string;- метод для добавления способа оплатыsetOrderField(field: keyof IOrderForm, value: string): void;- метод для заполнения обязательных к заполнению полей в формах оформления заказаvalidatePaymentInfo(): boolean;- валидация форм для модального окна для ввода способа оплаты и адреса доставкиvalidateContactsInfo(): boolean;- валидация форм для модального окна для ввода номера телефона и электронной почты"updateOrder(): boolean;- метод для очистки форм заказа после оформления покупкиnotSelected(): void;- метод для обновления полей в данных товаров после оформления покупки
items: string[];- массив ID купленных товаровpayment: PaymentMethod;- способ оплатыtotalPrice: number;- сумма заказаaddress: string;- адрес доставкиemail: string;- электронная почтаphone: string;- номер телефона
type PaymentMethod = 'cash' | 'card';
type TPaymentInfo = Pick<IOrder, 'payment' | 'address'>
type TContactsInfo = Pick<IOrder, 'email' | 'phone'>
type TOrderForm = Pick<IOrder, 'payment' | 'address' | 'email' | 'phone'>
id: string;- уникальный IDtitle: string;- название товараcategory: string;- категория товараdescription: string;- описание товараimage: string;- ссылка на картинкуprice: number | null;- цена товара выражается числом либо null, если в качестве цены указывается «Бесценно»isSelected: boolean;- наличие товара в корзине
counter: number;- счётчик товаров в корзинеcatalog: HTMLElement[]- массив карточек с товарамиlocked: boolean;- переключатель для блокировки, отключает прокрутку страницы
list: HTMLElement[];- массив элементов с товарами, добавленными в корзинуtotalPrice: number;- общая цена товаров в корзине
export interface IOrderResult { id: string; total: number; }
Представляет собой абстрактную базовую модель для работы с данными и событиями в приложении.
Конструктор принимает для хранения данные объекта и эмиттер событий: constructor(data: Partial<T>, protected events: IEvents).
Метод emitChanges(event: string, payload?: object) отвечает за вызов событий.
Описывает состояние приложения, наследует данные интерфейса IAppState.
В полях класса хранятся следующие данные:
catalog: ProductItem[];- массив со всеми товарамиbasket: ProductItem[] = [];- корзина с товарамиorder: IOrder = { items: [], totalPrice: 0, payment: '', address: '', email: '', phone: '' };- объект заказа пользователяformErrors: TFormErrors = {};- объект с ошибками форм
Для взаимодействия с данными используются следующие методы:
setCatalog(items: IProduct[]): void;- метод для преобразования данных, полученных с сервера, в тип данных приложенияaddToBasket(value: ProductItem): void;- метод для добавления товара в корзинуremoveFromBasket(id: string): void;- метод для удаления товара из корзиныgetBasketAmount(): number;- метод для подсчёта количества товаров, добавленных в корзинуgetTotalPrice(): number;- метод для суммирования цен товаров, добавленных в корзинуclearBasket(): void;- метод для очистки корзиныsetItemsID(): void;- метод для добавления ID товара в корзинеsetPayment(method: PaymentMethod): string;- метод для добавления способа оплатыsetOrderField(field: keyof IOrderForm, value: string): void;- метод для заполнения обязательных к заполнению полей в формах оформления заказаvalidatePaymentInfo(): boolean;- валидация форм для модального окна для ввода способа оплаты и адреса доставкиvalidateContactsInfo(): boolean;- валидация форм для модального окна для ввода номера телефона и электронной почтыupdateOrder(): boolean;- метод для очистки форм заказа после оформления покупкиnotSelected(): void;- метод для обновления полей в данных товаров после оформления покупки
Представляет собой абстрактный базовый класс для создания и управления элементами интерфейса.
Конструктор доступен в пределах самого класса и его подклассов и принимает родительский HTML-элемент, в котором будет размещен компонент: protected constructor(protected readonly container: HTMLElement);.
Методы:
toggleClass(element: HTMLElement, className: string, force?: boolean): void;– переключает классprotected setText(element: HTMLElement, value: string): void;- устанавливает текстовое содержимоеsetDisabled(element: HTMLElement, state: boolean): void;- сменяет статус блокировкиprotected setHidden(element: HTMLElement): void;- скрываетprotected setVisible(element: HTMLElement): void;- показываетprotected setImage(el: HTMLImageElement, src: string, alt?: string): void;- устанавливает изображение с альтернативным текстомrender(data?: Partial<T>): HTMLElement;- возвращает корневой DOM-элемент
Описывает главную страницу.
В полях класса хранятся следующие ссылки на внутренние элементы:
protected _counter: HTMLElement;
protected _catalog: HTMLElement;
protected _wrapper: HTMLElement;
protected _basket: HTMLElement;
Конструктор принимает родительский элемент и обработчик событий: constructor(container: HTMLElement, protected events: IEvents).
Используются следующие сеттеры:
set counter(value: number);- для счётчика товаров в корзинеset store(items: HTMLElement[]);- для карточек товаров на страницеset locked(value: boolean);- для блока прокрутки
Описывает карточку товара.
В полях класса хранятся следующие данные:
protected _title: HTMLElement;
protected _image: HTMLImageElement;
protected _category: HTMLElement;
protected _price: HTMLElement;
protected _button: HTMLButtonElement;
Конструктор принимает имя блока, родительский контейнер и объект с колбэк функциями:
constructor(protected blockName: string, container: HTMLElement, actions?: ICardActions);
Используются сеттеры и геттеры:
set id(value: string);get id(): string;- сеттер и геттер для уникального IDset title(value: string);get title(): string;- сеттер и гетер для названия товараset image(src: string);- сеттер для изображенияset isSelected(value: boolean);- сеттер для определения, выбран товар или нетset category(value: TProductCategory);- сеттер для категории товараset price(value: number | null);- сеттер для цены товара
Описывает корзину товаров.
В полях класса хранятся следующие данные:
protected _list: HTMLElement;
protected _price: HTMLElement;
protected _button: HTMLButtonElement;
Конструктор принимает имя блока, родительский элемент и обработчик событий:
constructor(protected blockName: string, container: HTMLElement, protected events: IEvents);
Используются сеттеры и методы:
set totalPrice(price: number);– сеттер для общей ценыset list(items: HTMLElement[]);– сеттер для списка товаровdisableButton();– метод, отключающий кнопку "Оформить"toggleButton(state: boolean)- метод для изменения состояния кнопки "Оформить"updateIndex(): void;– метод для обновления индексов таблички при удалении товара из корзины
Описывает модальное окно для указания способа оплаты и адреса доставки при оформлении заказа.
В полях класса хранятся следующие данные:
protected _card: HTMLButtonElement;
protected _cash: HTMLButtonElement;
protected _address: HTMLInputElement;
Конструктор принимает имя блока, родительский элемент и обработчик событий:
constructor(container: HTMLFormElement, protected events: IEvents);
Методы:
set payment(value: PaymentMethod)- сеттер для определения способа оплатыset address(value: string)- сеттер для внесения адреса доставки
Описывает модальное окно для заполнения контактных данных при оформлении заказа.
Конструктор принимает родительский элемент и обработчик событий:
constructor(container: HTMLFormElement, events: IEvents);
Методы:
set phone(value: string)- сеттер для внесения номера телефонаset email(value: string)- сеттер для внесения электронной почты
Дочерний класс базового класса Api. Используется для взаимодействия с API для обмена данными с конкретным сервером приложения.
Конструктор принимает базовый url для загрузки изображений, базовый url для API, опциональный параметр для настройки HTTP-запросов:
constructor(cdn: string, baseUrl: string, options?: RequestInit)
Методы:
getProductList- возвращает массив товаров с сервераgetProduct- возвращает конкретный товар с сервера по переданному idcreateOrder- отправляет введённые данные заказа на сервер и возвращает результат
Код, описывающий взаимодействие представления и данных между собой, находится в файле index.ts, выполняющем роль презентера.
Взаимодействие осуществляется за счет событий, генерируемых с помощью брокера событий и обработчиков этих событий, описанных в index.ts.
В index.ts сначала создаются экземпляры всех необходимых классов, а затем настраивается обработка событий.
Список событий, которые могут генерироваться в системе:
items:changed– перерисовывает список товаров на странице при его измененииcard:select– открывает модальное окно с подробным описанием товара по клику на карточку товара на главной страницеcard:toBasket– добавляет выбранный товар в корзинуbasket:open– открывает модальное окно по клику на кнопку «Корзина»basket:delete– удаляет выбранный товар из массива добавленных в корзину товаровorder:open– открывает модальное окно с формой для заполнения способа оплаты и адреса доставки при оформлении заказаorderFormErrors:change– проверяет внесение всех обязательных данных в форме для заполнения способа оплаты и адресаcontactsFormErrors:change– проверяет внесение всех обязательных данных в форме для заполнения номера телефона и электронной почты/^order\..*:change$/- изменение полей в форме для заполнения способа оплаты и адреса/^contacts\..*:change$/- изменение полей в форме для заполнения номера телефона и электронной почтыorder:submit– переходит на второй этап оформления заказа, где необходимо внести номер телефона и электронную почтуcontacts:submit– переходит на модальное окно об успешном оформлении заказаmodal:close– закрывает модальное окно по клику на кнопку закрытия или по клику вне модального окна