---
phase: 120-alert-component-unification
plan: 01
subsystem: ui
tags: [alerts, flash, components, scss, php-view, accessibility, dismissable]

requires:
  - phase: 113-fakturownia-foundation
    provides: Flash usage pattern, fakturownia.php view (bug reporter)
  - phase: 118-fakturownia-single-instance
    provides: fakturownia.php single-form view that exposed missing .alert--info

provides:
  - Reusable view component for alerts (`resources/views/components/alert.php`)
  - .alert--info SCSS variant + flex layout with icon/body/dismiss
  - Dismiss JS module (`alert-dismiss.js`) with delegated click handler
  - Flash::push(type, message) + Flash::all() with legacy heuristic
  - Central flash renderer in 3 layouts (app/auth/public)
  - 36 views migrated off inline alert markup

affects: [future settings views, future Flash::push usage, login UX, any new admin views]

tech-stack:
  added: []
  patterns:
    - Component include with extracted locals (`$type`, `$message`, `$dismissible`, `$messageHtml`)
    - Central renderer in layout consuming queued + legacy flash entries
    - Idempotent vanilla JS modules guarded via window flags

key-files:
  created:
    - resources/views/components/alert.php
    - public/assets/js/modules/alert-dismiss.js
  modified:
    - resources/scss/shared/_ui-components.scss
    - public/assets/css/app.css (rebuilt)
    - public/assets/css/login.css (rebuilt)
    - src/Core/Support/Flash.php
    - resources/views/layouts/app.php
    - resources/views/layouts/auth.php
    - resources/views/layouts/public.php

key-decisions:
  - "Component-based view include over template engine partial - no DI needed, BC z `extract` pattern"
  - "Flash::set/get pozostawione BC; kontrolery NIE dotykane - migracja widokow wystarczyla"
  - "Heurystyka klucza legacy (`.save`/`error`/`warning`) zamiast wymuszania Flash::push - migracja stopniowa"
  - "messageHtml jako trusted opt-in dla wpisow z markup (uvaga: lista faktur/paragonow/debug pre)"
  - "JS alerty w email-mailboxes.php pozostawione na klasach SCSS - markup komponentu poza zakresem"

patterns-established:
  - "Alert markup: `<?php $type=...; $message=...; $dismissible=...; include dirname(__DIR__) . '/components/alert.php'; ?>`"
  - "Trusted HTML w alert: ob_start() ... $messageHtml = ob_get_clean(); include ...; unset($messageHtml);"
  - "Central layout flash render: foreach Flash::all() → include components/alert.php (wrap .alerts-stack)"

duration: ~50min
started: 2026-05-12T15:00:00Z
completed: 2026-05-12T15:40:00Z
---

# Phase 120 Plan 01: Alert Component Unification

**Reusable PHP alert component z `.alert--info` (brakujacy wariant), inline SVG ikona per typ, dismiss button + central Flash renderer w 3 layoutach; 36 widokow zmigrowanych.**

## Performance

| Metric | Value |
|--------|-------|
| Duration | ~50 minut |
| Started | 2026-05-12T15:00:00Z |
| Completed | 2026-05-12T15:40:00Z |
| Tasks | 3 z 3 ukonczone |
| Files modified | 42 (component + JS + SCSS + 3 layouty + Flash + 36 widokow + 2 CSS rebuilds) |

## Acceptance Criteria Results

| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Komponent alert + brakujacy wariant info | Pass | `.alert--info` (#eff6ff/#bfdbfe/#1e3a8a) w `app.css` zweryfikowany; ikona SVG + dismiss × renderowane przez `components/alert.php`. Test polaczenia fakturownia → niebieski alert z ikona "i" i ×. |
| AC-2: Centralny renderer flash w layoutach | Pass | `Flash::all()` w `app.php`, `auth.php`, `public.php` (3 hits w grep); typowana kolejka push + legacy fallback z heurystyka klucza. |
| AC-3: Migracja widokow + flash--error | Pass | `grep 'class="alert alert--' resources/views/` → tylko `components/alert.php`; `grep 'flash--' resources/views/` → 0. 36 widokow przeszlo `php -l`. |

## Accomplishments

- Component-based alert markup dostepny w jednym pliku — `resources/views/components/alert.php` z ikonami SVG inline per typ (info/success/warning/danger) i opcjonalnym dismiss.
- Brakujacy `.alert--info` (#eff6ff bg, #1e3a8a tekst, #bfdbfe border) — zwerfikowany w skompilowanym `public/assets/css/app.css` (63 560 B, rebuilt via `npx sass`).
- `Flash::push(type, message)` + `Flash::all()` z BC dla `Flash::set/get` — heurystyka klucza legacy mapuje `.save/.created/.deleted/.toggled/success` → success, `error/fail/danger` → danger, `warning` → warning, reszta → info.
- Central flash renderer w 3 layoutach (`app.php`, `auth.php`, `public.php`) — przyszle `Flash::push()` zadziala bez ifow w widokach.
- 36 widokow zmigrowanych off inline `<div class="alert alert--TYPE">` (34 z planu + odkryte `orders/show.php` i `shipments/prepare.php` ze starym wzorcem `.flash--error/success`).
- Vanilla JS dismiss z idempotent guardem + delegated click handlerem — brak duplikowanego bindowania.

## Task Commits

Brak atomowych commits per task — caly plan zostanie wyemitowany jako single commit w transition phase (zgodnie z konwencja projektu, faza 119/118 dziedzicza ten wzorzec).

| Task | Commit | Type | Description |
|------|--------|------|-------------|
| Task 1: Komponent + SCSS + JS + layouty | (transition) | feat | Alert component, SCSS info/icon/dismiss, JS, central layout render |
| Task 2: Flash push/all + BC | (transition) | feat | Flash::push/all + legacy heuristic |
| Task 3: Migracja 36 widokow | (transition) | refactor | Inline alert/flash markup → component include |

## Files Created/Modified

| File | Change | Purpose |
|------|--------|---------|
| `resources/views/components/alert.php` | Created | Reusable alert component z ikona/body/dismiss |
| `public/assets/js/modules/alert-dismiss.js` | Created | Vanilla JS dismiss z idempotent guardem |
| `resources/scss/shared/_ui-components.scss` | Modified | `.alert` flex + `__icon`/`__body`/`__dismiss`, `.alert--info`, `.alerts-stack` |
| `public/assets/css/app.css` | Rebuilt | Wygenerowany z SCSS (`npx sass --style=compressed`) |
| `public/assets/css/login.css` | Rebuilt | Wygenerowany z SCSS |
| `src/Core/Support/Flash.php` | Modified | `push()`, `all()`, `inferTypeFromKey()` (private); BC dla `set/get` |
| `resources/views/layouts/app.php` | Modified | Central flash render + `alert-dismiss.js` script tag |
| `resources/views/layouts/auth.php` | Modified | Central flash render + `alert-dismiss.js` script tag |
| `resources/views/layouts/public.php` | Modified | Central flash render + `alert-dismiss.js` script tag |
| `resources/views/settings/fakturownia.php` | Modified | Inline alerts → component (bug reporter) |
| `resources/views/settings/{hostedsms,smsplanet,inpost,apaczka,allegro,company,cron,database,delivery-statuses,delivery-status-form,email-mailboxes,email-templates,email-templates-form,integrations,printing,project-mappings,shoppro,statuses,accounting,accounting-receipts,accounting-receipt-edit,accounting-invoices,accounting-invoice-edit}.php` | Modified | Inline alerts → component (23 plikow) |
| `resources/views/orders/{list,show,receipt-create}.php` | Modified | Inline alerts + `.flash--*` → component (3 pliki) |
| `resources/views/shipments/prepare.php` | Modified | 4× `.flash--error` → component |
| `resources/views/accounting/invoice_form.php` | Modified | Inline alerts + warning HTML → component z `$messageHtml` |
| `resources/views/automation/{index,form}.php` | Modified | Inline alerts → component |
| `resources/views/users/index.php` | Modified | Inline alerts → component |
| `resources/views/statistics/orders.php` | Modified | Debug warning HTML → component z `$messageHtml` |
| `resources/views/auth/login.php` | Modified | `.alert--danger login-alert` → component (`flash--error` flow) |
| `.paul/codebase/architecture.md` | Modified | Sekcja "Phase 120 — Alert Component Unification" |
| `.paul/codebase/tech_changelog.md` | Modified | Wpis dla Phase 120 |

## Decisions Made

| Decision | Rationale | Impact |
|----------|-----------|--------|
| Component przez `include` z extracted locals zamiast template helper | Zero infrastruktury, BC z istniejacym wzorcem `<?php include ... ?>` w widokach | Latwa migracja, brak nowych zaleznosci |
| Kontrolery NIE zmieniane (BC `Flash::set/get`) | Plan boundary: DO NOT CHANGE controllers. Migracja widokow wystarcza, central renderer obsluguje przyszle `Flash::push()` | Zachowany dotychczasowy flow flash z pre-fetchem w kontrolerze |
| `messageHtml` jako trusted opt-in (4 widoki: invoice_form, receipt-create, printing, statistics/orders) | `<ul>`/`<pre>`/`<strong>` content wymaga HTML — alternatywa byloby budowanie list w kontrolerze co rozmywa odpowiedzialnosc | Component obsluguje zarowno simple text jak i markup wewnetrzny |
| Heurystyka klucza legacy w `Flash::all()` | Migracja kontrolerow odlozona; klucze `module.save/error/test` daja sygnal typu | Operator widzi poprawny kolor bez zmian w kontrolerach |
| `unset($messageHtml)` po kazdym uzyciu | PHP `include` widzi zmienne z scope kontekstu; bez unsetu kolejny `include` w tym samym widoku falszywie wykrywa `isset($messageHtml)` | Kazde wywolanie komponentu jest izolowane |
| CSS rebuild wykonany inline (Phase 120) | Plan boundary mowil "build poza zakresem"; uzytkownik poprosil explicit | `app.css` i `login.css` aktualne, `.alert--info` zweryfikowany w skompilowanym CSS |

## Deviations from Plan

### Summary

| Type | Count | Impact |
|------|-------|--------|
| Auto-fixed | 2 | Eliminacja `.flash--error` z 2 dodatkowych widokow (out-of-list) |
| Scope additions | 1 | CSS rebuild zrobiony inline na zyczenie uzytkownika |
| Deferred | 2 | Migracja JS alerts w email-mailboxes; usuniecie `.flash--*` z SCSS |

**Total impact:** Essential fixes, no scope creep. Plan AC-3 wymagal `flash--error` = 0 — dodatkowe 2 pliki musialy zostac zmigrowane.

### Auto-fixed Issues

**1. [Coverage] `orders/show.php` i `shipments/prepare.php` z `.flash--error/success`**
- **Found during:** Task 3 final verify (`grep 'flash--' resources/views/`)
- **Issue:** Plan files_modified wymienial 34 widoki + login.php, ale grep ujawnil dodatkowe 2 widoki uzywajace starego `.flash--*` wzorca (5 wystapien lacznie).
- **Fix:** Zmigrowane na komponent `alert.php` z `$type='danger'/'success'`.
- **Files:** `resources/views/orders/show.php`, `resources/views/shipments/prepare.php`.
- **Verification:** `grep 'flash--' resources/views/` → 0.

**2. [Build] CSS rebuild via `npx sass`**
- **Found during:** Po Task 3, na zyczenie uzytkownika ("Przebuduj css")
- **Issue:** Plan boundary mowil "build SCSS poza zakresem"; bez rebuildu `.alert--info` nie zadzialalby w przegladarce.
- **Fix:** `npx --yes sass --style=compressed --no-source-map resources/scss/{app,login}.scss public/assets/css/{app,login}.css`.
- **Files:** `public/assets/css/app.css` (63 560 B), `public/assets/css/login.css` (7 409 B).
- **Verification:** `grep 'alert--info' app.css` → `border-color:#bfdbfe;background:#eff6ff;color:#1e3a8a`.

### Deferred Items

- **ALERT-JS-MIGRATION-120**: `resources/views/settings/email-mailboxes.php` linie 398/400/406 — JS-generowane alerty AJAX testu SMTP (`resultDiv.className = 'mt-12 alert alert--success'`). Uzywaja unified `.alert` SCSS, ale nie maja markupu komponentu (brak ikony/dismiss). Migracja wymagalaby JS template helpera — out of scope (discovered w Task 3).
- **FLASH-SCSS-CLEANUP-120**: `.flash--error/success/warning` w `_ui-components.scss` (jezeli istnieja) — nieuzywane po Phase 120, ale plan boundary explicit zostawia. Usuniecie w przyszlej fazie cleanup.

## Issues Encountered

| Issue | Resolution |
|-------|------------|
| `$messageHtml` persiste po pierwszym include w widoku — kolejne include widzialy `isset($messageHtml)` jako true | `unset($messageHtml)` po kazdym wywolaniu komponentu z `$messageHtml` (4 widoki) |
| `npm run build:css` failed — `sass` not in PATH | Uzyto `npx --yes sass` — pobiera deklaracje z `devDependencies` package.json |

## Next Phase Readiness

**Ready:**
- Komponent alert dostepny dla wszystkich przyszlych widokow — wzorzec `<?php $type=...; $message=...; $dismissible=...; include dirname(__DIR__) . '/components/alert.php'; ?>`.
- `Flash::push($type, $message)` dostepny dla kontrolerow ktore chca dolaczyc typowane flash entries bez magic keys.
- Central renderer w layoutach — dowolny nowy `Flash::push()` (lub `Flash::set()`) automatycznie renderuje sie u gory strony.
- CSS aktualny — operator moze odpalic smoke testy bez dalszych krokow build.

**Concerns:**
- Kontrolery dalej mieszaja `Flash::set('module.key', '...')` z konwencja key-based — przy migracji ku `Flash::push()` heurystyka klucza staje sie redundantna. Mozna zmigrowac stopniowo w kolejnych fazach.
- JS alerty w email-mailboxes.php beda wygladaly nieco inaczej (bez ikony/dismiss) niz PHP-renderowane — nieuwage UX, ale spojnosc wizualna 95%.

**Blockers:** None.

---
*Phase: 120-alert-component-unification, Plan: 01*
*Completed: 2026-05-12*
