https://github.com/HelenVirtanen/weblarek
Стек: HTML, SCSS, TS, Vite
Структура проекта:
- src/ — исходные файлы проекта
- src/components/ — папка с JS компонентами
- src/components/base/ — папка с базовым кодом
Важные файлы:
- index.html — HTML-файл главной страницы
- src/types/index.ts — файл с типами
- src/main.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
«Web-Larёk» — это интернет-магазин с товарами для веб-разработчиков, где пользователи могут просматривать товары, добавлять их в корзину и оформлять заказы. Сайт предоставляет удобный интерфейс с модальными окнами для просмотра деталей товаров, управления корзиной и выбора способа оплаты, обеспечивая полный цикл покупки с отправкой заказов на сервер.
Код приложения разделен на слои согласно парадигме MVP (Model-View-Presenter), которая обеспечивает четкое разделение ответственности между классами слоев Model и View. Каждый слой несет свой смысл и ответственность:
Model - слой данных, отвечает за хранение и изменение данных.
View - слой представления, отвечает за отображение данных на странице.
Presenter - презентер содержит основную логику приложения и отвечает за связь представления и данных.
Взаимодействие между классами обеспечивается использованием событийно-ориентированного подхода. Модели и Представления генерируют события при изменении данных или взаимодействии пользователя с приложением, а Презентер обрабатывает эти события используя методы как Моделей, так и Представлений.
Является базовым классом для всех компонентов интерфейса.
Класс является дженериком и принимает в переменной T тип данных, которые могут быть переданы в метод render для отображения.
Конструктор:
constructor(container: HTMLElement) - принимает ссылку на DOM элемент за отображение, которого он отвечает.
Поля класса:
container: HTMLElement - поле для хранения корневого DOM элемента компонента.
Методы класса:
render(data?: Partial<T>): HTMLElement - Главный метод класса. Он принимает данные, которые необходимо отобразить в интерфейсе, записывает эти данные в поля класса и возвращает ссылку на DOM-элемент. Предполагается, что в классах, которые будут наследоваться от Component будут реализованы сеттеры для полей с данными, которые будут вызываться в момент вызова render и записывать данные в необходимые DOM элементы.
setImage(element: HTMLImageElement, src: string, alt?: string): void - утилитарный метод для модификации DOM-элементов <img>
Содержит в себе базовую логику отправки запросов.
Конструктор:
constructor(baseUrl: string, options: RequestInit = {}) - В конструктор передается базовый адрес сервера и опциональный объект с заголовками запросов.
Поля класса:
baseUrl: string - базовый адрес сервера
options: RequestInit - объект с заголовками, которые будут использованы для запросов.
Методы:
get(uri: string): Promise<object> - выполняет GET запрос на переданный в параметрах ендпоинт и возвращает промис с объектом, которым ответил сервер
post(uri: string, data: object, method: ApiPostMethods = 'POST'): Promise<object> - принимает объект с данными, которые будут переданы в JSON в теле запроса, и отправляет эти данные на ендпоинт переданный как параметр при вызове метода. По умолчанию выполняется POST запрос, но метод запроса может быть переопределен заданием третьего параметра при вызове.
handleResponse(response: Response): Promise<object> - защищенный метод проверяющий ответ сервера на корректность и возвращающий объект с данными полученный от сервера или отклоненный промис, в случае некорректных данных.
Брокер событий реализует паттерн "Наблюдатель", позволяющий отправлять события и подписываться на события, происходящие в системе. Класс используется для связи слоя данных и представления.
Конструктор класса не принимает параметров.
Поля класса:
_events: Map<string | RegExp, Set<Function>>) - хранит коллекцию подписок на события. Ключи коллекции - названия событий или регулярное выражение, значения - коллекция функций обработчиков, которые будут вызваны при срабатывании события.
Методы класса:
on<T extends object>(event: EventName, callback: (data: T) => void): void - подписка на событие, принимает название события и функцию обработчик.
emit<T extends object>(event: string, data?: T): void - инициализация события. При вызове события в метод передается название события и объект с данными, который будет использован как аргумент для вызова обработчика.
trigger<T extends object>(event: string, context?: Partial<T>): (data: T) => void - возвращает функцию, при вызове которой инициализируется требуемое в параметрах событие с передачей в него данных из второго параметра.
Данные разделены на две основные сущности:
- о товаре
- о заказе покупателя
- Интерфейс IProduct:
- название
- описание
- изображение
- категория товара
- цена
Реализация в API через GET-запросы: Product List:
- total: number
- items: IProduct[]
Product Item:
- id: string
- description: string
- image: string
- title: string
- category: string
- price: number | null
- Интерфейс IBuyer:
- способ оплаты
- адрес доставки
- емейл
- телефон
Реализация в API через POST-запрос: Response (success):
- id: string
- total: number
Body:
- payment: TPayment ('card' | 'cash')
- email: string
- phone: string
- address: string
- total: number
- items: string[]
- Каталог товаров для веб-разработчиков на главной
- хранение товаров, которые можно купить в приложении;
Поля класса:
productsList: IProduct[]
selectedProduct: IProduct | null;
Методы класса:
setProducts(products) - сохранение массива товаров полученного в параметрах метода;
getProducts() - получение массива товаров из модели;
getProductById(id) - получение одного товара по его id;
setSelectedProduct(id) - сохранение товара для подробного отображения по его id;
getSelectedProduct() - получение товара для подробного отображения.
- Корзина с товарами
- хранение товаров, которые пользователь выбрал для покупки;
Поля класса:
products: IProduct[]
Методы класса:
getCartProducts() - получение массива товаров в корзине;
addProductToCart(product) - добавление товара, который был получен в параметре, в массив корзины;
removeProductFromCart(product) - удаление товара, полученного в параметре из массива корзины;
clearCart() - очистка корзины;
getTotalCartPrice() - получение стоимости всех товаров в корзине;
getTotalCartProducts() - получение количества товаров в корзине;
isProductInCart(id) - проверка наличия товара в корзине по его id, полученного в параметр метода.
- Покупатель
- данные покупателя, которые тот должен указать при оформлении заказа;
Поля класса:
customerData = IBuyer | null;
Методы класса:
setCustomerData(detail: Partial<IBuyer>) - сохранение данных в модели. Возможность сохранить только одно значение, например, только адрес или только телефон, не удалив при этом значения других полей, которые уже могут храниться в классе;
getCustomerData() - получение всех данных покупателя;
clearCustomerData() - очистка данных покупателя;
isCustomerDataValid() - валидация данных. Поле является валидным, если оно не пустое. Метод валидации дает возможность определить не только валидность каждого поля, но и предоставлять информацию об ошибке, связанной с проверкой конкретного значения.
Класс ApiCommunication - коммуникатор для работы с интерфейсом IApi и Api.
Поля класса наследуются из класса Api:
baseUrl: string
options: RequestInit
Методы:
getCatalog() - запрос на эндпоинт /product/ - возвращает массив товаров (использует метод get класса Api)
createOrder() - на эндпоинт /order/ - в теле данные о покупателе и выбранных товарах (использует метод post класса Api)
Тело запроса POST для order:
- payment: string,
- email: string,
- phone: string,
- address: string,
- total: number,
- items: string[]
Переиспользуемые сущности (базовые абстрактные классы):
- Card - карточка товара Используется как общий класс для карточек
- в каталоге (класс CardCatalog)
- в модальном окне (класс CardPreview)
- в корзине (класс CardBasket)
Конструктор: container: HTMLElement
Поля:
- cardTitle: название товара
- cardPrice: цена товара
- data: данные товара для рендеринга дочерних классов
Методы:
- set title: устанавливает название товара
- set price: устанавливает цену товара
- Form - форма Используется как общий класс для форм
- выбор оплаты и ввод адреса
- контактные данные (email и телефон)
Конструктор:
- container: HTMLElement,
- actions - обьект с обработчиком действий формы
Поля:
- errorsInfo: отображение ошибок формы
- submitButton: кнопка отправки формы
Методы:
- set errors: устанавливает текст ошибки
- set submitButtonDisabled: включает/отключает кнопку отправки формы
- removeErrors - очищает текст ошибки
- checkErrors - проверяет наличие ошибок формы и активирует/блокирует кнопку отправки
- Modal - модальное окно Используется как класс-контейнер для других классов. Не наследуется, но принимает в себя другие темплейты.
- Header - Корзина с счетчиком товаров (в хедере)
Конструктор:
- container: HTMLElement,
- events - обьект для генерации событий
Поля:
- cartCounter: количество товаров в корзине
- cartButton: кнопка открытия корзины
- events: ссылка на объект событий для уведомления о действиях пользователя
Метод:
- set counter: устанавливает количество товаров в корзине
- Gallery - каталог товаров
Конструктор:
- container: HTMLElement
Поле:
- catalogElement: контейнер для отображения карточек товаров
Метод:
- set catalog: заменяет содержимое карточками товаров
- Basket - корзина
Конструктор:
- container: HTMLElement
- events - обьект для генерации событий
Поля:
- basketTitle: заголовок модального окна корзины
- basketList: контейнер для списка карточек товаров
- basketButton: кнопка оформления заказа
- basketPrice: общая стоимость корзины
Методы:
- set buttonText: меняет текст кнопки оформления товара в корзине
- set buttonDisabled - включает/отключает кнопку оформления заказа
- set basket - обновляет список товаров в корзине
- set total - обновляет общую стоимость товаров в корзине
- CardCatalog - карточка товара в каталоге
Конструктор:
- container: HTMLElement,
- events - обьект для генерации событий
Поля:
- cardImage: изображение товара
- cardCategory: категория товара
- events: ссылка на объект событий для уведомления о действиях пользователя
Методы:
- set category: устанавливает текст категории и CSS-классы согласно categoryMap
- set image: устанавливает изображение товара
- render: рендерит карточку по данным в data
- CardPreview - детали карточки товара
Конструктор:
- container: HTMLElement,
- events - обьект для генерации событий
Поля:
- cardImage: изображение товара
- cardCategory: категория товара
- cardText: описание товара
- cardButton: кнопка добавления/удаления товара
- inCart: булево значение, находится ли товар в корзине
- events: ссылка на объект событий для уведомления о действиях пользователя
Методы:
- set category: устанавливает текст категории и CSS-классы согласно categoryMap
- set image: устанавливает изображение товара
- set description: устанавливает текст описания товара
- render: рендерит карточку по данным в data
- CardBasket - карточка товара в корзине (как пункт списка)
Конструктор:
- container: HTMLElement,
- events - обьект для генерации событий
Поля:
- cardItemIndex: порядковый номер товара в корзине
- cardDeleteItem: кнопка удаления товара из корзины
- events: ссылка на объект событий для уведомления о действиях пользователя
Методы:
- set index: устанавливает порядковый номер
- render: рендерит карточку по данным в data
- FormOrder - форма с выбором оплаты и адреса
Конструктор:
- container: HTMLElement,
- actions - обьект с обработчиком действий формы
- events - ссылка на объект событий для уведомления о действиях пользователя
Поля:
- paymentCard: кнопка выбора оплаты картой
- paymentCash: кнопка выбора оплаты наличными
- addressInput: поле ввода адреса
Методы:
- selectPayment: выбор способа оплаты
- set payment: устанавливает способ оплаты
- set address: устанавливает адрес
- isAddressValid: проверяет корректность адреса
- FormContacts - форма с контактными данными
Конструктор:
- container: HTMLElement,
- actions - обьект с обработчиком действий формы
Поля:
- emailInput: поле ввода почты
- phoneInput: поле ввода телефона
Методы:
- set email: устанавливает значение поля email
- set phone: устанавливает значение поля телефона
- isContactsValid: проверяет корректность почты и телефона
- Success - подтверждение успешного заказа
Конструктор:
- container: HTMLElement,
- actions - обьект с обработчиком действий формы
Поля:
- successDescription: отображение списанной суммы
- successButton: кнопка закрытия окна
Методы:
- set total: устанавливает сумму списания
- связывает Модели, Представления и API, организует бизнес-логику приложения и управление событиями.
Инициализация событийного брокера:
const events = new EventEmitter();
Обработка событий Презентер подписан на события через events.on(...):
- catalog:changed - рендер карточек каталога в галерее после обновления модели Catalog.
- card:select - открывает модальное окно с превью карточки товара.
- card:add-product / card:remove-product - добавляет или удаляет товар из корзины, обновляет счетчик в Header.
- cart-counter:changed - обновляет счетчик в Header при изменении количества товаров.
- cart:open - открывает модальное окно с корзиной. Создает карточки товаров корзины (CardBasket) и рендерит их. Отображает общую сумму заказа.
- cart:order - открывает форму заказа (FormOrder) в модальном окне. Подписывается на выбор способа оплаты и ввод адреса через onPaymentSelect и onAddressInput. Данные покупателя сохраняются в модели Buyer.
- cart:contacts - открывает форму контактов (FormContacts) в модальном окне. Обновляет данные покупателя в Buyer. Создает объект IOrderRequest и вызывает apiCommunication.createOrder(...). После успешного создания заказа генерирует событие cart:success.
- cart:success - открывает модальное окно успешно созданного заказа (Success), показывает сумму списанных синапсов. При закрытии очищает корзину и данные покупателя.