@mashka818/exam-de-template 1.0.0 → 1.0.2

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 (145) hide show
  1. package/exam-guides/EXAM_COMMANDS.txt +1 -1
  2. package/exam-guides/commented-code/client/index.html +7 -0
  3. package/exam-guides/commented-code/client/package-lock.json +541 -6
  4. package/exam-guides/commented-code/client/package.json +1 -0
  5. package/exam-guides/commented-code/client/public/images/README.txt +4 -24
  6. package/exam-guides/commented-code/client/public/images/about-cleaning.png +0 -0
  7. package/exam-guides/commented-code/client/public/images/admin-banner.png +0 -0
  8. package/exam-guides/commented-code/client/public/images/empty-requests.png +0 -0
  9. package/exam-guides/commented-code/client/public/images/footer-photo-1.png +0 -0
  10. package/exam-guides/commented-code/client/public/images/footer-photo-2.png +0 -0
  11. package/exam-guides/commented-code/client/public/images/footer-photo-3.png +0 -0
  12. package/exam-guides/commented-code/client/public/images/home-hero.png +0 -0
  13. package/exam-guides/commented-code/client/public/images/login-banner.png +0 -0
  14. package/exam-guides/commented-code/client/public/images/logo.png +0 -0
  15. package/exam-guides/commented-code/client/public/images/new-request-banner.png +0 -0
  16. package/exam-guides/commented-code/client/public/images/register-banner.png +0 -0
  17. package/exam-guides/commented-code/client/public/images/requests-banner.png +0 -0
  18. package/exam-guides/commented-code/client/public/images/slide-1.png +0 -0
  19. package/exam-guides/commented-code/client/public/images/slide-2.png +0 -0
  20. package/exam-guides/commented-code/client/public/images/slide-3.png +0 -0
  21. package/exam-guides/commented-code/client/src/App.jsx +14 -0
  22. package/exam-guides/commented-code/client/src/api.js +16 -2
  23. package/exam-guides/commented-code/client/src/components/FormField.jsx +7 -0
  24. package/exam-guides/commented-code/client/src/components/Layout.jsx +8 -0
  25. package/exam-guides/commented-code/client/src/components/PageImage.jsx +7 -0
  26. package/exam-guides/commented-code/client/src/components/ProtectedRoute.jsx +7 -0
  27. package/exam-guides/commented-code/client/src/components/UserNav.jsx +7 -0
  28. package/exam-guides/commented-code/client/src/components/landing/HeroSlider.jsx +7 -0
  29. package/exam-guides/commented-code/client/src/components/landing/LandingLayout.jsx +7 -0
  30. package/exam-guides/commented-code/client/src/components/landing/SiteFooter.jsx +7 -0
  31. package/exam-guides/commented-code/client/src/config/images.js +26 -28
  32. package/exam-guides/commented-code/client/src/constants/services.js +7 -0
  33. package/exam-guides/commented-code/client/src/context/AuthContext.jsx +8 -0
  34. package/exam-guides/commented-code/client/src/index.css +8 -0
  35. package/exam-guides/commented-code/client/src/main.jsx +8 -0
  36. package/exam-guides/commented-code/client/src/pages/AdminPage.jsx +59 -24
  37. package/exam-guides/commented-code/client/src/pages/LandingPage.jsx +7 -0
  38. package/exam-guides/commented-code/client/src/pages/LoginPage.jsx +8 -0
  39. package/exam-guides/commented-code/client/src/pages/RegisterPage.jsx +8 -0
  40. package/exam-guides/commented-code/client/src/pages/RequestFormPage.jsx +7 -0
  41. package/exam-guides/commented-code/client/src/pages/RequestsPage.jsx +7 -0
  42. package/exam-guides/commented-code/client/src/utils/validation.js +8 -0
  43. package/exam-guides/commented-code/client/vite.config.js +7 -0
  44. package/exam-guides/commented-code/server/.env.example +8 -0
  45. package/exam-guides/commented-code/server/db/init.js +7 -0
  46. package/exam-guides/commented-code/server/db/pool.js +7 -0
  47. package/exam-guides/commented-code/server/db/schema.sql +5 -0
  48. package/exam-guides/commented-code/server/db/seed.sql +5 -0
  49. package/exam-guides/commented-code/server/index.js +7 -0
  50. package/exam-guides/commented-code/server/middleware/auth.js +7 -0
  51. package/exam-guides/commented-code/server/routes/admin.js +23 -3
  52. package/exam-guides/commented-code/server/routes/auth.js +7 -0
  53. package/exam-guides/commented-code/server/routes/requests.js +7 -0
  54. package/exam-guides/commented-code/server/routes/services.js +7 -0
  55. package/exam-guides/commented-code/server/utils/validation.js +7 -0
  56. package/exam-project/EXAM_COMMANDS.txt +47 -0
  57. package/exam-project/README.md +4 -7
  58. package/exam-project/THEME_BANQUETAM_NET.md +106 -0
  59. package/exam-project/client/index.html +7 -0
  60. package/exam-project/client/package-lock.json +541 -6
  61. package/exam-project/client/package.json +1 -0
  62. package/exam-project/client/public/images/README.txt +4 -24
  63. package/exam-project/client/public/images/about-cleaning.png +0 -0
  64. package/exam-project/client/public/images/admin-banner.png +0 -0
  65. package/exam-project/client/public/images/empty-requests.png +0 -0
  66. package/exam-project/client/public/images/footer-photo-1.png +0 -0
  67. package/exam-project/client/public/images/footer-photo-2.png +0 -0
  68. package/exam-project/client/public/images/footer-photo-3.png +0 -0
  69. package/exam-project/client/public/images/home-hero.png +0 -0
  70. package/exam-project/client/public/images/login-banner.png +0 -0
  71. package/exam-project/client/public/images/logo.png +0 -0
  72. package/exam-project/client/public/images/new-request-banner.png +0 -0
  73. package/exam-project/client/public/images/register-banner.png +0 -0
  74. package/exam-project/client/public/images/requests-banner.png +0 -0
  75. package/exam-project/client/public/images/slide-1.png +0 -0
  76. package/exam-project/client/public/images/slide-2.png +0 -0
  77. package/exam-project/client/public/images/slide-3.png +0 -0
  78. package/exam-project/client/src/App.jsx +35 -1
  79. package/exam-project/client/src/api.js +37 -2
  80. package/exam-project/client/src/components/FormField.jsx +22 -1
  81. package/exam-project/client/src/components/Layout.jsx +34 -4
  82. package/exam-project/client/src/components/PageImage.jsx +24 -1
  83. package/exam-project/client/src/components/ProtectedRoute.jsx +23 -1
  84. package/exam-project/client/src/components/UserNav.jsx +20 -0
  85. package/exam-project/client/src/components/landing/HeroSlider.jsx +23 -2
  86. package/exam-project/client/src/components/landing/LandingLayout.jsx +23 -1
  87. package/exam-project/client/src/components/landing/SiteFooter.jsx +20 -0
  88. package/exam-project/client/src/config/images.js +45 -26
  89. package/exam-project/client/src/constants/services.js +20 -1
  90. package/exam-project/client/src/context/AuthContext.jsx +26 -1
  91. package/exam-project/client/src/index.css +28 -1
  92. package/exam-project/client/src/main.jsx +20 -1
  93. package/exam-project/client/src/pages/AdminPage.jsx +65 -7
  94. package/exam-project/client/src/pages/LandingPage.jsx +23 -0
  95. package/exam-project/client/src/pages/LoginPage.jsx +28 -2
  96. package/exam-project/client/src/pages/RegisterPage.jsx +29 -1
  97. package/exam-project/client/src/pages/RequestFormPage.jsx +28 -3
  98. package/exam-project/client/src/pages/RequestsPage.jsx +26 -1
  99. package/exam-project/client/src/utils/validation.js +26 -1
  100. package/exam-project/client/vite.config.js +22 -1
  101. package/exam-project/scripts/unpack-template.js +2 -1
  102. package/exam-project/server/.env.example +8 -0
  103. package/exam-project/server/db/init.js +27 -3
  104. package/exam-project/server/db/pool.js +20 -1
  105. package/exam-project/server/db/schema.sql +17 -0
  106. package/exam-project/server/db/seed.sql +8 -0
  107. package/exam-project/server/index.js +24 -1
  108. package/exam-project/server/middleware/auth.js +22 -1
  109. package/exam-project/server/routes/admin.js +44 -4
  110. package/exam-project/server/routes/auth.js +27 -1
  111. package/exam-project/server/routes/requests.js +27 -4
  112. package/exam-project/server/routes/services.js +21 -1
  113. package/exam-project/server/utils/validation.js +27 -2
  114. package/package.json +1 -1
  115. package/scripts/unpack-template.js +2 -1
  116. package/exam-guides/commented-code/client/public/images/about-cleaning.svg +0 -4
  117. package/exam-guides/commented-code/client/public/images/admin-banner.svg +0 -1
  118. package/exam-guides/commented-code/client/public/images/empty-requests.svg +0 -1
  119. package/exam-guides/commented-code/client/public/images/footer-photo-1.svg +0 -4
  120. package/exam-guides/commented-code/client/public/images/footer-photo-2.svg +0 -4
  121. package/exam-guides/commented-code/client/public/images/footer-photo-3.svg +0 -4
  122. package/exam-guides/commented-code/client/public/images/home-hero.svg +0 -4
  123. package/exam-guides/commented-code/client/public/images/login-banner.svg +0 -1
  124. package/exam-guides/commented-code/client/public/images/logo.svg +0 -4
  125. package/exam-guides/commented-code/client/public/images/new-request-banner.svg +0 -1
  126. package/exam-guides/commented-code/client/public/images/register-banner.svg +0 -1
  127. package/exam-guides/commented-code/client/public/images/requests-banner.svg +0 -1
  128. package/exam-guides/commented-code/client/public/images/slide-1.svg +0 -6
  129. package/exam-guides/commented-code/client/public/images/slide-2.svg +0 -5
  130. package/exam-guides/commented-code/client/public/images/slide-3.svg +0 -5
  131. package/exam-project/client/public/images/about-cleaning.svg +0 -4
  132. package/exam-project/client/public/images/admin-banner.svg +0 -1
  133. package/exam-project/client/public/images/empty-requests.svg +0 -1
  134. package/exam-project/client/public/images/footer-photo-1.svg +0 -4
  135. package/exam-project/client/public/images/footer-photo-2.svg +0 -4
  136. package/exam-project/client/public/images/footer-photo-3.svg +0 -4
  137. package/exam-project/client/public/images/home-hero.svg +0 -4
  138. package/exam-project/client/public/images/login-banner.svg +0 -1
  139. package/exam-project/client/public/images/logo.svg +0 -4
  140. package/exam-project/client/public/images/new-request-banner.svg +0 -1
  141. package/exam-project/client/public/images/register-banner.svg +0 -1
  142. package/exam-project/client/public/images/requests-banner.svg +0 -1
  143. package/exam-project/client/public/images/slide-1.svg +0 -6
  144. package/exam-project/client/public/images/slide-2.svg +0 -5
  145. package/exam-project/client/public/images/slide-3.svg +0 -5
