Align lot document upload layout

This commit is contained in:
gitea_admin committed 2026-09-08 11:51:04 +02:00
1 parent 5b0a623f4b
commit a31057f0c0
1 file changed
+7 -6
+7 -6
View File
@@ -300,7 +300,7 @@ function auth_format_lager_quantity(float $value): string
function auth_render_lager_documents(array $documents, bool $editable, string $scope): string
{
$html = '<section class="sg-form-sections-card__chapter" data-lager-documents="' . auth_escape_html($scope) . '"><h2 class="sg-strong sg-form-sections-card__chapter-title">Dokumente</h2>';
$html = '<div class="sg-card-segment sg-card-segment--body" data-lager-documents="' . auth_escape_html($scope) . '"><section class="sg-form-sections-card__chapter"><h2 class="sg-strong sg-form-sections-card__chapter-title">Dokumente</h2>';
$html .= '<div data-lager-documents-read="' . auth_escape_html($scope) . '">';
if ($documents === []) {
$html .= '<p class="sg-body">Keine Dokumente vorhanden.</p>';
@@ -325,10 +325,10 @@ function auth_render_lager_documents(array $documents, bool $editable, string $s
$comment = (string) ($document['comment'] ?? '');
$html .= '<div class="sg-form-sections-card__field-group" data-lager-document-edit-row="' . $documentId . '"><label class="sg-labeled-input-row"><span class="sg-label">' . auth_escape_html($filename) . '</span><input class="sg-interaction-element sg-input-single-line" type="text" value="' . auth_escape_html($comment) . '" data-lager-document-comment-input="' . $documentId . '"></label><button class="sg-interaction-element sg-button sg-button--warning" type="button" data-lager-document-delete="' . $documentId . '">Löschen</button><article class="sg-card sg-card--overlay-host sg-delete-confirmation-pattern__floating-card" role="dialog" aria-modal="true" aria-labelledby="lager-document-delete-title-' . $documentId . '" data-lager-document-confirmation="' . $documentId . '" hidden><div class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__body"><p class="sg-body sg-delete-confirmation-pattern__text" id="lager-document-delete-title-' . $documentId . '"><strong>Dokument löschen?</strong></p><p class="sg-body sg-delete-confirmation-pattern__text">Bestätige durch Eingabe von <span class="sg-delete-confirmation-pattern__code">DELETE</span>.</p><label class="sg-labeled-input-row"><span class="sg-label">Bestätigung</span><input class="sg-interaction-element sg-input-single-line" type="text" data-lager-document-delete-input="' . $documentId . '"></label><div class="sg-delete-confirmation-pattern__actions"><button class="sg-interaction-element sg-button sg-button--active" type="button" data-lager-document-delete-cancel="' . $documentId . '">Abbrechen</button><button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive" type="button" disabled data-lager-document-delete-confirm="' . $documentId . '">Löschen</button></div></div></article></div>';
}
$html .= '<form class="sg-file-upload" data-pattern="file-upload" data-lager-document-upload-form="' . auth_escape_html($scope) . '"><div class="sg-file-upload__dropzone sg-labeled-input-row"><label class="sg-label" for="lager-document-file-' . auth_escape_html($scope) . '">Dateien auswählen</label><input class="sg-file-input__control" id="lager-document-file-' . auth_escape_html($scope) . '" type="file" multiple aria-describedby="lager-document-file-status-' . auth_escape_html($scope) . '" data-lager-document-file><button class="sg-interaction-element sg-button sg-button--active sg-file-upload__trigger" type="button">Dateien auswählen</button></div><label class="sg-labeled-input-row"><span class="sg-label">Kommentar</span><input class="sg-interaction-element sg-input-single-line" type="text" data-lager-document-comment></label><p class="sg-body sg-file-upload__status" id="lager-document-file-status-' . auth_escape_html($scope) . '" data-lager-document-status aria-live="polite">Noch keine Dateien ausgewählt.</p><button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive" type="submit" disabled aria-disabled="true">Hochladen</button></form>';
$html .= '<form class="sg-file-upload" data-pattern="file-upload" data-lager-document-upload-form="' . auth_escape_html($scope) . '"><div class="sg-file-input" data-component="file-input"><div class="sg-file-upload__dropzone sg-labeled-input-row"><label class="sg-label" for="lager-document-file-' . auth_escape_html($scope) . '">Dateien auswählen</label><input class="sg-file-input__control" id="lager-document-file-' . auth_escape_html($scope) . '" type="file" multiple aria-describedby="lager-document-file-status-' . auth_escape_html($scope) . '" data-lager-document-file><button class="sg-interaction-element sg-button sg-button--active sg-file-upload__trigger" type="button">Dateien auswählen</button></div></div><p class="sg-body sg-file-upload__status" id="lager-document-file-status-' . auth_escape_html($scope) . '" data-lager-document-status aria-live="polite">Noch keine Dateien ausgewählt.</p><label class="sg-labeled-input-row"><span class="sg-label">Kommentar</span><input class="sg-interaction-element sg-input-single-line" type="text" data-lager-document-comment></label><button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive" type="submit" disabled aria-disabled="true">Hochladen</button></form>';
$html .= '</div>';
}
return $html . '</section>';
return $html . '</section></div>';
}
function auth_render_lager_historical_lots(array $lagerProducts): string
@@ -352,8 +352,9 @@ function auth_render_lager_historical_lots(array $lagerProducts): string
. '<strong>MHD:</strong> ' . auth_format_lager_date($lot['expiry_date'] ?? null) . '<br>'
. '<strong>Hersteller:</strong> ' . auth_escape_html((string) ($lot['manufacturer_name'] ?? 'Nicht hinterlegt')) . '<br>'
. '<strong>Hersteller-Chargennummer:</strong> ' . auth_escape_html((string) ($lot['manufacturer_lot_number'] ?? 'Nicht hinterlegt')) . '</p>'
. '</p></div>'
. auth_render_lager_documents($lot['documents'] ?? [], false, 'historical-' . (int) ($lot['lot_id'] ?? 0))
. '</div></article>';
. '</article>';
}
$html[] = '</div>';
}
@@ -445,7 +446,7 @@ function auth_render_lager_content(array $lagerProducts, array $lagerArtikel, ar
. '<div data-lager-drawer-topic="open-lots" aria-label="Offene Chargen">' . auth_render_lager_open_lots($lagerProducts, $manufacturerOptions) . '</div>'
. '<article class="sg-card sg-card--content-card" data-component="content-card" data-lager-drawer-topic="lot" aria-label="Aktive Charge">'
. '<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkgreen sg-object-card__header" data-component-part="card-header"><div class="sg-strong sg-text-on-dark">Aktive Charge</div><button class="sg-interaction-element sg-button sg-button--active" type="button" data-lager-edit-open>Bearbeiten</button></div>'
. '<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-lager-read-view><p class="sg-body"><strong>Naurua-Chargennummer:</strong> <span data-lager-drawer-lot-number></span><br><strong>Aktueller Bestand:</strong> <span data-lager-drawer-current-qty></span><br><strong>Eingangsmenge:</strong> <span data-lager-drawer-qty-in></span><br><strong>Hersteller:</strong> <span data-lager-drawer-manufacturer-name></span><br><strong>Hersteller-Chargennummer:</strong> <span data-lager-drawer-manufacturer-lot-number></span><br><strong>Herstellungsdatum:</strong> <span data-lager-drawer-mfg-date></span><br><strong>MHD:</strong> <span data-lager-drawer-expiry-date></span><br><strong>Einkaufsdatum:</strong> <span data-lager-drawer-purchase-date></span></p>' . auth_render_lager_documents([], false, 'current-read') . '</div>'
. '<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-lager-read-view><p class="sg-body"><strong>Naurua-Chargennummer:</strong> <span data-lager-drawer-lot-number></span><br><strong>Aktueller Bestand:</strong> <span data-lager-drawer-current-qty></span><br><strong>Eingangsmenge:</strong> <span data-lager-drawer-qty-in></span><br><strong>Hersteller:</strong> <span data-lager-drawer-manufacturer-name></span><br><strong>Hersteller-Chargennummer:</strong> <span data-lager-drawer-manufacturer-lot-number></span><br><strong>Herstellungsdatum:</strong> <span data-lager-drawer-mfg-date></span><br><strong>MHD:</strong> <span data-lager-drawer-expiry-date></span><br><strong>Einkaufsdatum:</strong> <span data-lager-drawer-purchase-date></span></p></div>' . auth_render_lager_documents([], false, 'current-read')
. '<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-lager-edit-form hidden><div class="sg-form-sections-card-wrapper" data-pattern="form-sections" aria-label="Aktive Charge bearbeiten">'
. '<form class="sg-form-sections-card" data-lager-edit-form-element><div class="sg-form-sections-card__body" data-pattern-part="form-body"><h2 class="sg-strong sg-form-sections-card__title">Aktive Charge bearbeiten</h2>'
. '<section class="sg-form-sections-card__chapter" aria-labelledby="lager-charge-traceability-title"><h2 id="lager-charge-traceability-title" class="sg-strong sg-form-sections-card__chapter-title">Rückverfolgbarkeit</h2>'
@@ -865,7 +866,7 @@ function render_auth_home_page(array $user, array $otcProducts = [], array $best
echo " document.addEventListener('click', (event) => { const trigger = event.target.closest('[data-lager-drawer-open]'); if (!trigger || trigger.dataset.lagerDrawerType !== 'Produkt' || window.matchMedia('(max-width: 767px)').matches) { return; } setLagerEditMode(false); const drawer = getDrawer(); const currentQty = drawer?.querySelector('[data-lager-drawer-current-qty]'); const qtyIn = drawer?.querySelector('[data-lager-drawer-qty-in]'); const lotNumber = drawer?.querySelector('[data-lager-lot-number]'); if (currentQty) { currentQty.textContent = trigger.dataset.lagerDrawerCurrentQty || '0'; } if (qtyIn) { qtyIn.textContent = trigger.dataset.lagerDrawerQtyIn || '0'; } if (lotNumber) { lotNumber.value = trigger.dataset.lagerDrawerLotNumber || ''; } const productId = trigger.closest('[data-lager-row]')?.dataset.lagerId || ''; contentRoot.querySelectorAll('[data-lager-historical-product]').forEach((product) => { product.hidden = product.dataset.lagerHistoricalProduct !== productId; }); });";
echo " const postLagerChange = async (payload) => { const response = await fetch('/api/lager-charge.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...payload, csrfToken: contentRoot.querySelector('[data-lager-csrf-token]')?.dataset.lagerCsrfToken || '' }) }); const result = await response.json(); if (!response.ok || result.ok !== true) { throw new Error(result.error || 'Speichern fehlgeschlagen'); } syncLagerForecast(result.forecast, result.productId); const trigger = contentRoot.querySelector('[data-lager-drawer-open][aria-expanded=\"true\"]') || contentRoot.querySelector('[data-lager-row][data-lager-id=\"' + (result.productId || '') + '\"] [data-lager-drawer-open]'); const drawer = getDrawer(); const warningValue = drawer?.querySelector('[data-lager-drawer-warning-value]'); if (warningValue) { warningValue.textContent = getLagerForecastWarningText(result.forecast, trigger, trigger?.dataset.lagerDrawerForecast || 'Keine Prognose'); } return result; };";
echo " const getLagerDocumentLotId = (form) => form.closest('[data-lager-open-card-wrapper]')?.dataset.lagerOpenCardWrapper || getDrawer()?.dataset.lagerActiveLotId || '';";
echo " document.addEventListener('click', (event) => { const trigger = event.target.closest('[data-component=\"file-input\"] .sg-file-input__trigger, .sg-file-upload__trigger'); if (trigger) { trigger.closest('[data-lager-document-upload-form]')?.querySelector('[data-lager-document-file]')?.click(); } });";
echo " contentRoot.querySelectorAll('[data-lager-document-upload-form]').forEach((form) => { const input = form.querySelector('[data-lager-document-file]'); const trigger = form.querySelector('.sg-file-input__trigger'); if (input && trigger) { trigger.addEventListener('click', () => input.click()); } });";
echo " document.addEventListener('change', (event) => { const input = event.target.closest('[data-lager-document-file]'); if (!input) { return; } const form = input.closest('[data-lager-document-upload-form]'); const submit = form?.querySelector('[type=\"submit\"]'); const status = form?.querySelector('[data-lager-document-status]'); const count = input.files?.length || 0; if (status) { status.textContent = count ? count + ' Datei(en) ausgewählt.' : 'Noch keine Dateien ausgewählt.'; } if (submit) { submit.disabled = count === 0; submit.setAttribute('aria-disabled', String(count === 0)); submit.classList.toggle('sg-button--process-inactive', count === 0); } });";
echo " document.addEventListener('submit', async (event) => { const form = event.target.closest('[data-lager-document-upload-form]'); if (!form) { return; } event.preventDefault(); const input = form.querySelector('[data-lager-document-file]'); const submit = form.querySelector('[type=\"submit\"]'); const status = form.querySelector('[data-lager-document-status]'); const files = Array.from(input?.files || []); if (!files.length) { return; } if (files.some((file) => file.size > 52428800)) { if (status) { status.textContent = 'Dokument darf maximal 50 MB groß sein.'; } return; } if (submit) { submit.disabled = true; } if (status) { status.textContent = 'Upload läuft …'; } try { for (const file of files) { const data = new FormData(); data.append('action', 'upload_document'); data.append('csrfToken', contentRoot.querySelector('[data-lager-csrf-token]')?.dataset.lagerCsrfToken || ''); data.append('lotId', getLagerDocumentLotId(form)); data.append('comment', form.querySelector('[data-lager-document-comment]')?.value || ''); data.append('document', file); const response = await fetch('/api/lager-charge.php', { method: 'POST', body: data }); const result = await response.json(); if (!response.ok || result.ok !== true) { throw new Error(result.error || 'Upload fehlgeschlagen'); } } window.location.reload(); } catch (error) { if (status) { status.textContent = error instanceof Error ? error.message : 'Upload fehlgeschlagen'; } if (submit) { submit.disabled = false; } } });";
echo " document.addEventListener('blur', async (event) => { const input = event.target.closest('[data-lager-document-comment-input]'); if (!input) { return; } try { await postLagerChange({ action: 'update_document_comment', documentId: input.dataset.lagerDocumentCommentInput, comment: input.value }); } catch (error) { input.setCustomValidity(error instanceof Error ? error.message : 'Kommentar konnte nicht gespeichert werden'); input.reportValidity(); } }, true);";