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:
2026-03-22 23:53:44 +01:00
parent e379557533
commit 91963d5173
8 changed files with 591 additions and 48 deletions

View File

@@ -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 + '"]');