Skip to content

Repository files navigation

🍽 SPA-приложение - Сервис выбора ресторанов

Учебный проект, выполненный в рамках курса по React. Приложение позволяет просматривать список ресторанов, их меню и отзывы, а также взаимодействовать с корзиной и оставлять свои отзывы. Приложение, выполнено с помощью двух подходов:

  • на связке React + Redux + React router + Vite
  • на основе фреймворка Next.

🚀 Стек технологий

  • React 18
  • Redux Toolkit + RTK Query
  • React Router DOM
  • Next.js (v13+ с App Router)
  • CSS Modules, classnames
  • localStorage / Suspense / Fetch API

Развитие проекта по веткам

Ветка Описание изменений
hw-2 Начало проекта: отрисовка ресторанов по мок-данным
hw-3 Реализован счетчик блюд, layout и табы ресторанов
hw-4 Добавлена форма отзывов, кастомные счетчики, useReducer
hw-5 Добавлены scroll progress bar, useCallback, useMemo
hw-6 Контексты темы и пользователя, стилизация через CSS Modules
hw-7 Redux Toolkit, нормализованные данные, слайсы данных, реализована корзина
hw-8 Внедрён React Router DOM, реализована навигация и вложенные маршруты
hw-9 Переход от моков к реальному API, использованы createAsyncThunk, createEntityAdapter
hw-10 Переход на RTK Query для запроса данных и реализации формы добавления отзывов
hw-11 Миграция на Next.js, замена React Router на Next Router
hw-12 Переход на fetch() для запроса данных. Реализация Suspense, loading, generateMetadata

Запустить проект

npm install
npm run dev

Для запуска API-сервера:

npm run start-server

Примечания

Проект строился итеративно по ДЗ. Каждое ДЗ реализовано в отдельной ветке.
Ветка main содержит итоговую версию на Next.js, без react-router-dom, с использованием fetch() и generateMetadata.
Другие подходы можно найти в предыдущих ветках (hw-7 - hw-10).

Нажмите, чтобы раскрыть полное описание домашних заданий

ДЗ - 2

  1. поставить node.js - https://nodejs.org/en
  2. поставить расширение prettier https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode и форматировать свой код. В vs code можно настроить прогон на сохранения файла
  3. создать ветку для ДЗ - hw-2
  4. создать проект с помощью vite - https://vitejs.dev/guide/#scaffolding-your-first-vite-project (можете использовать любой пакетный менеджер)
  5. почистить проект и установить зависимости
  6. скопировать к себе моковые данные из этого проекта (materials/mock.js)
  7. Отобразить все рестораны из моковых данных (импортируем константу в main.jsx и используем данные). Отображаем рестораны друг за другом.
    1. Название ресторана
    2. Заголовок - Меню (h3)
    3. Список названий блюд (используем тег ul и li)
    4. Заголовок - Отзывы (h3)
    5. Список текстов отзывов (используем тег ul и li)
  8. сделать коммит и запушить
  9. открыть ПР из ветки с ДЗ в основную ветку
  10. отправить ссылку на ПР в ветку ДЗ-2

ДЗ - 3

  • установить расширение eslint - https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint и поправить конфиг в соответствии с лекционным проектом
  • установить react расширение для браузера - https://chromewebstore.google.com/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
  • разбить приложение на компоненты
  • необходимо в блюдо добавить счетчик. Минимальное значение 0, максимальное 5, по умолчанию 0. Кнопки +-
  • добавить условный рендеринг, где могут отсутствовать данные
  • реализовать компонент лейаута с хедером, футером и обернуть приложение

Реализовать табы - кнопки с названием ресторана, по одной на каждый ресторан

  • Кнопки отображаем между хедером и рестораном
  • Единовременно отображаем только 1 ресторан
  • По умолчанию - отображаем первый
  • По клику на кнопку отображаем соответствующий ей ресторан. При повторном клике на активную кнопку ничего не происходит.

ДЗ - 4

  • сделать форму отзыва ReviewForm: имя, текст, рейтинг (от 1 до 5). Добавить кнопку “clear”, по клику на которую форма сбрасывается в изначальное состояние. Использовать хук useReducer
  • форма рисуется после всех отзывов о ресторане
  • переиспользовать компонент счетчика Counter между блюдом и отзывом. Важно, именно компонент, который отвечает за UI, логика счетчика блюда лежит отдельно. Можно создать DishCounter и в нем реализовать необходимую логику, но использовать для UI компонент Counter

ДЗ - 5

  • Размножить активный ресторан, чтобы на странице появился длинный скролл и сделать "скролл прогресс". Логику реализовать в отдельном компоненте ProgressBar и добавить его в Layout. Демо тут - https://www.cssscript.com/demo/scroll-progress-bar/
  • провести анализ кода и добавить useCallback, useMemo по необходимости

