---
phase: 120-alert-component-unification
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - resources/scss/shared/_ui-components.scss
  - resources/views/components/alert.php
  - public/assets/js/modules/alert-dismiss.js
  - resources/views/layouts/app.php
  - resources/views/layouts/auth.php
  - resources/views/layouts/public.php
  - src/Core/Support/Flash.php
  - resources/views/settings/fakturownia.php
  - resources/views/settings/accounting-invoice-edit.php
  - resources/views/settings/smsplanet.php
  - resources/views/settings/hostedsms.php
  - resources/views/settings/accounting.php
  - resources/views/settings/accounting-receipt-edit.php
  - resources/views/settings/accounting-receipts.php
  - resources/views/settings/accounting-invoices.php
  - resources/views/accounting/invoice_form.php
  - resources/views/users/index.php
  - resources/views/statistics/orders.php
  - resources/views/settings/statuses.php
  - resources/views/settings/shoppro.php
  - resources/views/settings/printing.php
  - resources/views/settings/project-mappings.php
  - resources/views/settings/integrations.php
  - resources/views/settings/email-templates.php
  - resources/views/settings/inpost.php
  - resources/views/settings/email-templates-form.php
  - resources/views/settings/email-mailboxes.php
  - resources/views/settings/delivery-statuses.php
  - resources/views/settings/database.php
  - resources/views/settings/delivery-status-form.php
  - resources/views/settings/cron.php
  - resources/views/settings/company.php
  - resources/views/settings/apaczka.php
  - resources/views/settings/allegro.php
  - resources/views/orders/receipt-create.php
  - resources/views/orders/list.php
  - resources/views/automation/index.php
  - resources/views/automation/form.php
  - resources/views/auth/login.php
autonomous: true
delegation: off
---

<objective>
## Goal
Ujednolicic alerty/flash messages w calej aplikacji: reusable komponent widoku, brakujacy wariant `--info`, ikony i dismiss button, centralny renderer flash w layoutach. Po teście połączenia w `/settings/integrations/fakturownia` alert "OK (HTTP 200)" pojawia sie jako wyraznie wystylizowany `alert--info` z ikona i mozliwoscia zamkniecia.

## Purpose
Obecnie 34 widoki uzywaja inline `<div class="alert alert--TYPE">` z roznym wzorcem; brak `.alert--info` powoduje czarny tekst na bialym tle (bug widoczny w fakturownia.php). Brak centralnego renderowania flash zmusza kazdy controller+widok do recznego przekazywania zmiennych `$flashSave/$flashTest/$flashError`. Jedno zrodlo prawdy upraszcza UX i przyszle utrzymanie.

## Output
- `resources/views/components/alert.php` (komponent z paramami `$type`, `$message`, `$dismissible`)
- `resources/scss/shared/_ui-components.scss` z `.alert--info`, ikonami i stylami dismiss
- `public/assets/js/modules/alert-dismiss.js` (vanilla JS, idempotent guard)
- `src/Core/Support/Flash.php` rozszerzone o `push()` + `all()` z zachowaniem `set()/get()` (BC)
- Centralny render flash w `layouts/app.php` (+ `auth.php`, `public.php`)
- Migracja 34 widokow na komponent + zamiana `.flash--*` w login.php
</objective>

<context>
<clarifications>
- **Zakres** — Jak szeroki zakres migracji widokow w tej fazie?
  → Odpowiedz: Komponent + migracja wszystkich (34 widoki).
- **Funkcje** — Jakie warianty i funkcje ma obslugiwac komponent alert?
  → Odpowiedz: Wariant info (brakujacy), Ikona per typ (info/success/warning/danger), Przycisk dismiss (×). Auto-hide pominiete.
- **Flash legacy** — Czy ujednolicic rowniez stary wzorzec `.flash--error` (login.php) z nowym `.alert--*`?
  → Odpowiedz: Tak, zastapic `.flash--*` przez `.alert--*`.
- **Flash render** — Czy wyswietlanie alertow z sesji (Flash::get) zrobic tez przez komponent (centralny render np. w layoucie)?
  → Odpowiedz: Centralny renderer flash w layoucie app.php (i auth/public).
