Reservation Management System

Aplikacja SPA do zarządzania rezerwacjami zbudowana w React 19 + Vite 8. Umożliwia klientom przeglądanie dostępnych terminów, dokonywanie rezerwacji z płatnością depozytu, zarządzanie historią rezerwacji oraz wystawianie opinii. Administratorzy mają dostęp do panelu zarządzania, kalendarza rezerwacji, analityki i eksportu danych.


Uruchomienie

# Terminal 1  REST API (json-server na porcie 3001)
npm run api

# Terminal 2  Vite dev server (port 5173)
npm run dev

# Testy jednostkowe (Vitest + RTL)
npm test

# Testy e2e (Playwright)
node test_rms.mjs

# Storybook (port 6006)
npm run storybook

Uwaga: przed uruchomieniem test_rms.mjs oba serwery muszą być aktywne. Test automatycznie przywraca dane seed (r1, r2) do stanu pending przed każdym przebiegiem.


Dane testowe

Rola E-mail Hasło
Admin admin@reservations.dev Admin1234!
Klient anna.kowalski@example.com Client1234!

Logowanie zawsze uruchamia weryfikację 2FA kod jest wyświetlany bezpośrednio w interfejsie (symulowany e-mail).


Stos technologiczny

Warstwa Technologia
UI React 19, Vite 8, SCSS Modules
Routing React Router v7
Zapytania REST TanStack React Query v5 + Axios
Zapytania GraphQL Apollo Client v4 + SchemaLink (in-memory)
Formularze Formik + Zod (zod-formik-adapter)
Ikony Lucide React
REST mock json-server (db.json)
Testy jednostkowe Vitest + React Testing Library
Testy e2e Playwright
Dokumentacja Storybook 8

Struktura projektu

