---
phase: 04-polish-ux
plan: 01
type: execute
wave: 1
depends_on: ["03-01"]
files_modified:
  - wp-content/plugins/media-folder-pro/assets/js/folder-tree.js
  - wp-content/plugins/media-folder-pro/assets/js/media-filter.js
  - wp-content/plugins/media-folder-pro/assets/css/admin.css
  - wp-content/plugins/media-folder-pro/includes/class-ajax-handler.php
  - wp-content/plugins/media-folder-pro/media-folder-pro.php
autonomous: true
---

<objective>
## Goal
Dopracowac UX pluginu: bulk przypisywanie mediow do folderow, dynamiczne countery, "Uncategorized" filtr, potwierdzenia operacji, stany puste, oraz drag & drop folderow miedzy soba w drzewku.

## Purpose
Core features dzialaja — teraz potrzebny jest polish, ktory zamieni prototyp w uzyteczne narzedzie. Bez bulk operations i dobrych stanow pustych plugin bedzie frustrujacy w uzyciu.

## Output
- Bulk select + assign do folderu
- "Bez folderu" filtr (uncategorized media)
- Drag & drop folderow (zmiana hierarchii)
- Dynamiczne countery (live update)
- Toast notifications zamiast alert()
- Empty states i loading indicators
</objective>

<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md

## Prior Work
@.paul/phases/03-media-modal/03-01-SUMMARY.md
- Pelna integracja: sidebar tree + grid filter + modal dropdown + upload assign
- 7 AJAX endpoints (create/rename/delete/move/get_folders/assign_media/upload_to_folder)
- HTML5 D&D media→folders dziala, mfp-folder-changed event sync

## Source Files
@wp-content/plugins/media-folder-pro/assets/js/folder-tree.js
@wp-content/plugins/media-folder-pro/assets/js/media-filter.js
@wp-content/plugins/media-folder-pro/assets/css/admin.css
@wp-content/plugins/media-folder-pro/includes/class-ajax-handler.php
@wp-content/plugins/media-folder-pro/media-folder-pro.php
</context>

<acceptance_criteria>

## AC-1: Bulk assign mediow do folderu
```gherkin
Given plugin aktywny, widok grid na upload.php
When uzytkownik zaznacza wiele mediow (WP bulk select) i wybiera "Przenies do folderu"
Then pojawia sie dropdown z folderami
And po wyborze folderu wszystkie zaznaczone media zostaja przypisane
And countery folderow aktualizuja sie
```

## AC-2: Filtr "Bez folderu" (uncategorized)
```gherkin
Given plugin aktywny, istnieja media bez przypisanego folderu
When uzytkownik klika "Bez folderu" w drzewku sidebar
Then grid pokazuje tylko media nieprzypisane do zadnego folderu
```

## AC-3: Drag & drop folderow w drzewku
```gherkin
Given plugin aktywny, istnieja foldery w drzewku
When uzytkownik przeciaga folder na inny folder
Then przeniesiony folder staje sie podfolderem docelowego
And drzewko odswierza sie z nowa hierarchia
And przenoszenie na root (poza drzewko) robi folder top-level
```

## AC-4: Toast notifications i empty states
```gherkin
Given plugin aktywny
When uzytkownik wykonuje operacje (assign, create, delete, move)
Then pojawia sie toast notification (nie alert()) z wynikiem
And po zakonczeniu toast znika po 3 sekundach

Given brak folderow w systemie
When uzytkownik otwiera upload.php
Then w sidebar widoczny jest empty state z CTA "Utworz pierwszy folder"
```

</acceptance_criteria>

<tasks>

<task type="auto">
  <name>Task 1: Bulk assign + uncategorized filter + folder drag & drop</name>
  <files>wp-content/plugins/media-folder-pro/assets/js/folder-tree.js, wp-content/plugins/media-folder-pro/assets/js/media-filter.js, wp-content/plugins/media-folder-pro/assets/css/admin.css, wp-content/plugins/media-folder-pro/media-folder-pro.php</files>
  <action>
    1. Bulk assign w media-filter.js:
       - Dodaj button "Przenies do folderu" do WP bulk actions bar
       - Hook na wp.media.view.AttachmentsBrowser lub na DOM (bulk select mode)
       - Metoda: po kliknieciu pokaz dropdown z folderami (reuse flattenFolders z modala)
       - Po wyborze folderu: zbierz IDs zaznaczonych mediow
         - Uzyj wp.media.frame selection lub querySelectorAll('.attachment.selected')
       - Wywolaj mfp_assign_media z tablica IDs
       - Po sukcesie: refreshTree() + odswierz grid

    2. "Bez folderu" w folder-tree.js:
       - Dodaj pozycje "Bez folderu" pod "Wszystkie media" w sidebar
       - Klikniecie dispatcha 'mfp-folder-selected' z folderId: -1
       - W media-filter.js: jesli folderId === -1, ustaw media_folder: -1
         (MFP_Media_Query juz obsluguje -1 jako NOT EXISTS)
       - Dodaj ikone i styl (np. szary folder z ?)

    3. Drag & drop folderow w folder-tree.js:
       - Na kazdym .mfp-folder__row: draggable="true"
       - dragstart: ustaw dataTransfer z type 'mfp-folder' + folder ID
         - Uzyj innego MIME type niz media drag (np. 'application/mfp-folder')
       - W drop handler: sprawdz typ danych
         - Jesli 'application/mfp-folder': to folder move → wywolaj mfp_move_folder
         - Jesli 'text/plain' (liczba): to media assign (istniejace zachowanie)
       - Drop na root area (poza folderami): new_parent_id = 0 (top-level)
       - Po sukcesie: refreshTree()
       - Wizualne: inny styl drop target dla folder-on-folder (np. zolty outline)

    4. W admin.css:
       - Style dla "Bez folderu" linku
       - Style dla folder drag (rozny od media drag)
       - Style dla bulk assign dropdown/popup
       - .mfp-folder-drop-target (zolty, rozny od mfp-drop-target niebieski)

    5. W media-folder-pro.php:
       - Dodaj i18n: 'uncategorized', 'moveToFolder', 'bulkAssigned'

    Avoid: Nie komplikowac bulk assign — prosty dropdown popup wystarczy.
    Avoid: Folder drag nie moze kolidowac z media drag — rozne dataTransfer types.
  </action>
  <verify>
    - Zaznaczenie wielu mediow + bulk assign → przypisuje do wybranego folderu
    - "Bez folderu" klikalny, filtruje nieprzypisane media
    - Przeciaganie folderu na inny folder → zmiana hierarchii
    - Brak kolizji miedzy media drag a folder drag
    - Countery odswiezone po kazdej operacji
  </verify>
  <done>AC-1 + AC-2 + AC-3 satisfied: bulk, uncategorized, folder D&D</done>
