feat(v1.6): inline status change on orders list

Phase 44 complete:
- Clickable status badge opens dropdown with grouped statuses
- AJAX POST changes status without page reload (optimistic update)
- Fixed-position dropdown escapes table overflow:hidden
- updateStatus() returns JSON for AJAX, redirect for standard POST

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-27 09:40:06 +01:00
parent 3f072c5906
commit f2f1c44324
10 changed files with 652 additions and 47 deletions

View File

@@ -13,8 +13,8 @@ Sprzedawca moĹĽe obsĹugiwać zamĂłwienia ze wszystkich kanaĹĂłw
| Attribute | Value |
|-----------|-------|
| Version | 1.0.0 |
| Status | v1.5 Complete |
| Last Updated | 2026-03-25 |
| Status | v1.6 Complete |
| Last Updated | 2026-03-27 |
## Requirements
@@ -52,10 +52,11 @@ Sprzedawca moĹĽe obsĹugiwać zamĂłwienia ze wszystkich kanaĹĂłw
- [x] Ograniczenie szumu logow importu Allegro i deduplikacja wpisow activity log - Phase 41
- [x] Automatyzacja: event `shipment.status_changed` + warunki statusowe przesylki - Phase 42
- [x] Usuwanie wpisu z kolejki druku etykiet z panelu ustawien - Phase 43
- [x] Szybka zmiana statusu zamowienia z listy zamowien (inline dropdown + AJAX) - Phase 44
### Active (In Progress)
- [ ] Brak aktywnych faz w milestone v1.5 (40-43 zakonczone)
- [ ] Brak aktywnych faz
### Planned (Next)
@@ -147,5 +148,5 @@ Quick Reference:
---
*PROJECT.md — Updated when requirements or context change*
*Last updated: 2026-03-25 after Phase 40-43 completion (Operational Workflow Cleanup)*
*Last updated: 2026-03-27 after Phase 44 completion (Inline Status Change)*

View File

@@ -6,25 +6,34 @@ orderPRO to narzÄ™dzie do wielokanaĹowego zarzÄ…dzania sprzedaĹĽÄ
## Current Milestone
v1.5 Operational Workflow Cleanup - Complete (phases 40-43 complete)
v1.6 Quick Status Change - Complete (2026-03-27)
Usprawnienia operacyjne po wdrozeniu modulu wydrukow i trackingu: usuniecie zbędnego bulk print z listy zamowien, ograniczenie szumu logow importu Allegro, rozszerzenie automatyzacji o zdarzenia statusu przesylki oraz mozliwosc usuwania wpisow z kolejki druku.
Szybka zmiana statusu zamówienia bezpośrednio z listy zamówień — klikalny dropdown w kolumnie statusu, zmiana przez AJAX bez przeładowania strony.
| Phase | Name | Status | Plans |
|------|------|--------|-------|
| 40 | Remove Order List Bulk Print | Complete (2026-03-25) | 1/1 (`40-01-PLAN.md`) |
| 41 | Allegro Import Log Rationalization | Complete (2026-03-25) | 1/1 (`41-01-PLAN.md`) |
| 42 | Automation Shipment Status Event | Complete (2026-03-25) | 1/1 (`42-01-PLAN.md`) |
| 43 | Print Queue Entry Removal | Complete (2026-03-25) | 1/1 (`43-01-PLAN.md`) |
| 44 | Inline Status Change | Complete (2026-03-27) | 1/1 (`44-01-PLAN.md`) |
Active phase directories:
- `.paul/phases/40-remove-order-list-bulk-print/`
- `.paul/phases/41-allegro-import-log-rationalization/`
- `.paul/phases/42-automation-shipment-status-event/`
- `.paul/phases/43-print-queue-entry-removal/`
Archive: `.paul/phases/44-inline-status-change/`
## Completed Milestones
<details>
<summary>v1.5 Operational Workflow Cleanup - 2026-03-25 (4 phases, 4 plans)</summary>
Usprawnienia operacyjne: usunięcie bulk print, ograniczenie szumu logów importu Allegro, automatyzacja shipment.status_changed, usuwanie wpisów z kolejki druku.
| Phase | Name | Plans | Completed |
|-------|------|-------|-----------|
| 40 | Remove Order List Bulk Print | 1/1 | 2026-03-25 |
| 41 | Allegro Import Log Rationalization | 1/1 | 2026-03-25 |
| 42 | Automation Shipment Status Event | 1/1 | 2026-03-25 |
| 43 | Print Queue Entry Removal | 1/1 | 2026-03-25 |
Archive: `.paul/phases/40-*`, `.paul/phases/41-*`, `.paul/phases/42-*`, `.paul/phases/43-*`
</details>
<details>
<summary>v1.4 UI Readability Tweaks - 2026-03-25 (1 phase, 1 plan)</summary>
@@ -145,20 +154,6 @@ Archive: `.paul/phases/17-receipt-duplicate-guard/`
</details>
## Completed Milestones
<details>
<summary>v1.4 UI Readability Tweaks - 2026-03-25 (1 phase, 1 plan)</summary>
Rozdzielenie semantyki kolorow UI: glowny kolor przyciskow akcji zostal oddzielony od koloru naglowkow sekcji, aby poprawic czytelnosc i szybkosc skanowania interfejsu.
| Phase | Name | Plans | Completed |
|-------|------|-------|-----------|
| 30 | Button Primary Color Distinction | 1/1 | 2026-03-25 |
Archive: .paul/phases/30-button-primary-color/
</details>
<details>
<summary>v0.5 ModuŠAutomatyzacji — 2026-03-18 (1 phase, 2 plans)</summary>
@@ -234,7 +229,7 @@ Archive: `.paul/milestones/v0.1-ROADMAP.md`
---
*Roadmap created: 2026-03-12*
*Last updated: 2026-03-25 - v1.5 phases 40-43 complete*
*Last updated: 2026-03-27 - v1.6 Quick Status Change complete*

