Files
2026-05-06 00:18:37 +02:00

263 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 09-finalizacja
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- wp-content/plugins/yacht-booking-system/frontend/assets/js/calendar.js
- wp-content/plugins/yacht-booking-system/frontend/assets/css/calendar.scss
- wp-content/plugins/yacht-booking-system/frontend/assets/css/calendar.css
- wp-content/plugins/yacht-booking-system/frontend/class-calendar-widget.php
autonomous: false
delegation: off
---
<objective>
## Goal
Wprowadzić wizualne oznaczenie „pół-dnia" na pierwszym i ostatnim dniu rezerwacji w kalendarzu frontowym (FullCalendar) oraz dostroić domyślną kolorystykę widgetu Elementor `yacht-calendar` do palety strony jachty3.pagedev.pl (granat + czerwony akcent).
## Purpose
Klient zgłosił, że obecna wizualizacja kalendarza nie odzwierciedla rzeczywistego rytmu wynajmu jachtów: jacht jest wydawany danego dnia od ustalonej godziny odbioru (po południu) i zwracany w dniu zakończenia rano. Pełne zablokowanie skrajnych dni rezerwacji wprowadza w błąd potencjalnych klientów — sugeruje, że dzień odbioru/zwrotu jest niedostępny, podczas gdy w praktyce można wtedy rozpocząć/zakończyć inną rezerwację. Dodatkowo obecna paleta zieleń+czerwień nie pasuje do granatowo-czerwonego brandingu strony.
## Output
- Zmodyfikowany kalendarz frontowy (JS + CSS) renderujący skos „pół-zajętego" dnia dla pierwszego i ostatniego dnia każdej ciągłej blokady (booking, GCal, iCal)
- Zaktualizowane domyślne kolory widgetu Elementor (`primary`, `available`, `booked`) dopasowane do palety strony
- Zachowana kompatybilność z istniejącymi instancjami widgetu (override przez ustawienia Elementora dalej działa)
</objective>
<context>
<clarifications>
- **Half-day** — Który dzień ma być wypełniony „w połowie"?
→ Odpowiedź: Pierwszy i ostatni dzień rezerwacji. Wizualnie: dzień startu = lewa połowa wolna, prawa połowa zajęta (odbiór po południu); dzień końca = lewa połowa zajęta, prawa połowa wolna (zwrot rano).
- **Kolorystyka** — Skąd brać kolory dopasowane do strony?
→ Odpowiedź: Zmienić domyślne wartości w `Calendar_Widget` (Elementor). Istniejące instancje będą mogły zachować swoje ustawienia (override) lub zresetować do nowych defaultów.
- **Blocked GCal** — Czy half-day dotyczy też blokad zewnętrznych (Google Calendar / iCal, bez `booking_id`)?
→ Odpowiedź: Tak — analogicznie. Pierwszy i ostatni dzień ciągłego pasma `blocked` także jest pół-zajęty. Detekcja na podstawie ciągłości statusu (poprzedni/następny dzień ma inny status lub inny `booking_id`).
- **Scope** — Czy to plan fazy 9 czy hotfix?
→ Odpowiedź: Plan 09-01 fazy 9 (UX/UI polish). Plany 09-02 (settings page), 09-03 (security audit), 09-04 (testy/tłumaczenia/dokumentacja) idą później.
- **Selectability ostatniego dnia** (wynika z odpowiedzi 1) — Czy pierwszy/ostatni dzień rezerwacji ma być klikalny dla nowej rezerwacji?
→ Odpowiedź: Wizualnie tak (skos pokazuje, że pół dnia jest wolne), natomiast logika walidacji rezerwacji **pozostaje bez zmian** w tym planie — overlap dalej blokuje wybór skrajnych dni. Zmiana logiki to osobna decyzja biznesowa (godziny check-in/out, polityka rezerwacji) i będzie tematem oddzielnego planu jeśli klient tego zechce.
</clarifications>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
@.paul/codebase/architecture.md
## Source Files
@wp-content/plugins/yacht-booking-system/frontend/assets/js/calendar.js
@wp-content/plugins/yacht-booking-system/frontend/assets/css/calendar.scss
@wp-content/plugins/yacht-booking-system/frontend/class-calendar-widget.php
@wp-content/plugins/yacht-booking-system/includes/class-availability.php
</context>
<acceptance_criteria>
## AC-1: Skos na pierwszym dniu rezerwacji
```gherkin
Given jacht ma rezerwację w terminie 2124 maja
When użytkownik otwiera kalendarz tego jachtu
Then dzień 21 maja renderuje się z lewą połową w kolorze "available" i prawą połową w kolorze "booked" (gradient po przekątnej z lewego dołu do prawej góry, lub liniowo 50/50)
And dni 22 i 23 maja są w pełni w kolorze "booked"
```
## AC-2: Skos na ostatnim dniu rezerwacji
```gherkin
Given jacht ma rezerwację w terminie 2124 maja
When użytkownik otwiera kalendarz tego jachtu
Then dzień 24 maja renderuje się z lewą połową w kolorze "booked" i prawą połową w kolorze "available"
```
## AC-3: Detekcja ciągłości — różne booking_id obok siebie
```gherkin
Given jacht ma rezerwację A (1518 maja, booking_id=10) i rezerwację B (1922 maja, booking_id=11)
When kalendarz renderuje maj
Then dzień 18 jest "ostatni" rezerwacji A (skos prawy = available) ale jeśli 19 jest pierwszym B, na styku 18/19 oba dni mają skosy w przeciwnych kierunkach
And dni 16, 17 (środek A) oraz 20, 21 (środek B) są w pełni booked
```
## AC-4: Skos także dla blokad GCal/iCal
```gherkin
Given jacht ma blokadę zewnętrzną (status=blocked, booking_id=null) w dniach 57 czerwca
When kalendarz renderuje czerwiec
Then dzień 5 czerwca = lewa połowa available, prawa booked
And dzień 7 czerwca = lewa booked, prawa available
And dzień 6 czerwca = w pełni booked
```
## AC-5: Nowa paleta domyślna widgetu
```gherkin
Given administrator dodaje świeży widget "Yacht Calendar" w Elementorze
When otwiera ustawienia stylu
Then domyślne kolory to: primary = granat strony (np. #0a2a5e), available = jasny / transparentny (np. #f5f9ff lub rgba), booked = czerwień strony (np. #d63638)
And istniejące widgety (z zapisanymi własnymi kolorami) zachowują swoje wartości nie są nadpisywane
```
## AC-6: Walidacja wyboru dat niezmieniona
```gherkin
Given jacht ma rezerwację 2124 maja
When użytkownik próbuje wybrać 2426 maja w kalendarzu
Then system blokuje wybór (alert "Wybrane daty zawierają niedostępne terminy")
# Zmiana logiki check-in/check-out poza zakresem tego planu.
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Wzbogacić REST/JS o detekcję krawędzi rezerwacji i wyrenderować skos</name>
<files>
wp-content/plugins/yacht-booking-system/frontend/assets/js/calendar.js,
wp-content/plugins/yacht-booking-system/frontend/assets/css/calendar.scss,
wp-content/plugins/yacht-booking-system/frontend/assets/css/calendar.css
</files>
<action>
**Detekcja krawędzi (klient-side, w `events` callback):**
1. Po pobraniu danych z `/availability/{yacht_id}` posortować dni po dacie.
2. Dla każdego dnia o statusie != 'available' obliczyć:
- `isStart` = poprzedni dzień (date - 1) jest 'available' LUB ma inny `booking_id` LUB ma inny status (booked vs blocked).
- `isEnd` = następny dzień (date + 1) j.w.
- Jeżeli zarówno `isStart` jak i `isEnd` to dzień jest "single" (1-dniowa blokada) → traktuj jako pełen booked (nie skos), albo opcjonalnie skos w kształcie klepsydry — w tym planie: pełen booked dla 1-dniowych.
3. Zamiast pojedynczego eventu `display: 'background'` z jednym kolorem, dodaj `classNames`:
- `yacht-day-booked` (środek)
- `yacht-day-booked-start` (pierwszy dzień)
- `yacht-day-booked-end` (ostatni dzień)
- analogicznie `yacht-day-blocked-*` dla statusu 'blocked'
4. Zachować istniejący `backgroundColor` jako fallback dla starszych przeglądarek; rzeczywiste tło renderować przez CSS (linear-gradient).
5. Przekazać kolor `availableBg` i `bookedBg` do CSS przez CSS custom properties ustawiane na wrapperze: `--yacht-available-bg`, `--yacht-booked-bg`.
- Set `$wrapper.css({'--yacht-available-bg': availableBg, '--yacht-booked-bg': bookedBg})`.
**CSS (calendar.scss + skompilowany calendar.css):**
1. Dodaj reguły:
```css
.yacht-day-booked-start .fc-bg-event,
.yacht-day-booked-start.fc-day {
background: linear-gradient(to right,
var(--yacht-available-bg) 0%,
var(--yacht-available-bg) 50%,
var(--yacht-booked-bg) 50%,
var(--yacht-booked-bg) 100%) !important;
}
.yacht-day-booked-end .fc-bg-event,
.yacht-day-booked-end.fc-day {
background: linear-gradient(to right,
var(--yacht-booked-bg) 0%,
var(--yacht-booked-bg) 50%,
var(--yacht-available-bg) 50%,
var(--yacht-available-bg) 100%) !important;
}
/* Analogicznie dla blocked-* */
```
2. Skos liniowy 50/50 — preferowany nad ukośnym (`to bottom right`), bo zachowuje czytelność daty i nie nakłada się na cyfrę.
3. Zaktualizować legendę widgetu o trzeci stan "Częściowo zajęty" (gradient sample) — tylko jeśli widget już renderuje legendę; jeśli nie, pominąć.
**Nie zmieniać:**
- logiki walidacji `selectAllow` / `select` (AC-6).
- struktury REST API (`/availability/{yacht_id}` zwraca dalej te same pola).
**Avoid:**
- Mutacji `event.display` — zostaw `'background'`, klasy CSS wystarczą.
- Inline styles na komórkach (FullCalendar je nadpisuje na re-render).
</action>
<verify>
1. `php -l wp-content/plugins/yacht-booking-system/frontend/class-calendar-widget.php` — syntax OK.
2. Skompilować SCSS → CSS (lub edytować oba pliki ręcznie spójnie); `git diff calendar.css` pokazuje nowe selektory.
3. Manualnie: po deployu FTP otworzyć /rezerwacja-maja/, sprawdzić że dla istniejącej rezerwacji pierwszy/ostatni dzień ma skos. (CHECKPOINT human-verify w Task 3).
</verify>
<done>AC-1, AC-2, AC-3, AC-4, AC-6 spełnione.</done>
</task>
<task type="auto">
<name>Task 2: Zaktualizować domyślne kolory widgetu Elementor do palety strony</name>
<files>
wp-content/plugins/yacht-booking-system/frontend/class-calendar-widget.php
</files>
<action>
W `Calendar_Widget::register_controls()` (linie ~218245 oraz ~272274 dla `render()` i ~530532 dla `_content_template()`) zmienić wartości `'default'` na paletę dopasowaną do strony jachty3.pagedev.pl:
- `primary_color`: `#2271b1` → `#0a2a5e` (granat główny strony)
- `available_color`: `#35b56a` → `#f5f9ff` (bardzo jasny niebieski / prawie biały)
- `booked_color`: `#e53935` → `#d63638` (czerwień akcentu strony, taka sama jak CTA)
Jeśli paleta strony zostanie później doprecyzowana — wartości można dostroić w ramach UNIFY. Punkt wyjścia: granat #0a2a5e + czerwień #d63638 (zgodne z screenshotem strony).
Dodatkowo:
- W szablonie legendy (linie ~566570) zaktualizować `background-color` swatch'y do nowych defaultów (lub jeszcze lepiej: użyć CSS custom properties z wrappera, żeby legenda też reagowała na zmianę w Elementorze).
- Fallback w `calendar.js` (`normalizeColor`) — dodać stare zielone/czerwone `#35b56a` i `#e53935` jako "legacyColor", aby instancje wciąż używające tych wartości automatycznie dostały nowe domyślne. Dla istniejących instancji ze świadomie dobranymi kolorami (np. brand klienta) zachować jak jest — czyli **nie ruszać** instancji, gdzie wartość jest inna niż stary default.
**Avoid:**
- Migracji wartości w bazie danych (Elementor zapisuje per-widget; nie ruszamy istniejących).
- Łamania backward-compatibility dla widgetów bez ustawionego koloru (puste = nowy default).
</action>
<verify>
1. `php -l wp-content/plugins/yacht-booking-system/frontend/class-calendar-widget.php`.
2. Po deployu: dodać nowy widget Yacht Calendar w Elementor → sprawdzić że suwaki pokazują nowe wartości HEX.
3. Otworzyć stronę z istniejącym widgetem — kolory niezmienione (jeśli zapisane w meta) lub odświeżone (jeśli legacy zielony/czerwony).
</verify>
<done>AC-5 spełnione.</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<what-built>
Wizualne oznaczenie pół-dni i nowa paleta widgetu na środowisku produkcyjnym (po deployu FTP).
</what-built>
<how-to-verify>
1. Po wgraniu plików przez ftp-kr odświeżyć z hard-reload: https://jachty3.pagedev.pl/rezerwacja-maja/
2. Wybrać miesiąc, w którym istnieje rezerwacja (lub stworzyć testową).
3. Sprawdzić wizualnie:
- Pierwszy dzień rezerwacji: lewa połowa jasna, prawa czerwona.
- Środkowe dni: w pełni czerwone.
- Ostatni dzień: lewa czerwona, prawa jasna.
- Tło wolnych dni: jasno-niebieskie / białe (dopasowane do strony).
- Brak regresji w wyborze dat (selecton działa, walidacja overlap aktywna).
4. Sprawdzić w Elementorze: nowy widget Yacht Calendar → defaultowe kolory = granat/jasny/czerwień.
5. Mobile (DevTools 375px) — skos czytelny, data nie znika.
</how-to-verify>
<resume-signal>Wpisz "approved" aby kontynuować, lub opisz problemy do poprawienia (kolor, kierunek skosu, kontrast itp.)</resume-signal>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- `wp-content/plugins/yacht-booking-system/api/class-rest-controller.php` — REST API surface bez zmian.
- `wp-content/plugins/yacht-booking-system/includes/class-availability.php` — schemat danych i metody bez zmian.
- Logika walidacji rezerwacji w `Rest_Controller::create_booking()` i `selectAllow` w JS — nie zmieniać polityki overlap.
- `wp_yacht_availability` — schemat tabeli niezmieniony.
- Backend admin (`admin/class-admin.php` itd.) — plan dotyczy tylko frontendu.
- Istniejące zapisane ustawienia kolorów w meta widgetów Elementora.
## SCOPE LIMITS
- Tylko frontend kalendarza (FullCalendar w widgecie + shortcode).
- Tylko CSS + JS detekcja krawędzi; brak nowych endpointów REST.
- Bez zmian w polityce check-in/check-out (godziny odbioru/zwrotu jako konfiguracja → ewentualnie osobny plan).
- Bez zmian w systemie email / templates.
- Bez tłumaczeń .po/.mo (osobny plan 09-04).
</boundaries>
<verification>
- [ ] `php -l` na zmodyfikowanych plikach PHP — bez błędów składni.
- [ ] Skompilowany `calendar.css` zsynchronizowany z `calendar.scss`.
- [ ] Brak nowych warningów w konsoli przeglądarki (DevTools) na /rezerwacja-maja/.
- [ ] FullCalendar nadal renderuje miesiąc/dni i refetch działa po zmianie jachtu.
- [ ] Wszystkie AC (AC-1..AC-6) zweryfikowane wizualnie w checkpoint human-verify.
</verification>
<success_criteria>
- Skos na pierwszym/ostatnim dniu każdej ciągłej blokady (booked + blocked).
- Środkowe dni renderują się w pełnym kolorze booked.
- 1-dniowe blokady renderują się jako pełen booked (decyzja: nie używamy klepsydry).
- Nowe defaulty kolorów w widgecie pasują wizualnie do palety strony (granat + czerwień).
- Istniejące widgety z customowymi kolorami nie tracą swoich ustawień.
- Klient potwierdza ("approved") w checkpoint human-verify.
</success_criteria>
<output>
Po zakończeniu: `.paul/phases/09-finalizacja/09-01-SUMMARY.md`
</output>