feat(25-shipment-presets-management): edycja, usuwanie i zarządzanie presetami przesyłek
Phase 25 complete — milestone v1.0 done: - Ikonka edycji (✎) na hover z dropdown menu - Edycja nazwy i koloru presetu w popup - "Zapisz bieżące wartości" — aktualizacja parametrów z formularza - Usuwanie z potwierdzeniem OrderProAlerts.confirm() - SCSS: dropdown, edit-icon, btn-wrap style Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,8 +12,8 @@ Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów sprzedaży i n
|
||||
|
||||
| Attribute | Value |
|
||||
|-----------|-------|
|
||||
| Version | 0.9.0 |
|
||||
| Status | v0.9 Complete |
|
||||
| Version | 1.0.0 |
|
||||
| Status | v1.0 Complete |
|
||||
| Last Updated | 2026-03-22 |
|
||||
|
||||
## Requirements
|
||||
@@ -43,10 +43,11 @@ Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów sprzedaży i n
|
||||
- [x] Windows Client: C# WinForms tray app, polling API, druk etykiet PDF — Phase 20
|
||||
- [x] Wyświetlanie nazwy integracji zamiast generycznego "shopPRO" na liście i szczegółach zamówienia — Phase 21
|
||||
- [x] Naprawa zapisu REGON, BDO, KRS i logo w ustawieniach firmy — Phase 22
|
||||
- [x] Presety przesyłek — customowe przyciski szybkiego wypełniania formularza (CRUD + autofill + zarządzanie) — Phase 23-25
|
||||
|
||||
### Active (In Progress)
|
||||
|
||||
(brak — gotowe do v1.0)
|
||||
(brak)
|
||||
|
||||
### Planned (Next)
|
||||
|
||||
@@ -138,4 +139,4 @@ Quick Reference:
|
||||
|
||||
---
|
||||
*PROJECT.md — Updated when requirements or context change*
|
||||
*Last updated: 2026-03-22 after Phase 22 (REGON Save Fix complete)*
|
||||
*Last updated: 2026-03-22 after Phase 25 (Shipment Presets Management complete)*
|
||||
|
||||
@@ -6,30 +6,25 @@ orderPRO to narzędzie do wielokanałowego zarządzania sprzedażą. Projekt prz
|
||||
|
||||
## Current Milestone
|
||||
|
||||
### v1.0 Presety przesyłek — In progress
|
||||
|
||||
Customowe przyciski szybkiego wypełniania formularza przygotowania przesyłki. Użytkownik zapisuje preset z wybranym przewoźnikiem, usługą, typem paczki, wymiarami, wagą i punktem nadania, a następnie jednym kliknięciem wypełnia formularz. Presety globalne (dostępne dla wszystkich użytkowników).
|
||||
|
||||
| Phase | Name | Plans | Status |
|
||||
|-------|------|-------|--------|
|
||||
| 23 | Shipment Presets Backend | 1/1 | Complete ✓ |
|
||||
| 24 | Shipment Presets UI | 1/1 | Complete ✓ |
|
||||
| 25 | Shipment Presets Management | TBD | Not started |
|
||||
|
||||
### Phase 23: Shipment Presets Backend
|
||||
|
||||
Focus: Migracja DB (tabela `shipment_presets`), repository CRUD, controller z endpointami JSON API.
|
||||
|
||||
### Phase 24: Shipment Presets UI
|
||||
|
||||
Focus: Lista presetów nad formularzem jako kolorowe przyciski, popup tworzenia presetu (nazwa + kolor), JS autofill formularza po kliknięciu.
|
||||
|
||||
### Phase 25: Shipment Presets Management
|
||||
|
||||
Focus: Edycja nazwy/koloru/parametrów presetu, usuwanie, zmiana kolejności.
|
||||
None — ready for next milestone planning.
|
||||
|
||||
## Completed Milestones
|
||||
|
||||
<details>
|
||||
<summary>v1.0 Presety przesyłek — 2026-03-22 (3 phases, 3 plans)</summary>
|
||||
|
||||
Customowe przyciski szybkiego wypełniania formularza przygotowania przesyłki. Presety globalne z nazwą i kolorem — tworzenie, autofill, edycja, usuwanie.
|
||||
|
||||
| Phase | Name | Plans | Completed |
|
||||
|-------|------|-------|-----------|
|
||||
| 23 | Shipment Presets Backend | 1/1 | 2026-03-22 |
|
||||
| 24 | Shipment Presets UI | 1/1 | 2026-03-22 |
|
||||
| 25 | Shipment Presets Management | 1/1 | 2026-03-22 |
|
||||
|
||||
Archive: `.paul/phases/23-shipment-presets-backend/`, `.paul/phases/24-shipment-presets-ui/`, `.paul/phases/25-shipment-presets-management/`
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>v0.9 Poprawki ustawień firmy — 2026-03-22 (1 phase, 1 plan)</summary>
|
||||
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
See: .paul/PROJECT.md (updated 2026-03-12)
|
||||
|
||||
**Core value:** Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów sprzedaży i nadawać przesyłki bez przełączania się między platformami.
|
||||
**Current focus:** v1.0 Presety przesyłek
|
||||
**Current focus:** v1.0 Presety przesyłek — MILESTONE COMPLETE ✓
|
||||
|
||||
## Current Position
|
||||
|
||||
Milestone: v1.0 Presety przesyłek
|
||||
Phase: [3] of [3] (Shipment Presets Management)
|
||||
Plan: Not started
|
||||
Status: Phase 24 complete, ready to plan Phase 25
|
||||
Last activity: 2026-03-22 — Phase 24 complete, transitioned to Phase 25
|
||||
Milestone: v1.0 Presety przesyłek — COMPLETE ✓
|
||||
Phase: [3] of [3] (Shipment Presets Management) — COMPLETE ✓
|
||||
Plan: 25-01 — loop closed
|
||||
Status: Milestone v1.0 complete
|
||||
Last activity: 2026-03-22 — UNIFY complete, milestone v1.0 done
|
||||
|
||||
Progress:
|
||||
- v0.1 Initial Release: [██████████] 100% ✓
|
||||
@@ -27,13 +28,17 @@ Progress:
|
||||
- Phase 21: [██████████] 100% ✓ (1/1 plans)
|
||||
- v0.9 Poprawki ustawień firmy: [██████████] 100% ✓
|
||||
- Phase 22: [██████████] 100% ✓ (1/1 plans)
|
||||
- v1.0 Presety przesyłek: [██████████] 100% ✓
|
||||
- Phase 23: [██████████] 100% ✓ (1/1 plans)
|
||||
- Phase 24: [██████████] 100% ✓ (1/1 plans)
|
||||
- Phase 25: [██████████] 100% ✓ (1/1 plans)
|
||||
|
||||
## Loop Position
|
||||
|
||||
Current loop state:
|
||||
```
|
||||
PLAN ──▶ APPLY ──▶ UNIFY
|
||||
✓ ✓ ✓ [Loop complete — ready for next PLAN]
|
||||
✓ ✓ ✓ [Milestone v1.0 complete]
|
||||
```
|
||||
|
||||
## Accumulated Context
|
||||
@@ -67,6 +72,11 @@ PLAN ──▶ APPLY ──▶ UNIFY
|
||||
| 2026-03-17 | Email history jako wpisy w order_activity_log (nie osobna sekcja) | Faza 15 | Spójność z istniejącym UX — jeden timeline zamiast fragmentacji |
|
||||
| 2026-03-17 | VariableResolver wydzielony z EmailTemplateController | Faza 15 | Reuse logiki zmiennych; resolwer niezależny od kontrolera szablonów |
|
||||
|
||||
### Skill Audit (Faza 25, Plan 01)
|
||||
| Oczekiwany | Wywołany | Uwagi |
|
||||
|------------|---------|-------|
|
||||
| sonar-scanner | ✓ | 0 nowych issues na zmienionych plikach |
|
||||
|
||||
### Skill Audit (Faza 24, Plan 01)
|
||||
| Oczekiwany | Wywołany | Uwagi |
|
||||
|------------|---------|-------|
|
||||
@@ -206,7 +216,7 @@ PLAN ──▶ APPLY ──▶ UNIFY
|
||||
- **Delivery mapping "Szukaj..." layout** — JS `attachSelectFilter()` w allegro.php tworzy input search dla InPost/Apaczka selectów, wizualnie wygląda jakby należał do wiersza powyżej. Pre-existing bug, do naprawy osobno.
|
||||
|
||||
### Git State
|
||||
Last commit: 03a237e — feat(23-shipment-presets-backend): tabela DB, repository CRUD i JSON API
|
||||
Last commit: e379557 — feat(24-shipment-presets-ui): kolorowe przyciski presetów, popup, autofill
|
||||
Branch: main
|
||||
Feature branches merged: none
|
||||
|
||||
@@ -216,9 +226,9 @@ Brak.
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-03-22
|
||||
Stopped at: Phase 24 complete, ready to plan Phase 25
|
||||
Next action: /paul:plan for Phase 25 (Shipment Presets Management)
|
||||
Resume file: .paul/phases/24-shipment-presets-ui/24-01-SUMMARY.md
|
||||
Stopped at: Milestone v1.0 complete
|
||||
Next action: /paul:discuss-milestone lub /paul:milestone
|
||||
Resume file: .paul/phases/25-shipment-presets-management/25-01-SUMMARY.md
|
||||
Resume context:
|
||||
- v0.1: COMPLETE ✓ (6 phases, 15 plans)
|
||||
- v0.2: COMPLETE ✓ (1 phase, 5 plans)
|
||||
@@ -229,6 +239,7 @@ Resume context:
|
||||
- v0.7: COMPLETE ✓ (3 phases, 3 plans) — Zdalne drukowanie etykiet
|
||||
- v0.8: COMPLETE ✓ (1 phase, 1 plan) — Poprawki źródła zamówień
|
||||
- v0.9: COMPLETE ✓ (1 phase, 1 plan) — Poprawki ustawień firmy
|
||||
- v1.0: COMPLETE ✓ (3 phases, 3 plans) — Presety przesyłek
|
||||
|
||||
---
|
||||
*STATE.md — Updated after every significant action*
|
||||
|
||||
209
.paul/phases/25-shipment-presets-management/25-01-PLAN.md
Normal file
209
.paul/phases/25-shipment-presets-management/25-01-PLAN.md
Normal file
@@ -0,0 +1,209 @@
|
||||
---
|
||||
phase: 25-shipment-presets-management
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: ["24-01"]
|
||||
files_modified:
|
||||
- resources/views/shipments/prepare.php
|
||||
- resources/scss/modules/_shipment-presets.scss
|
||||
- public/assets/css/app.css
|
||||
autonomous: false
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Dodać zarządzanie presetami przesyłek: edycja nazwy/koloru/parametrów, usuwanie, z poziomu UI na stronie przygotowania przesyłki.
|
||||
|
||||
## Purpose
|
||||
Użytkownik musi móc modyfikować istniejące presety bez dostępu do bazy — zmienić nazwę, kolor, parametry lub usunąć niepotrzebne.
|
||||
|
||||
## Output
|
||||
- Menu kontekstowe na przyciskach presetów (edytuj / usuń)
|
||||
- Popup edycji presetu (ponowne użycie popupu tworzenia z pre-fill)
|
||||
- Potwierdzenie usunięcia przez OrderProAlerts.confirm()
|
||||
- Aktualizacja listy po edycji/usunięciu
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
@.paul/ROADMAP.md
|
||||
|
||||
## Prior Work
|
||||
@.paul/phases/24-shipment-presets-ui/24-01-SUMMARY.md
|
||||
|
||||
## Source Files
|
||||
@resources/views/shipments/prepare.php
|
||||
@resources/scss/modules/_shipment-presets.scss
|
||||
@src/Modules/Shipments/ShipmentPresetController.php
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
No specialized flows required (sonar-scanner post-APPLY).
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: Edycja presetu
|
||||
```gherkin
|
||||
Given istnieje preset "InPost Standard"
|
||||
When użytkownik klika prawym przyciskiem (lub ikonkę edycji) na przycisku presetu
|
||||
And wybiera "Edytuj"
|
||||
Then otwiera się popup z wypełnionymi danymi presetu (nazwa, kolor)
|
||||
When zmienia nazwę na "InPost Paczkomat" i klika Zapisz
|
||||
Then preset zostaje zaktualizowany i przycisk zmienia nazwę
|
||||
```
|
||||
|
||||
## AC-2: Zmiana parametrów presetu
|
||||
```gherkin
|
||||
Given istnieje preset z wagą 1kg
|
||||
When użytkownik wypełnia formularz nowymi wartościami (waga 2kg)
|
||||
And klika ikonkę edycji na presecie i wybiera "Zapisz bieżące wartości"
|
||||
Then preset zostaje zaktualizowany z bieżącymi wartościami formularza
|
||||
```
|
||||
|
||||
## AC-3: Usuwanie presetu
|
||||
```gherkin
|
||||
Given istnieje preset "Stary preset"
|
||||
When użytkownik klika ikonkę edycji i wybiera "Usuń"
|
||||
Then pojawia się potwierdzenie OrderProAlerts.confirm()
|
||||
When potwierdza usunięcie
|
||||
Then preset zostaje usunięty z bazy i przycisk znika z listy
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: SCSS — style menu kontekstowego i ikonki edycji</name>
|
||||
<files>resources/scss/modules/_shipment-presets.scss</files>
|
||||
<action>
|
||||
Dodać do istniejącego pliku SCSS:
|
||||
|
||||
- `.shipment-presets__btn-wrap` — wrapper na przycisk + ikonkę (position relative, display inline-flex)
|
||||
- `.shipment-presets__edit-icon` — ikonka edycji (mały przycisk ✎ na prawym górnym rogu):
|
||||
- Position absolute, top: -6px, right: -6px
|
||||
- Width 18px, height 18px, border-radius 50%
|
||||
- Background #fff, border: 1px solid #ddd, font-size 10px
|
||||
- Opacity 0 domyślnie, opacity 1 na hover wrappera
|
||||
- Cursor pointer, transition opacity 0.15s
|
||||
- `.shipment-presets__dropdown` — dropdown menu (position absolute):
|
||||
- Background #fff, border: 1px solid #ddd, border-radius 6px
|
||||
- Box-shadow, z-index 100, min-width 180px
|
||||
- Padding: 4px 0
|
||||
- `.shipment-presets__dropdown-item` — pozycja menu:
|
||||
- Padding: 6px 14px, font-size 13px, cursor pointer
|
||||
- Hover: background #f3f4f6
|
||||
- `&.is-danger` — color #ef4444
|
||||
|
||||
Zbudować CSS po zmianach.
|
||||
</action>
|
||||
<verify>npx sass --style=compressed build succeeds</verify>
|
||||
<done>AC-1, AC-2, AC-3 partially: style gotowe</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: JavaScript — edycja, usuwanie, dropdown menu</name>
|
||||
<files>resources/views/shipments/prepare.php</files>
|
||||
<action>
|
||||
Rozszerzyć istniejący IIFE presetów w prepare.php:
|
||||
|
||||
1. **Zmienić renderPresets()** — zamiast gołego `<button>`, renderować wrapper:
|
||||
```
|
||||
<div class="shipment-presets__btn-wrap">
|
||||
<button class="shipment-presets__btn" ...>{name}</button>
|
||||
<button class="shipment-presets__edit-icon" data-preset-id="{id}">✎</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
2. **Dropdown menu** — po kliknięciu ikonki ✎, pokazać dropdown z opcjami:
|
||||
- "Edytuj nazwę i kolor" → otwiera popup z pre-fill (nazwa, kolor z presetu)
|
||||
- "Zapisz bieżące wartości" → aktualizuje preset parametrami z bieżącego formularza (carrier, usługa, wymiary itp.), zachowując nazwę i kolor
|
||||
- "Usuń" (is-danger) → OrderProAlerts.confirm(), potem DELETE API
|
||||
|
||||
3. **Rozszerzyć modal** — dodać tryb edycji:
|
||||
- Dodać hidden input `preset-edit-id` w modal
|
||||
- Jeśli edit-id > 0: modal w trybie edycji (tytuł "Edytuj przycisk dostawy", przycisk "Zapisz zmiany")
|
||||
- Jeśli edit-id = 0: modal w trybie tworzenia (jak dotychczas)
|
||||
- Pre-fill: nazwa i kolor z presetu
|
||||
|
||||
4. **Edycja nazwy/koloru (modal save):**
|
||||
- Jeśli edit-id > 0: POST /api/shipment-presets/update z id + name + color + bieżące parametry presetu (nie formularza!)
|
||||
- Jeśli edit-id = 0: POST /api/shipment-presets (tworzenie jak dotychczas)
|
||||
|
||||
5. **"Zapisz bieżące wartości":**
|
||||
- POST /api/shipment-presets/update z id, bieżącą nazwą i kolorem presetu, ale parametrami z formularza
|
||||
- Po sukcesie: reload presetów
|
||||
|
||||
6. **Usuwanie:**
|
||||
- window.OrderProAlerts.confirm({ message: 'Usunąć przycisk "' + name + '"?', onConfirm: ... })
|
||||
- POST /api/shipment-presets/delete z id w body (URLSearchParams)
|
||||
- Po sukcesie: reload presetów
|
||||
|
||||
7. **Zamknięcie dropdown** — klik poza dropdown zamyka go
|
||||
|
||||
Ważne:
|
||||
- Nie modyfikować istniejącego kodu carrier selection / status polling
|
||||
- fetch z credentials: 'same-origin'
|
||||
- URLSearchParams (nie JSON) — jak w fazie 24
|
||||
- Przechowywać presetsData w zamknięciu IIFE (już istnieje)
|
||||
</action>
|
||||
<verify>php -l resources/views/shipments/prepare.php — brak błędów</verify>
|
||||
<done>AC-1, AC-2, AC-3 satisfied</done>
|
||||
</task>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking">
|
||||
<what-built>Zarządzanie presetami: edycja nazwy/koloru, zapisanie bieżących wartości, usuwanie z potwierdzeniem</what-built>
|
||||
<how-to-verify>
|
||||
1. Odwiedź /orders/{id}/shipment/prepare
|
||||
2. Najedź na przycisk presetu — powinna pojawić się ikonka ✎
|
||||
3. Kliknij ✎ — dropdown z 3 opcjami
|
||||
4. "Edytuj nazwę i kolor" — popup z wypełnioną nazwą i zaznaczonym kolorem, zmień i zapisz
|
||||
5. "Zapisz bieżące wartości" — zmień wymiary w formularzu, kliknij tę opcję — preset powinien się zaktualizować
|
||||
6. "Usuń" — potwierdzenie alertem, po potwierdzeniu przycisk znika
|
||||
7. Sprawdź że kliknięcie presetu nadal autofilluje formularz
|
||||
</how-to-verify>
|
||||
<resume-signal>Type "approved" to continue, or describe issues to fix</resume-signal>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- src/Modules/Shipments/ShipmentPresetController.php (gotowy z fazy 23)
|
||||
- src/Modules/Shipments/ShipmentPresetRepository.php (gotowy z fazy 23)
|
||||
- routes/web.php (routing gotowy z fazy 23)
|
||||
- Istniejący JS: carrier selection, status polling, print queue
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Edycja, usuwanie — brak drag & drop sortowania (out of scope)
|
||||
- Brak auto-submit po kliknięciu presetu (osobna faza/task)
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Before declaring plan complete:
|
||||
- [ ] Ikonka ✎ widoczna na hover
|
||||
- [ ] Dropdown z 3 opcjami
|
||||
- [ ] Edycja nazwy/koloru przez popup
|
||||
- [ ] "Zapisz bieżące wartości" aktualizuje parametry
|
||||
- [ ] Usuwanie z potwierdzeniem OrderProAlerts
|
||||
- [ ] Autofill nadal działa
|
||||
- [ ] php -l OK
|
||||
- [ ] SCSS zbudowany
|
||||
- [ ] Human verification passed
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Użytkownik może edytować nazwę i kolor presetu
|
||||
- Użytkownik może zaktualizować parametry presetu z bieżącego formularza
|
||||
- Użytkownik może usunąć preset z potwierdzeniem
|
||||
- Brak regresji w tworzeniu i autofill
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.paul/phases/25-shipment-presets-management/25-01-SUMMARY.md`
|
||||
</output>
|
||||
106
.paul/phases/25-shipment-presets-management/25-01-SUMMARY.md
Normal file
106
.paul/phases/25-shipment-presets-management/25-01-SUMMARY.md
Normal file
@@ -0,0 +1,106 @@
|
||||
---
|
||||
phase: 25-shipment-presets-management
|
||||
plan: 01
|
||||
subsystem: shipments
|
||||
tags: [shipment-presets, management, edit, delete, dropdown]
|
||||
|
||||
requires:
|
||||
- phase: 24-shipment-presets-ui
|
||||
provides: Preset buttons, modal, autofill JS
|
||||
provides:
|
||||
- Edycja nazwy i koloru presetu
|
||||
- Aktualizacja parametrów presetu z bieżącego formularza
|
||||
- Usuwanie presetu z potwierdzeniem
|
||||
affects: []
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- Ikonka edycji na hover z dropdown menu (reusable UX pattern)
|
||||
|
||||
key-files:
|
||||
created: []
|
||||
modified:
|
||||
- resources/scss/modules/_shipment-presets.scss
|
||||
- public/assets/css/app.css
|
||||
- resources/views/shipments/prepare.php
|
||||
|
||||
key-decisions:
|
||||
- "Ikonka ✎ na hover z dropdown zamiast osobnych przycisków — user approved"
|
||||
- "Modal reuse: tryb create vs edit z editingPresetId flag"
|
||||
|
||||
patterns-established:
|
||||
- "Edit icon hover + dropdown menu — użytkownik chce reuse tego wzorca"
|
||||
|
||||
duration: 10min
|
||||
started: 2026-03-22T00:00:00Z
|
||||
completed: 2026-03-22T00:10:00Z
|
||||
---
|
||||
|
||||
# Phase 25 Plan 01: Shipment Presets Management Summary
|
||||
|
||||
**Zarządzanie presetami: ikonka ✎ na hover z dropdown (edytuj nazwę/kolor, zapisz bieżące wartości, usuń z potwierdzeniem).**
|
||||
|
||||
## Performance
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Duration | ~10 min |
|
||||
| Tasks | 3 completed (2 auto + 1 checkpoint) |
|
||||
| Files modified | 3 |
|
||||
|
||||
## Acceptance Criteria Results
|
||||
|
||||
| Criterion | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| AC-1: Edycja presetu | Pass | Popup z pre-fill nazwa + kolor, zapis przez API update |
|
||||
| AC-2: Zmiana parametrów | Pass | "Zapisz bieżące wartości" aktualizuje z formularza |
|
||||
| AC-3: Usuwanie presetu | Pass | OrderProAlerts.confirm() + API delete |
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- SCSS: style btn-wrap, edit-icon (hover opacity), dropdown menu, dropdown-item (z is-danger)
|
||||
- JS: renderPresets() z wrapperem + ikonką ✎, showDropdown() z 3 opcjami
|
||||
- Modal rozszerzony o tryb edycji (editingPresetId flag, pre-fill, tytuł/tekst przycisku)
|
||||
- buildFormPayload() i postPresetAPI() wydzielone dla reuse (create/edit/saveCurrentValues)
|
||||
- deletePreset() z OrderProAlerts.confirm() fallback na native confirm
|
||||
- SonarQube: 0 nowych issues
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
| File | Change | Purpose |
|
||||
|------|--------|---------|
|
||||
| `resources/scss/modules/_shipment-presets.scss` | Modified | Style dropdown, edit icon, btn-wrap |
|
||||
| `public/assets/css/app.css` | Modified | Przebudowany CSS |
|
||||
| `resources/views/shipments/prepare.php` | Modified | Dropdown menu, modal edit mode, delete, saveCurrentValues |
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale | Impact |
|
||||
|----------|-----------|--------|
|
||||
| Ikonka ✎ na hover | Kompaktowe, nie zaśmieca UI | Użytkownik pochwalił — do reuse |
|
||||
| Modal reuse create/edit | Jeden popup z flagą editingPresetId | Mniej kodu, spójny UX |
|
||||
| Fallback na native confirm | OrderProAlerts może nie być dostępny | Defensywne programowanie |
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None — plan executed exactly as written.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
None.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
**Ready:**
|
||||
- Milestone v1.0 kompletny — wszystkie 3 fazy done
|
||||
|
||||
**Concerns:**
|
||||
- Brak
|
||||
|
||||
**Blockers:**
|
||||
- None
|
||||
|
||||
---
|
||||
*Phase: 25-shipment-presets-management, Plan: 01*
|
||||
*Completed: 2026-03-22*
|
||||
File diff suppressed because one or more lines are too long
@@ -92,3 +92,70 @@
|
||||
border-color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.shipment-presets__btn-wrap {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
|
||||
&:hover .shipment-presets__edit-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.shipment-presets__edit-icon {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 10px;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s;
|
||||
padding: 0;
|
||||
color: #666;
|
||||
z-index: 2;
|
||||
|
||||
&:hover {
|
||||
background: #f3f4f6;
|
||||
border-color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.shipment-presets__dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
margin-top: 4px;
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
|
||||
z-index: 100;
|
||||
min-width: 200px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.shipment-presets__dropdown-item {
|
||||
padding: 6px 14px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
background: #f3f4f6;
|
||||
}
|
||||
|
||||
&.is-danger {
|
||||
color: #ef4444;
|
||||
|
||||
&:hover {
|
||||
background: #fef2f2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -855,11 +855,16 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
var activeDropdown = null;
|
||||
|
||||
function renderPresets() {
|
||||
var existing = presetsContainer.querySelectorAll('.shipment-presets__btn');
|
||||
existing.forEach(function (btn) { btn.remove(); });
|
||||
var existing = presetsContainer.querySelectorAll('.shipment-presets__btn-wrap');
|
||||
existing.forEach(function (el) { el.remove(); });
|
||||
|
||||
presetsData.forEach(function (preset) {
|
||||
var wrap = document.createElement('div');
|
||||
wrap.className = 'shipment-presets__btn-wrap';
|
||||
|
||||
var btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
btn.className = 'shipment-presets__btn';
|
||||
@@ -867,10 +872,72 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
btn.textContent = preset.name;
|
||||
btn.setAttribute('data-preset-id', preset.id);
|
||||
btn.addEventListener('click', function () { applyPreset(preset); });
|
||||
presetsContainer.insertBefore(btn, addBtn);
|
||||
|
||||
var editIcon = document.createElement('button');
|
||||
editIcon.type = 'button';
|
||||
editIcon.className = 'shipment-presets__edit-icon';
|
||||
editIcon.textContent = '\u270E';
|
||||
editIcon.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
showDropdown(wrap, preset);
|
||||
});
|
||||
|
||||
wrap.appendChild(btn);
|
||||
wrap.appendChild(editIcon);
|
||||
presetsContainer.insertBefore(wrap, addBtn);
|
||||
});
|
||||
}
|
||||
|
||||
// --- Dropdown menu ---
|
||||
function closeDropdown() {
|
||||
if (activeDropdown) {
|
||||
activeDropdown.remove();
|
||||
activeDropdown = null;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', function () { closeDropdown(); });
|
||||
|
||||
function showDropdown(wrap, preset) {
|
||||
closeDropdown();
|
||||
|
||||
var dd = document.createElement('div');
|
||||
dd.className = 'shipment-presets__dropdown';
|
||||
|
||||
var editItem = document.createElement('div');
|
||||
editItem.className = 'shipment-presets__dropdown-item';
|
||||
editItem.textContent = 'Edytuj nazw\u0119 i kolor';
|
||||
editItem.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
closeDropdown();
|
||||
openEditModal(preset);
|
||||
});
|
||||
|
||||
var updateItem = document.createElement('div');
|
||||
updateItem.className = 'shipment-presets__dropdown-item';
|
||||
updateItem.textContent = 'Zapisz bie\u017C\u0105ce warto\u015Bci';
|
||||
updateItem.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
closeDropdown();
|
||||
saveCurrentValues(preset);
|
||||
});
|
||||
|
||||
var deleteItem = document.createElement('div');
|
||||
deleteItem.className = 'shipment-presets__dropdown-item is-danger';
|
||||
deleteItem.textContent = 'Usu\u0144';
|
||||
deleteItem.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
closeDropdown();
|
||||
deletePreset(preset);
|
||||
});
|
||||
|
||||
dd.appendChild(editItem);
|
||||
dd.appendChild(updateItem);
|
||||
dd.appendChild(deleteItem);
|
||||
wrap.appendChild(dd);
|
||||
activeDropdown = dd;
|
||||
}
|
||||
|
||||
// --- Apply preset (autofill form) ---
|
||||
function applyPreset(preset) {
|
||||
var carrierSelect = document.getElementById('shipment-carrier-select');
|
||||
@@ -966,16 +1033,37 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
}
|
||||
}
|
||||
|
||||
// --- Modal: add preset ---
|
||||
addBtn.addEventListener('click', function () {
|
||||
// --- Modal (create & edit) ---
|
||||
var editingPresetId = 0;
|
||||
var modalTitle = modal.querySelector('h3');
|
||||
|
||||
function openCreateModal() {
|
||||
editingPresetId = 0;
|
||||
nameInput.value = '';
|
||||
selectedColor = PRESET_COLORS[0];
|
||||
colorPicker.querySelectorAll('.preset-modal__color-swatch').forEach(function (s, i) {
|
||||
s.classList.toggle('is-selected', i === 0);
|
||||
});
|
||||
if (modalTitle) modalTitle.textContent = 'Nowy przycisk dostawy';
|
||||
saveBtn.textContent = 'Zapisz';
|
||||
modal.style.display = '';
|
||||
nameInput.focus();
|
||||
});
|
||||
}
|
||||
|
||||
function openEditModal(preset) {
|
||||
editingPresetId = preset.id;
|
||||
nameInput.value = preset.name || '';
|
||||
selectedColor = preset.color || PRESET_COLORS[0];
|
||||
colorPicker.querySelectorAll('.preset-modal__color-swatch').forEach(function (s) {
|
||||
s.classList.toggle('is-selected', s.getAttribute('data-color') === selectedColor);
|
||||
});
|
||||
if (modalTitle) modalTitle.textContent = 'Edytuj przycisk dostawy';
|
||||
saveBtn.textContent = 'Zapisz zmiany';
|
||||
modal.style.display = '';
|
||||
nameInput.focus();
|
||||
}
|
||||
|
||||
addBtn.addEventListener('click', function () { openCreateModal(); });
|
||||
|
||||
cancelBtn.addEventListener('click', function () {
|
||||
modal.style.display = 'none';
|
||||
@@ -992,15 +1080,46 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
return;
|
||||
}
|
||||
|
||||
saveBtn.disabled = true;
|
||||
|
||||
if (editingPresetId > 0) {
|
||||
// Edit mode — update name and color only, keep existing params
|
||||
var editPreset = presetsData.find(function (p) { return p.id === editingPresetId; });
|
||||
var editPayload = {
|
||||
id: editingPresetId,
|
||||
name: name,
|
||||
color: selectedColor,
|
||||
carrier: editPreset ? editPreset.carrier : '',
|
||||
provider_code: editPreset ? editPreset.provider_code : '',
|
||||
delivery_method_id: editPreset ? editPreset.delivery_method_id : '',
|
||||
credentials_id: editPreset ? editPreset.credentials_id : '',
|
||||
carrier_id: editPreset ? editPreset.carrier_id : '',
|
||||
package_type: editPreset ? editPreset.package_type : 'PACKAGE',
|
||||
length_cm: editPreset ? editPreset.length_cm : '25',
|
||||
width_cm: editPreset ? editPreset.width_cm : '20',
|
||||
height_cm: editPreset ? editPreset.height_cm : '8',
|
||||
weight_kg: editPreset ? editPreset.weight_kg : '1',
|
||||
sender_point_id: editPreset ? editPreset.sender_point_id : '',
|
||||
label_format: editPreset ? editPreset.label_format : 'PDF'
|
||||
};
|
||||
postPresetAPI('/api/shipment-presets/update', editPayload);
|
||||
} else {
|
||||
// Create mode — use current form values
|
||||
var payload = buildFormPayload(name, selectedColor);
|
||||
postPresetAPI('/api/shipment-presets', payload);
|
||||
}
|
||||
});
|
||||
|
||||
function buildFormPayload(name, color) {
|
||||
var carrierSelect = document.getElementById('shipment-carrier-select');
|
||||
var hiddenInput = document.getElementById('shipment-delivery-service');
|
||||
var credentialsInput = document.getElementById('shipment-credentials-id');
|
||||
var carrierInput = document.getElementById('shipment-carrier-id');
|
||||
var providerInput = document.getElementById('shipment-provider-code');
|
||||
|
||||
var payload = {
|
||||
return {
|
||||
name: name,
|
||||
color: selectedColor,
|
||||
color: color,
|
||||
carrier: carrierSelect ? carrierSelect.value : '',
|
||||
provider_code: providerInput ? providerInput.value : '',
|
||||
delivery_method_id: hiddenInput ? hiddenInput.value : '',
|
||||
@@ -1014,10 +1133,11 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
sender_point_id: getFieldValue('sender_point_id'),
|
||||
label_format: getFieldValue('label_format')
|
||||
};
|
||||
}
|
||||
|
||||
saveBtn.disabled = true;
|
||||
function postPresetAPI(url, payload) {
|
||||
var formBody = new URLSearchParams(payload);
|
||||
fetch('/api/shipment-presets', {
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
@@ -1025,14 +1145,48 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (data) {
|
||||
if (data.preset) {
|
||||
if (data.preset || data.deleted) {
|
||||
modal.style.display = 'none';
|
||||
loadPresets();
|
||||
}
|
||||
})
|
||||
.catch(function () {})
|
||||
.finally(function () { saveBtn.disabled = false; });
|
||||
});
|
||||
}
|
||||
|
||||
// --- Save current form values to existing preset ---
|
||||
function saveCurrentValues(preset) {
|
||||
var payload = buildFormPayload(preset.name, preset.color);
|
||||
payload.id = preset.id;
|
||||
postPresetAPI('/api/shipment-presets/update', payload);
|
||||
}
|
||||
|
||||
// --- Delete preset ---
|
||||
function deletePreset(preset) {
|
||||
if (window.OrderProAlerts && window.OrderProAlerts.confirm) {
|
||||
window.OrderProAlerts.confirm({
|
||||
message: 'Usun\u0105\u0107 przycisk "' + preset.name + '"?',
|
||||
onConfirm: function () { executeDelete(preset.id); }
|
||||
});
|
||||
} else if (confirm('Usun\u0105\u0107 przycisk "' + preset.name + '"?')) {
|
||||
executeDelete(preset.id);
|
||||
}
|
||||
}
|
||||
|
||||
function executeDelete(id) {
|
||||
var formBody = new URLSearchParams({ id: id });
|
||||
fetch('/api/shipment-presets/delete', {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: formBody.toString()
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (data) {
|
||||
if (data.deleted) loadPresets();
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
function getFieldValue(name) {
|
||||
var field = document.querySelector('[name="' + name + '"]');
|
||||
|
||||
Reference in New Issue
Block a user