web_projekt/
├── db.json                     # Baza danych json-server (users, services, reservations)
├── test_rms.mjs                # Testy e2e Playwright (32 testy)
├── src/
│   ├── main.jsx                # Punkt wejścia: Apollo Client, QueryClient, renderowanie
│   ├── App.jsx                 # Router, lazy loading, ErrorBoundary, Suspense, ProtectedRoute
│   ├── index.css               # Reset + CSS custom properties (tryb ciemny/jasny)
│   ├── styles/
│   │   ├── _variables.scss     # Tokeny projektu: kolory, spacing, typografia, cienie, media queries
│   │   └── main.scss           # Globalne style bazowe
│   ├── api/
│   │   ├── reservations.js     # CRUD rezerwacji przez Axios (json-server :3001)
│   │   ├── services.js         # Pobieranie listy usług
│   │   └── users.js            # Pobieranie i aktualizacja użytkowników
│   ├── context/
│   │   ├── AuthContext.jsx     # Stan uwierzytelnienia, 2FA, role, sesja w localStorage
│   │   └── ThemeContext.jsx    # Przełącznik jasny/ciemny motyw (data-theme na <html>)
│   ├── hocs/
│   │   └── withRole.jsx        # HOC: renderuje komponent tylko dla dozwolonych ról
│   ├── hooks/
│   │   ├── useCreateReservation.js  # useMutation: POST /reservations
│   │   ├── useDeleteReservation.js  # useMutation: DELETE /reservations/:id
│   │   ├── useReservations.js       # useQuery: GET /reservations (wszystkie)
│   │   ├── useServices.js           # useQuery: GET /services
│   │   ├── useSlotReservations.js   # useQuery: GET /reservations?serviceId&date
│   │   ├── useUpdateReservation.js  # useMutation: PATCH /reservations/:id
│   │   └── useUserReservations.js   # useQuery: GET /reservations?userId
│   ├── pages/
│   │   ├── LoginPage.jsx       # Formularz logowania (Formik+Zod) + ekran 2FA z podglądem kodu
│   │   ├── LoginPage.module.scss
│   │   ├── RegisterPage.jsx    # Rejestracja z walidacją Zod i weryfikacją e-mail
│   │   ├── RegisterPage.module.scss
│   │   ├── DashboardPage.jsx   # Panel klienta: AvailabilitySearch, SlotFinder, BookingWizard, MyReservations, ProfileEditModal
│   │   ├── DashboardPage.module.scss
│   │   ├── ReservationsPage.jsx # Historia rezerwacji z filtrami, anulowaniem, RescheduleModal, ReviewsSection, Google Calendar, re-book
│   │   ├── ReservationsPage.module.scss
│   │   ├── AdminPage.jsx       # Panel admina: tabela rezerwacji, UserManagement, AnalyticsDashboard, AdminCalendar, blokowanie terminów (useTransition)
│   │   └── AdminPage.module.scss
│   ├── components/
│   │   ├── AvailabilitySearch.jsx        # Wyszukiwanie wolnych slotów z synchronizacją URL (useSearchParams)
│   │   ├── AvailabilitySearch.module.scss
│   │   ├── BookingWizard.jsx             # 4-krokowy kreator rezerwacji (Usługa → Data → Wymagania → Podsumowanie)
│   │   ├── BookingWizard.module.scss
│   │   ├── BookingForm.jsx               # Uproszczony formularz rezerwacji (react-hook-form)
│   │   ├── BookingForm.module.scss
│   │   ├── SlotFinder.jsx                # Inteligentny finder slotów z punktacją (scoreSlot, findSlots)
│   │   ├── SlotFinder.module.scss
│   │   ├── PaymentModal.jsx              # Modal płatności: Karta / Google Pay / Przelew bankowy (Portal)
│   │   ├── PaymentModal.module.scss
│   │   ├── RescheduleModal.jsx           # Modal zmiany terminu rezerwacji (Portal)
│   │   ├── RescheduleModal.module.scss
│   │   ├── ProfileEditModal.jsx          # Modal edycji profilu i preferencji powiadomień (Portal, Formik+Zod)
│   │   ├── ProfileEditModal.module.scss
│   │   ├── ReviewsSection.jsx            # Sekcja opinii (GraphQL: useQuery + useMutation przez Apollo)
│   │   ├── ReviewsSection.module.scss
│   │   ├── ProfileView.jsx               # Widok profilu (GraphQL: userProfile query)
│   │   ├── ProfileView.module.scss
│   │   ├── MyReservations.jsx            # Sidebar z aktywnymi rezerwacjami użytkownika
│   │   ├── MyReservations.module.scss
│   │   ├── AdminCalendar.jsx             # Widok kalendarza dla admina (miesiąc, kliknięcie dnia, panel boczny)
│   │   ├── AdminCalendar.module.scss
│   │   ├── AnalyticsDashboard.jsx        # Statystyki rezerwacji z eksportem CSV (DataRenderer, useMemo)
│   │   ├── AnalyticsDashboard.module.scss
│   │   ├── UserManagement.jsx            # Zarządzanie użytkownikami przez admina (tabela, dezaktywacja, reset hasła)
│   │   ├── UserManagement.module.scss
│   │   ├── Modal.jsx                     # Bazowy komponent modala (Portal, useCallback, Escape key, aria)
│   │   ├── Modal.module.scss
│   │   ├── StatusBadge.jsx               # Odznaka statusu rezerwacji (warianty kolorów, rozmiary, aria-label)
│   │   ├── StatusBadge.module.scss
│   │   ├── StatusBadge.test.jsx          # Testy RTL dla StatusBadge
│   │   ├── ThemeToggle.jsx               # Przycisk przełączania motywu (jasny/ciemny)
│   │   ├── ThemeToggle.module.scss
│   │   ├── DataRenderer.jsx              # Render-prop: opakowuje useQuery, przekazuje dane przez children()
│   │   ├── ErrorBoundary.jsx             # Class component: łapie błędy runtime, wyświetla fallback UI
│   │   ├── ErrorBoundary.module.scss
│   │   ├── LoadingSpinner.jsx            # Animowany spinner ładowania
│   │   ├── LoadingSpinner.module.scss
│   │   └── ProtectedRoute.jsx            # Guard routingu: sprawdza rolę i przekierowuje
│   ├── stories/
│   │   ├── StatusBadge.stories.jsx       # Storybook: wszystkie warianty odznaki statusu
│   │   ├── Modal.stories.jsx             # Storybook: modal informacyjny i destrukcyjny
│   │   └── ThemeToggle.stories.jsx       # Storybook: przełącznik motywu
│   └── tests/
│       ├── LoginPage.test.jsx            # RTL: formularz logowania, błędy walidacji
│       ├── BookingForm.test.jsx          # RTL: formularz rezerwacji, react-hook-form
│       ├── ProtectedRoute.test.jsx       # RTL: ochrona tras, przekierowania
│       └── StatusBadge.test.jsx          # RTL: warianty statusu
└── public/
    └── index.html                        # Zawiera <div id="root"> i <div id="portal-root">

