feat(helpdesk): show manual domain input when customer has no domains
When the domain API returns an empty list for a selected customer, the domain select is replaced with two text inputs: domain name (required) and URL (optional). JS syncs the manual values into the existing hidden domain_no/domain_url fields so the server-side validation and save logic is unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -488,6 +488,9 @@
|
|||||||
"Select a customer first...": "Bitte zuerst einen Kunden auswählen...",
|
"Select a customer first...": "Bitte zuerst einen Kunden auswählen...",
|
||||||
"Loading domains...": "Domains werden geladen...",
|
"Loading domains...": "Domains werden geladen...",
|
||||||
"No domains found for this customer": "Keine Domains für diesen Kunden gefunden",
|
"No domains found for this customer": "Keine Domains für diesen Kunden gefunden",
|
||||||
|
"No domains found for this customer. Enter domain name manually:": "Keine Domains für diesen Kunden gefunden. Domain-Name manuell eingeben:",
|
||||||
|
"Domain name (e.g. example.de)": "Domain-Name (z. B. example.de)",
|
||||||
|
"URL (optional, e.g. https://example.de)": "URL (optional, z. B. https://example.de)",
|
||||||
"Failed to load domains": "Domains konnten nicht geladen werden",
|
"Failed to load domains": "Domains konnten nicht geladen werden",
|
||||||
"Please select a domain": "Bitte wählen Sie eine Domain",
|
"Please select a domain": "Bitte wählen Sie eine Domain",
|
||||||
"Delete": "Löschen",
|
"Delete": "Löschen",
|
||||||
|
|||||||
@@ -488,6 +488,9 @@
|
|||||||
"Select a customer first...": "Select a customer first...",
|
"Select a customer first...": "Select a customer first...",
|
||||||
"Loading domains...": "Loading domains...",
|
"Loading domains...": "Loading domains...",
|
||||||
"No domains found for this customer": "No domains found for this customer",
|
"No domains found for this customer": "No domains found for this customer",
|
||||||
|
"No domains found for this customer. Enter domain name manually:": "No domains found for this customer. Enter domain name manually:",
|
||||||
|
"Domain name (e.g. example.de)": "Domain name (e.g. example.de)",
|
||||||
|
"URL (optional, e.g. https://example.de)": "URL (optional, e.g. https://example.de)",
|
||||||
"Failed to load domains": "Failed to load domains",
|
"Failed to load domains": "Failed to load domains",
|
||||||
"Please select a domain": "Please select a domain",
|
"Please select a domain": "Please select a domain",
|
||||||
"Delete": "Delete",
|
"Delete": "Delete",
|
||||||
|
|||||||
@@ -149,11 +149,23 @@ if ($canManage && $mode === 'assign' && $step === 2) {
|
|||||||
data-initial-domain="<?php e($form['domain_no'] ?? ''); ?>"
|
data-initial-domain="<?php e($form['domain_no'] ?? ''); ?>"
|
||||||
>
|
>
|
||||||
<label for="wizard-domain"><?php e(t('Domain')); ?> <span class="handover-form-required">*</span></label>
|
<label for="wizard-domain"><?php e(t('Domain')); ?> <span class="handover-form-required">*</span></label>
|
||||||
<select id="wizard-domain" name="domain_no" disabled>
|
<div class="app-wizard-domain-select-wrap">
|
||||||
<option value=""><?php e(t('Select a customer first...')); ?></option>
|
<select id="wizard-domain" name="domain_no" disabled>
|
||||||
</select>
|
<option value=""><?php e(t('Select a customer first...')); ?></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<input type="hidden" name="domain_url" id="wizard-domain-url" value="<?php e($form['domain_url'] ?? ''); ?>">
|
<input type="hidden" name="domain_url" id="wizard-domain-url" value="<?php e($form['domain_url'] ?? ''); ?>">
|
||||||
<div id="wizard-domain-feedback" class="app-wizard-field-feedback" role="alert" hidden></div>
|
<div id="wizard-domain-feedback" class="app-wizard-field-feedback" role="alert" hidden></div>
|
||||||
|
|
||||||
|
<!-- Manual entry — shown by JS when no domains exist for this customer -->
|
||||||
|
<div id="wizard-domain-manual" hidden>
|
||||||
|
<p class="app-wizard-field-hint"><?php e(t('No domains found for this customer. Enter domain name manually:')); ?></p>
|
||||||
|
<input type="text" id="wizard-domain-manual-no" placeholder="<?php e(t('Domain name (e.g. example.de)')); ?>"
|
||||||
|
value="<?php e($form['domain_no'] ?? ''); ?>" autocomplete="off">
|
||||||
|
<input type="text" id="wizard-domain-manual-url" placeholder="<?php e(t('URL (optional, e.g. https://example.de)')); ?>"
|
||||||
|
value="<?php e($form['domain_url'] ?? ''); ?>" autocomplete="off" style="margin-top:0.4rem;">
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php if (!empty($errors['domain_no'])): ?>
|
<?php if (!empty($errors['domain_no'])): ?>
|
||||||
<p class="field-error"><?php e($errors['domain_no']); ?></p>
|
<p class="field-error"><?php e($errors['domain_no']); ?></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ export function initHandoverDomainSelect(root = document) {
|
|||||||
const domainSelect = group.querySelector('#wizard-domain');
|
const domainSelect = group.querySelector('#wizard-domain');
|
||||||
const domainUrlInput = group.querySelector('#wizard-domain-url');
|
const domainUrlInput = group.querySelector('#wizard-domain-url');
|
||||||
const feedback = group.querySelector('#wizard-domain-feedback');
|
const feedback = group.querySelector('#wizard-domain-feedback');
|
||||||
|
const manualBlock = group.querySelector('#wizard-domain-manual');
|
||||||
|
const manualNoInput = group.querySelector('#wizard-domain-manual-no');
|
||||||
|
const manualUrlInput = group.querySelector('#wizard-domain-manual-url');
|
||||||
if (!lookupContainer || !domainSelect) {
|
if (!lookupContainer || !domainSelect) {
|
||||||
return EMPTY_API;
|
return EMPTY_API;
|
||||||
}
|
}
|
||||||
@@ -67,6 +70,24 @@ export function initHandoverDomainSelect(root = document) {
|
|||||||
feedback.dataset.variant = variant || '';
|
feedback.dataset.variant = variant || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const showManual = (show) => {
|
||||||
|
if (!manualBlock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
manualBlock.hidden = !show;
|
||||||
|
domainSelect.closest('.app-wizard-domain-select-wrap')?.toggleAttribute('hidden', show);
|
||||||
|
if (!show && manualNoInput) {
|
||||||
|
manualNoInput.value = '';
|
||||||
|
}
|
||||||
|
if (!show && manualUrlInput) {
|
||||||
|
manualUrlInput.value = '';
|
||||||
|
}
|
||||||
|
// When showing manual, clear the hidden domain_no/url so only manual values submit
|
||||||
|
if (show && domainUrlInput) {
|
||||||
|
domainUrlInput.value = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const resetDomain = () => {
|
const resetDomain = () => {
|
||||||
clearOptions();
|
clearOptions();
|
||||||
addPlaceholder(textInitial);
|
addPlaceholder(textInitial);
|
||||||
@@ -75,6 +96,7 @@ export function initHandoverDomainSelect(root = document) {
|
|||||||
domainUrlInput.value = '';
|
domainUrlInput.value = '';
|
||||||
}
|
}
|
||||||
setFeedback('', '');
|
setFeedback('', '');
|
||||||
|
showManual(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadDomains = async (debitorNo) => {
|
const loadDomains = async (debitorNo) => {
|
||||||
@@ -95,9 +117,11 @@ export function initHandoverDomainSelect(root = document) {
|
|||||||
|
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
domainSelect.disabled = true;
|
domainSelect.disabled = true;
|
||||||
setFeedback(textEmpty, 'warning');
|
setFeedback('', '');
|
||||||
|
showManual(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
showManual(false);
|
||||||
|
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
const opt = document.createElement('option');
|
const opt = document.createElement('option');
|
||||||
@@ -126,6 +150,23 @@ export function initHandoverDomainSelect(root = document) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sync manual inputs → hidden domain_no / domain_url fields
|
||||||
|
if (manualNoInput) {
|
||||||
|
on(manualNoInput, 'input', () => {
|
||||||
|
const hiddenNo = scope.querySelector('input[name="domain_no"]');
|
||||||
|
if (hiddenNo) {
|
||||||
|
hiddenNo.value = manualNoInput.value.trim();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (manualUrlInput) {
|
||||||
|
on(manualUrlInput, 'input', () => {
|
||||||
|
if (domainUrlInput) {
|
||||||
|
domainUrlInput.value = manualUrlInput.value.trim();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
on(lookupContainer, 'lookup:select', (event) => {
|
on(lookupContainer, 'lookup:select', (event) => {
|
||||||
const debitorNo = event.detail?.value || '';
|
const debitorNo = event.detail?.value || '';
|
||||||
if (debitorNo) {
|
if (debitorNo) {
|
||||||
|
|||||||
Reference in New Issue
Block a user