@@ -1,4 +1,38 @@
1
-
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/App.jsx
4
+ * МАРШРУТЫ (react-router). Пункты ДЭ = пути ниже.
5
+ * / → pages/LandingPage.jsx
6
+ * /register → RegisterPage.jsx (п.1)
7
+ * /login → LoginPage.jsx (п.2)
8
+ * /requests → RequestsPage.jsx (п.3)
9
+ * /requests/form → RequestFormPage.jsx (п.4)
10
+ * /admin → AdminPage.jsx (п.5)
11
+ * Новая страница: import + <Route path="..." element={...} />
12
+ * =============================================================================
13
+ */
14
+
15
+ /**
16
+ * =============================================================================
17
+ * App.jsx — МАРШРУТЫ REACT (react-router-dom)
18
+ * =============================================================================
19
+ * Каждый пункт задания ДЭ = отдельный path + страница в pages/
20
+ *
21
+ * п.1 /register → RegisterPage.jsx
22
+ * п.2 /login → LoginPage.jsx
23
+ * п.3 /requests → RequestsPage.jsx (история + кнопка на форму)
24
+ * п.4 /requests/form → RequestFormPage.jsx (форма заявки)
25
+ * п.5 /admin → AdminPage.jsx (только role=admin)
26
+ * / LandingPage.jsx — лендинг для всех (гость и после входа по логотипу)
27
+ *
28
+ * ProtectedRoute role="user"|"admin" — без токена редирект на /login
29
+ * /requests/new → редирект на /requests/form (старый путь, можно не трогать)
30
+ * path="*" → на главную /
31
+ *
32
+ * НОВАЯ СТРАНИЦА: import + <Route path="/about" element={...} /> — см. GUIDE_PAGES.md §6
33
+ * БАНКЕТАМ.НЕТ: пути те же; тексты и логика — в pages/, не здесь
34
+ * =============================================================================
35
+ */
2
36
  import { Routes, Route, Navigate } from 'react-router-dom';