Architektura danych

REST (json-server :3001)

  • GET/POST /reservations rezerwacje
  • GET /services usługi
  • GET/PATCH /users użytkownicy
  • Filtrowanie przez query params: ?userId=, ?serviceId=, ?date=

GraphQL (Apollo Client in-memory, bez zewnętrznego serwera)

Schema i resolvery zdefiniowane w main.jsx, wykonywane lokalnie przez SchemaLink:

type Query {
  userProfile(id: ID!): UserProfile
  serviceReviews(serviceId: String!): [Review!]!
  userReviews(userId: String!): [Review!]!
}
type Mutation {
  submitReview(reservationId: String!, serviceId: String!, ...): Review!
}

Lista wymagań i ich realizacja

Wymagania funkcjonalne (11)

# Kryterium Realizacja Status
F1 System uwierzytelniania i autoryzacji AuthContext.jsx logowanie e-mail + 2FA (kod wyświetlany w UI); role client/admin; sesja w localStorage; rejestracja z weryfikacją e-mail (RegisterPage.jsx); ProtectedRoute blokuje dostęp wg roli [OK]
F2 Zarządzanie profilami użytkowników ProfileEditModal.jsx edycja danych (Formik+Zod, PATCH /users), 5 preferencji powiadomień (toggle switches: potwierdzenie, anulowanie, przypomnienie 24h, zmiana terminu, promocje); ProfileView.jsx dane z GraphQL; historia w ReservationsPage.jsx [OK]
F3 Wyszukiwanie i przeglądanie dostępności AvailabilitySearch.jsx filtracja po dacie i usłudze, siatka slotów, URL sync (useSearchParams); SlotFinder.jsx ranking slotów w zakresie dat z preferencjami (rano/południe/wieczór), pasek score [OK]
F4 Proces rezerwacji BookingWizard.jsx 4 kroki: wybór usługi, data+czas (blokada zajętych slotów), wymagania specjalne, podsumowanie z ceną; PaymentModal.jsx 3 metody płatności, potwierdzenie z paragonem [OK]
F5 System płatności online PaymentModal.jsx karta kredytowa (Formik, walidacja), Google Pay (symulacja), przelew bankowy (IBAN/BIC, numer referencyjny); depozyt 50% ceny; transactionId zapisywany w rezerwacji [OK]
F6 Zarządzanie rezerwacjami przez użytkowników ReservationsPage.jsx filtry (wszystkie/nadchodzące/minione/anulowane), anulowanie z potwierdzeniem, RescheduleModal.jsx (zmiana terminu), "Book again" (re-book), Google Calendar link [OK]
F7 Panel zarządzania rezerwacjami (admin) AdminPage.jsx tabela rezerwacji (Confirm/Cancel/Delete), AdminCalendar.jsx (miesiąc, panel dnia), blokowanie i zwalnianie terminów z datepickerem i listą [OK]
F8 Zarządzanie użytkownikami (admin) UserManagement.jsx tabela użytkowników, dezaktywacja konta (toggle), symulacja resetu hasła; dostęp chroniony przez HOC withRole(['admin']) [OK]
F9 Analityka i raportowanie AnalyticsDashboard.jsx statystyki (łączna liczba, potwierdzone, anulowane, przychód z depozytów, średnia ocena); wykresy słupkowe CSS; eksport CSV z nagłówkami [OK]
F10 Integracja z zewnętrznymi systemami Google Calendar: link eventedit generowany dynamicznie z datą/godziną/tytułem dla każdej nadchodzącej rezerwacji; pełne REST API dostępne dla zewnętrznych integracji [OK]
F11 System opinii i ocen ReviewsSection.jsx ocena gwiazdkowa (15) + komentarz, zapis przez GraphQL mutation submitReview; pobieranie przez serviceReviews query; widoczne po rozwinięciu minionej rezerwacji [OK]

Wymagania wizualne BIU ZAO (6)