</clarifications>

## Project Context
@.paul/PROJECT.md
@.paul/STATE.md
@.paul/codebase/architecture.md

## Source Files
@resources/scss/shared/_ui-components.scss
@resources/views/settings/fakturownia.php
@resources/views/layouts/app.php
@resources/views/auth/login.php
@src/Core/Support/Flash.php
</context>

<acceptance_criteria>

## AC-1: Komponent alert + brakujacy wariant info
```gherkin
Given uzytkownik otwiera /settings/integrations/fakturownia i wykonuje udany test polaczenia
When kontroler ustawia Flash::push('info', 'OK (HTTP 200)') i widok renderuje sie ponownie
Then na gorze strony pokazuje sie alert z niebieskim tlem (#eff6ff), niebieska ramka, ikona "i" po lewej, tekstem "OK (HTTP 200)" w czytelnym kontraście oraz przyciskiem × po prawej; klikniecie × usuwa alert z DOM bez przeladowania
```

## AC-2: Centralny renderer flash w layoutach
```gherkin
Given kontroler wywoluje Flash::push('success', 'Zapisano') albo legacy Flash::set('module.save', 'Zapisano')
When renderowany jest widok dziedziczacy z layouts/app.php (lub auth.php / public.php)
Then layout automatycznie wyswietla wszystkie zakolejkowane flash entries u gory glownego obszaru, bez koniecznosci ifow w widoku; po pobraniu Flash::all() kolejne zadanie nie pokazuje juz tych wpisow
```

## AC-3: Migracja widokow i flash--error
```gherkin
Given kazdy z 34 widokow wymienionych w files_modified
When przegladam ich kod
Then zaden nie zawiera inline `<div class="alert alert--...">` z zmiennymi flash (zamiast tego uzywa komponentu lub renderowanie jest delegowane do layoutu); login.php nie zawiera klasy `.flash--error` (zostala zastapiona alert--danger przez komponent); wizualnie alerty na fakturownia/hostedsms/smsplanet/login wygladaja identycznie i spojnie
```

</acceptance_criteria>

<tasks>

