Files
carei.pagedev.pl/.paul/phases/02-form-ui-step1/02-01-PLAN.md
2026-03-25 00:41:16 +01:00

12 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous
phase plan type wave depends_on files_modified autonomous
02-form-ui-step1 01 execute 1
01-01
wp-content/plugins/carei-reservation/assets/css/carei-reservation.css
wp-content/plugins/carei-reservation/assets/js/carei-reservation.js
wp-content/plugins/carei-reservation/includes/class-elementor-widget.php
false
## Goal Zbudować kompletny frontend formularza rezerwacji (Krok 1) zgodny z projektem Figma — HTML, CSS, JS z dynamicznym ładowaniem danych z API Softra (oddziały, klasy pojazdów, opcje dodatkowe).

Purpose

To jest core UI — to co widzi użytkownik po kliknięciu "Złóż zapytanie o rezerwację". Bez tego formularza nie ma produktu.

Output

Działający formularz w modalu Elementor z pełnym stylingiem Figma i integracją API.

## Project Context @.paul/PROJECT.md @.paul/ROADMAP.md

Prior Work

@.paul/phases/01-reservation-form-plugin/01-01-SUMMARY.md

  • Widget Elementor z modalem (mount point: #carei-form-container)
  • REST proxy endpoints: GET /branches, POST /car-classes, POST /pricelist, GET /agreements
  • JS localized vars: careiReservation.restUrl, careiReservation.nonce

Design Spec

@docs/figma-formularz/README.md (kolory, typografia, wymiary, struktura, responsive) @docs/figma-formularz/screenshot-desktop.png @docs/figma-formularz/screenshot-mobile.png

<acceptance_criteria>

AC-1: Formularz renderuje się w modalu zgodnie z Figmą

Given użytkownik kliknie przycisk "Złóż zapytanie o rezerwację"
When modal się otworzy
Then widoczny jest formularz z sekcjami: dane wynajmu, opcje dodatkowe, dane najemcy, wiadomość, stopka
And kolory, typografia i wymiary odpowiadają specyfikacji Figma
And na desktop formularz jest wycentrowanym modalem (max 800px)
And na mobile formularz jest full-screen bottom sheet

AC-2: Dynamiczne dane z API

Given modal jest otwarty
When formularz się ładuje
Then dropdown "Miejsce odbioru" zawiera listę oddziałów z API /branches
And dropdown "Segment pojazdu" jest początkowo pusty (wymaga wybrania dat i oddziału)
When użytkownik wybierze oddział i daty
Then dropdown "Segment pojazdu" ładuje klasy z API /car-classes
And "Wybrano: X dni" oblicza się automatycznie

AC-3: Interakcje formularza działają poprawnie

Given formularz jest wyświetlony
When użytkownik zaznacza/odznacza "Zwrot w tej samej lokalizacji"
Then pole "Miejsce zwrotu" pojawia się/znika
When użytkownik zaznacza opcje dodatkowe
Then checkboxy wizualnie się zmieniają (Carei Blue fill)
When użytkownik klika "Wyślij" bez wypełnienia wymaganych pól
Then wyświetlane są komunikaty walidacji przy pustych polach
When formularz jest poprawnie wypełniony i "Wyślij" kliknięte
Then dane są zbierane i gotowe do wysłania (console.log na razie — Phase 3 obsłuży submission)

</acceptance_criteria>

Task 1: HTML formularza + CSS zgodny z Figmą wp-content/plugins/carei-reservation/includes/class-elementor-widget.php, wp-content/plugins/carei-reservation/assets/css/carei-reservation.css **class-elementor-widget.php — przebuduj render():** - Usuń placeholder `

Formularz rezerwacji — ładowanie...

` - Przenieś WSZYSTKIE style inline (z obecnego render()) do pliku CSS - Wstaw kompletny HTML formularza w `#carei-form-container`:
Struktura HTML (klasy BEM: `carei-form__*`):
```
form.carei-form
  ├─ .carei-form__section (Dane wynajmu)
  │  ├─ .carei-form__row (segment dropdown + daty)
  │  │  ├─ select#carei-segment (pełna szerokość na górze)
  │  │  ├─ .carei-form__dates (Od kiedy + Do kiedy obok siebie)
  │  │  └─ .carei-form__days-count ("Wybrano: X dni")
  │  ├─ .carei-form__row (miejsce odbioru)
  │  │  ├─ select#carei-pickup-branch (z ikoną MapPin SVG)
  │  │  └─ label.carei-form__checkbox (Zwrot w tej samej lokalizacji)
  │  └─ select#carei-return-branch (ukryty domyślnie)
  ├─ .carei-form__divider + label "Opcje dodatkowe"
  ├─ .carei-form__section.carei-form__extras
  │  ├─ .carei-form__extra-card (Ubezpieczenie — checkbox + opis + cena)
  │  └─ .carei-form__extra-card (Fotelik — checkbox + opis + cena)
  ├─ .carei-form__divider + label "Dane najemcy"
  ├─ .carei-form__section (Dane osobowe)
  │  ├─ .carei-form__row (Imię + Nazwisko — 2 kolumny desktop, 1 mobile)
  │  ├─ .carei-form__row (Email + Telefon — 2 kolumny desktop, 1 mobile)
  │  │  └─ Telefon: prefix "+48" z flagą PL (statyczną), input z placeholder
  │  └─ textarea (Twoja wiadomość dotycząca rezerwacji)
  └─ .carei-form__footer
     ├─ label.carei-form__checkbox (Zgadzam się na Politykę Prywatności — link)
     └─ button.carei-form__submit (ikona strzałki + "Wyślij")
```

- Dropdown "Segment pojazdu": `<select>` z `<option disabled selected>` placeholder
- Dropdown "Miejsce odbioru": `<select>` z opcjami ładowanymi z API
- Daty: `<input type="datetime-local">` dla "Od kiedy", `<input type="datetime-local">` dla "Do kiedy"
- Opcje dodatkowe: karty z checkbox, tytułem bold, opisem, ceną w kolorze red
- Telefon: div z flagą PL (emoji 🇵🇱 lub SVG) + "+48" + input type="tel"
- Script tag z modal open/close (zachowaj istniejącą logikę)

**carei-reservation.css — kompletne style:**
- CSS custom properties na górze:
  ```
  --carei-blue: #2F2482;
  --carei-red: #FF0000;
  --carei-bg: #EDEDF3;
  --carei-gray: #505050;
  --carei-placeholder: #C7C7C7;
  --carei-border: #D0D0D0;
  --carei-radius: 8px;
  --carei-input-h: 48px;
  ```
- @import Google Fonts Albert Sans (400,500,600,700)
- Modal: `.carei-modal-overlay`, `.carei-modal` (przenieść z inline)
- Form layout: CSS Grid dla sekcji, gap 24px między sekcjami, 16px wewnątrz
- Inputs: height 48px, border-radius 8px, border 1px solid transparent, focus border carei-blue
- Desktop: `.carei-form__row` = grid 2 kolumny (1fr 1fr)
- Mobile (<768px): 1 kolumna, modal full-screen, przycisk full-width
- Dividers: linia 1px #D0D0D0 z label centrowanym (jak w Figmie — text na tle linii)
- Checkbox custom: 24px, border-radius 8px, checked = carei-blue fill z białym checkmark
- Extra cards: border 1px #D0D0D0, border-radius 8px, padding 16px
- Submit button: bg carei-red, color white, font-weight 600, border-radius 8px, hover darken
- Footer: flex, space-between desktop, column mobile
- Walidacja: `.carei-form__field--error` z czerwonym border + komunikat
`php -l wp-content/plugins/carei-reservation/includes/class-elementor-widget.php` — brak syntax errors. CSS plik zawiera minimum 100 linii stylów. AC-1 satisfied: formularz renderuje się w modalu zgodnie z Figmą Task 2: JavaScript — API integration, dynamiczne dane, interakcje wp-content/plugins/carei-reservation/assets/js/carei-reservation.js **carei-reservation.js — kompletna logika formularza:**
Moduł IIFE `(function() { ... })()` korzystający z `careiReservation.restUrl` i `careiReservation.nonce`.

**1. API Helper:**
```js
async function apiGet(endpoint) — fetch GET z nonce header
async function apiPost(endpoint, data) — fetch POST z nonce header + JSON body
```

**2. Inicjalizacja (na DOMContentLoaded + modal open):**
- `loadBranches()` — GET /branches → populate select#carei-pickup-branch i select#carei-return-branch
- Ustawić domyślne daty: "Od kiedy" = jutro 10:00, "Do kiedy" = pojutrze 10:00
- Oblicz "Wybrano: X dni"

**3. Dynamiczne ładowanie klas pojazdów:**
- Event listener na zmianę dat i oddziału
- Gdy dateFrom + dateTo + branchName wypełnione → POST /car-classes → populate select#carei-segment
- Pokazać loading spinner w select podczas ładowania
- Gdy brak wyników → opcja "Brak dostępnych klas"

**4. Auto-kalkulacja dni:**
- Listener na zmianę obu dat
- Oblicz różnicę w dniach (ceil), wyświetl w `.carei-form__days-count`
- Walidacja: dateTo > dateFrom

**5. Checkbox "Zwrot w tej samej lokalizacji":**
- Default: checked → pole zwrotu ukryte
- Uncheck → pokaż select#carei-return-branch (animate slideDown)
- Check → ukryj (animate slideUp)

**6. Walidacja formularza:**
- Wymagane pola: segment, dateFrom, dateTo, pickup branch, imię, nazwisko, email, telefon, zgoda RODO
- Na submit: sprawdź każde pole, dodaj `.carei-form__field--error` + komunikat pod polem
- Na focus na polu z błędem: usuń error
- Email: prosty regex check
- Telefon: min 9 cyfr

**7. Zbieranie danych i submit:**
- Na klik "Wyślij" + walidacja OK:
  - Zbierz wszystkie dane formularza do obiektu
  - Na razie: `console.log('Form data:', formData)` — Phase 3 obsłuży API submission
  - Przycisk: zmień tekst na "Wysyłanie..." + disable (przygotowanie na Phase 3)
- NIE wysyłaj jeszcze do API booking — to Phase 3

**8. Opcje dodatkowe z API:**
- Po załadowaniu cennika (gdy klasa + daty + oddział wybrane) → POST /pricelist
- Z odpowiedzi wyciągnij `additionalItems` → dynamicznie wygeneruj karty opcji dodatkowych
- Jeśli API nie zwróci additionalItems → pokaż statyczne opcje (ubezpieczenie 300zł, fotelik 50zł) jako fallback
Plik JS nie zawiera syntax errors (brak `SyntaxError` w `node -e "require('fs').readFileSync('...','utf8')" 2>&1`). Plik JS zawiera minimum 150 linii kodu. AC-2 (dynamiczne dane z API), AC-3 (interakcje formularza) Kompletny formularz rezerwacji (Krok 1) w modalu Elementor z integracją API Softra 1. Wgraj pliki na serwer (carei.pagedev.pl) 2. Otwórz https://carei.pagedev.pl/ 3. Kliknij "Złóż zapytanie o rezerwację" 4. Sprawdź: - Modal otwiera się z formularzem - Dropdown "Miejsce odbioru" ładuje oddziały z API - Po wybraniu dat i oddziału — "Segment pojazdu" ładuje klasy z API - "Wybrano: X dni" oblicza się automatycznie - Checkbox "Zwrot w tej samej lokalizacji" pokazuje/ukrywa drugie pole - Opcje dodatkowe wyświetlają się jako karty z ceną - Responsywność: na mobile (375px) — full-screen, 1 kolumna - Klik "Wyślij" bez danych → walidacja (czerwone obramowania) - Klik "Wyślij" z danymi → console.log z obiektem danych 5. Porównaj wizualnie z screenshotami Figma w docs/figma-formularz/ Type "approved" to continue to Phase 3, or describe issues to fix

DO NOT CHANGE

  • wp-content/plugins/carei-reservation/carei-reservation.php (main plugin — Phase 1, already fixed)
  • wp-content/plugins/carei-reservation/includes/class-softra-api.php (API client — Phase 1)
  • wp-content/plugins/carei-reservation/includes/class-rest-proxy.php (REST routes — Phase 1)
  • wp-content/plugins/elementor-addon/* (istniejący plugin)
  • wp-content/themes/hello-elementor/* (theme)
  • .env, docs/*

SCOPE LIMITS

  • Ten plan buduje UI formularza i integrację API do ładowania danych
  • NIE implementuje wysyłki rezerwacji (Phase 3)
  • NIE buduje Kroku 2 / Overlay (Phase 3)
  • Przycisk "Wyślij" zbiera dane i loguje do console — nie wysyła do API
Before declaring plan complete: - [ ] `php -l` na class-elementor-widget.php — brak błędów - [ ] CSS plik ma >100 linii z pełnym stylingiem - [ ] JS plik ma >150 linii z API integration - [ ] Formularz renderuje HTML z wszystkimi sekcjami z Figmy - [ ] Responsive: desktop 2-kolumny, mobile 1-kolumna - [ ] Human verify: wizualne porównanie z Figmą na żywym serwerze

<success_criteria>

  • Formularz wygląda jak w Figmie (desktop + mobile)
  • Dane z API Softra ładują się dynamicznie
  • Interakcje (checkboxy, daty, walidacja) działają
  • Dane formularza zbierane i gotowe do wysłania (Phase 3) </success_criteria>
After completion, create `.paul/phases/02-form-ui-step1/02-01-SUMMARY.md`