@mashka818/exam-de-template 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/exam-guides/COMMENTS_GUIDE.md +53 -0
  2. package/exam-guides/EXAM_COMMANDS.txt +47 -0
  3. package/exam-guides/GUIDE_PAGES.md +529 -0
  4. package/exam-guides/NPM_PACKAGE.md +206 -0
  5. package/exam-guides/README.md +40 -0
  6. package/exam-guides/RESPONSIVE.md +224 -0
  7. package/exam-guides/TECH_STACK.txt +142 -0
  8. package/exam-guides/THEME_BANQUETAM_NET.md +106 -0
  9. package/exam-guides/commented-code/README.txt +5 -0
  10. package/exam-guides/commented-code/client/index.html +14 -0
  11. package/exam-guides/commented-code/client/package-lock.json +2298 -0
  12. package/exam-guides/commented-code/client/package.json +21 -0
  13. package/exam-guides/commented-code/client/public/images/README.txt +26 -0
  14. package/exam-guides/commented-code/client/public/images/about-cleaning.svg +4 -0
  15. package/exam-guides/commented-code/client/public/images/admin-banner.svg +1 -0
  16. package/exam-guides/commented-code/client/public/images/empty-requests.svg +1 -0
  17. package/exam-guides/commented-code/client/public/images/footer-photo-1.svg +4 -0
  18. package/exam-guides/commented-code/client/public/images/footer-photo-2.svg +4 -0
  19. package/exam-guides/commented-code/client/public/images/footer-photo-3.svg +4 -0
  20. package/exam-guides/commented-code/client/public/images/home-hero.svg +4 -0
  21. package/exam-guides/commented-code/client/public/images/login-banner.svg +1 -0
  22. package/exam-guides/commented-code/client/public/images/logo.svg +4 -0
  23. package/exam-guides/commented-code/client/public/images/new-request-banner.svg +1 -0
  24. package/exam-guides/commented-code/client/public/images/register-banner.svg +1 -0
  25. package/exam-guides/commented-code/client/public/images/requests-banner.svg +1 -0
  26. package/exam-guides/commented-code/client/public/images/slide-1.svg +6 -0
  27. package/exam-guides/commented-code/client/public/images/slide-2.svg +5 -0
  28. package/exam-guides/commented-code/client/public/images/slide-3.svg +5 -0
  29. package/exam-guides/commented-code/client/src/App.jsx +72 -0
  30. package/exam-guides/commented-code/client/src/api.js +71 -0
  31. package/exam-guides/commented-code/client/src/components/FormField.jsx +25 -0
  32. package/exam-guides/commented-code/client/src/components/Layout.jsx +83 -0
  33. package/exam-guides/commented-code/client/src/components/PageImage.jsx +38 -0
  34. package/exam-guides/commented-code/client/src/components/ProtectedRoute.jsx +35 -0
  35. package/exam-guides/commented-code/client/src/components/UserNav.jsx +33 -0
  36. package/exam-guides/commented-code/client/src/components/landing/HeroSlider.jsx +103 -0
  37. package/exam-guides/commented-code/client/src/components/landing/LandingLayout.jsx +76 -0
  38. package/exam-guides/commented-code/client/src/components/landing/SiteFooter.jsx +74 -0
  39. package/exam-guides/commented-code/client/src/config/images.js +104 -0
  40. package/exam-guides/commented-code/client/src/constants/services.js +19 -0
  41. package/exam-guides/commented-code/client/src/context/AuthContext.jsx +72 -0
  42. package/exam-guides/commented-code/client/src/index.css +73 -0
  43. package/exam-guides/commented-code/client/src/main.jsx +28 -0
  44. package/exam-guides/commented-code/client/src/pages/AdminPage.jsx +151 -0
  45. package/exam-guides/commented-code/client/src/pages/LandingPage.jsx +131 -0
  46. package/exam-guides/commented-code/client/src/pages/LoginPage.jsx +81 -0
  47. package/exam-guides/commented-code/client/src/pages/RegisterPage.jsx +117 -0
  48. package/exam-guides/commented-code/client/src/pages/RequestFormPage.jsx +196 -0
  49. package/exam-guides/commented-code/client/src/pages/RequestsPage.jsx +112 -0
  50. package/exam-guides/commented-code/client/src/utils/validation.js +71 -0
  51. package/exam-guides/commented-code/client/vite.config.js +31 -0
  52. package/exam-guides/commented-code/server/db/init.js +67 -0
  53. package/exam-guides/commented-code/server/db/pool.js +23 -0
  54. package/exam-guides/commented-code/server/db/schema.sql +53 -0
  55. package/exam-guides/commented-code/server/db/seed.sql +15 -0
  56. package/exam-guides/commented-code/server/index.js +45 -0
  57. package/exam-guides/commented-code/server/middleware/auth.js +38 -0
  58. package/exam-guides/commented-code/server/package-lock.json +1084 -0
  59. package/exam-guides/commented-code/server/package.json +17 -0
  60. package/exam-guides/commented-code/server/routes/admin.js +96 -0
  61. package/exam-guides/commented-code/server/routes/auth.js +128 -0
  62. package/exam-guides/commented-code/server/routes/requests.js +115 -0
  63. package/exam-guides/commented-code/server/routes/services.js +31 -0
  64. package/exam-guides/commented-code/server/utils/validation.js +81 -0
  65. package/exam-guides/exam-starter/README.txt +22 -0
  66. package/exam-guides/exam-starter/package.json +13 -0
  67. package/exam-guides//320/243/320/224/320/220/320/233/320/230/320/242/320/254-/320/237/320/225/320/240/320/225/320/224-/320/241/320/224/320/220/320/247/320/225/320/231.txt +9 -0
  68. package/exam-project/README.md +16 -0
  69. package/exam-project/client/index.html +14 -0
  70. package/exam-project/client/package-lock.json +2298 -0
  71. package/exam-project/client/package.json +21 -0
  72. package/exam-project/client/public/images/README.txt +26 -0
  73. package/exam-project/client/public/images/about-cleaning.svg +4 -0
  74. package/exam-project/client/public/images/admin-banner.svg +1 -0
  75. package/exam-project/client/public/images/empty-requests.svg +1 -0
  76. package/exam-project/client/public/images/footer-photo-1.svg +4 -0
  77. package/exam-project/client/public/images/footer-photo-2.svg +4 -0
  78. package/exam-project/client/public/images/footer-photo-3.svg +4 -0
  79. package/exam-project/client/public/images/home-hero.svg +4 -0
  80. package/exam-project/client/public/images/login-banner.svg +1 -0
  81. package/exam-project/client/public/images/logo.svg +4 -0
  82. package/exam-project/client/public/images/new-request-banner.svg +1 -0
  83. package/exam-project/client/public/images/register-banner.svg +1 -0
  84. package/exam-project/client/public/images/requests-banner.svg +1 -0
  85. package/exam-project/client/public/images/slide-1.svg +6 -0
  86. package/exam-project/client/public/images/slide-2.svg +5 -0
  87. package/exam-project/client/public/images/slide-3.svg +5 -0
  88. package/exam-project/client/src/App.jsx +52 -0
  89. package/exam-project/client/src/api.js +50 -0
  90. package/exam-project/client/src/components/FormField.jsx +11 -0
  91. package/exam-project/client/src/components/Layout.jsx +61 -0
  92. package/exam-project/client/src/components/PageImage.jsx +22 -0
  93. package/exam-project/client/src/components/ProtectedRoute.jsx +20 -0
  94. package/exam-project/client/src/components/UserNav.jsx +20 -0
  95. package/exam-project/client/src/components/landing/HeroSlider.jsx +89 -0
  96. package/exam-project/client/src/components/landing/LandingLayout.jsx +61 -0
  97. package/exam-project/client/src/components/landing/SiteFooter.jsx +61 -0
  98. package/exam-project/client/src/config/images.js +83 -0
  99. package/exam-project/client/src/constants/services.js +7 -0
  100. package/exam-project/client/src/context/AuthContext.jsx +55 -0
  101. package/exam-project/client/src/index.css +54 -0
  102. package/exam-project/client/src/main.jsx +17 -0
  103. package/exam-project/client/src/pages/AdminPage.jsx +128 -0
  104. package/exam-project/client/src/pages/LandingPage.jsx +115 -0
  105. package/exam-project/client/src/pages/LoginPage.jsx +63 -0
  106. package/exam-project/client/src/pages/RegisterPage.jsx +97 -0
  107. package/exam-project/client/src/pages/RequestFormPage.jsx +178 -0
  108. package/exam-project/client/src/pages/RequestsPage.jsx +94 -0
  109. package/exam-project/client/src/utils/validation.js +54 -0
  110. package/exam-project/client/vite.config.js +17 -0
  111. package/exam-project/package.json +18 -0
  112. package/exam-project/scripts/init-project.js +86 -0
  113. package/exam-project/scripts/prepack.js +27 -0
  114. package/exam-project/scripts/unpack-template.js +105 -0
  115. package/exam-project/server/db/init.js +50 -0
  116. package/exam-project/server/db/pool.js +11 -0
  117. package/exam-project/server/db/schema.sql +41 -0
  118. package/exam-project/server/db/seed.sql +12 -0
  119. package/exam-project/server/index.js +29 -0
  120. package/exam-project/server/middleware/auth.js +24 -0
  121. package/exam-project/server/package-lock.json +1084 -0
  122. package/exam-project/server/package.json +17 -0
  123. package/exam-project/server/routes/admin.js +76 -0
  124. package/exam-project/server/routes/auth.js +109 -0
  125. package/exam-project/server/routes/requests.js +99 -0
  126. package/exam-project/server/routes/services.js +18 -0
  127. package/exam-project/server/utils/validation.js +63 -0
  128. package/package.json +25 -0
  129. package/scripts/init-project.js +86 -0
  130. package/scripts/prepack.js +27 -0
  131. package/scripts/unpack-template.js +105 -0
