CMS Catalog - Ecommerce

1784747667640.png1784747748403.png
Добавлена иконка сброса параметров (RotateCcw) в заголовок блока Характеристики:
  • Динамическое отображение: Кнопка сброса параметров появляется в заголовке блока «Характеристики» только когда выбран хотя бы один параметр из характеристик (activeSpecsFiltersCount > 0).
  • Функционал: Нажатие на иконку мгновенно сбрасывает все выбранные фильтры в блоке характеристик.

В модальном окне "Фильтр по характеристикам" , тоже все необходимое реализовано, по сбросу выбранных параметров.

Функционал выбора количества колонок успешно реализован!​

Что было сделано:​

  1. Выбор колонок для десктопа (экран от 640px и выше):
    • Добавлены переключатели 2, 3, 4 и 5 колонок (catalog_cols_desktop).
    • Настройки доступны как прямо в панели управления каталогом, так и в раскрывающемся меню «Настройки».
  2. Выбор колонок для мобильных устройств:
    • На узких экранах автоматически отображается выбор 1 или 2 колонок (catalog_cols_mobile).
  3. Сохранение в браузере (localStorage):
    • Выбор количества колонок как гостем, так и авторизованным пользователем мгновенно сохраняется на устройстве и сохраняется при повторных визитах или обновлении страницы.
  • Выпадающий список выбора колонок:
    • Добавил опцию «Авто (по умолчанию)», которая использует оптимальную адаптивную сетку в зависимости от переключения боковой панели.
    • Оформил аккуратный стильный <select> с плавной фокусной подсветкой и компактными отступами.
    • Уменьшил размер подписи «Колонки:» (text-[9px] sm:text-[10px]).
    • Выбор колонок сохраняется в браузерном хранилище (localStorage).

1784752074887.png

Выполнена интеграция метаданных и функционала продления (Renew) на странице профиля в разделе «Product Listings».​

1784756871313.png

Реализованные изменения:​

  1. Компонент сведений о товаре (ListingItemDetails.tsx):
    • Категория товара: Отображение наименования категории с соответствующим иконка-тегом.
    • Артикул (SKU): Вывод артикула товара (SKU) или отметки N/A.
    • Дата добавления / обновления: Динамический вывод даты создания («Добавлено: [дата]») или даты последнего редактирования («Обновлено: [дата]»).
    • Рейтинг объявления: Расчет и отображение среднего рейтинга на основе проверенных отзывов.
    • Количество отзывов: Отображение суммарного числа отзывов к объявлению.
    • Срок окончания показа: Вывод даты истечения срока размещения с цветовым индицированием статуса («Истекает», «Истёк», «Бессрочно»).
  2. Модальное окно продления объявления (RenewListingModal.tsx):
    • Добавлена интерактивная кнопка «Продлить» (Renew) прямо в блоке срока размещения и в панели действий.
    • Выбор из предустановленных системой вариантов продления: 7 дней, 14 дней, 30 дней, 90 дней и 365 дней (1 год).
    • Предпросмотр текущего срока и мгновенный расчёт нового срока окончания показа.
    • Автоматическая реактивация завершённых/черновиковых объявлений при продлении.
  3. Обновление REST API и серверов:
    • В server/routes/products.ts и public/php_rest_api/controllers/ProductController.php обновлен эндпоинт POST /api/products/:id/renew, обеспечивающий точный расчёт expires_at, сброс флага черновика и обновление updated_at.
  4. Локализация (translations.ts):
    • Зарегистрированы и добавлены фразы для русской и английской локализаций.

