Files
orderPRO/.paul/phases/95-ajax-table-refresh/95-01-PLAN.md
2026-04-12 01:35:19 +02:00

192 lines
7.6 KiB
Markdown

---
phase: 95-ajax-table-refresh
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- src/Modules/Orders/OrdersController.php
- public/assets/js/modules/inline-status-change.js
- resources/views/orders/list.php
- resources/views/components/table-list.php
- resources/views/components/order-status-panel.php
autonomous: false
delegation: off
---
<objective>
## Goal
Zamiana `location.reload()` po zmianie statusu zamówienia na AJAX refresh samej tabeli, paginacji i panelu statusów — bez przeładowania całej strony.
## Purpose
Zmiana statusu inline powoduje pełny reload strony, co jest wolne i resetuje scroll, filtry wizualne, itp. AJAX refresh da szybszą, płynniejszą obsługę.
## Output
- Kontroler `index()` rozpoznaje AJAX request i zwraca JSON z HTML fragmentami (tabela + panel statusów)
- JS po zmianie statusu fetchuje aktualną tabelę i panel, podmienia DOM bez reload
</objective>
<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
## Source Files
@src/Modules/Orders/OrdersController.php (metoda index() linie 44-157, metoda updateStatus() linia 250)
@public/assets/js/modules/inline-status-change.js (location.reload() linia 155)
@resources/views/orders/list.php (struktura strony, require table-list.php linia 22)
@resources/views/components/table-list.php (tabela + paginacja)
@resources/views/components/order-status-panel.php (panel statusów z licznikami)
@src/Core/View/Template.php (render() z null layout zwraca sam HTML)
</context>
<skills>
No specialized flows configured.
</skills>
<acceptance_criteria>
## AC-1: AJAX refresh tabeli po zmianie statusu
```gherkin
Given użytkownik jest na /orders/list z filtrami/paginacją
When zmieni status zamówienia przez inline dropdown
Then tabela i paginacja odświeżą się bez przeładowania strony
And filtry, strona i sortowanie pozostaną zachowane
And scroll pozycja strony nie zmieni się
```
## AC-2: AJAX refresh panelu statusów
```gherkin
Given użytkownik zmienił status zamówienia
When tabela się odświeży
Then panel statusów (liczniki) też się odświeży z aktualnymi wartościami
```
## AC-3: Obsługa błędu AJAX refresh
```gherkin
Given zmiana statusu się powiodła ale fetch tabeli zawiódł
When sieć jest niedostępna lub serwer zwraca błąd
Then badge statusu pozostaje zaktualizowany (optimistic update)
And strona nie crashuje użytkownik może kontynuować pracę
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Endpoint AJAX dla fragmentów tabeli i panelu</name>
<files>src/Modules/Orders/OrdersController.php</files>
<action>
W metodzie `index()` dodać detekcję AJAX requestu (header `X-Requested-With: XMLHttpRequest`).
Gdy request jest AJAX:
1. Zbudować te same dane co normalnie (filtry, paginacja, tableRows, statusPanel)
2. Renderować dwa fragmenty osobno przez `$this->template->render()` BEZ layoutu (null):
- `components/table-list` z danymi `$tableList` (tabela + paginacja)
- `components/order-status-panel` z danymi `$statusPanelList` i `$statusPanelTitle`
3. Zwrócić JSON: `{"tableHtml": "...", "panelHtml": "..."}`
Zmienne potrzebne do renderowania partiali muszą być przekazane w `$data`:
- Dla table-list: klucz `tableList` (już jest budowany)
- Dla order-status-panel: klucze `statusPanelList`, `statusPanelTitle`, `query` (filtry)
Ważne:
- Użyć `Response::json()` dla AJAX odpowiedzi
- Helpery `$e`, `$t` i inne muszą być dostępne w renderowanych partialach (Template::render je dodaje)
- Nie zmieniać normalnego (nie-AJAX) flow — ma działać jak dotychczas
</action>
<verify>
curl -H "X-Requested-With: XMLHttpRequest" "http://localhost/orders/list?page=1"
powinien zwrócić JSON z kluczami tableHtml i panelHtml
</verify>
<done>AC-1 i AC-2 częściowo — backend zwraca fragmenty HTML przez AJAX</done>
</task>
<task type="auto">
<name>Task 2: JS — AJAX refresh zamiast location.reload()</name>
<files>public/assets/js/modules/inline-status-change.js</files>
<action>
W funkcji `changeStatus()` zamienić `location.reload()` (linia 155) na:
1. Po udanej zmianie statusu (result.ok && result.data.success):
- Badge już jest zaktualizowany (optimistic update — zostaje)
- Pobrać aktualny URL strony: `window.location.pathname + window.location.search`
- Fetch GET na ten URL z headerem `X-Requested-With: XMLHttpRequest`
- Z odpowiedzi JSON wyciągnąć `tableHtml` i `panelHtml`
2. Podmiana DOM:
- Znaleźć kontener tabeli: `document.querySelector('.table-list')` (lub odpowiedni selektor dla table-list.php)
- Znaleźć kontener panelu statusów: `document.querySelector('.order-status-panel')`
- Zamienić innerHTML obu kontenerów na nowe HTML
3. Obsługa błędu:
- Jeśli fetch tabeli się nie powiedzie — nie robić nic (badge już zaktualizowany, dane nieco nieaktualne ale nie krytyczne)
- Nie wyświetlać błędu użytkownikowi — zmiana statusu się powiodła
Ważne:
- NIE usuwać optimistic update badge'a (linie 121-125) — to zostaje
- Scroll pozycja się nie zmieni bo nie robimy reload
- Po podmianie innerHTML, eventy inline-status-change nadal będą działać bo używają delegacji na document
</action>
<verify>
Na /orders/list zmienić status zamówienia — tabela i panel statusów odświeżą się bez reload strony, scroll się nie zmieni
</verify>
<done>AC-1, AC-2, AC-3 — pełny AJAX refresh bez reload</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<what-built>AJAX refresh tabeli i panelu statusów po zmianie statusu zamówienia</what-built>
<how-to-verify>
1. Otwórz /orders/list
2. Przewiń stronę w dół
3. Zmień status dowolnego zamówienia przez kliknięcie w badge
4. Potwierdź:
- Tabela odświeżyła się (nowy status widoczny)
- Panel statusów (liczniki) zaktualizował się
- Strona NIE przeładowała się (scroll pozycja zachowana)
- Filtry i paginacja zachowane
5. Zmień stronę paginacji, powtórz zmianę statusu — to samo zachowanie
6. Zastosuj filtr (np. po źródle), zmień status — filtr zachowany po refresh
</how-to-verify>
<resume-signal>Type "approved" to continue, or describe issues to fix</resume-signal>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- resources/views/components/table-list.php (struktura HTML — tylko czytać, nie modyfikować)
- resources/views/components/order-status-panel.php (struktura HTML — tylko czytać)
- src/Core/View/Template.php (engine renderowania)
- routes/web.php (nie potrzeba nowej trasy — istniejąca GET /orders/list wystarczy)
## SCOPE LIMITS
- Tylko zmiana statusu inline — nie dotyczy innych akcji na liście
- Nie dodawać animacji/transition przy refresh (prostota)
- Nie zmieniać struktury HTML table-list ani order-status-panel
</boundaries>
<verification>
Before declaring plan complete:
- [ ] Zmiana statusu inline odświeża tabelę przez AJAX (bez reload)
- [ ] Panel statusów odświeża się razem z tabelą
- [ ] Scroll pozycja zachowana
- [ ] Filtry i paginacja zachowane po refresh
- [ ] Normalny (nie-AJAX) request na /orders/list nadal zwraca pełną stronę
- [ ] Brak błędów JS w konsoli
</verification>
<success_criteria>
- location.reload() usunięty z inline-status-change.js
- Kontroler index() zwraca JSON z fragmentami HTML dla AJAX requestów
- Tabela, paginacja i panel statusów odświeżają się bez przeładowania strony
</success_criteria>
<output>
After completion, create `.paul/phases/95-ajax-table-refresh/95-01-SUMMARY.md`
</output>