This commit is contained in:
2026-04-12 01:35:19 +02:00
parent 91a8b85f38
commit d04e02020c
70 changed files with 8634 additions and 207 deletions

View File

@@ -0,0 +1,429 @@
---
phase: 94-order-preview-popup
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- src/Modules/Orders/OrdersController.php
- routes/web.php
- resources/views/orders/list.php
- resources/views/orders/partials/preview-modal.php
- resources/scss/app.scss
- resources/scss/components/_order-preview-modal.scss
- resources/lang/pl.php
autonomous: true
delegation: off
---
<objective>
## Goal
Dodanie przycisku "Podglad" na liscie zamowien, ktory otwiera popup (modal) ze szczegolami zamowienia. Uzytkownik moze szybko podejrzec dane i skopiowac je do schowka bez wchodzenia w szczegoly.
## Purpose
Oszczednosc czasu — sprzedawca nie musi wchodzic na strone szczegolowy zamowienia, zeby skopiowac adres, numer zamowienia, dane kupujacego itp. Jeden klik otwiera podglad z ikonami kopiowania.
## Output
- Endpoint AJAX: `GET /api/orders/{id}/preview` zwracajacy HTML fragmentu podgladu
- Partial: `resources/views/orders/partials/preview-modal.php` — modal overlay
- Przycisk oka w kolumnie `order_ref` kazdego wiersza na liscie
- Ikony kopiowania przy kluczowych polach (adres dostawy, kupujacy, nr zamowienia)
</objective>
<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
## Source Files
@src/Modules/Orders/OrdersController.php
@src/Modules/Orders/OrdersRepository.php
@resources/views/orders/list.php
@resources/views/orders/show.php
@resources/views/components/table-list.php
@resources/views/orders/partials/email-send-modal.php
@routes/web.php
@resources/scss/app.scss
@resources/lang/pl.php
</context>
<acceptance_criteria>
## AC-1: Przycisk podgladu widoczny na liscie zamowien
```gherkin
Given lista zamowien /orders/list jest wyswietlona
When uzytkownik widzi wiersz zamowienia
Then w kolumnie numeru zamowienia (order_ref) widoczna jest ikona oka (podglad)
And ikona ma tooltip "Podglad"
```
## AC-2: Klikniecie ikony otwiera popup z danymi zamowienia
```gherkin
Given lista zamowien jest wyswietlona
When uzytkownik klika ikone podgladu przy zamowieniu
Then otwiera sie modal overlay z danymi zamowienia zaladowanymi przez AJAX
And modal zawiera: dane kupujacego, adres dostawy, produkty, podsumowanie kwot, nr zamowienia
And podczas ladowania widoczny jest wskaznik ladowania (spinner/tekst)
```
## AC-3: Kopiowanie danych do schowka
```gherkin
Given popup podgladu zamowienia jest otwarty
When uzytkownik klika ikone kopiowania przy polu (np. adres dostawy, imie kupujacego, nr zamowienia)
Then tresc pola jest kopiowana do schowka
And pojawia sie krotkie potwierdzenie (np. zmiana ikony na checkmark na 1.5s)
```
## AC-4: Zamykanie popupu
```gherkin
Given popup podgladu jest otwarty
When uzytkownik klika przycisk X lub tlo (backdrop) lub naciska Escape
Then popup sie zamyka
```
## AC-5: Link do pelnych szczegolow z popupu
```gherkin
Given popup podgladu jest otwarty
When uzytkownik klika "Pelne szczegoly" w stopce popupu
Then zostaje przekierowany na /orders/{id}
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Endpoint AJAX preview + routing</name>
<files>
src/Modules/Orders/OrdersController.php,
routes/web.php
</files>
<action>
1. W `OrdersController` dodac metode `preview(Request $request): Response`:
- Pobierac `id` z request
- Wywolac `$this->orders->findDetails($orderId)` (istniejaca metoda)
- Jezeli null -> Response::json(['error' => 'Not found'], 404)
- Przygotowac dane do widoku: order, items, addresses (customer/delivery/invoice), payments summary
- Wyrenderowac partial `orders/partials/preview-content` (sam content, bez modala — modal jest w liscie)
- Zwrocic Response::html($html) (fragment HTML, nie pelna strona)
2. W `routes/web.php` dodac route:
```php
$router->get('/api/orders/{id}/preview', [$ordersController, 'preview'], [$authMiddleware]);
```
Dodac PO linii z `/api/orders/search`.
Metoda `preview()` renderuje partial BEZ layoutu (nie przekazywac layoutu do template->render).
Uzyc `$this->template->renderPartial('orders/partials/preview-content', $data)` lub render bez layoutu.
Sprawdzic jak dziala renderPartial w Template — jezeli nie istnieje, uzyc `render()` z trzecim parametrem null/pustym.
Avoid: NIE zwracac JSON — zwracamy gotowy HTML fragment do wstawienia w modal
</action>
<verify>
GET /api/orders/{id}/preview zwraca HTML fragment z danymi zamowienia (nie pelna strone)
</verify>
<done>AC-2 (backend) satisfied — endpoint zwraca HTML podgladu</done>
</task>
<task type="auto">
<name>Task 2: Modal partial + przycisk w liscie + JS fetch + kopiowanie</name>
<files>
resources/views/orders/partials/preview-modal.php,
resources/views/orders/list.php,
src/Modules/Orders/OrdersController.php
</files>
<action>
**preview-modal.php** — kontener modala (pusty, wypelniany AJAXem):
```php
<div class="order-preview-overlay" id="order-preview-overlay" style="display:none">
<div class="order-preview-modal">
<div class="order-preview-modal__header">
<h3 class="order-preview-modal__title">Podglad zamowienia</h3>
<button type="button" class="order-preview-modal__close" id="order-preview-close">&times;</button>
</div>
<div class="order-preview-modal__body" id="order-preview-body">
<div class="order-preview-loading">Ladowanie...</div>
</div>
<div class="order-preview-modal__footer">
<a href="#" class="btn btn--primary btn--sm" id="order-preview-details-link">Pelne szczegoly</a>
<button type="button" class="btn btn--secondary btn--sm" id="order-preview-close-btn">Zamknij</button>
</div>
</div>
</div>
```
**preview-content partial** (renderowane przez endpoint, wstawiane do #order-preview-body):
Nowy plik `resources/views/orders/partials/preview-content.php`:
- Sekcja: Kupujacy (imie, email, telefon) — z ikonami kopiowania (data-copy-value)
- Sekcja: Nr zamowienia (internal_order_number, external_order_id) — z ikonami kopiowania
- Sekcja: Adres dostawy (pelny adres sformatowany w jednej linii) — z ikona kopiowania calego adresu
- Sekcja: Produkty — lista (nazwa, qty, cena) — kompaktowa tabela
- Sekcja: Podsumowanie (total, oplacono, waluta, typ platnosci)
Kazde pole z kopiowaniem: `<span class="copy-field" data-copy-value="WARTOSC"><span class="copy-field__text">WARTOSC</span><button type="button" class="copy-field__btn" title="Kopiuj">&#x1F4CB;</button></span>`
Zamiast emoji uzyc SVG inline lub znaku Unicode — np. ikona clipboard (ten sam pattern co Phase 92 buyer name copy).
**list.php** — dodac:
1. Na koncu pliku (przed zamykajacym tagiem) dolaczyc partial: `<?php require __DIR__ . '/partials/preview-modal.php'; ?>`
2. Dolaczyc skrypt JS (inline lub osobny plik) obslugi:
**JS w list.php** (inline `<script>`):
- Delegacja klikniecia: `document.addEventListener('click', ...)` na `.js-order-preview-btn`
- Po kliknieciu:
a) Pobrac `data-order-id` z przycisku
b) Otworzyc overlay (display:flex)
c) Ustawic body na "Ladowanie..."
d) fetch(`/api/orders/${id}/preview`) → wstawic HTML do `#order-preview-body`
e) Ustawic href `#order-preview-details-link` na `/orders/${id}`
- Zamykanie: klik X, klik backdrop (overlay), Escape
- Delegacja kopiowania: klik na `.copy-field__btn`:
a) Pobrac `data-copy-value` z rodzica `.copy-field`
b) `navigator.clipboard.writeText(value)`
c) Zmienic ikone na checkmark (✓) na 1.5s, potem przywrocic
**OrdersController::toTableRow()** — dodac ikone podgladu w kolumnie `order_ref`:
Dodac przycisk z ikona oka PRZED linkiem zamowienia:
```php
'<button type="button" class="btn-icon js-order-preview-btn" data-order-id="' . (int) ($row['id'] ?? 0) . '" title="Podglad">&#x1F441;</button>'
```
Uzyc ikony SVG inline lub unicode eye (👁) — preferowac prosty SVG jak w istniejacych ikonach projektu.
Dodac ten przycisk w `order_ref` HTML, np. na poczatku diva `orders-ref`.
Avoid:
- NIE uzywac natywnych alert()/confirm()
- NIE ladowac pelnej strony w modalu (tylko fragment)
- NIE dodawac nowych zaleznosci JS
</action>
<verify>
1. Na liscie zamowien widoczna ikona oka przy kazdym zamowieniu
2. Klikniecie ikony otwiera modal z danymi zamowienia (AJAX)
3. Ikona kopiowania kopiuje dane do schowka
4. X / backdrop / Escape zamyka modal
5. "Pelne szczegoly" prowadzi do /orders/{id}
</verify>
<done>AC-1, AC-2, AC-3, AC-4, AC-5 satisfied</done>
</task>
<task type="auto">
<name>Task 3: Style SCSS + tlumaczenia</name>
<files>
resources/scss/components/_order-preview-modal.scss,
resources/scss/app.scss,
resources/lang/pl.php
</files>
<action>
**_order-preview-modal.scss** — nowy plik SCSS:
```scss
.order-preview-overlay {
position: fixed;
inset: 0;
z-index: 1000;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.order-preview-modal {
background: var(--c-surface);
border: 1px solid var(--c-border);
border-radius: 10px;
box-shadow: 0 16px 48px rgba(0,0,0,0.18);
width: 100%;
max-width: 640px;
max-height: 85vh;
display: flex;
flex-direction: column;
&__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
border-bottom: 1px solid var(--c-border);
}
&__title {
font-size: 16px;
font-weight: 600;
margin: 0;
}
&__close {
background: none;
border: none;
font-size: 22px;
cursor: pointer;
color: var(--c-muted);
padding: 0 4px;
line-height: 1;
&:hover { color: var(--c-text); }
}
&__body {
padding: 16px 20px;
overflow-y: auto;
flex: 1;
}
&__footer {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
padding: 12px 20px;
border-top: 1px solid var(--c-border);
}
}
.order-preview-loading {
text-align: center;
padding: 32px;
color: var(--c-muted);
}
.order-preview-section {
margin-bottom: 14px;
&__title {
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
color: var(--c-muted);
margin-bottom: 6px;
letter-spacing: 0.04em;
}
}
.order-preview-kv {
display: grid;
grid-template-columns: auto 1fr;
gap: 2px 12px;
font-size: 13px;
dt { color: var(--c-muted); white-space: nowrap; }
dd { margin: 0; }
}
.order-preview-items {
width: 100%;
font-size: 13px;
border-collapse: collapse;
th, td { padding: 4px 8px; text-align: left; }
th { font-weight: 600; font-size: 11px; text-transform: uppercase; color: var(--c-muted); }
tbody tr + tr { border-top: 1px solid var(--c-border); }
}
.copy-field {
display: inline-flex;
align-items: center;
gap: 4px;
&__btn {
background: none;
border: none;
cursor: pointer;
font-size: 13px;
color: var(--c-muted);
padding: 0 2px;
line-height: 1;
opacity: 0.6;
transition: opacity 0.15s;
&:hover { opacity: 1; color: var(--c-primary, #4f6ef7); }
&.is-copied { color: #22c55e; opacity: 1; }
}
}
.btn-icon.js-order-preview-btn {
background: none;
border: none;
cursor: pointer;
font-size: 14px;
color: var(--c-muted);
padding: 2px 4px;
line-height: 1;
opacity: 0.6;
transition: opacity 0.15s;
vertical-align: middle;
&:hover { opacity: 1; color: var(--c-primary, #4f6ef7); }
}
```
**app.scss** — dodac import:
Znalezc istniejace importy komponentow i dodac: `@use "components/order-preview-modal";`
**pl.php** — dodac klucze tlumaczen w sekcji `orders`:
```php
'preview' => [
'title' => 'Podglad zamowienia',
'buyer' => 'Kupujacy',
'order_number' => 'Nr zamowienia',
'delivery_address' => 'Adres dostawy',
'products' => 'Produkty',
'summary' => 'Podsumowanie',
'full_details' => 'Pelne szczegoly',
'close' => 'Zamknij',
'loading' => 'Ladowanie...',
'copy_tooltip' => 'Kopiuj',
],
```
Po zmianach: `npm run build:css`
Avoid: NIE trzymac styli w pliku widoku — SCSS w osobnym pliku
</action>
<verify>
1. SCSS buduje sie bez bledow
2. Modal ma poprawne style — centrowany, zaokraglony, z cieniem
3. Ikony kopiowania sa widoczne i reaguja na hover
4. Tlumaczenia dostepne w pl.php
</verify>
<done>AC-1 (style), AC-2 (style), AC-3 (style) satisfied</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- resources/views/components/table-list.php (komponent reuzywany — nie modyfikowac)
- src/Modules/Orders/OrdersRepository.php (findDetails juz istnieje — uzyc bez zmian)
- resources/views/orders/show.php (strona szczegolow — bez zmian)
- resources/views/orders/partials/email-send-modal.php (istniejacy modal — bez zmian)
## SCOPE LIMITS
- Nie dodajemy edycji z popupu — tylko podglad i kopiowanie
- Nie dodajemy nowych zaleznosci npm/composer
- Nie modyfikujemy OrdersRepository — uzywamy istniejacego findDetails()
- Popup nie obsluguje akcji (zmiana statusu, platnosc itp.)
</boundaries>
<verification>
Before declaring plan complete:
- [ ] Ikona oka widoczna w kolumnie nr zamowienia na /orders/list
- [ ] Klikniecie ikony otwiera modal z danymi zamowienia (AJAX fetch)
- [ ] Dane w modalu: kupujacy, adres dostawy, produkty, podsumowanie
- [ ] Ikony kopiowania dzialaja (clipboard API)
- [ ] Zamykanie: X, backdrop, Escape
- [ ] "Pelne szczegoly" prowadzi do /orders/{id}
- [ ] SCSS zbudowane do CSS
- [ ] Brak bledow w konsoli przegladarki
- [ ] All acceptance criteria met
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- No errors or warnings introduced
- Uzytkownik moze szybko podejrzec i skopiowac dane zamowienia z listy
</success_criteria>
<output>
After completion, create `.paul/phases/94-order-preview-popup/94-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,125 @@
---
phase: 94-order-preview-popup
plan: 01
subsystem: ui
tags: [modal, preview, clipboard, orders-list, ajax]
requires: []
provides:
- Order preview popup on orders list with copy-to-clipboard
- AJAX endpoint GET /api/orders/{id}/preview returning HTML fragment
affects: []
tech-stack:
added: []
patterns: [ajax-html-fragment-modal, copy-to-clipboard-svg-feedback]
key-files:
created:
- resources/views/orders/partials/preview-content.php
- resources/views/orders/partials/preview-modal.php
- resources/scss/modules/_order-preview-modal.scss
modified:
- src/Modules/Orders/OrdersController.php
- routes/web.php
- resources/views/orders/list.php
- resources/scss/app.scss
- resources/lang/pl.php
key-decisions:
- "Server-rendered HTML fragment (nie JSON) — prostsze wstawienie do modala"
- "Ikona oka w kolumnie order_ref (nie osobna kolumna akcji)"
- "Clipboard API + SVG copy/check feedback (ten sam pattern co Phase 92)"
- "Modal 820px szerokosci, 90vh wysokosci — wieksza przestrzen na dane"
patterns-established:
- "AJAX preview modal: fetch HTML fragment, wstaw do body modala, delegacja eventow"
duration: ~12min
started: 2026-04-10
completed: 2026-04-10
---
# Phase 94 Plan 01: Order Preview Popup Summary
**Popup podgladu zamowienia na liscie zamowien z kopiowaniem danych, zdjeciami produktow, personalizacja i notatkami klienta**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~12min |
| Started | 2026-04-10 |
| Completed | 2026-04-10 |
| Tasks | 3 completed |
| Files modified | 10 |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Przycisk podgladu widoczny | Pass | Ikona oka SVG w kolumnie order_ref |
| AC-2: Popup z danymi zamowienia | Pass | AJAX fetch, HTML fragment, kupujacy/adres/produkty/kwoty/notatki |
| AC-3: Kopiowanie do schowka | Pass | Clipboard API + checkmark feedback 1.5s |
| AC-4: Zamykanie popupu | Pass | X / backdrop / Escape |
| AC-5: Link do pelnych szczegolow | Pass | Przycisk "Pelne szczegoly" -> /orders/{id} |
## Accomplishments
- Popup podgladu zamowienia z danymi kupujacego, adresem dostawy, produktami (ze zdjeciami i personalizacja), notatkami klienta i podsumowaniem kwot
- Kopiowanie do schowka kluczowych danych (nazwa kupujacego, email, nr zamowienia, caly adres, notatki)
- Endpoint AJAX zwracajacy HTML fragment (server-rendered, bez layoutu)
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `resources/views/orders/partials/preview-content.php` | Created | Tresc podgladu (server-rendered HTML) |
| `resources/views/orders/partials/preview-modal.php` | Created | Kontener modala overlay |
| `resources/scss/modules/_order-preview-modal.scss` | Created | Style modala, miniaturek, personalizacji, notatek |
| `src/Modules/Orders/OrdersController.php` | Modified | Metoda preview() + ikona oka w toTableRow() |
| `routes/web.php` | Modified | Route GET /api/orders/{id}/preview |
| `resources/views/orders/list.php` | Modified | Include modala + JS (fetch, kopiowanie, Escape) |
| `resources/scss/app.scss` | Modified | Import order-preview-modal |
| `resources/lang/pl.php` | Modified | Klucze orders.preview.* |
| `public/assets/css/app.css` | Modified | Zbudowany z SCSS |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| HTML fragment zamiast JSON | Prostsze — brak potrzeby budowania DOM w JS | Mniejszy JS, latwiejsze utrzymanie |
| Modal 820px | Wiecej miejsca na zdjecia i personalizacje | Lepszy UX |
| Notatki klienta w podgladzie | Czesto potrzebne do szybkiego skopiowania wiadomosci | Oszczednosc klikniec |
## Deviations from Plan
### Scope additions
| Type | Count | Impact |
|------|-------|--------|
| Scope additions | 3 | Na prosbe uzytkownika — zdjecia produktow, personalizacja, notatki klienta |
- Zdjecia produktow (miniaturki 36x36px) dodane na prosbe uzytkownika
- Personalizacja pozycji wyswietlana pod nazwa produktu
- Sekcja "Wiadomosc od klienta" z notatkami zamowienia
- Modal powiekszony z 640px do 820px
## Issues Encountered
None.
## Next Phase Readiness
**Ready:**
- Popup gotowy do uzycia, brak dalszych zmian potrzebnych
**Concerns:**
- None
**Blockers:**
- None
---
*Phase: 94-order-preview-popup, Plan: 01*
*Completed: 2026-04-10*