Реализовал расширенный функционал стран, городов, координат, приоритетов сортировки и внешних API сервисов для импорта географических данных:​


  • База данных и схема:
    • Таблица стран пополнена эмодзи-флагами (emoji) и порядком сортировки (sort_order).
    • Таблица городов расширена точными географическими координатами (latitude, longitude) и порядком сортировки (sort_order).
    • Обновлён database.sql и скрипты автоматической миграции при старте приложения.
  • Внешние API Сервисы:
    • REST Countries API: Интегрирован эндпоинт /api/locations/external/rest-countries для загрузки реестра стран с официальными кодами ISO и эмодзи-флагами.
    • OpenStreetMap Nominatim & GeoNames: Интегрирован эндпоинт /api/locations/external/import-cities для импорта крупных городов выбранной страны со встроенным геокодингом (широта и долгота).
  • Панель управления (Админка) :
    • Обновлён интерфейс LocationManagement.tsx с удобной навигацией по вкладкам «Страны», «Города» и «Импорт из REST API».
    • Добавлена возможность редактирования флагов эмодзи, порядка сортировки (приоритета), а также кликабельные ссылки координат городов на картах OpenStreetMap.
  • Профиль пользователя:
    • Выбор страны в профиле отображает наглядные эмодзи-флаги рядом с названием.

Реализована поддержка выбора режима и объёма импорта городов для любой выбранной страны с гарантированной защитой от дубликатов:​


  • Переключатель режима импорта в интерфейсе:
    • Все города и населенные пункты (Полный импорт) — опрашивает гео-базы GeoNames и OpenStreetMap Nominatim с расширенным лимитом (до 250–300+ населенных пунктов за раз, включая города, крупные поселки и муниципалитеты).
    • Только топовые / крупные города — загружает выборку ключевых областных центров и мегаполисов.
    • Поисковый запрос — опциональный фильтр для подгрузки конкретных регионов или городов.
  • Интеллектуальное исключение дубликатов: перед вставкой в базу данных сервис сверяет названия городов на русском и английском языках с уже существующими записями для этой страны в MySQL, добавляя только уникальные новые локации.
 
Последнее редактирование:
я бы купил бы такой CMS тыс эдак за 5к руб
 
я бы купил бы такой CMS тыс эдак за 5к руб
Спасибо большое за ваш интерес, за предложение и оценку :rolleyes:
На данный момент проект еще делаю, нужно максимально закрыть все баг репорты.
Пока что лучше примите участие в тестировании проекта. Буду очень благодарен.

Что нового было добавлено и улучшено :​

  1. Пошаговое и плавное увеличение (Zoom) :
    • Кнопка «+» (Увеличить) для постепенного масштабирования (100% → 125% → 150% → 200% → 300% → 400% → 600% → 800%).
    • Кнопка «-» (Уменьшить) для пошагового отдаления.
    • Индикатор текущего масштаба в процентах.
  2. Просмотр в 1:1 оригинальном разрешении :
    • Специальная кнопка «1:1 Оригинал» (автоматически рассчитывает реальное пиксельное разрешение снимка и отображает его пиксель-в-пиксель без сжатия).
    • Кнопка «Сбросить масштаб» (вписывает изображение обратно в экран).
  3. Интерактивное управление и перемещение (Pan & Drag) :
    • Перетаскивание зажатой мышью / пальцем: при приближении можно перетаскивать картинку в любую сторону.
    • Колесико мыши: скролл вверх приближает, скролл вниз отдаляет.
    • Двойной клик: переключает масштаб между обычным и оригинальным размером.
  4. Удобная галерея и навигация:
    • Нижняя карусель миниатюр для быстрого переключения фото.
    • Кнопки навигации «Вперед» / «Назад» и клавиатурные хоткеи (←, →, +, -, 0, Esc).

1784833193412.png

1784833288569.png



Проблема с кнопкой «Удалить» на странице товара была исправлена.

Причина возникновения проблемы​

В предварительном просмотре приложения, встроенном через iframe, вызовы браузерного Диалога window.confirm() блокируются политиками безопасности браузеров (Chrome/Webkit). Из-за этого window.confirm() мгновенно возвращал false без вывода окна, и запрос на удаление товара на сервер не отправлялся.


