Deploy: https://mali-zi.github.io/online-store/
Согласно техзаданию разработана frontend-часть интернет-магазина обуви.
Стек:
- React
- React Router
- Redux-Toolkit
- Redux-Persist
- TypeScript
- Bootstrap
Приложение содержит следующие самостоятельные экраны (страницы):
- Главная
- Каталог
- О магазине
- Контакты
- Страница товара
- Корзина
- 404
Навигационным центром приложения являются шапка и футер каждого экрана (страницы):
Из шапки можно попасть на следующие экраны:
- логотип и ссылка «Главная» — ведут на главную страницу (Route path='/');
- каталог — ведёт на страницу каталога (Route path='/catalog');
- о магазине — ведёт на страницу «О магазине» (Route path='/about');
- контакты — ведёт на страницу «Контакты» (Route path='/contacts').
Из футера можно попасть на следующие экраны:
- о магазине — ведёт на страницу «О магазине» (Route path='/about');
- каталог — ведёт на страницу каталога (Route path='/catalog');
- контакты — ведёт на страницу «Контакты» (Route path='/contacts').
Экран «Главная страница» доступен по умолчанию при открытии приложения. При загрузке любых данных с помощью сетевых запросов для каждого виджета отображается свой лоадер.
-
Хиты продаж — GET http://localhost:7070/api/top-sales. В ответ приходит JSON, содержащий данные, которые необходимо распарсить и вывести элементы. Если в ответе пришёл пустой массив, то есть хитов продаж нет, то компонент не должен ничего отображать, как и не должен занимать места на экране.
-
Категории каталога — GET http://localhost:7070/api/categories. В ответ приходит массив категорий без элемента «Все», он добавляется самостоятельно. По умолчанию выбранный элемент служит для определения того, какие будут загружаться товары из каталога. Если «Все» — загружаются все, если «Женская обувь» — загружается только женская обувь. Активный элемент выделен. При смене категории делается новый запрос, предыдущие загруженные данные удаляются.
-
Элементы каталога — GET http://localhost:7070/api/items для варианта «Все». При другой выбранной категории вы делаете запрос вида GET http://localhost:7070/api/items?categoryId=X. Возвращается массив элементов, соответствующих запросу.
-
Загрузить ещё — при запросе элементов каталога загружаются следующие 6. При нажатии на «Загрузить ещё» загружаются ещё 6: GET http://localhost:7070/api/items?offset=6, где offset определяет, сколько элементов пропустить. Если сервер вернул пустой массив или меньше 6 элементов, то кнопка «Загрузить ещё» исчезает. На время загрузки над кнопкой также показывается лоадер.
-
При загрузке по кнопке «Ещё» учитывается выбранная категория: то есть если выбрана категория «Женская обувь», то при нажатии на «Ещё» делается запрос GET http://localhost:7070/api/items?categoryId=X&offset=6 и т.д.
-
Рекламный баннер и текст на нём являются статичными.
Фактически он полностью повторяет функциональность каталога на главной странице, за одним исключением: у него есть поле поиска. При заполнении этого поля отправляется запрос вида: GET http://localhost:7070/api/items?q=<текст в строке поиска>. Строка поиска реагирует только на полный ввод, не live-поиск.
На всех страницах в шапке присутствует виджет поиска. По умолчанию поисковое поле скрыто, отображается только иконка. Эта иконка работает следующим образом: при первом клике открывает строку поиска, при втором, если был введён какой-то текст, то перенаправляет пользователя на страницу каталога (/catalog), при этом в поисковом поле должен быть отображён тот же текст, что был ввёден в строку поиска в шапке, и загрузка данных должна происходить исходя из этого. Поиск на сервере работает по точному совпадению цвета без учёта регистра, например, «чёрный», и по содержанию слова для названия без учёта регистра, например, можно найти «жар» в «Туфли Жар-птицы». Если пользователь не ввёл никакой текст, то строка поиска просто схлопывается обратно.
Это просто контентные страницы, в которые жёстко зашит контент. Никакой логики, кроме работы виджета поиска и ссылок, там нет.
Страница товара выглядит следующим образом:
Страница открывается при нажатии кнопок «Заказать» в карточках товаров(Route path='/catalog/:id'). Где id — это ID товара.
При загрузке показывается лоадер. Для загрузки полной информации о товаре нужно сделать GET http://localhost:7070/api/items/:id, где id — это ID товара. Слева выводится картинка. Сбоку выводится табличка с данными. Размеры — выводятся все доступные размеры, у которых флаг available равен true. Если флаг available равен false, то данный размер становится недоступным. По умолчанию ни один размер не выбран. После выбора он становится выделенным. Кнопка «В корзину» активируется только тогда, когда выбран размер. Размер можно выбрать только один. Количество — от 1 до 10. Особые случаи: если ни одного размера не доступно, блок «Количество» и кнопка «В корзину» не отображаются. После нажатия на кнопку «В корзину» пользователь перемещается в страницу корзины (Route path='/cart').
В корзину можно попасть, либо заказав что-то, либо кликнув на иконку корзины в шапке сайта. Корзина выглядит следующим образом:
Блок «Корзина» отображает товары, находящиеся в корзине. Одной позицией считается пара — товар + размер. То есть если купить те же босоножки другого размера, то это будет две позиции в корзине. А если два раза купить босоножки того же размера, то изменится количество и общая стоимость, но запись останется в табличке одна. Общая сумма рассчитывается на базе суммирования всех позиций при отображении. Соответственно, виджет корзинки отображает количество позиций в корзине. Если в корзине товаров нет вообще, то розового индикатора с числом тоже нет.
Состояние корзины между обновлениями браузера сохраняется в локальном хранилище localStorage с помошью библиотеки Redux Persist.
Блок оформления заказа позволяет оформить заказ — POST http://localhost:7070/api/order. В теле — JSON. После успешного оформления заказа все данные корзины очищаются. При отправке заказа на сервер пользователю показывается loader и сообщение об успехе.
При вводе несуществующего URL, не соответствующего ни одному из путей, пользователю показывается страница Page404 (Route path='*'):