3
37
  import ProtectedRoute from './components/ProtectedRoute.jsx';
4
38
  import LandingPage from './pages/LandingPage.jsx';
@@ -1,4 +1,33 @@
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/api.js
4
+ * ВСЕ запросы к бэкенду. Прокси: client/vite.config.js → localhost:3001
5
+ * Добавить метод: 1) server/routes/... 2) строка в export const api 3) вызов на странице
6
+ * Ошибки формы: catch (e) → e.data.errors
7
+ * =============================================================================
8
+ */
1
9
 
10
+ /**
11
+ * =============================================================================
12
+ * HTTP-ЗАПРОСЫ К API (все вызовы бэкенда в одном файле)
13
+ * =============================================================================
14
+ * Пути /api/... проксируются Vite на localhost:3001 (vite.config.js).
15
+ * При смене темы endpoints чаще всего те же; меняют тела запросов в routes на сервере.
16
+ *
17
+ * TOKEN_KEY — ключ в localStorage; можно не менять.
18
+ * БАНКЕТАМ.НЕТ: добавить postReview(requestId, { text }) → POST /api/requests/:id/review
19
+ *
20
+ * КАК ДОБАВИТЬ НОВЫЙ ЗАПРОС:
21
+ * 1) Метод в server/routes/...
22
+ * 2) Строка в export const api = { ... }
23
+ * 3) Вызов на странице: await api.myMethod(...)
24
+ *
25
+ * Ошибки с сервера: catch (err) { err.data?.errors } — объект полей для формы
26
+ * err.data?.message — одна строка (логин неверный)
27
+ *
28
+ * GUIDE_PAGES.md §8 | THEME_BANQUETAM_NET.md
29
+ * =============================================================================
30
+ */
2
31
 
3
32
  const TOKEN_KEY = 'exam_token';
4
33
 
