|
|
@@ -89,6 +89,14 @@
|
|
|
return (baseUrl ? baseUrl + '/' : '/') + normalizedPath;
|
|
|
}
|
|
|
|
|
|
+ function scrollWizardToTop() {
|
|
|
+ if (!wizardSection || wizardSection.classList.contains('hidden')) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ wizardSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
|
+ }
|
|
|
+
|
|
|
function setFeedbackText(target, text, isError) {
|
|
|
if (!target) {
|
|
|
return;
|
|
|
@@ -201,6 +209,15 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ function setResetActionVisible(isVisible) {
|
|
|
+ if (!resetDataBtn) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ resetDataBtn.classList.toggle('hidden', !isVisible);
|
|
|
+ resetDataBtn.disabled = !isVisible;
|
|
|
+ }
|
|
|
+
|
|
|
function enterCompactStatus(email) {
|
|
|
statusEmailValue.textContent = email;
|
|
|
startSection.classList.add('compact-mode');
|
|
|
@@ -218,6 +235,7 @@
|
|
|
startActions.classList.remove('hidden');
|
|
|
statusEmailValue.textContent = '-';
|
|
|
setDraftStatus('Noch nicht gespeichert', false);
|
|
|
+ setResetActionVisible(true);
|
|
|
}
|
|
|
|
|
|
function lockEmail(email) {
|
|
|
@@ -1046,6 +1064,42 @@
|
|
|
refreshRequiredMarkers();
|
|
|
}
|
|
|
|
|
|
+ function formatUploadTimestamp(isoDate) {
|
|
|
+ const formatted = formatTimestamp(String(isoDate || ''));
|
|
|
+ if (formatted !== '') {
|
|
|
+ return formatted;
|
|
|
+ }
|
|
|
+ return String(isoDate || '');
|
|
|
+ }
|
|
|
+
|
|
|
+ function buildUploadPreviewUrl(fieldKey, index) {
|
|
|
+ const params = new URLSearchParams();
|
|
|
+ params.set('csrf', boot.csrf);
|
|
|
+ params.set('email', state.email);
|
|
|
+ params.set('field', fieldKey);
|
|
|
+ params.set('index', String(index));
|
|
|
+ return appUrl('api/upload-preview.php') + '?' + params.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ async function deleteUploadedFile(fieldKey, index) {
|
|
|
+ const fd = new FormData();
|
|
|
+ fd.append('csrf', boot.csrf);
|
|
|
+ fd.append('email', state.email);
|
|
|
+ fd.append('website', '');
|
|
|
+ fd.append('field', fieldKey);
|
|
|
+ fd.append('index', String(index));
|
|
|
+
|
|
|
+ const response = await postForm(appUrl('api/delete-upload.php'), fd);
|
|
|
+ renderUploadInfo(response.uploads || {});
|
|
|
+
|
|
|
+ const ts = formatTimestamp(response.updated_at);
|
|
|
+ setDraftStatus('Gespeichert: ' + (ts || 'gerade eben'), false);
|
|
|
+
|
|
|
+ if (state.currentStep === state.summaryStep) {
|
|
|
+ renderSummary();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
function renderUploadInfo(uploads) {
|
|
|
state.uploads = uploads && typeof uploads === 'object' ? uploads : {};
|
|
|
|
|
|
@@ -1059,10 +1113,52 @@
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- state.uploads[field].forEach((item) => {
|
|
|
+ state.uploads[field].forEach((item, index) => {
|
|
|
const div = document.createElement('div');
|
|
|
div.className = 'upload-item';
|
|
|
- div.textContent = item.original_filename + ' (' + item.uploaded_at + ')';
|
|
|
+
|
|
|
+ const info = document.createElement('div');
|
|
|
+ info.className = 'upload-item-info';
|
|
|
+ const filename = String((item && item.original_filename) || (item && item.stored_filename) || 'Datei');
|
|
|
+ const uploadedAt = formatUploadTimestamp(item && item.uploaded_at);
|
|
|
+ info.textContent = uploadedAt !== '' ? filename + ' (' + uploadedAt + ')' : filename;
|
|
|
+ div.appendChild(info);
|
|
|
+
|
|
|
+ const actions = document.createElement('div');
|
|
|
+ actions.className = 'upload-item-actions';
|
|
|
+
|
|
|
+ const previewLink = document.createElement('a');
|
|
|
+ previewLink.className = 'upload-item-btn';
|
|
|
+ previewLink.href = buildUploadPreviewUrl(field, index);
|
|
|
+ previewLink.target = '_blank';
|
|
|
+ previewLink.rel = 'noopener noreferrer';
|
|
|
+ previewLink.textContent = 'Vorschau';
|
|
|
+ actions.appendChild(previewLink);
|
|
|
+
|
|
|
+ const deleteBtn = document.createElement('button');
|
|
|
+ deleteBtn.type = 'button';
|
|
|
+ deleteBtn.className = 'upload-item-btn upload-item-btn-danger';
|
|
|
+ deleteBtn.textContent = 'Löschen';
|
|
|
+ deleteBtn.addEventListener('click', async () => {
|
|
|
+ const confirmed = window.confirm('Diesen Upload wirklich löschen?');
|
|
|
+ if (!confirmed) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ deleteBtn.disabled = true;
|
|
|
+ try {
|
|
|
+ await deleteUploadedFile(field, index);
|
|
|
+ setFeedback('Upload gelöscht.', false);
|
|
|
+ } catch (err) {
|
|
|
+ const msg = (err.payload && err.payload.message) || err.message || 'Löschen fehlgeschlagen.';
|
|
|
+ setFeedback(msg, true);
|
|
|
+ } finally {
|
|
|
+ deleteBtn.disabled = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ actions.appendChild(deleteBtn);
|
|
|
+
|
|
|
+ div.appendChild(actions);
|
|
|
target.appendChild(div);
|
|
|
});
|
|
|
});
|
|
|
@@ -1283,6 +1379,7 @@
|
|
|
submitBtn.disabled = true;
|
|
|
nextBtn.disabled = true;
|
|
|
prevBtn.disabled = true;
|
|
|
+ setResetActionVisible(false);
|
|
|
if (submitLabel) {
|
|
|
submitLabel.textContent = 'Abgesendet';
|
|
|
}
|
|
|
@@ -1337,11 +1434,17 @@
|
|
|
try {
|
|
|
const result = await loadDraft(email);
|
|
|
lockEmail(email);
|
|
|
+ setResetActionVisible(true);
|
|
|
|
|
|
if (result.already_submitted) {
|
|
|
wizardSection.classList.add('hidden');
|
|
|
setDraftStatus('Antrag bereits abgeschlossen', false);
|
|
|
- setFeedback(boot.contactEmail ? 'Kontakt: ' + boot.contactEmail : '', false);
|
|
|
+ setFeedback(
|
|
|
+ result.message || 'Für diese E-Mail liegt bereits ein abgeschlossener Antrag vor.',
|
|
|
+ false,
|
|
|
+ 'start'
|
|
|
+ );
|
|
|
+ setResetActionVisible(false);
|
|
|
stopAutosave();
|
|
|
return;
|
|
|
}
|
|
|
@@ -1350,8 +1453,9 @@
|
|
|
fillFormData(result.data || {});
|
|
|
renderUploadInfo(result.uploads || {});
|
|
|
|
|
|
- state.currentStep = Math.min(Math.max(Number(result.step || 1), 1), state.totalSteps);
|
|
|
+ state.currentStep = 1;
|
|
|
updateProgress();
|
|
|
+ scrollWizardToTop();
|
|
|
startAutosave();
|
|
|
|
|
|
const loadedAt = formatTimestamp(result.updated_at);
|
|
|
@@ -1440,6 +1544,7 @@
|
|
|
}
|
|
|
state.currentStep -= 1;
|
|
|
updateProgress();
|
|
|
+ scrollWizardToTop();
|
|
|
} catch (err) {
|
|
|
const msg = (err.payload && err.payload.message) || err.message;
|
|
|
setFeedback(msg, true);
|
|
|
@@ -1455,6 +1560,7 @@
|
|
|
await saveDraft(false);
|
|
|
state.currentStep += 1;
|
|
|
updateProgress();
|
|
|
+ scrollWizardToTop();
|
|
|
} catch (err) {
|
|
|
const msg = (err.payload && err.payload.message) || err.message;
|
|
|
setFeedback(msg, true);
|
|
|
@@ -1484,6 +1590,7 @@
|
|
|
if (payload.already_submitted) {
|
|
|
wizardSection.classList.add('hidden');
|
|
|
setDraftStatus('Antrag bereits abgeschlossen', false);
|
|
|
+ setResetActionVisible(false);
|
|
|
}
|
|
|
}
|
|
|
});
|