# Kryterium Realizacja Status
V1 Spójny i nowoczesny interfejs Jeden design system: tokeny w _variables.scss (paleta primary/accent/gray, spacing 4px scale, typografia, cienie), spójne BEM, Lucide icons, karty z border-radius, modale z overlay [OK]
V2 Pełna responsywność 12 breakpointów w SCSS ($bp-xs 480px$bp-2xl 1536px); grid w DashboardPage stackuje kolumny, tabela admina scrolluje poziomo, wizard adaptuje układ pól [OK]
V3 Animacje i efekty przejścia CSS transition na przyciskach/kartach/modalach; @keyframes pulse na wyróżnionej karcie rezerwacji; spinner ładowania CSS; hover lift (box-shadow + transform) [OK]
V4 Wizualny feedback dla interakcji StatusBadge kolorystycznie odróżnia statusy; :disabled/:hover/:focus-visible na wszystkich elementach interaktywnych; błędy inline w formularzach; spinner na przyciskach pending [OK]
V5 Estetyczne wykorzystanie SCSS SCSS Modules z BEM, @use '../styles/variables' as *, zagnieżdżone reguły &__, &--, CSS custom properties dla motywu (--clr-bg, --clr-text etc.), media queries przez zmienne [OK]
V6 Wykorzystanie wbudowanych komponentów Natywne <input type="date">, <input type="time">, <select>, <textarea>, <dialog role="dialog">; <dl>/<dt>/<dd> dla danych rezerwacji; semantyczny HTML5 (<header>, <main>, <aside>) [OK]

Wymagania techniczne BIU ZAO (10)

# Kryterium Realizacja Status
T1 Podstawowe hooki React useState stan formularzy, UI, modali; useEffect inicjalizacja auth z localStorage, scroll do karty przez useRef; useContext useAuth(), useTheme() w całej aplikacji [OK]
T2 Custom hooki 7 hooków w src/hooks/: useServices, useUserReservations, useSlotReservations, useReservations, useCreateReservation, useUpdateReservation, useDeleteReservation [OK]
T3 React Router React Router v7: BrowserRouter, Routes, Route, Navigate, Outlet, Link, useNavigate, useLocation, useSearchParams; chronione trasy przez ProtectedRoute z allowedRoles [OK]
T4 Zarządzanie stanem (Context API) AuthContext użytkownik, 2FA (pendingUser/twoFACode/verify2FA), role, sesja; ThemeContext motyw jasny/ciemny z localStorage i data-theme na <html> [OK]
T5 Obsługa zapytań API Axios w src/api/ dla REST (json-server); Apollo Client SchemaLink dla GraphQL (in-memory schema z resolverami w main.jsx) [OK]
T6 Techniki optymalizacyjne React.lazy + Suspense (DashboardPage, AdminPage); useMemo (statystyki w AnalyticsDashboard, maxScore w SlotFinder); useCallback (auth functions, Escape handler w Modal) [OK]
T7 Wzorce kompozycji komponentów HOC withRole(['admin'])(Component) z displayName; Render props DataRenderer delegacja renderowania przez children jako funkcję; oba używane w komponentach produkcyjnych [OK]
T8 Obsługa formularzy i walidacja Formik + Zod (toFormikValidationSchema): LoginPage, RegisterPage, ProfileEditModal; react-hook-form + zodResolver: BookingForm; walidacja krokowa w BookingWizard [OK]
T9 Konsekwentny styl kodu SCSS BEM, camelCase hooks/functions, PascalCase komponenty, styles['block__element--modifier'] we wszystkich SCSS Modules, ESLint, jednolite formatowanie [OK]
T10 Nowoczesny JavaScript Destrukturyzacja: const { user, logout } = useAuth(), const { password: _omit, ...safeUser } = match; spread: { ...prev, [key]: value }; optional chaining ?.; nullish ??; template literals [OK]

Wymagania dodatkowe BIU ZAO (11)