ДЗ - 6

  • стилизовать приложение, используя css модули (в свободном формате, на ваше усмотрение). Еще раз подумать над разбивкой UI по отдельным компонентам (ресторан, меню, блюдо, отзыв и тд)
  • для удобства предлагается использовать библиотеку classnames, чтобы подключать условно несколько классов - https://www.npmjs.com/package/classnames
  • подключить корневой css файл, чтобы почистить ненужные стили
  • расширение для удобства работы с css модулями - https://marketplace.visualstudio.com/items?itemName=clinyong.vscode-css-modules
  • Добавляем контекст темы. Кнопка переключения темы в шапке. По клику на кнопку все кнопки меняют тему (стили с дефолтных на альтернативные).
  • Добавляем контекст пользователя. В шапке делаем кнопку войти, по клику на кнопку добавляем в контекст мок-пользователя (просто имя любое). Если пользователь авторизован (есть в контексте имя), то кнопку войти меняем на имя пользователя и кнопку выйти, по клику на выйти убираем пользователя из контекста и снова рисуем кнопку войти. Кнопки +/- у блюда и форма отзыва рисуются только для авторизованного пользователя.

ДЗ - 7

  • установить библиотеки redux-toolkit, react-redux - https://redux-toolkit.js.org/introduction/getting-started#an-existing-app
  • установить redux расширения для браузера - https://chromewebstore.google.com/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd
  • сконфигурировать стор
  • скопировать к себе в репозиторий нормализованные моковые данные (materials/normalized-mock.js в этом проекте)
  • создать слайсы данных (рестораны, блюда, отзывы, юзеры) и отказаться от моковых данных (перейти на механизмы rtk)
  • репозиторий с кастомным редаксом - https://github.com/zubkov7/custom-redux
  • реализовать компонент корзины: добавляем блюда из ресторанов по кнопкам +- в каунтере. Текущее значение берем из слайса данных с корзиной

ДЗ-8

  • добавить RRD - https://reactrouter.com/start/library/installation
  • сделать страницу HomePage (контент на ваше усмотрение)
  • компонент корзины отображается над футером на всех страницах
  • сделать страницу /restaurants. На ней рисуем табы ресторанов
  • по клику на таб открываем подстраницу restaurants/:restaurantId с названием ресторана и двумя табами - меню и отзывы. Дефолтно открыт таб меню
  • по клику на табы меню, отзывы открываем подстраницу с меню или отзывами. restaurants/:restaurantId/menu и restaurants/:restaurantId/reviews
  • по клику на блюдо открываем отдельную страницу блюда. На ней отображаем инфу о блюде и количество с кнопками. Страница блюда не является подстраницей ресторана. ее путь dish/:dishId

ДЗ - 9

  • скопировать директорию сервера simple_api в корень проекта (materials/simple_api в этом проекте)
  • установить зависимости сервера (любым менеджером зависимостей внутри папки сервера)
  • скопировать в основной package.json команду start-server (из package.json лекционного проекта)
  • запустить сервер
  • перестать использовать моковые данные и начать использовать данные с сервера. Удалить моковые константы, чтобы было явно видно
  • на странице списка ресторанов /restaurants грузить данные о ресторанах (api /restaurants). Добавить проверку на наличие данных и если в сторе уже есть данные, то не грузить их
  • на странице ресторана restaurants/:restaurantId грузить данные о ресторане (api /restaurant/:restaurantId). Если в сторе уже есть нужный ресторан, то не грузить данные
  • на странице меню ресторана restaurants/:restaurantId/menu грузить блюда ресторана (api /dishes?restaurantId=restaurantId)
  • на странице отзывов ресторана restaurants/:restaurantId/reviews грузить отзывы ресторана (api /reviews?restaurantId=restaurantId) и пользователей (api /users. Добавить проверку на пользователей, если они есть в сторе, то не грузить)
  • на странице блюда dish/:dishId грузить данные о блюде (api /dish/:dishId). Добавить проверку на наличие данных и если в сторе уже есть данные, то не грузить их
  • использовать createEntityAdapter
  • В компонентах необходимо отображать состояния загрузки и ошибки. Для статусов запроса сделать константы

ДЗ - 10

  • перейти на RTK query: запрос данных и подход работы с данными в компонентах
  • реализовать форму добавления отзыва о ресторане
  • User id брать из контекста пользователя (захардкодим, так как для создания отзыва требуется пользователь)
  • при отправке отзыва необходимо перезапросить текущие отзывы, для этого использовать механизм разметки тегов
  • со звездочкой: реализовать изменение отзыва

ДЗ - 11

ДЗ - 12

  • перейти на механизм next.js для запроса данных - fetch. Использовать Suspense и loading файл для отображения состояния загрузки
  • предгенерировать страницы для ресторанов с id bb8afbec-2fec-491f-93e9-7f13950dd80b и d9241927-09e1-44f3-8986-a76346869037
  • реализовать API для инвалидации /restaurants сегмента
  • реализовать динамический title для страницы ресторана (использовать generateMetadata) (сделать запрос и кастомный тайтл)

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages