Adds domain selection (cascaded from debitor) to handover creation and edit, bulk delete with confirmation dialog, and various UI improvements to the handover wizard and list page. Includes migration for domain columns, domain-select AJAX endpoint, and updated tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
125 lines
3.7 KiB
JavaScript
125 lines
3.7 KiB
JavaScript
/**
|
|
* Dynamic domain select for handover wizard step 1.
|
|
*
|
|
* Reads config from data-* attributes on #wizard-domain-group:
|
|
* data-domains-url, data-text-initial, data-text-loading,
|
|
* data-text-select, data-text-empty, data-text-error,
|
|
* data-initial-debitor, data-initial-domain
|
|
*/
|
|
|
|
const group = document.getElementById('wizard-domain-group');
|
|
const lookupContainer = document.querySelector('[data-app-lookup]');
|
|
const domainSelect = document.getElementById('wizard-domain');
|
|
const domainUrlInput = document.getElementById('wizard-domain-url');
|
|
const feedback = document.getElementById('wizard-domain-feedback');
|
|
|
|
if (group && lookupContainer && domainSelect) {
|
|
const domainsUrl = group.dataset.domainsUrl || '';
|
|
const textInitial = group.dataset.textInitial || '';
|
|
const textLoading = group.dataset.textLoading || '';
|
|
const textSelect = group.dataset.textSelect || '';
|
|
const textEmpty = group.dataset.textEmpty || '';
|
|
const textError = group.dataset.textError || '';
|
|
|
|
function clearOptions() {
|
|
while (domainSelect.options.length > 0) {
|
|
domainSelect.remove(0);
|
|
}
|
|
}
|
|
|
|
function addPlaceholder(text) {
|
|
const opt = document.createElement('option');
|
|
opt.value = '';
|
|
opt.textContent = text;
|
|
domainSelect.appendChild(opt);
|
|
}
|
|
|
|
function setFeedback(text, variant) {
|
|
if (!feedback) return;
|
|
feedback.textContent = text;
|
|
feedback.hidden = !text;
|
|
feedback.dataset.variant = variant || '';
|
|
}
|
|
|
|
function resetDomain() {
|
|
clearOptions();
|
|
addPlaceholder(textInitial);
|
|
domainSelect.disabled = true;
|
|
if (domainUrlInput) domainUrlInput.value = '';
|
|
setFeedback('', '');
|
|
}
|
|
|
|
async function loadDomains(debitorNo) {
|
|
clearOptions();
|
|
addPlaceholder(textLoading);
|
|
domainSelect.disabled = true;
|
|
group.setAttribute('aria-busy', 'true');
|
|
setFeedback('', '');
|
|
|
|
try {
|
|
const res = await fetch(domainsUrl + '?debitor_no=' + encodeURIComponent(debitorNo), {
|
|
headers: { 'Accept': 'application/json' },
|
|
});
|
|
const data = await res.json();
|
|
const items = Array.isArray(data) ? data : [];
|
|
|
|
clearOptions();
|
|
addPlaceholder(textSelect);
|
|
|
|
if (items.length === 0) {
|
|
domainSelect.disabled = true;
|
|
setFeedback(textEmpty, 'warning');
|
|
return;
|
|
}
|
|
|
|
items.forEach(function (item) {
|
|
const opt = document.createElement('option');
|
|
opt.value = item.value || '';
|
|
opt.textContent = item.label || item.value || '';
|
|
opt.dataset.url = item.url || '';
|
|
domainSelect.appendChild(opt);
|
|
});
|
|
domainSelect.disabled = false;
|
|
} catch {
|
|
clearOptions();
|
|
addPlaceholder(textSelect);
|
|
domainSelect.disabled = true;
|
|
setFeedback(textError, 'error');
|
|
} finally {
|
|
group.removeAttribute('aria-busy');
|
|
}
|
|
}
|
|
|
|
domainSelect.addEventListener('change', function () {
|
|
const selected = domainSelect.options[domainSelect.selectedIndex];
|
|
if (domainUrlInput) {
|
|
domainUrlInput.value = selected?.dataset.url || '';
|
|
}
|
|
});
|
|
|
|
lookupContainer.addEventListener('lookup:select', function (e) {
|
|
const debitorNo = e.detail?.value || '';
|
|
if (debitorNo) {
|
|
loadDomains(debitorNo);
|
|
} else {
|
|
resetDomain();
|
|
}
|
|
});
|
|
|
|
lookupContainer.addEventListener('lookup:clear', function () {
|
|
resetDomain();
|
|
});
|
|
|
|
// Restore selection if returning to step 1 with session data
|
|
const initialDebitor = group.dataset.initialDebitor || '';
|
|
const initialDomain = group.dataset.initialDomain || '';
|
|
if (initialDebitor) {
|
|
loadDomains(initialDebitor).then(function () {
|
|
if (initialDomain && !domainSelect.disabled) {
|
|
domainSelect.value = initialDomain;
|
|
domainSelect.dispatchEvent(new Event('change'));
|
|
}
|
|
});
|
|
}
|
|
}
|