# Kryterium Realizacja Status
D1 React Suspense i Error Boundaries ErrorBoundary.jsx (class component z componentDidCatch, fallback UI + przycisk reload); <Suspense fallback={<LoadingSpinner/>}> w App.jsx opakowuje lazy-loaded strony [OK]
D2 Zaawansowana obsługa formularzy Formik + toFormikValidationSchema(zodSchema): LoginPage, RegisterPage, ProfileEditModal; react-hook-form + zodResolver: BookingForm; oba podejścia w jednym projekcie [OK]
D3 GraphQL z Apollo Client Apollo Client v4 + makeExecutableSchema + SchemaLink; in-memory resolvery dla userProfile, serviceReviews, userReviews, submitReview (store w pamięci); useQuery/useMutation z @apollo/client/react [OK]
D4 React Portals 4 komponenty mountowane do #portal-root przez createPortal(): Modal.jsx, PaymentModal.jsx, ProfileEditModal.jsx, RescheduleModal.jsx [OK]
D5 React.lazy i dynamic imports lazy(() => import('./pages/DashboardPage')) i lazy(() => import('./pages/AdminPage')) w App.jsx; ładowanie on-demand przy pierwszym wejściu na trasę [OK]
D6 Render props i HOC DataRenderer.jsx render prop (children jako funkcja), używany w AnalyticsDashboard; withRole.jsx HOC z displayName, używany w AdminPage; oba wzorce produkcyjne [OK]
D7 React Query TanStack React Query v5: 7 custom hooków, staleTime 5 min, invalidateQueries po mutacjach (lista rezerwacji odświeżana po każdej zmianie), isPending dla UX [OK]
D8 React DevTools WithRole.displayName dla czytelności drzewa; QueryClient kompatybilny z React Query Devtools; Apollo InMemoryCache widoczna w Apollo DevTools [OK]
D9 Testy z React Testing Library 5 plików testowych, 25+ testów (Vitest): LoginPage (formularz, błędy, submit), BookingForm (walidacja RHF), ProtectedRoute (przekierowania, role), StatusBadge (warianty x2) [OK]
D10 Storybook 3 pliki stories w src/stories/: StatusBadge (wszystkie statusy + rozmiary), Modal (Default + Danger z useState wrapper), ThemeToggle (z etykietą); Storybook 8 + @storybook/react-vite [OK]
D11 React Concurrent Mode useTransition w AdminPage.jsx: przełączanie zakładek (Tabela/Kalendarz/Analityka/Użytkownicy) przez startTransition(() => setMainTab(key)) nie blokuje UI przy ciężkich re-renderach [OK]

Wyniki testów

Vitest — testy jednostkowe

 src/tests/StatusBadge.test.jsx      6 tests
 src/tests/ProtectedRoute.test.jsx   4 tests
 src/components/StatusBadge.test.jsx 6 tests
 src/tests/BookingForm.test.jsx      5 tests
 src/tests/LoginPage.test.jsx        4 tests

 Test Files  5 passed (5)
 Tests      25 passed (25)
 Duration    1.22s

Playwright — testy e2e

  PASS  Login page loads (email field visible)
  PASS  Wrong credentials → error message
  PASS  Admin login → /admin
  PASS  Admin table — 56 rows
  PASS  Confirm button visible
  PASS  Confirm click updates row to Confirmed
  PASS  Delete confirmation modal opens
  PASS  Calendar tab button visible
  PASS  Calendar view renders month — June 2026
  PASS  Calendar weekday headers render
  WARN  No busy day cells visible in current month view
  PASS  Calendar next-month navigation — July 2026
  PASS  Admin logout → /login
  PASS  Client login → /dashboard
  PASS  AvailabilitySearch section renders
  PASS  Date syncs to URL
  PASS  Service syncs to URL
  PASS  Time slot grid renders (09:00 visible)
  PASS  Slot click (09:00) jumps wizard to step 3
  PASS  Wizard renders at step 1 after reload
  PASS  Service cards render
  PASS  Wizard step 2 (Date & Time)
  PASS  Wizard step 3 (Requirements)
  PASS  Wizard step 4 (Summary)
  PASS  Confirm & Pay button in step 4
  PASS  Payment modal opens
  PASS  Deposit amount displayed — $25.00
  PASS  Full booking flow — Booking Confirmed shown
  WARN  Receipt block not visible
  PASS  My Reservations sidebar renders
  PASS  My Reservations lists items
  PASS  Cancel from My Reservations updates status
  PASS  Dark mode toggle works
  PASS  Client blocked from /admin → redirected to /dashboard

  32 passed  ·  2 warnings  ·  0 failed
Description
No description provided
Readme 2.4 MiB
Languages
JavaScript 64.2%
SCSS 34.3%
Just 1.2%
Dockerfile 0.2%
HTML 0.1%