Что было сделано для исправления:​

  • Кастомное модальное окно подтверждения:
    • Заменен вызов window.confirm() на встроенный модальный диалог React в MainLayout.tsx.
    • При нажатии на кнопку «Удалить» на странице любого товара открывается интерактивное модальное окно с предупреждением и подтверждением действия («Вы уверены, что хотите удалить товар?»).
  • Надежная обработка запроса на сервере:
    • Обновлен роут DELETE /api/products/:id в server/routes/products.ts, с поддержкой передачи заголовка идентификации пользователя x-user-id.
    • Сервер каскадно удаляет все связанные записи (избранное, сравнения, отзывы, товар из подборок, корзин и историю) и удаляет сам товар из БД.
  • Обновление состояния и навигация:
    • При успешном удалении товара пользователь автоматически перенаправляется на главную страницу каталога (/), обнуляется выбранный товар, обновляются данные с сервера и выводится уведомление: «Товар успешно удален!».

1784835245424.png

При удалении товара полностью очищаются все его связи и ассоциированные данные, исключая появление «мусорных» или осиротевших записей в базе данных:

1. Связи и таблицы, которые автоматически очищаются​

  • Избранное (favorites): удаляются все записи у всех пользователей, которые добавили этот товар в свои «Закладки».
  • Сравнение товаров (comparisons): товар полностью удаляется из панелей сравнения.
  • Отзывы и рейтинги (reviews): удаляются все оценки, текстовые отзывы покупателей и ответы продавцов/администратора к данному товару.
  • Пользовательские коллекции (collection_products): товар удаляется из всех папок и подборок пользователей.
  • Корзина покупателей (cart_items): товар очищается из корзин текущих пользователей и гостей.
  • Значения характеристик (product_custom_values): удаляются значения всех настраиваемых полей и спецификаций данного товара.
  • История изменения цен (product_price_history): очищается график и хронология изменения цен товара.
  • История просмотров (viewing_history): удаляются записи из списков «Недавно просмотренные».
  • Системные уведомления (notifications): очищается привязка товара из оповещений пользователей.
  • Файловая система (/uploads/products/{id}/): с сервера удаляется отдельная папка со всеми загруженными изображениями и медиафайлами товара.



Реализован функционал фильтрации Дополнительных Характеристик (Пользовательских Полей) по выбранной Категории товара при добавлении и редактировании объявлений:​


  • Категориальная фильтрация пользовательских полей (useCategoryCustomFields):
    • Создан специализированный хук useCategoryCustomFields согласно методологии Feature-Sliced Design (FSD) и принципу Single Responsibility Principle (SRP).
    • При выборе или изменении Категории во вкладке «Общие параметры» список Дополнительных Характеристик автоматически фильтруется и загружает поля, привязанные непосредственно к выбранной категории, её родительским/дочерним категориям или универсальные (глобальные) характеристики.
  • Интерактивный UI во вкладке «Дополнительные характеристики» (CustomFieldsTab):
    • Добавлен информационный бейдж с иконкой и именем выбранной категории, отображающий количество доступных характеристик.
    • На кнопке переключения вкладок формы появился динамо-счетчик доступных полей для выбранной категории.
    • В случае отсутствия характеристик у категории или при невыбранной категории выводится информационное уведомление.
  • Сохранение и фильтрация данных:
    • При отправке формы сохраняются только те значения характеристик, которые принадлежат активной категории, что предотвращает появление устаревших мусорных записей в базе данных.
  • Поддержка PHP REST API и миграций:
    • В public/php_rest_api/config.php и ProductController.php обновлены схемы таблицы custom_fields (поля category_id и show_in_filter) с авто-миграциями ALTER TABLE для серверного хостинга.
  • Мультиязычная локализация:
    • Зарегистрированы и переведены все новые фразы на 5 языков (RU, EN, UK, DE, ES) в translations.ts.




Вся необходимая функциональность для связи Один ко Многим (1:M) между Пользовательскими Полями и Категориями:

1784839008114.png

1784838116195.png

1. Архитектура БД и PHP API Backend​

  • База данных: Создана связующая таблица custom_field_categories (field_id, category_id), поддерживающая множественную привязку характеристических полей к различным категориям каталога.
  • PHP REST API Controller: Методы createCustomField, updateCustomField, deleteCustomField и getDbStateData обновлены для синхронизации массива category_ids в таблице custom_field_categories.