</task>

<task type="auto">
  <name>Task 2: Toast notifications + empty states + final polish</name>
  <files>wp-content/plugins/media-folder-pro/assets/js/folder-tree.js, wp-content/plugins/media-folder-pro/assets/js/media-filter.js, wp-content/plugins/media-folder-pro/assets/css/admin.css</files>
  <action>
    1. System toast notifications:
       - Dodaj funkcje showToast(message, type) w folder-tree.js
         - type: 'success' (zielony), 'error' (czerwony), 'info' (niebieski)
         - Renderuj div.mfp-toast w prawym gornym rogu (fixed)
         - Auto-hide po 3s z CSS transition (fade out)
       - Wyeksportuj jako window.mfpToast(message, type)
       - Zamien WSZYSTKIE alert() i confirm() na:
         - alert() → showToast()
         - confirm() → natywny confirm() zostaje (jest OK dla destrukcji)

    2. Zamien alert() w folder-tree.js:
       - createFolder success → toast 'Folder utworzony'
       - renameFolder success → toast 'Nazwa zmieniona'
       - deleteFolder success → toast 'Folder usuniety'
       - Errory → toast z type 'error'

    3. Zamien alert() w media-filter.js:
       - assignMedia success → toast 'Media przypisane'
       - Errory → toast z type 'error'

    4. Empty states w folder-tree.js:
       - Obecny empty state juz istnieje ("Kliknij + aby utworzyc...")
       - Ulepsz: dodaj ikone folderu, wieksza czcionka, przycisk CTA
       - Loading state: zamien '...' na spinner CSS (animated)

    5. CSS w admin.css:
       - .mfp-toast: fixed position, right:20px, top:50px, z-index:10000
       - .mfp-toast--success: zielone tlo
       - .mfp-toast--error: czerwone tlo
       - .mfp-toast--info: niebieskie tlo
       - Animacja: slide-in + fade-out
       - .mfp-empty ulepszone: ikona + CTA button
       - .mfp-spinner: CSS-only spinner (border animation)

    Avoid: Nie uzywac zewnetrznych bibliotek toast (np. toastr).
    Avoid: Nie zastepowac confirm() przy usuwaniu — potrzebne jest potwierdzenie.
  </action>
  <verify>
    - Tworzenie folderu → toast "Folder utworzony" (zielony, 3s auto-hide)
    - Blad AJAX → toast z bledem (czerwony)
    - Brak folderow → empty state z ikona i CTA
    - Ladowanie folderow → spinner
    - Brak alert() w kodzie (oprocz confirm dla delete)
    - Brak JS errors w konsoli
  </verify>
  <done>AC-4 satisfied: toast notifications i empty states</done>
</task>

</tasks>

<boundaries>

## DO NOT CHANGE
- wp-content/plugins/elementor-pro/*
- wp-content/plugins/media-folder-pro/includes/class-taxonomy.php
- wp-content/plugins/media-folder-pro/includes/class-media-query.php
- wp-content/plugins/media-folder-pro/assets/js/modal-integration.js (stabilna)

## SCOPE LIMITS
- Brak keyboard navigation (nice-to-have, nie MVP)
- Brak accessibility ARIA (nice-to-have, nie MVP)
- Brak i18n .pot file (osobny task poza MVP)
- Brak settings page (nie potrzebna w MVP)

</boundaries>

<verification>
Before declaring plan complete:
- [ ] Bulk select + assign dziala
- [ ] "Bez folderu" filtruje uncategorized media
- [ ] Folder drag & drop zmienia hierarchie
- [ ] Toast notifications zamiast alert()
- [ ] Empty state z CTA gdy brak folderow
- [ ] Loading spinner podczas ladowania
- [ ] Brak regresji: wszystkie Phase 1-3 features dzialaja
- [ ] Brak JS errors w konsoli
- [ ] Brak PHP errors/warnings
</verification>

<success_criteria>
- Wszystkie taski ukonczone
- Plugin gotowy jako MVP v0.1
- Wszystkie 4 fazy dzialaja razem
- UX jest plynny i profesjonalny
</success_criteria>

<output>
After completion, create `.paul/phases/04-polish-ux/04-01-SUMMARY.md`
</output>