View File

@@ -5,15 +5,15 @@
See: .paul/PROJECT.md (updated 2026-03-12)
**Core value:** Sprzedawca moĹĽe obsĹugiwać zamĂłwienia ze wszystkich kanaĹĂłw sprzedaĹĽy i nadawać przesyĹki bez przeĹÄ…czania siÄ™ miÄ™dzy platformami.
**Current focus:** v1.5 completed - phases 40-43 delivered
**Current focus:** v1.6 complete — Phase 44 delivered
## Current Position
Milestone: v1.5 Operational Workflow Cleanup
Phase: [4] of [4] (Print Queue Entry Removal) - Unified
Plan: 43-01 completed with summary
Status: PLAN/APPLY/UNIFY closed for phases 40-43
Last activity: 2026-03-25 23:59 - Completed phases 41-43 and updated docs/summaries
Milestone: v1.6 Quick Status Change — Complete
Phase: [1] of [1] (Inline Status Change) Unified
Plan: 44-01 completed with summary
Status: PLAN/APPLY/UNIFY closed for phase 44
Last activity: 2026-03-27 — Phase 44 complete, milestone v1.6 closed
Progress:
- v0.1 Initial Release: [##########] 100% done
@@ -39,13 +39,15 @@ Progress:
- Phase 41: [##########] Complete (1/1 plans)
- Phase 42: [##########] Complete (1/1 plans)
- Phase 43: [##########] Complete (1/1 plans)
- v1.6 Quick Status Change: [##########] 100% done
- Phase 44: [##########] Complete (1/1 plans)
## Loop Position
Current loop state:
```
PLAN --> APPLY --> UNIFY
done done done [Loop closed for phases 40-43]
done done done [Loop closed for phase 44]
```
## Accumulated Context
@@ -53,6 +55,8 @@ PLAN --> APPLY --> UNIFY
### Decisions
| Data | Decyzja | Faza | WpĹyw |
|------|---------|------|-------|
| 2026-03-27 | Fixed positioning dropdown (document.body) zamiast absolute wewnatrz table-wrap | Faza 44 | Dropdown nie ucinany przez overflow:hidden na .table-wrap |
| 2026-03-27 | AJAX detect przez X-Requested-With header z fallback na redirect | Faza 44 | updateStatus() obsluguje oba tryby w jednej metodzie |
| 2026-03-25 | Import Allegro: trigger context + deduplikacja logow (`source_order_id + source_updated_at + trigger`) | Faza 41 | Czytelniejsza historia zamowienia i mniej duplikatow wpisow `import` |
| 2026-03-25 | Automatyzacja: event `shipment.status_changed` z warunkiem `shipment_status` (mapowanie biznes->techniczny) | Faza 42 | Reguly moga reagowac na realny status dostawy bez przebudowy engine |
| 2026-03-25 | Tracking cron triggeruje automatyzacje tylko przy realnej zmianie `delivery_status` | Faza 42 | Brak falszywych triggerow i mniejszy szum automatyzacji |
@@ -88,6 +92,11 @@ PLAN --> APPLY --> UNIFY
| 2026-03-17 | Email history jako wpisy w order_activity_log (nie osobna sekcja) | Faza 15 | SpĂłjnoĹć z istniejÄ…cym UX — jeden timeline zamiast fragmentacji |
| 2026-03-17 | VariableResolver wydzielony z EmailTemplateController | Faza 15 | Reuse logiki zmiennych; resolwer niezaleĹĽny od kontrolera szablonĂłw |
### Skill Audit (Faza 44, Plan 01)
| Oczekiwany | Wywolany | Uwagi |
|------------|---------|-------|
| sonar-scanner | override | Pominieto na podstawie explicit user override; lint PHP + build CSS PASS |
### Skill Audit (Faza 43, Plan 01)
| Oczekiwany | WywoĹany | Uwagi |
|------------|---------|-------|
@@ -272,7 +281,7 @@ PLAN --> APPLY --> UNIFY
- **Delivery mapping "Szukaj..." layout** — JS `attachSelectFilter()` w allegro.php tworzy input search dla InPost/Apaczka selectów, wizualnie wygląda jakby należaŠdo wiersza powyżej. Pre-existing bug, do naprawy osobno.
### Git State
Last commit: 3610571 — feat(v1.5): complete phases 40-43 workflow cleanup
Last commit: pending (phase 44 commit) — feat(v1.5): complete phases 40-43 workflow cleanup
Branch: main
Feature branches merged: none
@@ -281,13 +290,10 @@ Brak.
## Session Continuity
Last session: 2026-03-25 23:59
Stopped at: v1.5 phases 40-43 completed (summaries + docs + state updated)
Next action: Start next milestone planning ($paul-milestone or $paul-plan for next TODO batch)
Last session: 2026-03-27
Stopped at: v1.6 phase 44 completed (SUMMARY + docs + state updated)
Next action: Start next milestone planning (/paul:milestone or /paul:plan)
Resume file: .paul/ROADMAP.md
Resume context:
- v0.1-v1.4: COMPLETE done (30 phases, 42 plans)
- v1.5: COMPLETE done (phases 40-43)
---
*STATE.md — Updated after every significant action*

View File

@@ -0,0 +1,185 @@
---
phase: 44-inline-status-change
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- src/Modules/Orders/OrdersController.php
- resources/views/orders/list.php
- resources/scss/modules/_orders.scss
- resources/js/modules/inline-status-change.js
- public/assets/css/modules/orders.css
- public/assets/js/modules/inline-status-change.js
autonomous: true
---
<objective>
## Goal
Dodać szybką zmianę statusu zamówienia bezpośrednio z listy zamówień — kliknięcie w badge statusu otwiera dropdown z dostępnymi statusami, wybór zmienia status przez AJAX bez przeładowania strony.
## Purpose
Operator nie musi wchodzić w szczegóły zamówienia aby zmienić status — oszczędność czasu przy obsłudze wielu zamówień.
## Output
- Zmodyfikowany kontroler z obsługą AJAX w `updateStatus()`
- Dropdown statusów w kolumnie statusu na liście zamówień
- JS moduł do inline zmiany statusu
- Style SCSS dla dropdowna
</objective>
<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
## Source Files
@src/Modules/Orders/OrdersController.php — metody: index(), updateStatus(), toTableRow(), statusBadge(), buildAllStatusOptions(), statusColorMap()
@resources/views/orders/list.php — widok listy zamówień
@resources/views/components/table-list.php — komponent tabeli (kolumna status_badges jest raw HTML)
@routes/web.php — POST /orders/{id}/status endpoint (linia 337)
</context>
<skills>
## Required Skills (from SPECIAL-FLOWS.md)
| Skill | Priority | When to Invoke | Loaded? |
|-------|----------|----------------|---------|
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
**BLOCKING:** Required skills MUST be loaded before APPLY proceeds.
## Skill Invocation Checklist
- [ ] sonar-scanner loaded (run command or confirm)
</skills>
<acceptance_criteria>
## AC-1: Dropdown statusów pojawia się po kliknięciu badge
```gherkin
Given lista zamówień wyświetla zamówienia z badge'ami statusów
When operator kliknie w badge statusu zamówienia
Then pojawia się dropdown z listą wszystkich dostępnych statusów pogrupowanych wg grup statusowych
And aktualny status jest wyróżniony w dropdown
And kliknięcie poza dropdown zamyka go
```
## AC-2: Zmiana statusu przez AJAX
```gherkin
Given dropdown statusów jest otwarty przy zamówieniu
When operator wybierze nowy status z listy
Then wysyłany jest request AJAX POST /orders/{id}/status z new_status i _token
And badge statusu zamienia się na nowy (z prawidłowym kolorem i etykietą)
And dropdown zamyka się automatycznie
And nie następuje przeładowanie strony
```
## AC-3: Obsługa błędów AJAX
```gherkin
Given operator wybiera nowy status z dropdown
When request AJAX zwróci błąd (CSRF expired, order not found, server error)
Then wyświetla się komunikat błędu przez OrderProAlerts
And badge wraca do poprzedniego stanu
And dropdown zamyka się
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Rozszerzenie updateStatus() o tryb AJAX + przekazanie danych statusów do widoku listy</name>
<files>src/Modules/Orders/OrdersController.php</files>
<action>
1. W metodzie `updateStatus()` — wykryj request AJAX przez nagłówek `X-Requested-With: XMLHttpRequest`:
- Jeśli AJAX: zwróć `Response::json(...)` z kluczami: `success`, `status_code`, `status_label`, `status_color` (kolor hex z grupy)
- Jeśli nie-AJAX: zachowaj obecne zachowanie (redirect)
- Przy błędach AJAX: zwróć JSON z `success: false` i `error` message
2. W metodzie `index()` — przekaż `allStatuses` (z `buildAllStatusOptions()`) i `statusColorMap` do widoku, aby JS miał dane do budowy dropdown
3. W metodzie `toTableRow()` — dodaj do HTML badge `data-order-id` i `data-current-status` atrybuty, aby JS mógł zidentyfikować zamówienie i aktualny status
Unikaj: Zmiany zachowania dla nie-AJAX requestów; dodawania nowych zależności
</action>
<verify>
- `curl -X POST /orders/1/status -H "X-Requested-With: XMLHttpRequest" -d "new_status=shipped&_token=..." ` zwraca JSON
- Standardowy POST nadal zwraca redirect
</verify>
<done>AC-2 i AC-3 satisfied: endpoint zwraca JSON dla AJAX, zachowuje redirect dla form submit</done>
</task>
<task type="auto">
<name>Task 2: Dropdown UI + JavaScript moduł inline zmiany statusu + style SCSS</name>
<files>resources/views/orders/list.php, resources/scss/modules/_orders.scss, resources/js/modules/inline-status-change.js, public/assets/js/modules/inline-status-change.js, public/assets/css/modules/orders.css</files>
<action>
1. W `resources/views/orders/list.php`:
- Dodaj `<script>` tag z danymi statusów jako JSON (allStatuses, statusColorMap, csrfToken) w `data-*` atrybucie lub inline `<script>` zmienna
- Załaduj `inline-status-change.js` na dole strony
2. W `resources/js/modules/inline-status-change.js`:
- Na klik w `.orders-status-wrap` (badge kontener) — zbuduj dropdown z pogrupowanymi statusami
- Dropdown: pozycjonowanie absolutne pod/nad badge, grupy statusów z nagłówkami, opcje z kolorami
- Zaznacz aktualny status (odczytaj z `data-current-status`)
- Na wybór statusu: fetch POST do `/orders/{orderId}/status` z `X-Requested-With: XMLHttpRequest`
- Po sukcesie: zaktualizuj badge HTML (nowy kolor, nowa etykieta), zamknij dropdown
- Po błędzie: `OrderProAlerts.alert(...)`, zamknij dropdown
- Klik poza dropdown: zamknij
- Obsługa wielu otwartych dropdown (tylko jeden naraz)
3. Skopiuj JS do `public/assets/js/modules/inline-status-change.js`
4. W `resources/scss/modules/_orders.scss`:
- Style dla `.orders-status-dropdown`: pozycja absolutna, max-height ze scroll, shadow, border-radius
- `.orders-status-dropdown__group-header`: etykieta grupy (muted, uppercase, mały font)
- `.orders-status-dropdown__item`: element opcji z kółkiem koloru i etykietą, hover state
- `.orders-status-dropdown__item.is-current`: wyróżnienie aktualnego statusu
- `.orders-status-wrap` cursor: pointer gdy dropdown aktywny
5. Zbuilduj SCSS do CSS
Unikaj: natywnych alert()/confirm(); inline CSS w widoku; jQuery (vanilla JS)
</action>
<verify>
- Na liście zamówień kliknięcie w status otwiera dropdown
- Wybór statusu zmienia badge bez przeładowania
- Kliknięcie poza dropdown zamyka go
- Build CSS przechodzi bez błędów
</verify>
<done>AC-1, AC-2, AC-3 satisfied: dropdown działa, AJAX zmienia status, błędy wyświetlane</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- resources/views/components/table-list.php (komponent generyczny — nie modyfikować)
- src/Modules/Orders/OrdersRepository.php (logika zapisu statusu działa poprawnie)
- database/migrations/* (brak zmian w schemacie)
- routes/web.php (endpoint POST /orders/{id}/status już istnieje)
## SCOPE LIMITS
- Tylko lista zamówień (/orders/list) — nie strona szczegółów
- Brak bulk zmiany statusu (tylko pojedyncze zamówienie)
- Brak drag & drop ani kanban — prosty dropdown
</boundaries>
<verification>
Before declaring plan complete:
- [ ] Kliknięcie badge na liście otwiera dropdown ze statusami
- [ ] Wybór statusu wysyła AJAX i aktualizuje badge
- [ ] Błędy wyświetlane przez OrderProAlerts
- [ ] Klik poza dropdown zamyka go
- [ ] Standardowy updateStatus (non-AJAX) nadal działa
- [ ] Build SCSS przechodzi bez błędów
- [ ] `php -l` na zmienionych plikach PHP bez błędów
</verification>
<success_criteria>
- Wszystkie taski ukończone
- Wszystkie kryteria akceptacji spełnione
- Brak błędów PHP syntax
- Build CSS bez błędów
- Zmiana statusu działa na liście bez przeładowania
</success_criteria>
<output>
After completion, create `.paul/phases/44-inline-status-change/44-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,123 @@
---
phase: 44-inline-status-change
plan: 01
subsystem: ui
tags: [ajax, dropdown, status, orders-list, vanilla-js]
requires:
- phase: none
provides: existing updateStatus() endpoint and status config
provides:
- Inline status change dropdown on orders list
- AJAX-enabled updateStatus() endpoint
affects: []
tech-stack:
added: []
patterns: [fixed-position dropdown to escape overflow:hidden containers]
key-files:
created:
- public/assets/js/modules/inline-status-change.js
modified:
- src/Modules/Orders/OrdersController.php
- resources/views/orders/list.php
- resources/scss/app.scss
- public/assets/css/app.css
key-decisions:
- "Fixed positioning for dropdown to escape table-wrap overflow:hidden"
- "AJAX with fallback — non-AJAX requests keep redirect behavior"
patterns-established:
- "AJAX endpoint pattern: detect X-Requested-With header, return JSON or redirect"
duration: ~15min
started: 2026-03-27
completed: 2026-03-27
---
# Phase 44 Plan 01: Inline Status Change Summary
**Klikalny dropdown zmiany statusu zamowienia bezposrednio z listy zamowien — AJAX bez przeladowania strony.**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~15min |
| Started | 2026-03-27 |
| Completed | 2026-03-27 |
| Tasks | 2 completed |
| Files modified | 5 |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Dropdown statusow po kliknieciu badge | Pass | Dropdown z pogrupowanymi statusami, aktualny wyrozniony |
| AC-2: Zmiana statusu przez AJAX | Pass | POST z X-Requested-With, badge aktualizowany in-place |
| AC-3: Obsluga bledow AJAX | Pass | OrderProAlerts.alert przy bledach, badge wraca do poprzedniego stanu |
## Accomplishments
- updateStatus() obsluguje AJAX (JSON response) i non-AJAX (redirect) w jednej metodzie
- Dropdown renderowany z position:fixed na document.body — nie ucinany przez overflow:hidden na table-wrap
- Optimistic update badge z rollback przy bledzie serwera
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `src/Modules/Orders/OrdersController.php` | Modified | AJAX w updateStatus(), allStatuses+statusColorMap do widoku, data-* na badge |
| `resources/views/orders/list.php` | Modified | JSON config block + script tag dla inline-status-change.js |
| `resources/scss/app.scss` | Modified | Style .orders-status-dropdown (fixed, grupy, hover, color dots) |
| `public/assets/css/app.css` | Rebuilt | Skompilowane style |
| `public/assets/js/modules/inline-status-change.js` | Created | Modul JS: dropdown, AJAX fetch, optimistic update, error handling |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| Fixed positioning zamiast absolute | table-wrap ma overflow:hidden — absolute dropdown ucinany | Dropdown widoczny niezaleznie od pozycji w tabeli |
| Dropdown na document.body | Jedyny sposob na unikniecie clip przez rodzicow | Wymaga getBoundingClientRect do pozycjonowania |
| Optimistic update z rollback | Szybsza percepcja — badge zmienia sie natychmiast | Przy bledzie badge wraca do poprzedniego stanu |
## Deviations from Plan
### Summary
| Type | Count | Impact |
|------|-------|--------|
| Auto-fixed | 1 | Niezbedna poprawka UX |
**Total impact:** Jedna poprawka pozycjonowania — zero scope creep.
### Auto-fixed Issues
**1. [UI] Dropdown ucinany przez overflow:hidden**
- **Found during:** Task 2 (UAT przez usera)
- **Issue:** `.table-wrap` ma `overflow: hidden` — dropdown renderowany wewnatrz byl ucinany
- **Fix:** Zmiana z `position: absolute` (wewnatrz wrap) na `position: fixed` (na document.body) z obliczaniem pozycji przez getBoundingClientRect
- **Files:** app.scss, inline-status-change.js
- **Verification:** User potwierdził poprawke
## Issues Encountered
None
## Next Phase Readiness
**Ready:**
- Inline status change dziala na liscie zamowien
- Endpoint updateStatus() gotowy do reuse w innych widokach
**Concerns:**
- None
**Blockers:**
- None
---
*Phase: 44-inline-status-change, Plan: 01*
*Completed: 2026-03-27*