2. Типизация и Хранилище Данных​

  • Интерфейс TypeScript (CustomField): Поле category_ids?: number[] добавлено в базовый тип CustomField.
  • Слой данных (db-store.ts): Автоматически объединяет и агрегирует списки категорий при загрузке состояния БД.

3. Интерактивный Модальный Выбор Категорий (CategorySelectorModal)​

  • Модальное окно вызова: В Admin Console в разделе «Пользовательские и зависимые поля» при создании или редактировании поля кнопка выбора открывает удобный модальный селектор.
  • Иерархическая структура: Поддерживает древовидное отображение родительских категорий и вложенных подкатегорий с раскрывающимися списками.
  • Быстрый поиск и пакетные действия: Интегрированы строка поиска по названию категорий, а также кнопки быстрого выбора («Выбрать все», «Снять выбор»).
  • Отображение бейджей: В таблице характеристик созданные поля наглядно отображают список всех привязанных категорий с помощью стильных цветовых индикаторов.

4. Динамическая Фильтрация в Форме Добавления Товара и Каталоге​

  • Форма создания товара: В блоке «Additional Specifications» / «Дополнительные Характеристики» отображаются пользовательские поля, привязанные как к самой выбранной категории, так и к её родительским или дочерним категориям, либо общие поля.
  • Боковой фильтр каталога (SidebarFilters): Функция getCategoryCustomFields с поддержкой массива category_ids обеспечивает корректную фильтрацию полей в поиске каталога.




Форма управления переводами для раздела «Пользовательские и зависимые поля» визуально улучшена и оптимизирована:
  • Языковые вкладки (Tabs): Вместо громоздких списков из 5 одновременно отображаемых текстовых полей, названия и варианты опций полей теперь переключаются с помощью удобных вкладок языков (RU 🇷🇺, EN 🇬🇧, UK 🇺🇦, DE 🇩🇪, ES 🇪🇸).
  • Визуальные индикаторы заполнения: На каждой языковой кнопке отображается цветная точка состояния (зеленая — язык заполнен, янтарная/серые — ожидают заполнения) и отметки обязательных языков (*).
  • Компактная таблица редактирования: В таблице существующих полей строка редактирования стала аккуратной и не растягивается по высоте.
  • Интеграция с PHP REST API: Все измененные структуры данных полностью сохранены и прозрачно передаются в REST API.


Старая версия:
1784841687335.png


Новая версия:
1784841764257.png



Обновлен серверный стек PHP REST API (public/php_rest_api), а также внесены улучшения в мобильный просмотрщик изображений товара:

1. Обновление PHP REST API (public/php_rest_api)​

  • Синхронизация состояния приложения (getDbStateData): В ProductController.php добавлены массивы countries и cities. Теперь при запросе /api/db-state из приложения на виртуальном хостинге страны и города передаются в клиентское состояние React.
  • Автоматическая инициализация данных (config.php): В функцию ensureDatabaseSchema добавлена авто-загрузка стран и крупных городов, если таблица countries пуста.
  • Дамп базы данных (database.sql): В файл database.sql добавлены начальные команды INSERT INTO countries и INSERT INTO cities.
  • Эндпоинт внешнего списка стран (LocationController.php & index.php): Реализован эндпоинт /api/locations/external/rest-countries (с встроенным резервным справочником WORLD_COUNTRIES_FALLBACK).
  • Справочник городов по умолчанию (MAJOR_CITIES_DICT): В метод импорта городов добавлены готовые наборы крупных городов для всех основных стран.

2. Оптимизация мобильного просмотрщика изображений (ProductImageLightbox.tsx)​

  • Уменьшены отступы элементов масштабирования: Компактные отступы и зазоры на мобильных экранах между кнопкой уменьшения масштаба, процентом (%) и кнопкой увеличения масштаба.
  • Классический вывод счетчика: Счетчик изображений выводится в формате 1/3 без выделения текста или фоновых плашек (select-none / pointer-events-none).

Исправлена логика и взаимосвязь полей Страна и Город во всех модулях приложения (в фильтрах каталога, сайдбаре/мобильной версии, модальном окне добавления/редактирования товара и профиле пользователя:

  • Зависимость и блокировка: Поле выбора города теперь заблокировано (disabled) и визуально отображается неактивным с подсказкой "Сначала выберите страну" до тех пор, пока не будет выбрана конкретная страна.
  • Автоматический сброс: При смене страны или выборе значения "Все страны" (или "Выберите страну...") выбранный ранее город автоматически сбрасывается (null), а выпадающий список городов снова становится неактивным.
  • Фильтрация по стране: При выборе страны список городов формируется строго для выбранного региона.

Новые улучшения и исправления:​

  • Ограничение видимости черновиков:
    • Черновики теперь отображаются исключительно владельцу соответствующего товара или Администратору (в каталоге, профиле и предпросмотре).
    • На страницах просмотра товара при попытке открыть чужой черновик выводятся блокирующие информационные уведомления.
  • Запрет отзывов и оценок самому себе:
    • Автор товара теперь не может отправлять отзыв или ставить рейтинг на свой собственный товар.
    • В форме отзывов ProductReviews для автора показывается соответствующее информационное сообщение, а на сервере (Express и PHP REST API) добавлена проверка безопасности.
  • Ссылка на страницу товара в боковой панели предпросмотра (details-panel):
    • В заголовок панели p-6 border-b border-slate-100 dark:border-slate-800 flex items-center justify-between bg-slate-50/50 dark:bg-slate-950/20 боковой панели предпросмотра добавлена кнопка «Страница товара» с иконкой внешней ссылки для прямого перехода на отдельную страницу объявления.
  • Исправления страницы профиля:
    • Дата регистрации: Исправлено отображение «Registered on N/A» на корректную локализованную дату регистрации пользователя (обновлены сопоставления в UserProfile.tsx, db-store.ts и ProductController.php).
    • Сохранение страницы при перезагрузке: Обновлен роутинг в AppContext.tsx и MainLayout.tsx — состояние simulatorView синхронизируется с URL (/profile), поэтому при обновлении страницы профиля пользователь остается на странице своего профиля, а не перенаправляется на главную.

Реализовал подсистему отслеживания активности пользователей и статуса присутствия для профилей в соответствии с принципами Feature-Sliced Design (FSD) и Single Responsibility Principle (SRP:(

1784920444730.png
Ключевые детали реализации:

Сервис активности и оптимизация базы данных (server/services/activityService.ts) :

  • Буферизованный механизм присутствия: Создан сервис кэширования в памяти (activityService) для отслеживания активности пользователей в реальном времени с минимальной нагрузкой на MySQL.
  • Низкочастотная запись в БД: Обновления полей last_activity_at и avg_daily_online_seconds в MySQL буферизируются и синхронизируются только при значимых действиях пользователя или через заданные интервалы.
  • Порог присутствия: Настроено 5-минутное окно активности (OFFLINE_TIMEOUT_MS = 300 000 мс) для точного различения статусов «в сети» и «не в сети».
  • Скользящее среднее за 7 дней: Автоматический расчёт среднего ежедневного времени присутствия в сети в часах и минутах за скользящий 7-дневный период.
Компонент активности пользователя (src/components/profile/UserActivityStatus.tsx) :
  • Визуальные индикаторы: Отображаются пульсирующие изумрудные точки статуса для активных сессий и приглушённые серые индикаторы при офлайн-статусе.
  • Форматированные строки присутствия: Отображается «В сети» при активности или «Был(а) в сети: дд.мм.гггг, чч:мм» при офлайн-статусе.
  • Среднесуточная активность: Форматируется среднее время (например, «В среднем 2 ч 15 мин в день»).
  • Интеграция в профиль: Встроен как в мобильные, так и в десктопные шапки обложки профиля, а также на вкладку «Обзор» панели управления в UserProfile.tsx.

Как работает статус «Онлайн / Оффлайн»​

1. Спустя какое время пользователь становится Оффлайн?​

Пользователь переходит в статус «Оффлайн» спустя 5 минут после своего последнего действия или последнего отправленного пинга.

  • Периодичность проверки (Heartbeat:( Пока страница сайта открыта и пользователь авторизован, приложение автоматически каждые 60 секунд (1 минуту) отправляет фоновый сигнал («пинг активности») на сервер.
  • Таймаут: Если от пользователя не поступает сигналов в течение 5 минут (300 секунд), система считывает время last_activity_at и переводит статус в «Не в сети» (Offline), а также отображает точную дату и время последнего визита.

2. Какие действия и поведение приводят к переходу в Оффлайн?​

Пользователь становится Оффлайн при следующих событиях:

  1. Закрытие вкладки или браузера — прекращается отправка ежеминутного пинга. Через 5 минут статус меняется на Оффлайн.
  2. Переход ПК / смартфона в спящий режим — приостанавливается выполнение фоновых скриптов браузера, пинги перестают отправляться.
  3. Отключение интернета или потеря сети — запросы с сайта перестают доходить до сервера.
  4. Выход из аккаунта (Logout) — при нажатии кнопки «Выйти» удаляется текущая сессия и немедленно прекращается отправка сигналов активности.

3. Совместимость с PHP REST API (public/php_rest_api)​

Все изменения полностью синхронизированы:

  • В public/php_rest_api/controllers/UserController.php добавлен метод pingActivity().
  • В public/php_rest_api/index.php зарегистрирован роут POST users/activity/ping.
  • В public/php_rest_api/config.php и database.sql обновлена структура таблицы users (last_activity_at и avg_daily_online_seconds INT DEFAULT 0).
При развертывании на виртуальном PHP-хостинге подсчет активности и динамика статусов будут работать точно так же, как и на Node.js сервере.

Архитектура очереди пингов и фонового воркера​

Да, именно такой архитектурный паттерн с буферизацией в памяти и асинхронным фоновым воркером внедрён в проект:

  • Мгновенный ответ (0 мс:( При каждом HTTP-пинге /ping сервер не делает мгновенный тяжёлый запись-запрос в MySQL, а за доли миллисекунды обновляет состояние в быстрой оперативной памяти (In-Memory Map) и добавляет userId в Set-очередь изменённых пользователей (dirtyUsersQueue).
  • Асинхронный воркер (каждые 10 секунд:( Специальный фоновый процесс каждые 10 секунд считывает накопленные user_id из очереди и выполняет эффективную пакетную запись в таблицу users

Почему фоновый воркер с очередью лучше:​

  1. Мгновенный отклик (0 ms задержки для пользователя)
    При выполнении HTTP-пинга клиент получает ответ моментально из оперативной памяти (RAM), не дожидаясь ответа от диска MySQL.
  2. Колоссальное сокращение операций записи (IOPS)
    • Без очереди: 1 000 активных пользователей генерируют 1 000 отдельных UPDATE запросов к диску в минуту.
    • С очередью и воркером (10 сек:( Все пинги накапливаются в памяти (Set очередь) и сбрасываются пакетно раз в 10 секунд. Дублирующие пинги от одного и того же пользователя объединяются в 1 запись. Нагрузка на диск снижается на 80–90%.
  3. Защита от блокировок таблиц (Lock Contentions)
    Частые постоянные записи в таблицу users приводят к блокировкам строк (Row Locking) в InnoDB. Накопление через очередь сглаживает пики нагрузки.

Логика работы статуса Онлайн / Оффлайн:​

  • Когда пользователь «В сети»:
    Клиент каждые 60 секунд отправляет легкий фоновый пинг. Пока разница с последним пингом не превышает 5 минут, статус пользователя отображается как «В сети».
  • Когда и почему статус меняется на «Не в сети»:
    1. Закрыл вкладку или браузер — пинги прекращают отправляться. Спустя 5 минут после последнего пинга статус автоматически меняется на «Не в сети / Был в сети Х минут назад».
    2. Потеря соединения / пропал интернет — клиент не может достучаться до сервера > 5 минут.
    3. Неактивность (ушел от компьютера) — если нет действий, статус становится оффлайн через 5 минут.
 
Последнее редактирование:
Назад
Сверху