<task type="auto">
  <name>Task 1: Komponent alert + SCSS info/ikony/dismiss + JS</name>
  <files>
    resources/scss/shared/_ui-components.scss,
    resources/views/components/alert.php,
    public/assets/js/modules/alert-dismiss.js,
    resources/views/layouts/app.php,
    resources/views/layouts/auth.php,
    resources/views/layouts/public.php
  </files>
  <action>
    1) SCSS — w `_ui-components.scss` po istniejacych `.alert--success/warning/danger` dodac:
       - `.alert` — display: flex; gap: 10px; align-items: flex-start; (zachowac padding/border-radius/border/font-size/min-height)
       - `.alert__icon` — flex: 0 0 18px; line-height: 1; svg width/height 18px; color: inherit
       - `.alert__body` — flex: 1; line-height: 1.4
       - `.alert__dismiss` — margin-left: auto; background: none; border: 0; cursor: pointer; padding: 2px 6px; color: inherit; opacity: 0.6; &:hover { opacity: 1 }
       - `.alert--info` — border-color: #bfdbfe; background: #eff6ff; color: #1e3a8a
       - Subtelnie wzmocnic kontrast tla istniejacych wariantow tylko jezeli wymaga to drobnej zmiany (np. zostawic jak jest dla --success/warning/danger).
    2) `resources/views/components/alert.php` — komponent renderujacy 1 alert. Params (przez extract):
       - `$type` (string, default 'info') — jeden z: info|success|warning|danger
       - `$message` (string) — escapowany przez `$e()`; alternatywnie `$messageHtml` (trusted HTML, opcjonalnie)
       - `$dismissible` (bool, default true)
       - Markup: `<div class="alert alert--{type}" role="alert" data-alert>` + `<span class="alert__icon" aria-hidden="true">{svgIconForType}</span>` + `<div class="alert__body">{message}</div>` + dismiss button (jezeli `$dismissible`).
       - Mapping typ → svg inline (info: i in circle; success: check; warning: triangle !; danger: x in circle). Trzymac SVG inline jako private map array `$ICONS` zdefiniowany w komponencie.
       - Walidacja: gdy `$type` nie z whitelist → fallback `info`.
    3) `public/assets/js/modules/alert-dismiss.js` — vanilla JS:
       - Idempotent guard: `if (window.__alertDismissBound) return; window.__alertDismissBound = true;`
       - `document.addEventListener('click', (e) => { const btn = e.target.closest('[data-alert-dismiss]'); if (!btn) return; const alert = btn.closest('[data-alert]'); if (alert) alert.remove(); });`
       - Brak zewnetrznych zaleznosci, brak jQuery.
    4) Layouty (`app.php`, `auth.php`, `public.php`):
       - Dodac `<link rel="stylesheet" href="/assets/css/app.css?ver=...">` juz istnieje — pliki SCSS sa kompilowane recznie (poza zakresem), nie ruszamy build pipeline.
       - Dodac `<script src="/assets/js/modules/alert-dismiss.js?ver=...">` przed `</body>` (analogicznie do innych modulow).
       - Dodac centralny render flash entries: na poczatku glownego content area, ITERACJA po `App\Core\Support\Flash::all()` i wywolanie komponentu `alert.php` dla kazdego wpisu `{type, message}`. Wzor:
         ```php
         <?php foreach (\App\Core\Support\Flash::all() as $entry): ?>
           <?php $type = (string) ($entry['type'] ?? 'info'); $message = (string) ($entry['message'] ?? ''); $dismissible = true; include __DIR__ . '/../components/alert.php'; ?>
         <?php endforeach; ?>
         ```
       - W `app.php` umiescic blok zaraz po otwarciu `<main>` (lub odpowiednim content wrap, znalezc grep "app-shell__main" / "content").
       - W `auth.php` i `public.php` — analogicznie, u gory glownego obszaru.
    Avoid:
       - Nie dodawac jQuery / bundlerow.
       - Nie zmieniac wygladu istniejacych alertow --success/--warning/--danger (poza dodaniem __icon + dismiss).
       - SVG inline (nie eksternalizowac do osobnych plikow).
  </action>
  <verify>
    1) `grep -rn "alert--info" resources/scss/shared/_ui-components.scss` zwraca definicje.
    2) Plik `resources/views/components/alert.php` istnieje i zawiera `<div class="alert alert--<?= $type ?>"`.
    3) `grep -rn "Flash::all" resources/views/layouts/` zwraca 3 wystapienia (app/auth/public).
    4) Ladowanie strony /settings/integrations/fakturownia po tescie polaczenia pokazuje niebieski alert info z ikona i przyciskiem × (manualny smoke test po skompilowaniu SCSS).
  </verify>
  <done>AC-1, AC-2 spelnione w zakresie infrastruktury (komponent + central render + style + JS).</done>
</task>

