---
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>
