Plan 02-03: Customization save + success modal (5/5 AC)
- 26-field squaremeter POST payload (verbose PL dim, qty_alt/qty_alth)
- Chain POST /module/ps_shoppingcart/ajax -> Bootstrap #blockcart-modal
- Critical fix: moved {/block} so inline script actually renders
- __p02p02InFlight re-entrancy guard
Plan 02-04: Live cena per-sqm label obok "Dodaj do koszyka" (5/5 AC)
- .p02p04-total-price label, gorna .current-price static
- Separate __p02p04Bound + setInterval reconciliation
- Poll-retry prestashop.on registration
Plan 02-05: Struktura materialu w POST payload (4/4 AC)
- Enumerate [name^="group["] spoza formy, doklej do payload
- Fix: group_5 select w .product-bar-box nie trafial do koszyka
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
72 lines
7.7 KiB
Markdown
72 lines
7.7 KiB
Markdown
# PROJECT.md
|
||
|
||
## Name
|
||
newwalls.pl — PrestaShop 1.7 (theme: ayon)
|
||
|
||
## Mission
|
||
Sklep z tapetami na wymiar. Klient prowadzi migrację wyglądu strony produktu na nowy layout. Do czasu zakończenia testów nowy layout jest warunkowany IP administratora.
|
||
|
||
## Core Constraints
|
||
- Stary i nowy wygląd strony produktu współegzystują w `themes/ayon/templates/catalog/product.tpl`:
|
||
- Stary layout: `{if $smarty.server.REMOTE_ADDR != '89.69.31.86'} ... {/if}`
|
||
- Nowy layout: `{if $smarty.server.REMOTE_ADDR == '89.69.31.86'} ... {/if}`
|
||
- Nie wolno modyfikować starego layoutu (produkcja działa dla zwykłych użytkowników).
|
||
- Partial `themes/ayon/templates/catalog/_partials/product-variants.tpl` jest współdzielony — zmiany w nim muszą być zgodne z oboma layoutami.
|
||
- Stack: PrestaShop 1.7, Smarty, jQuery, SCSS (`themes/ayon/assets/css/custom.scss` → `custom.css`).
|
||
|
||
## Value Proposition
|
||
Nowy layout strony produktu ma dać czystszy, bardziej prezentowalny UI konfiguratora tapety przy zachowaniu dotychczasowej funkcjonalności (wybór wariantu kolorystycznego, wymiary, dodanie do koszyka itd.).
|
||
|
||
## Known Broken After Redesign
|
||
|
||
### ✅ Naprawione (Phase 01)
|
||
- `.product-variants` (wariant kolorystyczny) — wygląd grid 3×1 wg Figma 27:9867 + klik zmienia wariant in-place (AJAX `action=refresh` + `history.pushState`).
|
||
|
||
### ✅ Naprawione (Phase 02)
|
||
- **Konfigurator „piece"** (Plan 02-01) — crop + odbicie lustrzane, drag + mirror, re-init po AJAX refresh. Reuse `#piece` z shared partial.
|
||
- **Add-to-cart submission** (Plan 02-02) — capture-phase native handler w custom.js + inline mirror, blockcart refresh, idempotency guard. Button+qty poza formą `#add-to-cart-or-refresh` — manualny serialize + POST.
|
||
- **Customization save + success modal** (Plan 02-03) — full squaremeter payload (26 fields, verbose PL dim), chain POST do `/module/ps_shoppingcart/ajax` → Bootstrap `#blockcart-modal`. `__p02p02InFlight` re-entrancy guard. Inline script finally renders (Plan 02-03 `{/block}` move).
|
||
- **Live cena labelka** (Plan 02-04) — `.p02p04-total-price` obok "Dodaj do koszyka", reactively updates z piece dimensions + variant AJAX refresh. Górna `.current-price` zostaje statyczna info-label.
|
||
- **Struktura materiału w POST payload** (Plan 02-05) — enumeracja external PS attribute groups (`[name^="group["]` poza formą) w POST payload. Wybrana „Tekstura materiału" (`<select id="group_5">`) trafia do koszyka z prawidłowym `id_product_attribute`.
|
||
|
||
### ⚠️ Do naprawy (Phase 03+ / deferred)
|
||
- **Plan 02-06 (deferred nice-to-have)** — systemowy cache-buster `?v=<mtime>` dla `<script src=custom.js>`; pozwoli wycofac inline mirror z Plan 02-02/02-03/02-04/02-05.
|
||
- **Plan 02-07** — Puste bloki `<div class="product-box--data"></div>`: `product-protect`, `product-installation`, `product-order-sample` — wypełnić treścią.
|
||
- Brakujące elementy dla pełnego PS `updatedProduct` flow (`.product-cover-thumbnails`, `.js-product-images2-modal`, `.product-details`, `.product-customization`, `.product-additional-info`) — edge case'y przy zmianie wariantu z różnymi miniaturami/opisami.
|
||
- Resize handles bezpośrednio na `#piece` (deferred bonus z Plan 02-01).
|
||
|
||
## Established Patterns (Phase 01)
|
||
- **Scoped CSS under `body#product .product-variants-data--new`** — izoluje zmiany nowego layoutu od globalnych reguł i starego widoku.
|
||
- **Własny AJAX refresh w `custom.js`** — `action=refresh` (nie `productrefresh`), POST na `window.location.href.split('?')[0].split('#')[0]`, `dataType: 'json'`, header `Accept: application/json`.
|
||
- **In-place DOM update**: `history.pushState(resp.product_url)` + `$('.product-prices-data .product-prices').replaceWith(resp.product_prices)` + `$('.product_image_wrapper').html(resp.product_cover_thumbnails)` + `prestashop.emit('updatedProduct', resp)`. Fallback na `window.location.reload()` przy błędzie.
|
||
- **Pipeline SCSS → CSS**: edytuj tylko `themes/ayon/assets/css/custom.scss`, `custom.css` auto-generowany przez user'a watcher (feedback memory).
|
||
|
||
## Established Patterns (Phase 02)
|
||
- **Capture-phase native addEventListener + `useCapture=true`** — blokuje PS core delegated handlers (bubble phase) w customowym flow, gdy trzeba całkowicie nadpisać PS behavior (Plan 02-02).
|
||
- **Idempotency guard per Plan** (`__p02pNNBound`) — kazdy plan ma own flag, nie shared; chroni inline mirror przed blokada gdy custom.js cached stale. Separate guards pozwalaja na plan-level cache-aware deployment (Plan 02-02/03/04).
|
||
- **Re-entrancy flag** (`__pNNInFlight`) — chroni przed podwójnym POST gdy handler i inline mirror oba firują. Reset w `complete:` callback jQuery.ajax (Plan 02-03).
|
||
- **Inline mirror IIFE w `{block name='content'}`** — `<script>` wewnatrz Smarty block, cache-safety dopóki systemowego cache-bustera (Plan 02-05) nie ma. `{/block}` musi zamykac się PO script (Plan 02-03 critical fix).
|
||
- **Playwright MCP ground truth capture** — temporary flip IP gate → capture 26-field OLD payload przed portowaniem do NEW (Plan 02-03). Bez tego verbose PL dim format i `qty_alt`/`qty_alth` by zostaly pominiete.
|
||
- **Manual FTP deploy via `curl -T ftp://...`** — ftp-kr VSCode watcher nie łapie zmian Claude Code Edit tool (feedback memory). Deploy 226 confirmation per file.
|
||
- **Poll-retry dla late globals** (`prestashop`, itp.) — inline script runtime, `window.prestashop` moze jeszcze nie istniec. `(function fn(){ if (avail) register(); else setTimeout(fn, 200); })()` niezawodnie obsługuje race (Plan 02-04).
|
||
- **Synchronous IIFE init zamiast jQuery(document).ready** — ready nie firuje konsekwentnie w inline Smarty block context. Synchronous call + recalc-safe early-return pokrywa DOM-not-ready case (Plan 02-04).
|
||
- **setInterval reconciliation** gdy external code overwritea nasz DOM po initial render (np. squaremeter init). 10×500ms okno = 5s pokrycie (Plan 02-04).
|
||
- **External PS attribute groups enumeration** — `[name^="group["]` inputs spoza `#add-to-cart-or-refresh` muszą być ręcznie enumerowane i dołączane do payload (`$form.serialize()` ich nie łapie). Defensive `closest('#form').length` skip (unika duplicate gdy kiedyś przesunięte do formy) + filter radio/checkbox przez `:checked` (Plan 02-05).
|
||
|
||
## Key Decisions (aggregated)
|
||
|
||
| Data | Faza/Plan | Decyzja | Wpływ |
|
||
|---|---|---|---|
|
||
| 2026-04-23 | 01-01 | Własny AJAX `action=refresh` + `history.pushState` zamiast PS core productrefresh | In-place wariant switch bez reload; base pattern dla wszystkich subsequent AJAX updates w NEW layoucie |
|
||
| 2026-04-23 | 02-01 | Override `totalpriceinfospecific`/`prod` na no-op | Spowodowało regresję squaremeter customization flow (Plan 02-02/03 fix); no-op zostaje ale fields syncowane manualnie w POST |
|
||
| 2026-04-23 | 02-02 | Capture-phase native handler (useCapture=true) | Pattern dla blokowania PS core bubble handlers przy customowym flow |
|
||
| 2026-04-23 | 02-02 | Inline mirror IIFE w product.tpl | Cache-safety dopóki Plan 02-05 nie dostarczy systemowego cache-bustera |
|
||
| 2026-04-24 | 02-03 | Playwright capture z flipped IP → ground truth payload | Bez tego verbose PL dim format + fields (qty_alt/qty_alth/calculated_total itp.) zostałyby pominięte; dał 5/5 AC pass |
|
||
| 2026-04-24 | 02-03 | Move `{/block}` inside script wrapper | Krytyczne: Smarty `{extends}` renderuje TYLKO blocki; inline script z Plan 02-02 był dead code przez cały czas |
|
||
| 2026-04-24 | 02-04 | Scope pivot: label zamiast `.current-price` | User request mid-task; górna cena zostaje info-label, konkretna suma blisko buttona |
|
||
| 2026-04-24 | 02-04 | Poll-retry prestashop.on + separate __p02p04Bound | Late-loading globals + stale-cache safety |
|
||
| 2026-04-24 | 02-05 | Enumerate `[name^="group["]` spoza formy → payload | Future-proof: kolejne PS attribute groups pokryte automatycznie bez code change |
|
||
|
||
---
|
||
*Last updated: 2026-04-24 after Phase 02 (5 plans)*
|