diff --git a/.paul/PROJECT.md b/.paul/PROJECT.md index 39c3126..36b52fc 100644 --- a/.paul/PROJECT.md +++ b/.paul/PROJECT.md @@ -75,6 +75,7 @@ Sprzedawca moĹĽe obsĹ‚ugiwać zamĂłwienia ze wszystkich kanałów - [x] Data wystawienia paragonu z dokladnoscia do godziny i minuty (DATE -> DATETIME) — Phase 64 - [x] Koszt wysylki jako pozycja paragonu (bugfix buildItemsSnapshot + delivery_price) — Phase 70 - [x] Import atrybutow produktow z shopPRO (attributes + custom_fields w personalizacji) — Phase 71 +- [x] Zapamiętywanie wybranej liczby wierszy na stronie (per_page) w localStorage — Phase 72 - [ ] Eliminacja zduplikowanego kodu: SslCertificateResolver, ToggleableRepositoryTrait, RedirectPathResolver, ReceiptService — Phase 68 ### Active (In Progress) diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md index 3cc3412..e4336da 100644 --- a/.paul/ROADMAP.md +++ b/.paul/ROADMAP.md @@ -32,6 +32,7 @@ Wersja mobilna aplikacji, modul po module. Cel: pelna uzywalnosc orderPRO na tel | 69 | Allegro Tracking English Statuses | 1/1 | Complete | | 70 | Receipt Shipping Cost | 1/1 | Complete | | 71 | Attributes Import | 1/1 | Complete | +| 72 | Per Page Persistence | 1/1 | Complete | | TBD | Mobile Orders List | - | Not started | | TBD | Mobile Order Details | - | Not started | | TBD | Mobile Settings | - | Not started | diff --git a/.paul/STATE.md b/.paul/STATE.md index 37ef811..1cea329 100644 --- a/.paul/STATE.md +++ b/.paul/STATE.md @@ -5,19 +5,19 @@ See: .paul/PROJECT.md (updated 2026-04-07) **Core value:** Sprzedawca moze obslugiwac zamowienia ze wszystkich kanalow sprzedazy i nadawac przesylki bez przelaczania sie miedzy platformami. -**Current focus:** Milestone v3.0 - Phase 71 complete, ready for next PLAN +**Current focus:** Milestone v3.0 - Phase 72 complete, ready for next PLAN ## Current Position Milestone: v3.0 Mobile Responsive - In progress -Phase: 71 (Attributes Import) — Complete -Plan: 71-01 unified +Phase: 72 (Per Page Persistence) — Complete +Plan: 72-01 unified Status: Loop complete, ready for next PLAN -Last activity: 2026-04-07 — Unified .paul/phases/71-attributes-import/71-01-PLAN.md +Last activity: 2026-04-07 — Unified .paul/phases/72-per-page-persistence/72-01-PLAN.md Progress: -- Milestone: [#######...] ~74% -- Phase 71: [##########] 100% +- Milestone: [########..] ~75% +- Phase 72: [##########] 100% ## Loop Position @@ -30,11 +30,11 @@ PLAN --> APPLY --> UNIFY ## Session Continuity Last session: 2026-04-07 -Stopped at: Plan 71-01 unified +Stopped at: Plan 72-01 unified Next action: Run /paul:plan for the next prioritized phase -Resume file: .paul/phases/71-attributes-import/71-01-SUMMARY.md +Resume file: .paul/phases/72-per-page-persistence/72-01-SUMMARY.md ## Git State -Last commit: 278f44b +Last commit: 6d0905d Branch: main diff --git a/.paul/phases/72-per-page-persistence/72-01-PLAN.md b/.paul/phases/72-per-page-persistence/72-01-PLAN.md new file mode 100644 index 0000000..f42b551 --- /dev/null +++ b/.paul/phases/72-per-page-persistence/72-01-PLAN.md @@ -0,0 +1,124 @@ +--- +phase: 72-per-page-persistence +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: [resources/views/components/table-list.php] +autonomous: true +--- + + +## Goal +Zapamiętywanie wybranej liczby wierszy na stronie (per_page) w localStorage przeglądarki na liście zamówień i innych listach korzystających z komponentu table-list. + +## Purpose +Użytkownik zmienia per_page na 50 lub 100, ale po powrocie na listę wartość resetuje się do domyślnej 20. Zmiana powinna być trwała w danej przeglądarce. + +## Output +Zmodyfikowany `resources/views/components/table-list.php` — zapis per_page do localStorage przy zmianie i odczyt przy ładowaniu strony. + + + +## Source Files +@resources/views/components/table-list.php (linie 311-325 per-page selector, 329-432 localStorage, 428-432 change handler) + + + + +## AC-1: Zapis per_page do localStorage +```gherkin +Given użytkownik jest na liście zamówień z per_page=20 +When zmieni per_page na 50 +Then wartość 50 zostaje zapisana w localStorage pod kluczem tableList_[basePath]_[listKey]_per_page +``` + +## AC-2: Odczyt per_page z localStorage +```gherkin +Given użytkownik wcześniej wybrał per_page=50 (zapisane w localStorage) +When wchodzi na listę zamówień bez parametru per_page w URL +Then formularz per_page automatycznie ustawia 50 i strona przeładowuje się z per_page=50 +``` + +## AC-3: Parametr URL ma priorytet nad localStorage +```gherkin +Given użytkownik ma per_page=50 w localStorage +When wchodzi na listę z jawnym per_page=20 w URL +Then wyświetla 20 rekordów (URL ma priorytet) i localStorage zostaje zaktualizowane na 20 +``` + +## AC-4: Brak pętli przeładowań +```gherkin +Given użytkownik ma per_page=50 w localStorage i wchodzi na stronę +When strona przeładowuje się z per_page=50 +Then nie następuje kolejne przeładowanie (brak nieskończonej pętli) +``` + + + + + + + Task 1: Dodanie persistence per_page w table-list.php + resources/views/components/table-list.php + + 1. Dodać klucz localStorage: `var perPageKey = storagePrefix + '_per_page';` (obok istniejących filterKey, colsKey, queryKey ~linia 336) + + 2. W handlerze change selecta per_page (~linia 428-432): przed `form.submit()` zapisać wybraną wartość do localStorage: + `writeJson(perPageKey, parseInt(select.value, 10));` + + 3. Na końcu sekcji DOMContentLoaded (po istniejących restore bloków), dodać logikę restore per_page: + - Odczytać `readJson(perPageKey, null)` + - Jeśli wartość istnieje i jest różna od aktualnie wybranej w selekcie per_page: + - Sprawdzić czy per_page jest obecne w URL (URLSearchParams) + - Jeśli per_page NIE jest w URL (użytkownik wszedł bez jawnego parametru): + - Ustawić wartość w selekcie i submitować formularz (to spowoduje przeładowanie z prawidłowym per_page w URL) + - Jeśli per_page JEST w URL: zaktualizować localStorage z wartości z URL (sync) + - Jeśli wartość jest taka sama jak w selekcie: nic nie rób (brak pętli) + + Wzorzec: użyć istniejących helperów readJson/writeJson. + Unikać: nieskończonej pętli przeładowań — kluczowy warunek: nie submitować jeśli wartość w selekcie już odpowiada localStorage. + + + 1. Otworzyć /orders/list — domyślnie 20 + 2. Zmienić na 50 — strona przeładowuje z per_page=50 + 3. Wejść na /orders/list (bez per_page w URL) — automatycznie przeładuje z per_page=50 + 4. Wejść na /orders/list?per_page=20 — wyświetli 20 i zaktualizuje localStorage + 5. Sprawdzić brak pętli przeładowań + + AC-1, AC-2, AC-3, AC-4 satisfied + + + + + + +## DO NOT CHANGE +- Backend PHP (OrdersController, OrdersRepository) +- Struktura HTML per-page selectora +- Inne localStorage keys (filters_open, hidden_cols, query) + +## SCOPE LIMITS +- Tylko frontend JS w table-list.php +- Bez zmian backendu — per_page nadal przychodzi jako query param + + + + +Before declaring plan complete: +- [ ] Brak błędów JS w konsoli przeglądarki +- [ ] Per_page zapisuje się w localStorage po zmianie +- [ ] Per_page odtwarza się po wejściu bez parametru w URL +- [ ] Brak nieskończonej pętli przeładowań +- [ ] Inne listy (np. paragony) też korzystają z persistence + + + +- Wybrana liczba wierszy jest zapamiętywana w localStorage +- Wejście na listę bez per_page w URL automatycznie stosuje zapamiętaną wartość +- Brak regresji w istniejącej funkcjonalności table-list + + + +After completion, create `.paul/phases/72-per-page-persistence/72-01-SUMMARY.md` + diff --git a/.paul/phases/72-per-page-persistence/72-01-SUMMARY.md b/.paul/phases/72-per-page-persistence/72-01-SUMMARY.md new file mode 100644 index 0000000..fe7f6e0 --- /dev/null +++ b/.paul/phases/72-per-page-persistence/72-01-SUMMARY.md @@ -0,0 +1,94 @@ +--- +phase: 72-per-page-persistence +plan: 01 +subsystem: ui +tags: [localStorage, pagination, table-list, UX] + +requires: [] +provides: + - Per page persistence via localStorage for all table-list instances +affects: [] + +tech-stack: + added: [] + patterns: [per-page localStorage key in table-list component] + +key-files: + created: [] + modified: [resources/views/components/table-list.php] + +key-decisions: + - "Dedykowany klucz per_page zamiast polegania na query restore" + - "URL per_page ma priorytet nad localStorage — sync a nie override" + +patterns-established: + - "perPageKey = storagePrefix + '_per_page' — nowy klucz w rodzinie tableList_ storage" + +duration: 5min +started: 2026-04-07T12:20:00Z +completed: 2026-04-07T12:25:00Z +--- + +# Phase 72 Plan 01: Per Page Persistence Summary + +**Zapamiętywanie wybranej liczby wierszy w localStorage — per_page persist dla wszystkich list table-list.** + +## Performance + +| Metric | Value | +|--------|-------| +| Duration | ~5min | +| Tasks | 1 completed | +| Files modified | 1 | + +## Acceptance Criteria Results + +| Criterion | Status | Notes | +|-----------|--------|-------| +| AC-1: Zapis per_page do localStorage | Pass | writeJson przy change + sync z URL | +| AC-2: Odczyt per_page z localStorage | Pass | Auto-submit gdy brak per_page w URL | +| AC-3: URL ma priorytet nad localStorage | Pass | urlParams.has('per_page') → sync only | +| AC-4: Brak pętli przeładowań | Pass | Po submit URL zawiera per_page → brak ponownego submit | + +## Accomplishments + +- Dodano `perPageKey` do rodziny kluczy localStorage w table-list.php +- Zapis przy zmianie selecta per_page (przed submit) +- Odczyt i auto-redirect przy wejściu bez per_page w URL +- Sync localStorage z URL gdy per_page jawnie podane + +## Files Created/Modified + +| File | Change | Purpose | +|------|--------|---------| +| `resources/views/components/table-list.php` | Modified | perPageKey + save/restore logic | + +## Decisions Made + +| Decision | Rationale | Impact | +|----------|-----------|--------| +| Dedykowany klucz per_page | Query restore przywraca caly URL (status, page, search) — per_page powinien byc niezalezny | Mozna zmienic per_page bez resetowania filtrow | +| URL ma priorytet | Jawny link z per_page=20 powinien dzialac przewidywalnie | Brak niespodzianek przy linkach bookmarkowanych | + +## Deviations from Plan + +None — plan executed exactly as written + +## Issues Encountered + +None + +## Next Phase Readiness + +**Ready:** +- Wszystkie listy table-list automatycznie korzystaja z persistence per_page + +**Concerns:** +- None + +**Blockers:** +- None + +--- +*Phase: 72-per-page-persistence, Plan: 01* +*Completed: 2026-04-07* diff --git a/DOCS/TECH_CHANGELOG.md b/DOCS/TECH_CHANGELOG.md index 63727a6..e25a742 100644 --- a/DOCS/TECH_CHANGELOG.md +++ b/DOCS/TECH_CHANGELOG.md @@ -1,5 +1,13 @@ # Tech Changelog +## 2026-04-07 (Phase 72 - Per Page Persistence, Plan 01) +- `resources/views/components/table-list.php`: + - Dodano klucz localStorage `perPageKey` (`tableList_[path]_[key]_per_page`). + - Przy zmianie selecta per_page: zapis do localStorage przed submit formularza. + - Przy ladowaniu strony: odczyt z localStorage i auto-submit jesli per_page nie jest w URL. + - URL per_page ma priorytet nad localStorage (sync, nie override). +- Brak zmian backendu — per_page nadal przychodzi jako query param. + ## 2026-04-07 (Phase 71 - Attributes Import, Plan 01) - `ShopproOrderMapper::extractPersonalization()`: rozszerzono o odczyt pola `attributes` z API shopPRO. - Metoda iteruje po `['attributes', 'custom_fields']` i laczy niepuste wyniki separatorem `\n`. diff --git a/resources/views/components/table-list.php b/resources/views/components/table-list.php index 9b343f6..a09a933 100644 --- a/resources/views/components/table-list.php +++ b/resources/views/components/table-list.php @@ -337,6 +337,7 @@ $buildUrl = static function (array $params = []) use ($basePath, $query): string var colsKey = storagePrefix + '_hidden_cols'; var queryKey = storagePrefix + '_query'; var clearKey = storagePrefix + '_cleared'; + var perPageKey = storagePrefix + '_per_page'; function readJson(key, fallback) { try { @@ -427,9 +428,22 @@ $buildUrl = static function (array $params = []) use ($basePath, $query): string root.querySelectorAll('.js-per-page-select').forEach(function(select) { select.addEventListener('change', function() { + writeJson(perPageKey, parseInt(select.value, 10)); var form = select.closest('form'); if (form) form.submit(); }); + + var urlParams = new URLSearchParams(window.location.search); + if (urlParams.has('per_page')) { + writeJson(perPageKey, parseInt(select.value, 10)); + } else { + var savedPerPage = readJson(perPageKey, null); + if (savedPerPage !== null && parseInt(select.value, 10) !== savedPerPage) { + select.value = savedPerPage; + var form = select.closest('form'); + if (form) form.submit(); + } + } }); var selectAll = root.querySelector('.js-table-select-all');