This commit is contained in:
2026-04-12 01:35:19 +02:00
parent 91a8b85f38
commit d04e02020c
70 changed files with 8634 additions and 207 deletions

View File

@@ -0,0 +1,191 @@
---
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>

View File

@@ -0,0 +1,83 @@
---
phase: 95-ajax-table-refresh
plan: 01
subsystem: ui
tags: [ajax, dom-replacement, inline-status, orders-list]
requires:
- phase: 80-status-change-reload
provides: inline status change with location.reload()
provides:
- AJAX table refresh without full page reload
- JSON endpoint for partial HTML fragments
affects: []
tech-stack:
added: []
patterns: [ajax-partial-render, json-html-fragments]
key-files:
modified:
- src/Modules/Orders/OrdersController.php
- public/assets/js/modules/inline-status-change.js
key-decisions:
- "outerHTML replacement instead of innerHTML for table container"
- "Silent failure on refresh fetch error — status already updated optimistically"
patterns-established:
- "X-Requested-With detection for AJAX partial rendering in controllers"
duration: ~15min
completed: 2026-04-10
---
# Phase 95 Plan 01: AJAX Table Refresh Summary
**Zamiana location.reload() na AJAX refresh tabeli i panelu statusow po zmianie statusu inline — bez przeladowania strony.**
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: AJAX refresh tabeli po zmianie statusu | Pass | Tabela i paginacja odswiezaja sie bez reload, scroll zachowany |
| AC-2: AJAX refresh panelu statusow | Pass | Panel licznikow aktualizuje sie razem z tabela |
| AC-3: Obsluga bledu AJAX refresh | Pass | Badge zaktualizowany optimistic, brak crash przy bledzie fetch |
## Accomplishments
- Controller `index()` wykrywa AJAX request i zwraca JSON z `tableHtml` + `panelHtml`
- JS `inline-status-change.js` po udanej zmianie statusu pobiera fragmenty i podmienia DOM
- Scroll, filtry, paginacja zachowane po refresh
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `src/Modules/Orders/OrdersController.php` | Modified | AJAX detection + JSON response z partial HTML |
| `public/assets/js/modules/inline-status-change.js` | Modified | Fetch + DOM replacement zamiast location.reload() |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| outerHTML zamiast innerHTML | Prostsza podmiana calego kontenera bez wrapper div | Eventy delegowane na document nadal dzialaja |
| Silent fail na fetch error | Zmiana statusu juz sie powiodla, refresh jest nice-to-have | UX nie przerywa pracy uzytkownika |
## Deviations from Plan
None — plan executed as written.
## Next Phase Readiness
**Ready:**
- Pattern AJAX partial render gotowy do reuse w innych miejscach
- Inline status change w pelni asynchroniczny
**Concerns:** None
**Blockers:** None
---
*Phase: 95-ajax-table-refresh, Plan: 01*
*Completed: 2026-04-10*