# 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

```bash
# 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`:

```graphql
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 (1–5) + 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
```
