feat(24-shipment-presets-ui): kolorowe przyciski presetów, popup tworzenia, autofill formularza
Phase 24 complete: - SCSS moduł _shipment-presets.scss (przyciski, popup, color picker) - Sekcja presetów nad formularzem przesyłki z przyciskiem "Dodaj" - Popup tworzenia presetu z nazwą i wyborem koloru (8 opcji) - JS autofill: carrier, usługa dostawy, wymiary, waga, label format - Obsługa 3 paneli: Allegro searchable, InPost select, Apaczka select Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -61,6 +61,28 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<section class="shipment-presets" id="shipment-presets">
|
||||
<button type="button" class="shipment-presets__add" id="preset-add-btn">+ Dodaj przycisk dostawy</button>
|
||||
</section>
|
||||
|
||||
<div class="preset-modal" id="preset-modal" style="display:none">
|
||||
<div class="preset-modal__content">
|
||||
<h3>Nowy przycisk dostawy</h3>
|
||||
<label class="form-field mt-12">
|
||||
<span class="field-label">Nazwa</span>
|
||||
<input class="form-control" type="text" id="preset-name-input" maxlength="100" placeholder="np. InPost Paczkomat Standard">
|
||||
</label>
|
||||
<div class="form-field mt-12">
|
||||
<span class="field-label">Kolor</span>
|
||||
<div class="preset-modal__colors" id="preset-color-picker"></div>
|
||||
</div>
|
||||
<div class="form-actions mt-16">
|
||||
<button type="button" class="btn btn--primary" id="preset-save-btn">Zapisz</button>
|
||||
<button type="button" class="btn btn--secondary" id="preset-cancel-btn">Anuluj</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" action="/orders/<?= $e((string) ($orderId ?? 0)) ?>/shipment/create" novalidate>
|
||||
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
|
||||
|
||||
@@ -790,3 +812,235 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var PRESET_COLORS = ['#3b82f6','#ef4444','#10b981','#f59e0b','#8b5cf6','#ec4899','#06b6d4','#6b7280'];
|
||||
var presetsContainer = document.getElementById('shipment-presets');
|
||||
var addBtn = document.getElementById('preset-add-btn');
|
||||
var modal = document.getElementById('preset-modal');
|
||||
var nameInput = document.getElementById('preset-name-input');
|
||||
var colorPicker = document.getElementById('preset-color-picker');
|
||||
var saveBtn = document.getElementById('preset-save-btn');
|
||||
var cancelBtn = document.getElementById('preset-cancel-btn');
|
||||
|
||||
if (!presetsContainer || !addBtn || !modal) return;
|
||||
|
||||
var selectedColor = PRESET_COLORS[0];
|
||||
var presetsData = [];
|
||||
|
||||
// --- Color picker ---
|
||||
PRESET_COLORS.forEach(function (color, idx) {
|
||||
var swatch = document.createElement('div');
|
||||
swatch.className = 'preset-modal__color-swatch' + (idx === 0 ? ' is-selected' : '');
|
||||
swatch.style.background = color;
|
||||
swatch.setAttribute('data-color', color);
|
||||
swatch.addEventListener('click', function () {
|
||||
colorPicker.querySelectorAll('.preset-modal__color-swatch').forEach(function (s) { s.classList.remove('is-selected'); });
|
||||
swatch.classList.add('is-selected');
|
||||
selectedColor = color;
|
||||
});
|
||||
colorPicker.appendChild(swatch);
|
||||
});
|
||||
|
||||
// --- Load presets ---
|
||||
function loadPresets() {
|
||||
fetch('/api/shipment-presets', { credentials: 'same-origin' })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (data) {
|
||||
presetsData = data.presets || [];
|
||||
renderPresets();
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
function renderPresets() {
|
||||
var existing = presetsContainer.querySelectorAll('.shipment-presets__btn');
|
||||
existing.forEach(function (btn) { btn.remove(); });
|
||||
|
||||
presetsData.forEach(function (preset) {
|
||||
var btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
btn.className = 'shipment-presets__btn';
|
||||
btn.style.background = preset.color || '#3b82f6';
|
||||
btn.textContent = preset.name;
|
||||
btn.setAttribute('data-preset-id', preset.id);
|
||||
btn.addEventListener('click', function () { applyPreset(preset); });
|
||||
presetsContainer.insertBefore(btn, addBtn);
|
||||
});
|
||||
}
|
||||
|
||||
// --- Apply preset (autofill form) ---
|
||||
function applyPreset(preset) {
|
||||
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');
|
||||
|
||||
if (!carrierSelect) return;
|
||||
|
||||
// Set carrier — use native change so existing handler shows correct panel
|
||||
carrierSelect.value = preset.carrier || '';
|
||||
if (carrierSelect._syncTrigger) carrierSelect._syncTrigger();
|
||||
carrierSelect.dispatchEvent(new Event('change'));
|
||||
|
||||
// The existing change handler clears hidden fields and resets selects.
|
||||
// We must wait for that to finish, then override with preset values.
|
||||
setTimeout(function () {
|
||||
// Hidden fields — set AFTER the change handler cleared them
|
||||
if (hiddenInput) hiddenInput.value = preset.delivery_method_id || '';
|
||||
if (credentialsInput) credentialsInput.value = preset.credentials_id || '';
|
||||
if (carrierInput) carrierInput.value = preset.carrier_id || '';
|
||||
if (providerInput) providerInput.value = preset.provider_code || '';
|
||||
|
||||
// Package fields
|
||||
setFieldValue('package_type', preset.package_type || 'PACKAGE');
|
||||
setFieldValue('length_cm', preset.length_cm || '25');
|
||||
setFieldValue('width_cm', preset.width_cm || '20');
|
||||
setFieldValue('height_cm', preset.height_cm || '8');
|
||||
setFieldValue('weight_kg', preset.weight_kg || '1');
|
||||
setFieldValue('sender_point_id', preset.sender_point_id || '');
|
||||
setFieldValue('label_format', preset.label_format || 'PDF');
|
||||
|
||||
// Select delivery service in the correct panel
|
||||
selectDeliveryService(preset);
|
||||
}, 200);
|
||||
}
|
||||
|
||||
function setFieldValue(name, value) {
|
||||
var field = document.querySelector('[name="' + name + '"]');
|
||||
if (!field) return;
|
||||
field.value = value;
|
||||
if (field.tagName === 'SELECT' && field._syncTrigger) {
|
||||
field._syncTrigger();
|
||||
}
|
||||
}
|
||||
|
||||
function selectDeliveryService(preset) {
|
||||
var carrier = preset.carrier || '';
|
||||
var methodId = preset.delivery_method_id || '';
|
||||
var credentialsId = preset.credentials_id || '';
|
||||
var carrierId = preset.carrier_id || '';
|
||||
|
||||
var hiddenInput = document.getElementById('shipment-delivery-service');
|
||||
var credentialsInput = document.getElementById('shipment-credentials-id');
|
||||
var carrierInput = document.getElementById('shipment-carrier-id');
|
||||
|
||||
if (carrier === 'allegro') {
|
||||
// Click the matching option in Allegro searchable dropdown
|
||||
var dropdown = document.getElementById('shipment-service-dropdown');
|
||||
if (dropdown) {
|
||||
var opts = dropdown.querySelectorAll('.searchable-select__option');
|
||||
opts.forEach(function (opt) {
|
||||
opt.classList.remove('is-selected');
|
||||
if (opt.getAttribute('data-value') === methodId) {
|
||||
opt.classList.add('is-selected');
|
||||
// Update search input to show selected service name
|
||||
var searchInput = document.getElementById('shipment-service-search');
|
||||
if (searchInput) searchInput.value = opt.getAttribute('data-label') || opt.textContent.trim();
|
||||
// Set hidden fields from option data attributes
|
||||
if (hiddenInput) hiddenInput.value = methodId;
|
||||
if (credentialsInput) credentialsInput.value = opt.getAttribute('data-credentials-id') || credentialsId;
|
||||
if (carrierInput) carrierInput.value = opt.getAttribute('data-carrier-id') || carrierId;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (carrier === 'inpost') {
|
||||
var inpostSelect = document.getElementById('shipment-inpost-select');
|
||||
if (inpostSelect) {
|
||||
inpostSelect.value = methodId;
|
||||
if (inpostSelect._syncTrigger) inpostSelect._syncTrigger();
|
||||
// Trigger change to set hidden fields via existing handler
|
||||
inpostSelect.dispatchEvent(new Event('change'));
|
||||
}
|
||||
} else if (carrier === 'apaczka') {
|
||||
var apaczkaSelect = document.getElementById('shipment-apaczka-select');
|
||||
if (apaczkaSelect) {
|
||||
apaczkaSelect.value = methodId;
|
||||
if (apaczkaSelect._syncTrigger) apaczkaSelect._syncTrigger();
|
||||
// Trigger change to set hidden fields via existing handler
|
||||
apaczkaSelect.dispatchEvent(new Event('change'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Modal: add preset ---
|
||||
addBtn.addEventListener('click', function () {
|
||||
nameInput.value = '';
|
||||
selectedColor = PRESET_COLORS[0];
|
||||
colorPicker.querySelectorAll('.preset-modal__color-swatch').forEach(function (s, i) {
|
||||
s.classList.toggle('is-selected', i === 0);
|
||||
});
|
||||
modal.style.display = '';
|
||||
nameInput.focus();
|
||||
});
|
||||
|
||||
cancelBtn.addEventListener('click', function () {
|
||||
modal.style.display = 'none';
|
||||
});
|
||||
|
||||
modal.addEventListener('click', function (e) {
|
||||
if (e.target === modal) modal.style.display = 'none';
|
||||
});
|
||||
|
||||
saveBtn.addEventListener('click', function () {
|
||||
var name = nameInput.value.trim();
|
||||
if (!name) {
|
||||
nameInput.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
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 = {
|
||||
name: name,
|
||||
color: selectedColor,
|
||||
carrier: carrierSelect ? carrierSelect.value : '',
|
||||
provider_code: providerInput ? providerInput.value : '',
|
||||
delivery_method_id: hiddenInput ? hiddenInput.value : '',
|
||||
credentials_id: credentialsInput ? credentialsInput.value : '',
|
||||
carrier_id: carrierInput ? carrierInput.value : '',
|
||||
package_type: getFieldValue('package_type'),
|
||||
length_cm: getFieldValue('length_cm'),
|
||||
width_cm: getFieldValue('width_cm'),
|
||||
height_cm: getFieldValue('height_cm'),
|
||||
weight_kg: getFieldValue('weight_kg'),
|
||||
sender_point_id: getFieldValue('sender_point_id'),
|
||||
label_format: getFieldValue('label_format')
|
||||
};
|
||||
|
||||
saveBtn.disabled = true;
|
||||
var formBody = new URLSearchParams(payload);
|
||||
fetch('/api/shipment-presets', {
|
||||
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.preset) {
|
||||
modal.style.display = 'none';
|
||||
loadPresets();
|
||||
}
|
||||
})
|
||||
.catch(function () {})
|
||||
.finally(function () { saveBtn.disabled = false; });
|
||||
});
|
||||
|
||||
function getFieldValue(name) {
|
||||
var field = document.querySelector('[name="' + name + '"]');
|
||||
return field ? field.value : '';
|
||||
}
|
||||
|
||||
// --- Init ---
|
||||
loadPresets();
|
||||
|
||||
})();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user