@@ -41,10 +70,16 @@ export const api = {
41
70
  // --- Заявки пользователя → server/routes/requests.js (п.3 mine, п.4 POST) ---
42
71
  getMyRequests: () => request('/requests/mine'),
43
72
  createRequest: (body) => request('/requests', { method: 'POST', body: JSON.stringify(body) }),
73
+ // БАНКЕТАМ.НЕТ: postReview: (id, body) => request(`/requests/${id}/review`, { method: 'POST', body: JSON.stringify(body) }),
44
74
 
45
75
  // --- Админ → server/routes/admin.js (п.5) ---
46
-
47
- adminGetRequests: () => request('/admin/requests'),
76
+ // params.status: 'all' | 'new' | 'in_progress' | 'completed' | 'cancelled'
77
+ adminGetRequests: (params = {}) => {
78
+ const q = new URLSearchParams();
79
+ if (params.status && params.status !== 'all') q.set('status', params.status);
80
+ const qs = q.toString();
81
+ return request(`/admin/requests${qs ? `?${qs}` : ''}`);
82
+ },
48
83
  adminUpdateStatus: (id, body) =>
49
84
  request(`/admin/requests/${id}/status`, { method: 'PATCH', body: JSON.stringify(body) }),
50
85
  };
@@ -1,4 +1,25 @@
1
-
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/components/FormField.jsx
4
+ * Обёртка label+input+ошибка. Менять label на страницах, не здесь.
5
+ * =============================================================================
6
+ */
7
+
8
+ /**
9
+ * =============================================================================
10
+ * FormField.jsx — ПОЛЕ ФОРМЫ (label + input + ошибка)
11
+ * =============================================================================
12
+ * САМ КОМПОНЕНТ не меняют. Меняют на страницах (RegisterPage, RequestFormPage):
13
+ * <FormField label="ФИО" error={errors.fullName}>
14
+ * <input ... />
15
+ * </FormField>
16
+ *
17
+ * error={errors.xxx} — текст с validateRegistration / validateRequestForm (validation.js).
18
+ * Добавить новое поле: label + children (input/select/textarea) + ключ в errors на странице.
19
+ *
20
+ * GUIDE_PAGES.md §2.4, §7.1
21
+ * =============================================================================
22
+ */
2
23
  export default function FormField({ label, error, children, className = '' }) {
3
24
  return (
4
25
  <label className={`block mb-4 ${className}`}>
@@ -1,12 +1,42 @@
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/components/Layout.jsx
4
+ * Шапка всех страниц кроме лендинга. Менять: brandName, brandTagline, headerStyles, logo в images.js
5
+ * variant со страницы: register | login | dashboard | admin
6
+ * =============================================================================
7
+ */
1
8
 
9
+ /**
10
+ * =============================================================================
11
+ * LAYOUT — общая обёртка всех страниц (шапка + контент)
12
+ * =============================================================================
13
+ * ЗАМЕНИТЕ при другой теме:
14
+ * brandName — название портала («Мой Не Сам» → «Автосервис», «Курсы»…)
15
+ * brandTagline — короткий слоган под логотипом
16
+ * headerStyles — цвета шапки по разделам (каждый раздел — своя «черта» по заданию)
17
+ * logo — картинка в config/images.js → file: 'logo.png'
18
+ *
19
+ * АДАПТИВ (мобильный / ПК):
20
+ * Сейчас: max-w-lg — узкая колонка (~390–512px), как макет 390×844.
21
+ * Для ПК добавьте lg:max-w-5xl lg:px-8 к header и main (см. RESPONSIVE.md).
22
+ * БАНКЕТАМ.НЕТ: brandName = 'Банкетам.Нет'; brandTagline = 'Бронирование банкетных залов'.
23
+ *
24
+ * variant со страницы: register | login | dashboard | admin | default
25
+ * → разный цвет шапки (отличительные черты по заданию)
26
+ * UserNav — только user + variant dashboard (п.3/п.4 в шапке)
27
+ * Link to="/" на логотипе — после входа возврат на лендинг
28
+ *
29
+ * GUIDE_PAGES.md §2 | RESPONSIVE.md (max-w-lg / lg:max-w-5xl)
30
+ * =============================================================================
31
+ */
2
32
  import { Link, useNavigate } from 'react-router-dom';
3
33
  import { useAuth } from '../context/AuthContext.jsx';
4
34
  import PageImage from './PageImage.jsx';
5
35
  import UserNav from './UserNav.jsx';
6
36
 
7
37
  // --- Тексты бренда (менять на экзамене в первую очередь) ---
8
- const brandName = 'Мой Не Сам';
9
- const brandTagline = 'Клининг без хлопот';
38
+ const brandName = 'Мой Не Сам'; // БАНКЕТАМ.НЕТ: 'Банкетам.Нет'
39
+ const brandTagline = 'Клининг без хлопот'; // БАНКЕТАМ.НЕТ: 'Бронирование банкетных залов'
10
40
 
11
41
  // --- Стили шапки: variant передаётся со страницы (register, login, dashboard, admin) ---
12
42
  const headerStyles = {
@@ -23,7 +53,7 @@ export default function Layout({ children, variant = 'default' }) {
23
53
 
24
54
  return (
25
55
  <div className="min-h-screen flex flex-col">
26
-
56
+ {/* === ШАПКА: логотип-картинка + название === */}
27
57
  <header className={`${headerStyles[variant]} shadow-sm animate-fade-up`}>
28
58
  <div className="mx-auto w-full max-w-lg lg:max-w-5xl px-4 lg:px-8 py-3 flex items-center justify-between gap-3">
29
59
  <Link to="/" className="flex items-center gap-2 min-w-0">
@@ -52,7 +82,7 @@ export default function Layout({ children, variant = 'default' }) {
52
82
  </div>
53
83
  </header>
54
84
 
55
-
85
+ {/* max-w-lg — мобильный макет; lg:max-w-5xl — шире на ПК (см. RESPONSIVE.md) */}
56
86
  <main className="flex-1 mx-auto w-full max-w-lg lg:max-w-5xl px-4 lg:px-8 py-6 lg:py-10">
57
87
  {children}
58
88
  </main>
@@ -1,4 +1,27 @@
1
-
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/components/PageImage.jsx
4
+ * Картинки: <PageImage imageKey="logo" />. Ключи в config/images.js
5
+ * =============================================================================
6
+ */
7
+
8
+ /**
9
+ * =============================================================================
10
+ * PageImage.jsx — КАРТИНКА НА СТРАНИЦЕ (единый способ)
11
+ * =============================================================================
12
+ * КАК МЕНЯТЬ КАРТИНКУ:
13
+ * 1) Файл в client/public/images/ (например banner.png)
14
+ * 2) Запись в client/src/config/images.js: myKey: { file: 'banner.png', alt: '...' }
15
+ * 3) На странице: <PageImage imageKey="myKey" className="w-full h-40 object-cover" />
16
+ *
17
+ * НЕ пишите <img src="/images/..."> напрямую в pages — иначе на экзамене запутаетесь.
18
+ *
19
+ * className — размер: h-9 (логотип), h-40 (баннер), rounded-full (аватар в футере).
20
+ * onError — скрывает битую картинку; при отладке временно закомментируйте.
21
+ *
22
+ * GUIDE_PAGES.md §3 | БАНКЕТАМ.НЕТ: slide-1…4, footer-photo-1…3
23
+ * =============================================================================
24
+ */
2
25
  import { imageAlt, imageUrl } from '../config/images.js';
3
26
 
4
27
  export default function PageImage({ imageKey, className = 'w-full h-auto rounded-xl object-cover' }) {
@@ -1,4 +1,26 @@
1
-
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/components/ProtectedRoute.jsx
4
+ * Защита маршрутов. role="user" | "admin". Без входа → /login
5
+ * =============================================================================
6
+ */
7
+
8
+ /**
9
+ * =============================================================================
10
+ * ЗАЩИТА МАРШРУТОВ — только для авторизованных
11
+ * =============================================================================
12
+ * role="user" — обычный заказчик (/requests)
13
+ * role="admin" — панель админа (/admin)
14
+ * При другой теме роли те же: user | admin (server/db/schema.sql users.role)
15
+ * БАНКЕТАМ.НЕТ: user → /requests (личный кабинет), admin → /admin
16
+ *
17
+ * loading — пока читается токен из localStorage и вызывается /api/auth/me
18
+ * !user — гость → /login
19
+ * user.role !== role — админ зашёл на /requests → редирект на /admin и наоборот
20
+ *
21
+ * Менять редко. Новый раздел «только для менеджера» — добавить role в БД + сюда.
22
+ * =============================================================================
23
+ */
2
24
  import { Navigate } from 'react-router-dom';
3
25
  import { useAuth } from '../context/AuthContext.jsx';
4
26
 
@@ -1,4 +1,24 @@
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/components/UserNav.jsx
4
+ * Вкладки в шапке заказчика: /requests и /requests/form. Менять подписи ссылок.
5
+ * =============================================================================
6
+ */
1
7
 
8
+ /**
9
+ * =============================================================================
10
+ * UserNav.jsx — ВКЛАДКИ В ШАПКЕ (только заказчик, variant="dashboard")
11
+ * =============================================================================
12
+ * Показывается в Layout.jsx когда user.role === 'user' и variant === 'dashboard'.
13
+ * NavLink подсвечивает активный раздел (isActive → bg-white/30).
14
+ *
15
+ * ЗАМЕНИТЕ: текст ссылок и title (подсказка при наведении).
16
+ * Пути /requests и /requests/form — по заданию ДЭ, обычно не меняют.
17
+ *
18
+ * БАНКЕТАМ.НЕТ: «Личный кабинет» → /requests; «Новое бронирование» → /requests/form
19
+ * GUIDE_PAGES.md §2.3
20
+ * =============================================================================
21
+ */
2
22
  import { NavLink } from 'react-router-dom';
3
23
 
4
24
  const linkClass = ({ isActive }) =>
@@ -1,8 +1,29 @@
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/components/landing/HeroSlider.jsx
4
+ * Слайдер лендинга. SLIDE_KEYS + slideText + PNG slide-1… в images.js. Интервал setInterval (Банкетам: 3000, 4 слайда).
5
+ * =============================================================================
6
+ */
1
7
 
8
+ /**
9
+ * =============================================================================
10
+ * HeroSlider.jsx — СЛАЙДЕР НА ЛЕНДИНГЕ (модуль 2 / М2)
11
+ * =============================================================================
12
+ * 1) SLIDE_KEYS — ключи из config/images.js (slide1, slide2…)
13
+ * 2) slideText — заголовок и подзаголовок на каждом слайде
14
+ * 3) public/images/slide-1.png … — файлы картинок (имена в images.js → file)
15
+ * 4) setInterval — автопрокрутка (БАНКЕТАМ.НЕТ: 3000 мс, 4 слайда)
16
+ *
17
+ * Кнопки ‹ › и точки внизу — переключение вручную (go, setIndex).
18
+ * БАНКЕТАМ.НЕТ: скопировать <HeroSlider /> в RequestsPage для п.3
19
+ *
20
+ * GUIDE_PAGES.md §3.2 | config/images.js (slide1…slide4)
21
+ * =============================================================================
22
+ */
2
23
  import { useEffect, useState } from 'react';
3
24
  import { imageAlt, imageUrl } from '../../config/images.js';
4
25
 
5
- const SLIDE_KEYS = ['slide1', 'slide2', 'slide3'];
26
+ const SLIDE_KEYS = ['slide1', 'slide2', 'slide3']; // БАНКЕТАМ.НЕТ: добавить 'slide4'
6
27
 
7
28
  const slideText = {
8
29
  slide1: { title: 'Общий клининг', subtitle: 'Поддерживаем порядок регулярно' },
@@ -16,7 +37,7 @@ export default function HeroSlider() {
16
37
  useEffect(() => {
17
38
  const timer = setInterval(() => {
18
39
  setIndex((i) => (i + 1) % SLIDE_KEYS.length);
19
- }, 5000);
40
+ }, 5000); // БАНКЕТАМ.НЕТ: 3000
20
41
  return () => clearInterval(timer);
21
42
  }, []);
22
43
 
@@ -1,9 +1,31 @@
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/components/landing/LandingLayout.jsx
4
+ * Шапка лендинга /. brandName, ссылки Вход/Регистрация.
5
+ * =============================================================================
6
+ */
1
7
 
8
+ /**
9
+ * =============================================================================
10
+ * LandingLayout.jsx — ШАПКА ЛЕНДИНГА (без Layout.jsx)
11
+ * =============================================================================
12
+ * Отдельная шапка для главной / — не путать с Layout на /register, /login…
13
+ * Клик по логотипу → всегда / (даже если пользователь вошёл).
14
+ *
15
+ * Гость: кнопки «Вход» / «Регистрация»
16
+ * user: ссылка в кабинет (/requests или /admin) + «Выйти»
17
+ *
18
+ * ЗАМЕНИТЕ: brandName, cabinetLabel («Мои заявки» → «Личный кабинет»)
19
+ * БАНКЕТАМ.НЕТ: brandName = 'Банкетам.Нет'
20
+ *
21
+ * GUIDE_PAGES.md §5 (лендинг)
22
+ * =============================================================================
23
+ */
2
24
  import { Link } from 'react-router-dom';
3
25
  import PageImage from '../PageImage.jsx';
4
26
  import { useAuth } from '../../context/AuthContext.jsx';
5
27
 
6
- const brandName = 'Мой Не Сам';
28
+ const brandName = 'Мой Не Сам'; // БАНКЕТАМ.НЕТ: 'Банкетам.Нет'
7
29
 
8
30
  export default function LandingLayout({ children }) {
9
31
  const { user, logout } = useAuth();
@@ -1,4 +1,24 @@
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/components/landing/SiteFooter.jsx
4
+ * Подвал лендинга. footerPhoto1-3 в images.js. Тексты компании.
5
+ * =============================================================================
6
+ */
1
7
 
8
+ /**
9
+ * =============================================================================
10
+ * SiteFooter.jsx — ПОДВАЛ ЛЕНДИНГА
11
+ * =============================================================================
12
+ * Три круглых фото: imageKey footerPhoto1, footerPhoto2, footerPhoto3
13
+ * → PNG в client/public/images/ → записи в config/images.js
14
+ *
15
+ * footerLinks — якоря (сейчас все на /; можно сделать id секций на LandingPage)
16
+ * ЗАМЕНИТЕ: название компании, описание, copyright год
17
+ *
18
+ * БАНКЕТАМ.НЕТ: «Банкетам.Нет», текст про банкетные залы
19
+ * GUIDE_PAGES.md §5.3
20
+ * =============================================================================
21
+ */
2
22
  import { Link } from 'react-router-dom';
3
23
  import PageImage from '../PageImage.jsx';
4
24
 
@@ -1,4 +1,33 @@
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/config/images.js
4
+ * КАРТИНКИ: только менять file и alt. Файлы PNG лежат в client/public/images/
5
+ * На экзамене: экспорт Figma → тот же файл (logo.png, slide-1.png…). Пути в коде не пишем — PageImage imageKey
6
+ * =============================================================================
7
+ */
1
8
 
9
+ /**
10
+ * =============================================================================
11
+ * КОНФИГУРАЦИЯ ИЗОБРАЖЕНИЙ
12
+ * =============================================================================
13
+ * Все картинки лежат в: client/public/images/
14
+ * В коде подключаются через URL: /images/имя-файла
15
+ *
16
+ * НА ЭКЗАМЕНЕ:
17
+ * 1) Экспорт из Figma → PNG в public/images/ (только PNG, не SVG)
18
+ * 2) Имя файла как ниже (logo.png, slide-1.png…) — замените файл, config не трогайте
19
+ * 3) alt — для доступности; замените текст под новую тему
20
+ * БАНКЕТАМ.НЕТ: slide4; alt про банкеты/залы; logo «Банкетам.Нет»
21
+ *
22
+ * Ключ (logo, slide1…) — НЕ переименовывайте без правки PageImage imageKey на страницах
23
+ * file — имя файла в public/images/
24
+ * imageUrl('logo') / imageAlt('logo') — если нужен прямой доступ без PageImage
25
+ *
26
+ * Слайды: slide-1.png … slide-4.png | Футер: footer-photo-1.png …
27
+ *
28
+ * GUIDE_PAGES.md §3 | PageImage.jsx
29
+ * =============================================================================
30
+ */
2
31
 
3
32
  /** Базовый путь. Менять не нужно, если папка называется images */
4
33
  export const IMAGES_BASE = '/images';
@@ -10,64 +39,54 @@ export const IMAGES_BASE = '/images';
10
39
  export const IMAGES = {
11
40
  // Шапка на всех страницах → логотип компании / портала
12
41
  logo: {
13
- file: 'logo.svg',
14
- alt: 'Логотип «Мой Не Сам»', // → название вашей организации
42
+ file: 'logo.png',
43
+ alt: 'Логотип «Мой Не Сам»',
15
44
  },
16
45
 
17
- // Главная (/) — иллюстрация услуги
18
46
  homeHero: {
19
- file: 'home-hero.svg',
47
+ file: 'home-hero.png',
20
48
  alt: 'Клининговые услуги на дому',
21
49
  },
22
50
 
23
- // Регистрация (/register)
24
51
  registerBanner: {
25
- file: 'register-banner.svg',
52
+ file: 'register-banner.png',
26
53
  alt: 'Регистрация нового заказчика',
27
54
  },
28
55
 
29
- // Вход (/login)
30
56
  loginBanner: {
31
- file: 'login-banner.svg',
57
+ file: 'login-banner.png',
32
58
  alt: 'Вход в личный кабинет',
33
59
  },
34
60
 
35
- // Список заявок (/requests)
36
61
  requestsBanner: {
37
- file: 'requests-banner.svg',
62
+ file: 'requests-banner.png',
38
63
  alt: 'История заявок на уборку',
39
64
  },
40
65
 
41
- // Новая заявка (/requests/new)
42
66
  newRequestBanner: {
43
- file: 'new-request-banner.svg',
67
+ file: 'new-request-banner.png',
44
68
  alt: 'Оформление заявки на услугу',
45
69
  },
46
70
 
47
- // Админ-панель (/admin)
48
71
  adminBanner: {
49
- file: 'admin-banner.svg',
72
+ file: 'admin-banner.png',
50
73
  alt: 'Панель администратора',
51
74
  },
52
75
 
53
- // Пустой список заявок
54
76
  emptyRequests: {
55
- file: 'empty-requests.svg',
77
+ file: 'empty-requests.png',
56
78
  alt: 'Заявок пока нет',
57
79
  },
58
80
 
59
- // --- Лендинг: слайдер (HeroSlider.jsx) ---
60
- slide1: { file: 'slide-1.svg', alt: 'Общий клининг' },
61
- slide2: { file: 'slide-2.svg', alt: 'Генеральная уборка' },
62
- slide3: { file: 'slide-3.svg', alt: 'Химчистка ковров и мебели' },
81
+ slide1: { file: 'slide-1.png', alt: 'Общий клининг' },
82
+ slide2: { file: 'slide-2.png', alt: 'Генеральная уборка' },
83
+ slide3: { file: 'slide-3.png', alt: 'Химчистка ковров и мебели' },
63
84
 
64
- // Лендинг: блок «О клининге»
65
- aboutCleaning: { file: 'about-cleaning.svg', alt: 'Профессиональный клининг' },
85
+ aboutCleaning: { file: 'about-cleaning.png', alt: 'Профессиональный клининг' },
66
86
 
67
- // Лендинг: футер 3 фото (команда / офис / работы)
68
- footerPhoto1: { file: 'footer-photo-1.svg', alt: 'Сотрудник 1' },
69
- footerPhoto2: { file: 'footer-photo-2.svg', alt: 'Сотрудник 2' },
70
- footerPhoto3: { file: 'footer-photo-3.svg', alt: 'Сотрудник 3' },
87
+ footerPhoto1: { file: 'footer-photo-1.png', alt: 'Сотрудник 1' },
88
+ footerPhoto2: { file: 'footer-photo-2.png', alt: 'Сотрудник 2' },
89
+ footerPhoto3: { file: 'footer-photo-3.png', alt: 'Сотрудник 3' },
71
90
  };
72
91
 
73
92
  /** Собрать полный URL для тега <img src="..."> */
@@ -1,6 +1,25 @@
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/constants/services.js
4
+ * Подписи услуг на лендинге. Синхронизировать с server/db/seed.sql
5
+ * =============================================================================
6
+ */
1
7
 
8
+ /**
9
+ * =============================================================================
10
+ * constants/services.js — НАЗВАНИЯ УСЛУГ НА ЛЕНДИНГЕ (только отображение)
11
+ * =============================================================================
12
+ * Реальный список для формы п.4 берётся из API GET /api/services (seed.sql).
13
+ * Этот массив — для блока «Наши услуги» на LandingPage.jsx.
14
+ *
15
+ * При смене темы: обновите И seed.sql И этот файл одинаковым списком.
16
+ * БАНКЕТАМ.НЕТ: четыре помещения (зал, ресторан, веранды)
17
+ *
18
+ * GUIDE_PAGES.md §5.2 | server/db/seed.sql
19
+ * =============================================================================
20
+ */
2
21
  export const DEFAULT_SERVICE_NAMES = [
3
- 'Общий клининг',
22
+ 'Общий клининг', // БАНКЕТАМ.НЕТ: заменить весь массив на 4 помещения
4
23
  'Генеральная уборка',
5
24
  'Послестроительная уборка',
6
25
  'Химчистка ковров и мебели',
@@ -1,4 +1,29 @@
1
-
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/context/AuthContext.jsx
4
+ * login / register / logout / user. JWT в localStorage (api.js TOKEN_KEY).
5
+ * После входа: user.role → 'user' | 'admin'
6
+ * =============================================================================
7
+ */
8
+
9
+ /**
10
+ * =============================================================================
11
+ * КОНТЕКСТ АВТОРИЗАЦИИ — user, login, register, logout
12
+ * =============================================================================
13
+ * Хранит JWT в localStorage (api.js setToken).
14
+ * При смене темы логика не меняется; поля user приходят с сервера (fullName, role…).
15
+ *
16
+ * КАК РАБОТАЕТ:
17
+ * login/register → api.js → setToken в localStorage → setUser
18
+ * logout → очистка токена → редирект на /login (на странице)
19
+ * user.role: 'user' | 'admin' — после входа Admin26 попадёт в /admin (см. LoginPage navigate)
20
+ *
21
+ * useAuth() на страницах: const { user, login, register, logout } = useAuth();
22
+ * БАНКЕТАМ.НЕТ: без изменений, если структура users та же.
23
+ *
24
+ * GUIDE_PAGES.md §7 | api.js
25
+ * =============================================================================
26
+ */
2
27
  import { createContext, useContext, useEffect, useState } from 'react';
3
28
  import { api, getToken, setToken } from '../api.js';
4
29
 
@@ -1,6 +1,33 @@
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/index.css
4
+ * Цвета бренда: @theme --color-brand. Анимации: animate-fade-up, animate-slide-in.
5
+ * Ошибки полей: .field-error, .input-error на input
6
+ * =============================================================================
7
+ */
8
+
1
9
  @import 'tailwindcss';
2
10
 
3
-
11
+ /**
12
+ * =============================================================================
13
+ * ГЛОБАЛЬНЫЕ СТИЛИ
14
+ * =============================================================================
15
+ * @theme — цвета бренда (ЗАМЕНИТЕ --color-brand под новую тему)
16
+ * .animate-* — анимации для модуля №3
17
+ * .field-error / .input-error — ошибки валидации на формах
18
+ *
19
+ * АДАПТИВ: ширина колонки задаётся в Layout.jsx (max-w-lg + lg:max-w-5xl).
20
+ * Подробная инструкция — файл RESPONSIVE.md в корне проекта.
21
+ * БАНКЕТАМ.НЕТ (М3): микроанимации уже есть; цвета @theme можно сменить на «банкетную» палитру.
22
+ *
23
+ * КАК ПОДКЛЮЧИТЬ К СТРАНИЦЕ:
24
+ * animate-fade-up на блоках (Layout header, карточки)
25
+ * .field-error на <p> под полем; .input-error на <input> при ошибке
26
+ * className="input-error" — см. RegisterPage inputClass + errors
27
+ *
28
+ * GUIDE_PAGES.md §3.3 | COMMENTS_GUIDE.md
29
+ * =============================================================================
30
+ */
4
31
 
5
32
  @theme {
6
33
  --color-brand: #0d9488;
@@ -1,4 +1,23 @@
1
-
1
+ /**
2
+ * =============================================================================
3
+ * ФАЙЛ: client/src/main.jsx
4
+ * ТОЧКА ВХОДА React. Обычно НЕ МЕНЯЮТ.
5
+ * Цепочка: index.html #root → main.jsx → AuthProvider → App.jsx
6
+ * =============================================================================
7
+ */
8
+
9
+ /**
10
+ * =============================================================================
11
+ * main.jsx — ТОЧКА ВХОДА REACT (запуск приложения в браузере)
12
+ * =============================================================================
13
+ * Обычно НЕ МЕНЯЮТ при смене темы.
14
+ *
15
+ * Цепочка: index.html (#root) → main.jsx → AuthProvider → App.jsx (маршруты).
16
+ *
17
+ * Если добавили глобальный контекст (тема, язык) — оберните <App /> ещё одним Provider.
18
+ * Подробнее: GUIDE_PAGES.md §6 (новая страница — маршрут всё равно в App.jsx).
19
+ * =============================================================================
20
+ */
2
21
  import { StrictMode } from 'react';
3
22
  import { createRoot } from 'react-dom/client';
4
23
  import { BrowserRouter } from 'react-router-dom';