Nowa metoda basketUpdateCustomFields() w ShopBasketController — AJAX endpoint z walidacją required fields, przeliczaniem product_code (MD5 hash) i merge duplikatów. UI: przycisk "Edytuj personalizację" + formularz inline + JS. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
115 lines
4.2 KiB
Markdown
115 lines
4.2 KiB
Markdown
---
|
|
phase: 10-basket-edit-custom-fields
|
|
plan: 01
|
|
subsystem: ui
|
|
tags: [basket, custom-fields, personalization, ajax, session]
|
|
|
|
requires:
|
|
- phase: none
|
|
provides: existing basket/custom fields infrastructure
|
|
|
|
provides:
|
|
- Edycja personalizacji produktu w koszyku (inline form + AJAX endpoint)
|
|
- Merge duplikatów przy identycznym product_code po edycji
|
|
|
|
affects: []
|
|
|
|
tech-stack:
|
|
added: []
|
|
patterns: [inline edit form with toggle display/edit, product_code recalculation]
|
|
|
|
key-files:
|
|
created: []
|
|
modified:
|
|
- autoload/front/Controllers/ShopBasketController.php
|
|
- templates/shop-basket/_partials/product-custom-fields.php
|
|
- templates/shop-basket/basket-details.php
|
|
- templates/shop-basket/basket.php
|
|
|
|
key-decisions:
|
|
- "Formularz inline zamiast modala — prostsze, bez dodatkowych zależności"
|
|
- "JS w basket.php zamiast basket-details.php — delegowane eventy działają po przeładowaniu AJAX"
|
|
- "ajax.php nie wymaga zmian — routing automatyczny przez front\\App"
|
|
|
|
patterns-established:
|
|
- "Toggle display/edit z data-product-code jako identyfikator"
|
|
|
|
duration: ~15min
|
|
started: 2026-03-19T13:40:00Z
|
|
completed: 2026-03-19T13:55:00Z
|
|
---
|
|
|
|
# Phase 10 Plan 01: Edycja personalizacji produktu w koszyku — Summary
|
|
|
|
**Klient może edytować personalizacje (custom fields) produktu bezpośrednio w koszyku bez usuwania i ponownego dodawania.**
|
|
|
|
## Performance
|
|
|
|
| Metric | Value |
|
|
|--------|-------|
|
|
| Duration | ~15 min |
|
|
| Tasks | 2 completed |
|
|
| Files modified | 4 |
|
|
| Tests | 820 passed, 0 failures |
|
|
|
|
## Acceptance Criteria Results
|
|
|
|
| Criterion | Status | Notes |
|
|
|-----------|--------|-------|
|
|
| AC-1: Przycisk edycji widoczny | Pass | Przycisk "Edytuj personalizację" przy pozycjach z custom fields, ukryty gdy brak |
|
|
| AC-2: Formularz z aktualnymi wartościami | Pass | Inline form z wypełnionymi wartościami, required oznaczone gwiazdką |
|
|
| AC-3: Zapis aktualizuje koszyk | Pass | AJAX POST → przeliczenie hash → reload strony |
|
|
| AC-4: Walidacja required | Pass | Client-side (input required + alert) + server-side (findCustomFieldCached + is_required check) |
|
|
| AC-5: Merge duplikatów | Pass | Gdy nowy hash == istniejący → sumowanie quantity, usunięcie starej pozycji |
|
|
|
|
## Accomplishments
|
|
|
|
- Endpoint `basketUpdateCustomFields()` w ShopBasketController z pełną logiką: walidacja, hash recalculation, merge
|
|
- UI: toggle display↔edit z formularzem inline, walidacja client-side
|
|
- XSS protection na wszystkich outputach (htmlspecialchars)
|
|
- Kompatybilność PHP < 8.0 (brak match, str_contains, union types)
|
|
|
|
## Files Created/Modified
|
|
|
|
| File | Change | Purpose |
|
|
|------|--------|---------|
|
|
| `autoload/front/Controllers/ShopBasketController.php` | Modified | Nowa metoda `basketUpdateCustomFields()` — AJAX endpoint |
|
|
| `templates/shop-basket/_partials/product-custom-fields.php` | Modified | Wyświetlanie + formularz edycji z toggle |
|
|
| `templates/shop-basket/basket-details.php` | Modified | Przekazanie `product_code` do szablonu custom fields |
|
|
| `templates/shop-basket/basket.php` | Modified | JavaScript: edycja, anulowanie, zapis AJAX |
|
|
|
|
## Deviations from Plan
|
|
|
|
### Summary
|
|
|
|
| Type | Count | Impact |
|
|
|------|-------|--------|
|
|
| Scope change | 2 | Minimalne — lepsze dopasowanie do architektury |
|
|
|
|
**Total impact:** Drobne odchylenia, brak wpływu na funkcjonalność.
|
|
|
|
### Details
|
|
|
|
1. **ajax.php nie zmodyfikowany** — plan zakładał rejestrację endpointu w ajax.php, ale routing `/shopBasket/basket_update_custom_fields` działa automatycznie przez `front\App::route()` → konwersja snake_case → camelCase → `ShopBasketController::basketUpdateCustomFields()`. Zmiana w ajax.php była niepotrzebna.
|
|
|
|
2. **JS w basket.php zamiast basket-details.php** — plan wskazywał basket-details.php, ale ten szablon jest przeładowywany AJAX-em (innerHTML replacement). Delegowane eventy muszą być w basket.php który jest stały. Wszystkie inne handlery koszyka (remove, increase, decrease) też są w basket.php.
|
|
|
|
## Issues Encountered
|
|
|
|
None.
|
|
|
|
## Next Phase Readiness
|
|
|
|
**Ready:**
|
|
- Edycja personalizacji w koszyku gotowa do testów manualnych na produkcji
|
|
|
|
**Concerns:**
|
|
- None
|
|
|
|
**Blockers:**
|
|
- None
|
|
|
|
---
|
|
*Phase: 10-basket-edit-custom-fields, Plan: 01*
|
|
*Completed: 2026-03-19*
|