<task type="auto">
  <name>Task 2: Flash::push/all + BC dla Flash::set/get</name>
  <files>src/Core/Support/Flash.php</files>
  <action>
    Rozszerzyc `App\Core\Support\Flash` o kolejke typowanych wpisow przy zachowaniu wstecznej kompatybilnosci.
    1) Dodac sekcje kolejki w sesji: `$_SESSION['_flash_queue']` (lista `['type' => string, 'message' => string]`).
    2) Nowa metoda: `public static function push(string $type, string $message): void`
       - Whitelist `$type`: info/success/warning/danger; fallback 'info'.
       - Append do `$_SESSION['_flash_queue']`.
    3) Nowa metoda: `public static function all(): array`
       - Zwraca i CZYSCI kolejke (consume-once).
       - Dodatkowo: skanuje legacy `$_SESSION['_flash']` (klucz-string => wartosc-string) i konwertuje do typowanych entries:
         - klucz konczacy sie na `.error` lub zawierajacy `error` → type=danger
         - klucz konczacy sie na `.save` / `.success` / zawierajacy `success`/`saved`/`saved` → type=success
         - klucz zawierajacy `warning` → type=warning
         - reszta (`.test`, `.info`, etc.) → type=info
       - Po konsumpcji czysci `_flash` analogicznie do `get()`.
       - Zachowac kolejnosc: najpierw push-queue, potem legacy.
    4) `set()`/`get()` pozostaja bez zmian (BC) — nie czyscic ich z `all()` jezeli `get()` nie zostal jeszcze wywolany; tj. `all()` POBIERA wszystkie pozostale legacy entries (controllery zwykle juz pobraly konkretne klucze przed renderem, wiec layout konsumuje to co zostalo).
    5) Brak zmian sygnatury istniejacych metod, brak removed methods.
  </action>
  <verify>
    1) `grep -n "public static function push" src/Core/Support/Flash.php` → 1 match.
    2) `grep -n "public static function all" src/Core/Support/Flash.php` → 1 match.
    3) Recznie: w widoku `Flash::set('fakturownia.test', 'OK (HTTP 200)'); Flash::all()` zwraca `[['type'=>'info','message'=>'OK (HTTP 200)']]`.
  </verify>
  <done>AC-2 spelnione w warstwie logiki (sesja → typowane entries).</done>
</task>

<task type="auto">
  <name>Task 3: Migracja 34 widokow + login flash--error</name>
  <files>
    resources/views/settings/fakturownia.php, resources/views/settings/accounting-invoice-edit.php,
    resources/views/settings/smsplanet.php, resources/views/settings/hostedsms.php,
    resources/views/settings/accounting.php, resources/views/settings/accounting-receipt-edit.php,
    resources/views/settings/accounting-receipts.php, resources/views/settings/accounting-invoices.php,
    resources/views/accounting/invoice_form.php, resources/views/users/index.php,
    resources/views/statistics/orders.php, resources/views/settings/statuses.php,
    resources/views/settings/shoppro.php, resources/views/settings/printing.php,
    resources/views/settings/project-mappings.php, resources/views/settings/integrations.php,
    resources/views/settings/email-templates.php, resources/views/settings/inpost.php,
    resources/views/settings/email-templates-form.php, resources/views/settings/email-mailboxes.php,
    resources/views/settings/delivery-statuses.php, resources/views/settings/database.php,
    resources/views/settings/delivery-status-form.php, resources/views/settings/cron.php,
    resources/views/settings/company.php, resources/views/settings/apaczka.php,
    resources/views/settings/allegro.php, resources/views/orders/receipt-create.php,
    resources/views/orders/list.php, resources/views/automation/index.php,
    resources/views/automation/form.php, resources/views/auth/login.php
  </files>
  <action>
    Strategia migracji per widok:
    1) Usunac inline bloki `<?php if ($flashXxx !== ''): ?><div class="alert alert--TYPE" role="...">...</div><?php endif; ?>`
       — flash wyswietlany jest teraz centralnie przez layout (Flash::all() → komponent).
       Kontrolery NIE wymagaja zmian w tej fazie (Flash::set zachowuje BC i jest konsumowany przez `Flash::all()` w layoucie).
    2) Dla alertow NIE-flashowych (np. statyczne komunikaty/stany w widoku, nie z sesji) — zamienic na include komponentu:
       ```php
       <?php $type='info'; $message='...'; $dismissible=false; include dirname(__DIR__) . '/components/alert.php'; ?>
       ```
       Sprawdzic kazdy widok — jezeli alert jest oparty na zmiennej $flashXxx (z sesji), usunac caly blok. Jezeli alert pokazuje stan biezacy (np. "Brak konfiguracji"), zostawic ale przepuscic przez komponent.
    3) `resources/views/auth/login.php` — zamienic `<div class="flash flash--error">...</div>` (lub podobny) na include komponentu `alert.php` z `$type='danger'`. Usunac wszystkie odwolania `.flash--error` w tym pliku. Login uzywa `layouts/auth.php` — flash messages tez przejda przez centralny render.
    4) Po migracji NIE usuwac SCSS `.flash--error` jeszcze (separate cleanup task w przyszlosci) — wystarczy ze nie jest uzywany w widokach.
    5) Smoke test recznie po kazdej grupie modulow (settings/, automation/, orders/, auth/) — sprawdzic w przegladarce ze flash success/error/info wyglada jak zaprojektowano.
    Avoid:
       - Nie dotykac kontrolerow (BC przez Flash::all() w layoucie).
       - Nie zmieniac semantyki: jezeli widok renderowal blad jako `alert--danger`, po migracji ma byc nadal danger.
       - Nie usuwac role="alert" / role="status" — komponent ma `role="alert"` na stale.
  </action>
  <verify>
    1) `grep -rn 'class="alert alert--' resources/views/` zwraca tylko `resources/views/components/alert.php` (komponent jest jedynym renderem).
    2) `grep -rn 'flash--error' resources/views/` zwraca 0 wynikow.
    3) `grep -rn '\$flashError\|\$flashSave\|\$flashTest' resources/views/` zwraca 0 wynikow lub tylko miejsca gdzie zmienna jest przekazywana z kontrolera ale nie renderowana (akceptowalne — kontroler i tak ja przekazuje, layout konsumuje przez Flash::all()).
    4) Smoke: /settings/integrations/fakturownia → test polaczenia → niebieski alert info z ikona i ×; klik × usuwa alert; reload strony nie pokazuje go ponownie.
    5) /auth/login z bledem logowania → czerwony alert danger z ikona.
  </verify>
  <done>AC-3 spelnione: 34 widoki + login zmigrowane, flash--error usuniety z widokow, wszystkie alerty wygladaja spojnie.</done>
