# 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 (jednostkowe):  25 passed, 0 failed
Playwright (e2e):      32 passed, 0 failed, 2 warnings
```
