# STATE.md ## Current Position Milestone: v0.1 Naprawa nowego layoutu strony produktu Phase: 2 of 2 (Product actions fixes) — **COMPLETE** (02-01/02/03/04/05 closed) Plan: 02-05 (struktura materiału w POST payload) — UNIFY ✓ Status: Phase 02 COMPLETE. 5 plans shipped + verified. Ready for phase transition + milestone finalization. Last activity: 2026-04-24 — Plan 02-05 UNIFY complete. Phase transition pending. Progress: - Milestone: [██████████] 99% (Phase 1 ✓; Phase 2 ✓; pending transition/IP gate removal) - Phase 1: [██████████] 100% - Phase 2: [██████████] 100% (02-01 ✓, 02-02 PARTIAL closed, 02-03 ✓, 02-04 ✓, 02-05 ✓; 02-06 cache-buster deferred nice-to-have) **MILESTONE READINESS:** Ready na transition + IP gate removal. Plan 02-06 (cache-buster) nie jest blocker. ## Loop Position Current loop state: ``` PLAN ──▶ APPLY ──▶ UNIFY ✓ ✓ ✓ [Plan 02-05 loop closed — Phase 02 COMPLETE] ``` ## Session Continuity Last session: 2026-04-24 Stopped at: Plan 02-05 UNIFY ✓ — Phase 02 (Product actions fixes) COMPLETE. 5 plans shipped, 2 files modified (custom.js + product.tpl). Next action: Phase transition (git commit feat(02-product-actions-fixes)) → milestone completion decision (IP gate removal). Resume file: `.paul/phases/02-product-actions-fixes/02-05-SUMMARY.md` ## Accumulated Context ### Git State Last commit: `ac03f80` feat(02-product-actions-fixes): Phase 02 complete Branch: main Feature branches merged: none ### Decisions (Phase 01) | Data | Decyzja | Wpływ | |---|---|---| | 2026-04-23 | Rozszerzenie scope Task 1 o wrapper `
` | Bez niego PS nie może AJAX-ować wariantu — konieczne do realizacji AC-2 | | 2026-04-23 | Ręczny AJAX w custom.js zamiast fake `.product-actions` | PS core handler szuka formy przez `.product-actions` — unikam dodawania problematycznej klasy (kolizja stylów), piszę własny flow | | 2026-04-23 | Edytuj tylko `custom.scss`, nie `custom.css` | User ma własny watcher SCSS — manualne zmiany w CSS są nadpisywane | | 2026-04-23 | In-place DOM update zamiast full redirect | User feedback "na starym layoucie działało bez reloadu" — `history.pushState` + manual replace `.product-prices` / `.product_image_wrapper` | | 2026-04-23 | `action=refresh` (nie `productrefresh`) | Empiryczne probowanie endpointów — `productrefresh` zwracał pustą odpowiedź | ### Decisions (Phase 02 — Plan 02-01) | Data | Decyzja | Wpływ | |---|---|---| | 2026-04-23 | Priorytet: piece/crop przed add-to-cart | User zmienił priorytety z ROADMAP — konfigurator fragmentu krytyczny dla produktu („na wymiar") | | 2026-04-23 | `#piece` reużywany z shared partial `product-cover-thumbnails.tpl` | Pierwotna próba dodania osobnego `
` tworzyła duplikat ID — rozwiązanie: reuse istniejącego + inherit stylowania ze starego SCSS | | 2026-04-23 | Override `totalpriceinfospecific` + `prod` na no-op w nowym layoucie | ⚠️ **WYWOŁAŁO regresję squaremeter customization flow**: hook wymaga `discretion=on` + dimension fields ktore były synchronizowane przez tę funkcję. Plan 02-02 ujawnił że customization nie zapisuje się. Do fix'u w Plan 02-03. | | 2026-04-23 | DOM stubs wstrzykiwane przez JS (nie template) | Smarty template cache + FTP sync delay — JS deploy'uje się niezawodniej. | | 2026-04-23 | Piece NIE auto-init'uje się na load — pojawia się tylko po kliknięciu trigger'a popupu | User feedback w trakcie checkpoint — zmiana wymaganej behawiorystyki vs pierwotny plan | | 2026-04-23 | Defensive `.pp_stick_parent` guard w fancybox handler | Element istnieje tylko w starym layoucie — bez guard'a popup aborts przed `$.fancybox()` w nowym | ### Decisions (Phase 02 — Plan 02-05) | Data | Decyzja | Wpływ | |---|---|---| | 2026-04-24 | Enumerate wszystkie `[name^="group["]` spoza formy zamiast hardcode group[5] | Future-proof — kolejne PS attribute groups automatycznie pokryte bez dalszych zmian kodu. | | 2026-04-24 | Defensive `closest('#add-to-cart-or-refresh').length` check | Unika double-include gdyby przyszly refactor przesunął select do formy. Robustne. | | 2026-04-24 | Filter radio/checkbox przez `:checked` | `[name^="group["]` łapie wszystkie radios z grupy (nie-checked też). Bez filtra payload by zawierał sprzeczne wartości. | ### Decisions (Phase 02 — Plan 02-04) | Data | Decyzja | Wpływ | |---|---|---| | 2026-04-24 | Scope pivot mid-task: label obok "Dodaj do koszyka" zamiast nadpisywania `.current-price` | User polecenie w trakcie Task 3 verification: "właściwą cenę jako napis obok Dodaj do koszyka. Ta cena u góry od xxx zł niech będzie stała." Gorna cena zostaje static info, konkretna suma blisko buttona. | | 2026-04-24 | Separate `__p02p04Bound` guard zamiast shared `__p02p02Bound` (vs. pierwotny plan) | Stale-cache safety: gdy browser cache'uje stare custom.js (bez P04) + fresh product.tpl (z P04 inline), shared guard by zablokowal inline rejestracje. Separate guard = niezalezna rejestracja. | | 2026-04-24 | Synchronous `__p02p04TryInitial()` zamiast `jQuery(document).ready` | jQuery ready w inline script wewnatrz Smarty `{block name='content'}` nie firuje konsekwentnie (function defined, callback nigdy nie wywolany). Synchronous call + interval early-return pokrywa DOM-not-ready case. | | 2026-04-24 | setInterval 10×500ms (5s okno) zamiast single retry | Squaremeter init overwrituje `.current-price` po pierwszym recalc. Pure interval reliably pokrywa late-override + late DOM stubs injection. Po expire user ma pelna reaktywnosc na input events. | | 2026-04-24 | Poll-retry rejestracja `prestashop.on('updatedProduct')` | `window.prestashop` moze nie istniec w momencie inline script parse (bundle loads po). Poll co 200ms az dostepny. AC-4 dziala niezawodnie. | | 2026-04-24 | Inline `style=""` na labelce zamiast SCSS edit | Unika dependency na user watcher + SCSS build. MVP widocznosc. Pozniejszy plan moze przeniesc do tokenow motywu. | ### Decisions (Phase 02 — Plan 02-03) | Data | Decyzja | Wpływ | |---|---|---| | 2026-04-24 | Playwright capture z flipped IP → ground truth 26-field OLD payload | Bez tego pominęlibyśmy verbose dim format i kluczowe pola (qty_alt/qty_alth osobno od qty). | | 2026-04-24 | Move inline script INSIDE `{block name='content'}` | **KRYTYCZNE:** Smarty `{extends}` renderuje TYLKO blocki. Inline script z Plan 02-02 był MIĘDZY `{/block}` i `{/if}` — dead code przez cały czas. Plan 02-02 AC-3 przechodził przez custom.js, nie przez "inline mirror". | | 2026-04-24 | basePrice przez `meta[property="product:price:amount"]` fallback | `#product_base_price`/`#product_fixed_price` są w shared OLD partial, nie w NEW layout. Meta tag działa w obu. | | 2026-04-24 | `__p02p02InFlight` re-entrancy guard | `__p02p02Bound` nie wystarczył — POST firował 2×. Guard reset przez `complete:` callback. Root cause doubling niepotwierdzony, ale guard skuteczny. | | 2026-04-24 | Manual FTP upload via curl | ftp-kr VSCode extension nie łapie edycji z Claude Code Edit tool (watcher issue). `curl -T ftp://` jako work-around. | | 2026-04-24 | Używać verbose Polish dim string (nie "200x150") | Squaremeter customization display w cart oczekuje tego formatu. | ### Decisions (Phase 02 — Plan 02-02) | Data | Decyzja | Wpływ | |---|---|---| | 2026-04-23 | Plan 02-02 = submission + cart widget (bez ceny) | Cena wydzielona do Plan 02-03 dla scope 2-3 task. W trakcie APPLY odkryto że customization + modal TEŻ są w Plan 02-03. | | 2026-04-23 | Task 1 = live diagnosis (checkpoint:human-verify) | Playwright ujawnił: button+qty są POZA formą `#add-to-cart-or-refresh` — PS core `closest('form')` zwraca 0, POST nigdy nie wychodzi. | | 2026-04-23 | Wybór S3 (własny AJAX submit handler) | S2 (restrukturyzacja form) naruszałoby Bootstrap grid + shared partial risk. S3 bezpieczniejsze. | | 2026-04-23 | Capture-phase native addEventListener (useCapture=true) zamiast jQuery `.on()` | Pierwsza iteracja dubluje POST (PS core i nasz oba firują). Capture phase fires PRZED bubble — całkowicie blokuje PS core. Verified. | | 2026-04-23 | Manual blockcart refresh po emit('updatedCart') | Natural PS listener nie odświeżał widget w nowym layoucie. Defensive $.get fallback działał. | | 2026-04-23 | Inline script mirror w product.tpl + idempotency guard | Browser cache serwuje old custom.js (transferSize=0). Inline HTML response zawsze fresh. Guard `window.__p02p02Bound` chroni przed double-register. | | 2026-04-23 | UNIFY Plan 02-02 jako PARTIAL | Core POST działa ale: (a) customization nie zapisuje się — squaremeter hook gate'owany `discretion=on` z brakującymi polami, (b) success modal brak — wymaga osobny POST do `/module/ps_shoppingcart/ajax`. Delegowane Plan 02-03. | ### Open observations (do kolejnych planów Phase 02) - **Plan 02-03 (wymagany dla production) — Customization + modal + cena + cache-buster:** - Przywrócić squaremeter dimension flow zamiast Plan 02-01 no-op override (`totalpriceinfospecific` / `prod`). Synchronizować pola: `discretion=on`, `dim`, `qty`, `qty_alth`, `product_total_price_calc`, `extrafeevalue`, `wastevalue`, `calculated_total`, `grand_calculated_total`, `converted_ea`, `directinput`, `qty_alt`, `qty_altd`, `width_module`, `height_module`, `unittype_module`. - Po udanym POST do `/koszyk` → drugi POST do `/module/ps_shoppingcart/ajax?action=add-to-cart` → pokazać modal (resp.modal HTML) z "Kontynuuj zakupy / Przejdź do koszyka". - Cena per-sqm calculation w UI (live update przy zmianie piece dimensions / qty). - Systemowy cache-buster `?v=` dla `