@@ -0,0 +1,53 @@
1
+ # Шпаргалка: что менять при другой теме
2
+
3
+ В **каждом** файле `client/src/**` и `server/**` (кроме `node_modules`) в начале есть блок `===` с пояснением: что менять, куда смотреть, метки `БАНКЕТАМ.НЕТ:`. Старые комментарии про клининг **не удаляйте**.
4
+
5
+ Поиск по проекту: `БАНКЕТАМ.НЕТ` | `ЗАМЕНИТЕ` | `GUIDE_PAGES`
6
+
7
+ ## Тема «Банкетам.Нет» (ваш вариант 09.02.07)
8
+
9
+ | Файл | Для чего |
10
+ |------|----------|
11
+ | **`GUIDE_PAGES.md`** | **Главный гайд:** кнопки, картинки, секции, новая страница, формы, админ-фильтр |
12
+ | **`THEME_BANQUETAM_NET.md`** | Таблица замен «клининг → банкеты» |
13
+ | **`RESPONSIVE.md`** | Мобильный 390px и ПК |
14
+
15
+ В коде ищите **`БАНКЕТАМ.НЕТ:`** — старые комментарии про клининг **не удаляйте**, они для шаблона «Мой Не Сам».
16
+
17
+ ---
18
+
19
+ ## Картинки (Figma → проект)
20
+
21
+ 1. Экспорт PNG в **`client/public/images/`**
22
+ 2. Имена файлов и `alt` — в **`client/src/config/images.js`**
23
+ 3. На страницах только `<PageImage imageKey="..." />`, пути вручную не пишем
24
+
25
+ ## Бэкенд
26
+
27
+ | Файл | Что менять |
28
+ |------|------------|
29
+ | `server/db/schema.sql` | Таблицы, поля, статусы CHECK |
30
+ | `server/db/seed.sql` | Список услуг |
31
+ | `server/db/init.js` | adminka/password |
32
+ | `server/utils/validation.js` | Правила полей |
33
+ | `server/routes/*.js` | SQL-запросы, подписи статусов |
34
+
35
+ ## Фронтенд
36
+
37
+ | Файл | Что менять |
38
+ |------|------------|
39
+ | `client/src/config/images.js` | Файлы картинок и alt |
40
+ | `client/src/components/Layout.jsx` | Название портала, цвета шапок |
41
+ | `client/src/pages/*.jsx` | Тексты, баннеры imageKey |
42
+ | `client/src/utils/validation.js` | Как на сервере |
43
+ | `client/index.html` | `<title>` |
44
+
45
+ ## Сущности
46
+
47
+ - `requests` → заявка на уборку (другая тема: заказ, бронь)
48
+ - `service_types` → виды услуг из задания
49
+ - `users.role`: `user` | `admin`
50
+
51
+ ## Адаптив
52
+
53
+ Мобильный макет 390×844 + версия под ПК — **`RESPONSIVE.md`**
@@ -0,0 +1,47 @@
1
+ ================================================================================
2
+ ЭКЗАМЕН — одна команда, две папки
3
+ ================================================================================
4
+ Нужны: Node.js, PostgreSQL, интернет, пакет на npm (см. NPM_PACKAGE.md)
5
+
6
+ Пакет: @mashka818/exam-de-template
7
+
8
+ --------------------------------------------------------------------------------
9
+ НА ЭКЗАМЕНЕ
10
+ --------------------------------------------------------------------------------
11
+
12
+ mkdir C:\DE\work
13
+ cd C:\DE\work
14
+ npx @mashka818/exam-de-template@1.0.0 init
15
+
16
+ Появятся:
17
+ exam-project\ — правите и запускаете ЗДЕСЬ
18
+ exam-guides\ — шпоры (удалить перед сдачей)
19
+
20
+ cd exam-project
21
+ copy server\.env.example server\.env
22
+ notepad server\.env
23
+ npm run db:init
24
+ npm run dev
25
+
26
+ Сайт: http://localhost:5173
27
+
28
+ --------------------------------------------------------------------------------
29
+ ПЕРЕД СДАЧЕЙ
30
+ --------------------------------------------------------------------------------
31
+
32
+ cd ..
33
+ rmdir /s /q exam-guides
34
+
35
+ (остаётся только exam-project — его и показываете)
36
+
37
+ --------------------------------------------------------------------------------
38
+ ДОМА (один раз)
39
+ --------------------------------------------------------------------------------
40
+
41
+ npm run sync:project
42
+ cd exam-project
43
+ npm publish --access public
44
+
45
+ Подробно: NPM_PACKAGE.md
46
+
47
+ ================================================================================
@@ -0,0 +1,529 @@
1
+ # Полный гайд: как править шаблон на экзамене
2
+
3
+ Этот файл — **пошаговая инструкция**, как из шаблона «Мой Не Сам» сделать другую тему (например **«Банкетам.Нет»**).
4
+
5
+ - В коде ищите **`БАНКЕТАМ.НЕТ:`** — короткие подсказки у строк.
6
+ - Таблица замен темы: **`THEME_BANQUETAM_NET.md`**.
7
+ - Запуск проекта: **`README.md`**.
8
+
9
+ **Важно:** старые комментарии про клининг **не удаляйте** — они описывают текущий шаблон. Добавляйте свои правки рядом или по гайду ниже.
10
+
11
+ ---
12
+
13
+ ## 1. Карта проекта (что за что отвечает)
14
+
15
+ ```
16
+ examTemplate/
17
+ ├── client/
18
+ │ ├── public/images/ ← файлы картинок (PNG/SVG из Figma)
19
+ │ ├── src/
20
+ │ │ ├── config/images.js ← имена файлов и alt (НЕ пути вручную в JSX!)
21
+ │ │ ├── pages/ ← страницы (один файл ≈ один экран)
22
+ │ │ ├── components/ ← общие части (Layout, FormField…)
23
+ │ │ ├── components/landing/ ← лендинг: слайдер, футер
24
+ │ │ ├── App.jsx ← URL → какая страница открывается
25
+ │ │ ├── api.js ← все запросы к серверу
26
+ │ │ └── utils/validation.js ← проверка полей на форме
27
+ │ └── index.html ← <title> вкладки браузера
28
+ ├── server/
29
+ │ ├── db/schema.sql ← таблицы
30
+ │ ├── db/seed.sql ← справочник (услуги / помещения)
31
+ │ ├── db/init.js ← админ при npm run db:init
32
+ │ ├── routes/ ← API
33
+ │ └── utils/validation.js ← проверка на сервере (как на клиенте!)
34
+ ```
35
+
36
+ ### URL → файл страницы
37
+
38
+ | Адрес | Файл | Задание ДЭ |
39
+ |-------|------|------------|
40
+ | `/` | `LandingPage.jsx` | лендинг (не в п.1–5, но для защиты) |
41
+ | `/register` | `RegisterPage.jsx` | п.1 регистрация |
42
+ | `/login` | `LoginPage.jsx` | п.2 вход |
43
+ | `/requests` | `RequestsPage.jsx` | п.3 личный кабинет / история |
44
+ | `/requests/form` | `RequestFormPage.jsx` | п.4 оформление заявки |
45
+ | `/admin` | `AdminPage.jsx` | п.5 админ |
46
+
47
+ Маршруты прописаны в **`client/src/App.jsx`**.
48
+
49
+ ---
50
+
51
+ ## 2. Как заменить название и тексты (самое частое)
52
+
53
+ ### 2.1. Название сайта в шапке
54
+
55
+ **Файл:** `client/src/components/Layout.jsx`
56
+
57
+ Найдите:
58
+
59
+ ```javascript
60
+ const brandName = 'Мой Не Сам'; // ← заменить текст в кавычках
61
+ const brandTagline = 'Клининг без хлопот';
62
+ ```
63
+
64
+ **Лендинг** (отдельная шапка): `client/src/components/landing/LandingLayout.jsx` — там тоже `brandName`.
65
+
66
+ ### 2.2. Заголовок вкладки браузера
67
+
68
+ **Файл:** `client/index.html`
69
+
70
+ ```html
71
+ <title>Мой Не Сам — портал клининговых услуг</title>
72
+ ```
73
+
74
+ ### 2.3. Тексты на конкретной странице
75
+
76
+ Откройте файл из `client/src/pages/`. Ищите:
77
+
78
+ - `<h1>`, `<h2>`, `<p>` — заголовки и абзацы;
79
+ - текст внутри `<Link>…</Link>` и `<button>…</button>`;
80
+ - `placeholder="..."` у `<input>`.
81
+
82
+ **Пример** (`RegisterPage.jsx`):
83
+
84
+ ```jsx
85
+ <h2 className="text-xl font-bold text-teal-900 mb-1">Регистрация</h2>
86
+ <p className="text-sm text-slate-500 mb-6">Все поля обязательны</p>
87
+ ```
88
+
89
+ Меняете только русский текст между тегами. **Классы** (`className="..."`) трогайте только если меняете дизайн.
90
+
91
+ ### 2.4. Подписи полей формы
92
+
93
+ Используется компонент **`FormField`**:
94
+
95
+ ```jsx
96
+ <FormField label="ФИО" error={errors.fullName}>
97
+ <input ... />
98
+ </FormField>
99
+ ```
100
+
101
+ Меняете **`label="..."`**. Для банкетов: `label="Помещение"`, `label="Дата начала банкета"` и т.д.
102
+
103
+ ---
104
+
105
+ ## 3. Картинки: куда класть и как подключить
106
+
107
+ ### 3.1. Куда положить файл
108
+
109
+ Папка: **`client/public/images/`**
110
+
111
+ Пример: `client/public/images/logo.png`
112
+
113
+ В браузере картинка откроется как: **`http://localhost:5173/images/logo.png`**
114
+
115
+ ### 3.2. Зарегистрировать в конфиге (обязательно!)
116
+
117
+ **Файл:** `client/src/config/images.js`
118
+
119
+ ```javascript
120
+ export const IMAGES = {
121
+ logo: {
122
+ file: 'logo.png', // имя файла в public/images/
123
+ alt: 'Логотип Банкетам.Нет', // для доступности
124
+ },
125
+ // добавьте новый ключ:
126
+ myBanner: {
127
+ file: 'my-banner.png',
128
+ alt: 'Описание картинки',
129
+ },
130
+ };
131
+ ```
132
+
133
+ ### 3.3. Показать на странице
134
+
135
+ **Не пишите** `src="/images/logo.png"` напрямую (так тоже можно, но в шаблоне принят единый способ):
136
+
137
+ ```jsx
138
+ import PageImage from '../components/PageImage.jsx';
139
+
140
+ <PageImage imageKey="logo" className="h-9 w-auto" />
141
+ ```
142
+
143
+ - `imageKey` — ключ из `IMAGES` (`logo`, `homeHero`, `registerBanner`…).
144
+ - `className` — размер и скругление (Tailwind).
145
+
146
+ ### 3.4. Добавить новую картинку с нуля
147
+
148
+ 1. Положите `new-photo.png` в `public/images/`.
149
+ 2. В `images.js` добавьте блок с ключом, например `newPhoto: { file: 'new-photo.png', alt: '...' }`.
150
+ 3. На странице: `<PageImage imageKey="newPhoto" className="w-full h-40 object-cover rounded-xl" />`.
151
+
152
+ ### 3.5. Заменить картинку (Figma → PNG)
153
+
154
+ 1. Экспорт из Figma с **тем же именем** (например `register-banner.png`).
155
+ 2. Замените файл в `public/images/` (перезапишите).
156
+ 3. В `images.js` поменяйте `file: 'register-banner.svg'` → `file: 'register-banner.png'`.
157
+ 4. Обновите страницу в браузере (F5).
158
+
159
+ ### 3.6. Слайдер (4 картинки)
160
+
161
+ **Файлы:** `HeroSlider.jsx`, `images.js`, `public/images/slide-1.png` … `slide-4.png`
162
+
163
+ В `HeroSlider.jsx`:
164
+
165
+ ```javascript
166
+ const SLIDE_KEYS = ['slide1', 'slide2', 'slide3', 'slide4']; // добавить slide4
167
+ ```
168
+
169
+ В `images.js` — ключи `slide1`…`slide4`.
170
+
171
+ Интервал смены:
172
+
173
+ ```javascript
174
+ }, 5000); // миллисекунды → для 3 сек: 3000
175
+ ```
176
+
177
+ Тексты на слайдах — объект `slideText` в том же файле.
178
+
179
+ ---
180
+
181
+ ## 4. Кнопки и ссылки
182
+
183
+ ### 4.1. Кнопка «отправить форму»
184
+
185
+ Уже есть на формах:
186
+
187
+ ```jsx
188
+ <button type="submit" className="w-full rounded-xl bg-teal-600 text-white py-3 ...">
189
+ Зарегистрироваться
190
+ </button>
191
+ ```
192
+
193
+ Меняете только текст между тегами. `type="submit"` не убирайте.
194
+
195
+ ### 4.2. Ссылка на другую страницу
196
+
197
+ ```jsx
198
+ import { Link } from 'react-router-dom';
199
+
200
+ <Link to="/register" className="text-teal-700 underline">
201
+ Еще не зарегистрированы? Регистрация
202
+ </Link>
203
+ ```
204
+
205
+ - `to="/register"` — куда ведёт (должен быть в `App.jsx`).
206
+ - Текст внутри `Link` — что видит пользователь.
207
+
208
+ ### 4.3. Добавить новую кнопку-ссылку
209
+
210
+ Скопируйте блок `Link` выше, вставьте под существующим, поменяйте `to` и текст.
211
+
212
+ ### 4.4. Удалить кнопку
213
+
214
+ Удалите целиком блок `<button>...</button>` или `<Link>...</Link>` **вместе с обёрткой**, если она только для этой кнопки.
215
+
216
+ **Пример — убрать «Отменить» в админке** (`AdminPage.jsx`):
217
+
218
+ Удалите блок:
219
+
220
+ ```jsx
221
+ {r.status !== 'cancelled' && (
222
+ <button ...>Отменить</button>
223
+ )}
224
+ ```
225
+
226
+ И поле «Причина отмены», если отмены больше нет в задании.
227
+
228
+ ### 4.5. Кнопка с действием (без перехода)
229
+
230
+ ```jsx
231
+ <button
232
+ type="button"
233
+ onClick={() => updateStatus(r.id, 'completed')}
234
+ className="px-3 py-1.5 rounded-lg bg-emerald-600 text-white text-xs"
235
+ >
236
+ Выполнено
237
+ </button>
238
+ ```
239
+
240
+ - `onClick` — что выполнить (функция в том же файле).
241
+ - Текст кнопки — подпись для пользователя.
242
+
243
+ Для «Банкетам.Нет» меняете текст на **«Банкет завершен»**, логику `updateStatus` не трогаете.
244
+
245
+ ---
246
+
247
+ ## 5. Как убрать / добавить секцию на странице
248
+
249
+ Страница — это набор блоков `<section>...</section>` или `<div>...</div>`.
250
+
251
+ ### 5.1. Удалить секцию
252
+
253
+ Найдите комментарий `{/* --- О клининге --- */}` и удалите **весь** блок от `<section` до `</section>` (или от `<div` до `</div>`).
254
+
255
+ **Проверка:** в редакторе должен остаться валидный JSX — у каждого открывающего тега есть закрывающий.
256
+
257
+ ### 5.2. Добавить секцию
258
+
259
+ Скопируйте похожую секцию с другой страницы (например с `LandingPage.jsx`), вставьте в нужное место, поменяйте тексты и `imageKey`.
260
+
261
+ Шаблон секции:
262
+
263
+ ```jsx
264
+ <section className="mx-auto max-w-lg lg:max-w-5xl px-4 py-10">
265
+ <h2 className="text-xl font-bold text-slate-800 mb-4">Заголовок блока</h2>
266
+ <p className="text-sm text-slate-600">Текст блока.</p>
267
+ </section>
268
+ ```
269
+
270
+ ### 5.3. Перенести слайдер в личный кабинет
271
+
272
+ 1. В `RequestsPage.jsx` вверху добавьте импорт:
273
+ ```jsx
274
+ import HeroSlider from '../components/landing/HeroSlider.jsx';
275
+ ```
276
+ 2. Внутри `return`, после шапки страницы:
277
+ ```jsx
278
+ <HeroSlider />
279
+ ```
280
+
281
+ ---
282
+
283
+ ## 6. Как создать новую страницу с нуля
284
+
285
+ ### Шаг 1. Файл страницы
286
+
287
+ Создайте `client/src/pages/MyPage.jsx`:
288
+
289
+ ```jsx
290
+ /**
291
+ * Описание страницы. URL: /my-page
292
+ */
293
+ import Layout from '../components/Layout.jsx';
294
+
295
+ export default function MyPage() {
296
+ return (
297
+ <Layout variant="default">
298
+ <h1 className="text-xl font-bold">Заголовок</h1>
299
+ <p className="text-slate-600">Содержимое.</p>
300
+ </Layout>
301
+ );
302
+ }
303
+ ```
304
+
305
+ `variant` для шапки: `default` | `register` | `login` | `dashboard` | `admin` (см. `Layout.jsx`).
306
+
307
+ ### Шаг 2. Маршрут
308
+
309
+ **Файл:** `App.jsx`
310
+
311
+ ```jsx
312
+ import MyPage from './pages/MyPage.jsx';
313
+
314
+ // внутри <Routes>:
315
+ <Route path="/my-page" element={<MyPage />} />
316
+ ```
317
+
318
+ Если страница только для вошедших:
319
+
320
+ ```jsx
321
+ <Route
322
+ path="/my-page"
323
+ element={
324
+ <ProtectedRoute role="user">
325
+ <MyPage />
326
+ </ProtectedRoute>
327
+ }
328
+ />
329
+ ```
330
+
331
+ ### Шаг 3. Ссылка на страницу
332
+
333
+ Где нужно — добавьте `<Link to="/my-page">Текст</Link>`.
334
+
335
+ ---
336
+
337
+ ## 7. Формы: поля, валидация, отправка
338
+
339
+ ### 7.1. Добавить поле в форму
340
+
341
+ 1. В `useState` формы добавьте ключ:
342
+ ```javascript
343
+ const [form, setForm] = useState({
344
+ address: '',
345
+ newField: '', // новое
346
+ });
347
+ ```
348
+ 2. В JSX:
349
+ ```jsx
350
+ <FormField label="Новое поле" error={errors.newField}>
351
+ <input
352
+ className={inputClass}
353
+ value={form.newField}
354
+ onChange={(e) => setForm((f) => ({ ...f, newField: e.target.value }))}
355
+ />
356
+ </FormField>
357
+ ```
358
+ 3. В `validateRegistration` / `validateRequestForm` (`client/src/utils/validation.js`) — проверка.
359
+ 4. То же в `server/utils/validation.js`.
360
+ 5. В `server/routes/...` — сохранение в SQL (INSERT/UPDATE).
361
+
362
+ ### 7.2. Убрать поле
363
+
364
+ Обратный порядок: удалите из JSX → из `useState` → из валидации → из API/SQL.
365
+
366
+ ### 7.3. Выпадающий список (select)
367
+
368
+ Уже есть в `RequestFormPage.jsx`:
369
+
370
+ ```jsx
371
+ <select value={form.serviceTypeId} onChange={set('serviceTypeId')}>
372
+ <option value="">— выберите —</option>
373
+ {services.map((s) => (
374
+ <option key={s.id} value={s.id}>{s.name}</option>
375
+ ))}
376
+ </select>
377
+ ```
378
+
379
+ Список приходит с API `/api/services` из таблицы `service_types` (`seed.sql`).
380
+
381
+ ### 7.4. Дата ДД.ММ.ГГГГ (для «Банкетам.Нет»)
382
+
383
+ Сейчас: `<input type="datetime-local" />`.
384
+
385
+ Заменить на:
386
+
387
+ ```jsx
388
+ <input
389
+ type="text"
390
+ placeholder="ДД.ММ.ГГГГ"
391
+ value={form.banquetDate}
392
+ onChange={set('banquetDate')}
393
+ />
394
+ ```
395
+
396
+ В `validation.js` добавить проверку регуляркой, например `/^\d{2}\.\d{2}\.\d{4}$/`.
397
+
398
+ На сервере при сохранении — преобразовать строку в дату для PostgreSQL.
399
+
400
+ ---
401
+
402
+ ## 8. База данных и API
403
+
404
+ ### 8.1. Сменить список услуг / помещений
405
+
406
+ **Файл:** `server/db/seed.sql` — замените `INSERT INTO service_types`.
407
+
408
+ После изменения: `npm run db:init` (или вручную очистить и вставить).
409
+
410
+ **Файл:** `client/src/constants/services.js` — массив для лендинга (должен совпадать по смыслу).
411
+
412
+ ### 8.2. Сменить админа
413
+
414
+ **Файл:** `server/db/init.js` — `login` и `password` в `seedAdmin()`.
415
+
416
+ Затем: `npm run db:init`.
417
+
418
+ ### 8.3. Сменить подписи статусов
419
+
420
+ | Где | Что |
421
+ |-----|-----|
422
+ | `server/routes/requests.js` | `STATUS_LABELS` |
423
+ | `server/routes/admin.js` | объект в `statusLabel` |
424
+ | `RequestsPage.jsx` | `statusColors` + отображение |
425
+ | `AdminPage.jsx` | тексты на кнопках |
426
+
427
+ Ключи в БД (`new`, `in_progress`, `completed`) можно **не менять** — меняйте только **русские подписи**.
428
+
429
+ ### 8.4. Добавить фильтр в админке (пошагово)
430
+
431
+ **Сейчас фильтра нет** — только комментарий. Как сделать:
432
+
433
+ **Вариант А — только на фронте (быстро на экзамене):**
434
+
435
+ 1. `AdminPage.jsx` — состояние:
436
+ ```javascript
437
+ const [filterStatus, setFilterStatus] = useState('all');
438
+ ```
439
+ 2. Перед списком — `<select>`:
440
+ ```jsx
441
+ <select value={filterStatus} onChange={(e) => setFilterStatus(e.target.value)}>
442
+ <option value="all">Все</option>
443
+ <option value="new">Новая</option>
444
+ <option value="in_progress">В работе</option>
445
+ <option value="completed">Выполнено</option>
446
+ </select>
447
+ ```
448
+ 3. Вместо `requests.map` используйте:
449
+ ```javascript
450
+ const visible = filterStatus === 'all'
451
+ ? requests
452
+ : requests.filter((r) => r.status === filterStatus);
453
+ ```
454
+ и `visible.map(...)`.
455
+
456
+ **Вариант Б — на сервере:** в `admin.js` читать `req.query.status` и добавлять `WHERE r.status = $1` в SQL.
457
+
458
+ **Сортировка:** `useState sortBy` + `.sort()` по дате или ФИО.
459
+
460
+ **Пагинация:** `const PAGE = 5`, `page` state, `slice((page-1)*PAGE, page*PAGE)`.
461
+
462
+ ---
463
+
464
+ ## 9. Отзывы (личный кабинет, «Банкетам.Нет»)
465
+
466
+ Сейчас **не реализовано** — только комментарии.
467
+
468
+ План:
469
+
470
+ 1. **schema.sql** — поле `review_text TEXT` в `requests` или таблица `reviews`.
471
+ 2. **API** — `POST /api/requests/:id/review` (только если `status !== 'new'`).
472
+ 3. **RequestsPage.jsx** — под карточкой заявки textarea + кнопка «Оставить отзыв», если админ уже менял статус.
473
+
474
+ ---
475
+
476
+ ## 10. Цвета и «отличительная черта» раздела
477
+
478
+ Каждая страница передаёт в Layout свой **`variant`**:
479
+
480
+ | Страница | variant | Цвет шапки |
481
+ |----------|---------|------------|
482
+ | Регистрация | `register` | бирюзовая |
483
+ | Вход | `login` | тёмная |
484
+ | Заявки | `dashboard` | градиент |
485
+ | Админ | `admin` | фиолетовая |
486
+
487
+ Менять цвета: `headerStyles` в `Layout.jsx`.
488
+
489
+ Кнопки на странице: классы Tailwind `bg-teal-600`, `bg-cyan-600` и т.д. — можно заменить на одну палитру под банкеты (золотой/бордовый).
490
+
491
+ ---
492
+
493
+ ## 11. Чек-лист перед сдачей
494
+
495
+ - [ ] `npm run db:init` прошёл без ошибок
496
+ - [ ] `npm run dev` — сайт открывается
497
+ - [ ] Регистрация → вход → заявка → видна в списке
498
+ - [ ] Админ видит заявки и меняет статус
499
+ - [ ] Картинки в `public/images/` отображаются
500
+ - [ ] На ширине 390px в DevTools ничего не обрезано
501
+ - [ ] Все тексты соответствуют **вашей** теме задания
502
+ - [ ] 3+ коммита в git (по заданию модуля 2/3)
503
+
504
+ ---
505
+
506
+ ## 12. Частые ошибки
507
+
508
+ | Проблема | Решение |
509
+ |----------|---------|
510
+ | Картинка не видна | Файл в `public/images/`? Ключ в `images.js`? `imageKey` верный? |
511
+ | 404 на API | Запущен ли `npm run dev` из корня? Сервер на :3001? |
512
+ | После входа белый экран | F12 → Console; проверьте токен / роль user vs admin |
513
+ | Валидация не совпадает | Правьте **и** client, **и** server `validation.js` |
514
+ | Список услуг пустой | `npm run db:init`, проверьте `seed.sql` |
515
+
516
+ ---
517
+
518
+ ## 13. Порядок работы на экзамене (60–90 мин)
519
+
520
+ 1. Прочитать задание, открыть **`THEME_BANQUETAM_NET.md`** или свой конспект.
521
+ 2. `Layout.jsx` + `LandingLayout` — название.
522
+ 3. `init.js` + `seed.sql` → `npm run db:init`.
523
+ 4. `validation.js` (×2) — логин/пароль/дата.
524
+ 5. Все `pages/*.jsx` — тексты и ссылки.
525
+ 6. `STATUS_LABELS` + админ-кнопки.
526
+ 7. Картинки Figma → `public/images/` + `images.js`.
527
+ 8. По оставшемуся времени: фильтр админа, отзывы, 4-й слайд.
528
+
529
+ Удачи на демоэкзамене.