Вивчай
Домашнє завдання #25 ·
балівintermediate

RecipeBox — менеджер рецептів

Побудуй повноцінний CRUD-додаток на Next.js. Бекенд — API routes, що працюють з JSON-файлом. Фронтенд — серверні компоненти для відображення та клієнтські для форм.


Підготовка

npx create-next-app@latest recipe-box --typescript --tailwind --app
cd recipe-box

Створи файл для "бази даних":

data/
  recipes.json
[
  {
    "id": "1",
    "title": "Борщ класичний",
    "category": "Перші страви",
    "cookingTime": 90,
    "ingredients": ["буряк", "картопля", "капуста", "морква", "цибуля", "томатна паста"],
    "instructions": "1. Зварити бульйон...",
    "imageUrl": "",
    "createdAt": "2026-01-15T10:00:00Z"
  }
]

Завдання

1. API Routes (бекенд)

Створи повний набір CRUD-ендпоінтів:

МетодURLЩо робить
GET/api/recipesСписок всіх рецептів
GET/api/recipes/[id]Один рецепт за ID
POST/api/recipesСтворити новий рецепт
PUT/api/recipes/[id]Оновити рецепт
DELETE/api/recipes/[id]Видалити рецепт

Дані зберігаються у data/recipes.json. Читай/записуй через fs.readFileSync / fs.writeFileSync.

Порада

Для генерації ID використай crypto.randomUUID() — вбудована функція Node.js, не потребує бібліотек.

Валідація в POST/PUT:

  • title — обов'язкове, мін. 3 символи
  • category — обов'язкове
  • ingredients — масив, мін. 1 елемент
  • При помилках — повертай статус 400 з описом

2. Список рецептів (головна сторінка)

Server Component, що завантажує рецепти і показує:

  • Картки рецептів (назва, категорія, час приготування, кількість інгредієнтів)
  • Фільтр за категорією (Перші страви, Другі страви, Десерти, Салати, Напої)
  • Пошук за назвою
  • Посилання на сторінку кожного рецепта

3. Сторінка рецепта (/recipes/[id])

  • Повна інформація: назва, категорія, час, інгредієнти (список), інструкція
  • Кнопки "Редагувати" та "Видалити"
  • Видалення з підтвердженням (confirm або модальне вікно)
  • Після видалення — перенаправлення на головну

4. Форма створення (/recipes/new)

Client Component з controlled формою:

  • Поля: назва, категорія (select), час приготування (number), інгредієнти (динамічний список — додати/видалити), інструкція (textarea), URL зображення
  • Валідація на клієнті перед відправкою
  • fetch('POST', '/api/recipes') при submit
  • Після створення — перенаправлення на сторінку нового рецепта

5. Форма редагування (/recipes/[id]/edit)

  • Та ж форма, що й для створення, але заповнена поточними даними
  • fetch('PUT', '/api/recipes/[id]') при submit
  • Після збереження — перенаправлення на сторінку рецепта

6. Layout та навігація

  • Спільний layout: header (логотип + навігація), main, footer
  • Навігація: Всі рецепти, Додати рецепт
  • Responsive дизайн

Структура проекту

src/
├── app/
│   ├── layout.tsx
│   ├── page.tsx              # Список рецептів
│   ├── recipes/
│   │   ├── new/
│   │   │   └── page.tsx      # Форма створення
│   │   └── [id]/
│   │       ├── page.tsx      # Сторінка рецепта
│   │       └── edit/
│   │           └── page.tsx  # Форма редагування
│   └── api/
│       └── recipes/
│           ├── route.ts      # GET all, POST
│           └── [id]/
│               └── route.ts  # GET one, PUT, DELETE
├── components/
│   ├── RecipeCard.tsx
│   ├── RecipeForm.tsx        # Спільна форма для create/edit
│   └── DeleteButton.tsx
└── types/
    └── recipe.ts
data/
└── recipes.json

Бонус

  • Додай завантаження зображення (зберігай в public/uploads/ через API route)
  • "Улюблені рецепти" — мітка зірочкою, фільтр по улюблених (додай поле favorite: boolean)
  • Сортування: за датою, за часом приготування, за назвою
  • SEO: generateMetadata для кожної сторінки рецепта
  • Друк рецепта: кнопка, що відкриває print-friendly версію (window.print())

Критерії оцінки

КритерійБали
API routes: GET all + GET one + POST + PUT + DELETE25
Валідація в API (400 для некоректних даних)10
Список рецептів (Server Component, фільтр, пошук)15
Сторінка рецепта (деталі + видалення)10
Форма створення (controlled, валідація, redirect)15
Форма редагування (заповнення поточними даними)10
Layout, навігація, стилізація10
TypeScript типи (Recipe, API responses)5
Бонус: Завантаження зображень / Улюблені / Сортування / SEO+20