diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..7a9a059 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,84 @@ +name: Build + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x, 20.x] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run lint scripts + run: npm run lint:scripts + + - name: Run lint styles + run: npm run lint:styles + + - name: Run tests + run: npm test + + - name: Build project + run: npm run build + + deploy: + runs-on: ubuntu-latest + needs: build + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' + + permissions: + contents: read + pages: write + id-token: write + + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build for GitHub Pages + run: npm run build + env: + VITE_BASE_URL: /tech-store/ + + - name: Setup Pages + uses: actions/configure-pages@v5 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./dist + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/README.md b/README.md index b3cc7a0..7ec472a 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![React](https://img.shields.io/badge/React-19-blue)](https://react.dev) [![Vite](https://img.shields.io/badge/Vite-7-646CFF)](https://vitejs.dev) [![MUI](https://img.shields.io/badge/MUI-9-007FFF)](https://mui.com) +[![Leaflet](https://img.shields.io/badge/Leaflet-1.9-green)](https://leafletjs.com) [![Vitest](https://img.shields.io/badge/Vitest-4-6E9F18)](https://vitest.dev) Современный интернет-магазин электроники с каталогом товаров, корзиной и системой промокодов. @@ -40,6 +41,14 @@ TechStore — это одностраничное приложение (SPA) и - **Сетка товаров** — отображение карточек с изображениями, ценами и описаниями - **Индикаторы скидок** — визуальное отображение товаров со скидкой - **Добавление в корзину** — быстрое добавление товаров из каталога +- **Слайдер баннеров** — промо-баннеры на главной странице +- **Популярные товары** — секция с рекомендуемыми товарами + +### Страница товара +- **Детальная информация** — полное описание товара с характеристиками +- **Галерея изображений** — просмотр фотографий товара с навигацией +- **Связанные товары** — рекомендации похожих товаров +- **Блок цены** — отображение цены со скидкой и без ### Корзина покупок - **Таблица товаров** — структурированное отображение выбранных товаров @@ -52,8 +61,14 @@ TechStore — это одностраничное приложение (SPA) и - **Автоматический расчёт** — применение скидки 15% при вводе кода `Кекс` - **Пересчёт итогов** — автоматическое обновление суммы заказа +### Карта и навигация +- **Интерактивная карта** — отображение местоположения на базе Leaflet +- **Маршрутизация** — построение маршрута между точками +- **Секция локации** — информация о местоположении магазина + ### Уведомления - **Информирование о лимитах** — предупреждение при достижении максимального количества товара +- **Страница 404** — страница для несуществующих маршрутов --- @@ -74,6 +89,13 @@ TechStore — это одностраничное приложение (SPA) и | [MUI Icons](https://mui.com/material-ui/material-icons/) | 9.0.0 | Иконки | | [Emotion](https://emotion.sh) | 11.14.x | CSS-in-JS стилизация | +### Карты и геолокация +| Технология | Версия | Назначение | +|------------|--------|------------| +| [Leaflet](https://leafletjs.com) | 1.9.4 | Интерактивные карты | +| [React Leaflet](https://react-leaflet.js.org) | 5.0.0 | React-компоненты для Leaflet | +| [Leaflet Routing Machine](https://www.liedman.net/leaflet-routing-machine/) | 3.2.12 | Построение маршрутов | + ### Качество кода | Технология | Версия | Назначение | |------------|--------|------------| @@ -96,20 +118,54 @@ TechStore — это одностраничное приложение (SPA) и ``` src/ +├── pages/ # Страницы приложения +│ ├── CartPage/ # Страница корзины +│ ├── CatalogPage/ # Страница каталога +│ ├── HomePage/ # Главная страница +│ └── ProductDetailPage/ # Страница детальной информации о товаре ├── components/ # React компоненты │ ├── App/ # Корневой компонент приложения +│ ├── BackButton/ # Кнопка возврата +│ ├── BannerSlider/ # Слайдер баннеров │ ├── CartItem/ # Элемент корзины │ ├── CartTable/ # Таблица корзины │ ├── CartTotals/ # Итоговые суммы корзины +│ ├── Footer/ # Подвал сайта +│ ├── GalleryDot/ # Точка навигации галереи +│ ├── GallerySlide/ # Слайд галереи │ ├── Header/ # Шапка сайта +│ ├── IntroSection/ # Вводная секция │ ├── LimitNotification/ # Уведомление о лимите +│ ├── LocationSection/ # Секция локации +│ ├── Map/ # Интерактивная карта +│ ├── NotFoundState/ # Страница 404 +│ ├── PopularProductsSection/ # Секция популярных товаров +│ ├── PriceBlock/ # Блок цены │ ├── ProductCard/ # Карточка товара +│ ├── ProductGallery/ # Галерея товара │ ├── ProductGrid/ # Сетка товаров -│ └── PromoCodeForm/ # Форма промокода +│ ├── ProductInfo/ # Информация о товаре +│ ├── PromoCodeForm/ # Форма промокода +│ ├── QuantityControl/ # Контроль количества +│ ├── RelatedProductCard/ # Карточка связанного товара +│ ├── RelatedProducts/ # Связанные товары +│ └── RoutingControl/ # Контроль маршрутизации +├── hooks/ # Кастомные хуки +│ ├── useCartItem/ # Логика элемента корзины +│ ├── useGallery/ # Логика галереи +│ ├── useLimitNotification/ # Логика уведомлений о лимите +│ └── useProductDetail/ # Логика страницы товара +├── utils/ # Утилиты +│ ├── array/ # Функции для работы с массивами +│ ├── cart/ # Функции для работы с корзиной +│ └── price/ # Функции для работы с ценами ├── constants/ # Константы приложения -│ └── cart.js # Параметры корзины (лимиты, промокоды) +│ ├── cart.js # Параметры корзины (лимиты, промокоды) +│ └── map.js # Координаты для карты ├── data/ # Данные приложения -│ └── products.js # Каталог товаров +│ ├── banners.js # Данные баннеров +│ ├── products.js # Каталог товаров +│ └── productsDetail.js # Детальная информация о товарах ├── assets/ # Статические ресурсы ├── index.css # Глобальные стили └── main.jsx # Точка входа diff --git a/package.json b/package.json index a9e0505..ad49a72 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "ai-project", + "name": "tech-store", "private": true, "version": "0.0.0", "type": "module", diff --git a/src/components/BackButton/BackButton.test.jsx b/src/components/BackButton/BackButton.test.jsx index aa0aade..b2882a8 100644 --- a/src/components/BackButton/BackButton.test.jsx +++ b/src/components/BackButton/BackButton.test.jsx @@ -1,6 +1,6 @@ import { render, screen, fireEvent } from '@testing-library/react'; import { describe, it, expect, vi } from 'vitest'; -import { MemoryRouter, useNavigate } from 'react-router-dom'; +import { MemoryRouter } from 'react-router-dom'; import { BackButton } from './BackButton'; const mockNavigate = vi.fn(); diff --git a/src/components/BannerSlider/BannerSlider.css b/src/components/BannerSlider/BannerSlider.css index 27b05a9..cc48d21 100644 --- a/src/components/BannerSlider/BannerSlider.css +++ b/src/components/BannerSlider/BannerSlider.css @@ -45,7 +45,7 @@ } .banner-slider__title { - margin: 0 0 16px 0; + margin: 0 0 16px; font-weight: 700; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); } @@ -60,15 +60,15 @@ position: absolute; top: 50%; transform: translateY(-50%); - background-color: rgba(255, 255, 255, 0.8) !important; - color: #333333 !important; + background-color: rgba(255, 255, 255, 0.8); + color: #333333; width: 48px; height: 48px; z-index: 10; } .banner-slider__nav:hover { - background-color: rgba(255, 255, 255, 0.95) !important; + background-color: rgba(255, 255, 255, 0.95); } .banner-slider__nav--prev { diff --git a/src/components/BannerSlider/BannerSlider.jsx b/src/components/BannerSlider/BannerSlider.jsx index a340d9f..b47de06 100644 --- a/src/components/BannerSlider/BannerSlider.jsx +++ b/src/components/BannerSlider/BannerSlider.jsx @@ -27,7 +27,9 @@ export function BannerSlider() { }; useEffect(() => { - if (!isAutoPlaying) return; + if (!isAutoPlaying) { + return; + } const interval = setInterval(goToNext, 5000); return () => clearInterval(interval); @@ -87,9 +89,9 @@ export function BannerSlider() { - {banners.map((_, index) => ( + {banners.map((banner, index) => (