</task>

</tasks>

<boundaries>

## DO NOT CHANGE
- `src/Modules/**/*Controller.php` — kontrolery dalej uzywaja `Flash::set('module.key', '...')` (BC).
- `resources/modules/jquery-alerts/` — modul dialogow OrderProAlerts (osobny system, nie alerty stronowe).
- `resources/scss/modules/_customer-risk-alert.scss` — inny komponent (banner ostrzezenia o kliencie).
- Istniejace warianty `.alert--success`, `.alert--warning`, `.alert--danger` (zachowac kolory; mozna tylko dodac `__icon`/`__dismiss` strukture).

## SCOPE LIMITS
- Brak migracji kontrolerow na `Flash::push()` w tej fazie (BC zapewnia layout przez `Flash::all()`).
- Brak auto-hide (timer JS) — zdjete z zakresu w odpowiedzi clarifications.
- Brak usuwania SCSS `.flash--error` z `_ui-components.scss` (deferred cleanup).
- Brak nowych endpointow API ani migracji DB.
- Build SCSS → CSS jest robiony recznie przez operatora poza tym planem; plan modyfikuje pliki .scss, ale `public/assets/css/app.css` zostanie zregenerowany osobno (operator/build pipeline).

</boundaries>

<verification>
Before declaring plan complete:
- [ ] `grep -rn 'class="alert alert--' resources/views/` → tylko `components/alert.php`
- [ ] `grep -rn 'flash--error' resources/views/` → 0
- [ ] `grep -rn 'Flash::all' resources/views/layouts/` → 3
- [ ] Manual smoke: /settings/integrations/fakturownia po teste polaczenia → niebieski alert info z ikona + dismiss
- [ ] Manual smoke: /auth/login z blednym haslem → czerwony alert danger z ikona
- [ ] Manual smoke: zapis dowolnego ustawienia (np. fakturownia save) → zielony alert success
- [ ] AC-1, AC-2, AC-3 wszystkie spelnione
</verification>

<success_criteria>
- Komponent `alert.php` jest jedynym renderem alertu w widokach.
- `.alert--info` istnieje i ma czytelny kontrast.
- Centralny renderer flash dziala w 3 layoutach (app/auth/public).
- Flash::push/all dodane bez breakingu Flash::set/get.
- 34 widoki + login zmigrowane, brak inline `<div class="alert alert--...">` z flash zmiennymi.
</success_criteria>

<output>
After completion, create `.paul/phases/120-alert-component-unification/120-01-SUMMARY.md`
</output>
