Marktname öffnet Detailkarte mit Lese- und Editieransicht

This commit is contained in:
gitea_admin committed 2026-09-20 09:07:19 +02:00
1 parent f720782736
commit 1921464e27
2 files changed
+33 -14

No files matched your search

+16 -9
View File
@@ -182,8 +182,10 @@ function auth_render_market_definitions_content(array $marketTable): string
$website = (string) ($row['website_url'] ?? '');
$websiteValue = $website === '' ? 'Nicht hinterlegt' : $website;
$status = ($row['archived_at'] ?? null) === null ? 'Aktiv' : 'Archiviert';
$html[] = '<div class="' . $rowClass . '" role="row" data-component-part="large-table-row">';
$html[] = '<div class="sg-large-table__cell" role="cell">' . auth_escape_html((string) ($row['name'] ?? '')) . '</div>';
$marketId = (int) ($row['id'] ?? 0);
$marketName = (string) ($row['name'] ?? '');
$html[] = '<div class="' . $rowClass . '" role="row" data-component-part="large-table-row" data-market-definition-row data-market-definition-id="' . $marketId . '">';
$html[] = '<div class="sg-large-table__cell" role="cell"><button class="sg-interaction-element sg-hyperlink" type="button" aria-haspopup="dialog" aria-expanded="false" data-market-definition-open data-market-definition-id="' . $marketId . '" data-market-definition-name="' . auth_escape_html($marketName) . '" data-market-definition-category-id="' . (int) ($row['category_id'] ?? 0) . '" data-market-definition-category-name="' . auth_escape_html((string) ($row['category_name'] ?? $row['category_code'] ?? '')) . '" data-market-definition-website="' . auth_escape_html($website) . '">' . auth_escape_html($marketName) . '</button></div>';
$html[] = '<div class="sg-large-table__cell" role="cell">' . auth_escape_html((string) ($row['category_name'] ?? $row['category_code'] ?? '')) . '</div>';
$html[] = '<div class="sg-large-table__cell" role="cell">' . auth_escape_html($websiteValue) . '</div>';
$html[] = '<div class="sg-large-table__cell" role="cell">' . auth_escape_html((string) ($row['occurrence_count'] ?? 0)) . '</div>';
@@ -192,7 +194,7 @@ function auth_render_market_definitions_content(array $marketTable): string
}
$html[] = '</article></section>';
$html[] = '<div class="sg-card-list-page-drawer-backdrop" aria-hidden="true" data-market-definition-drawer-backdrop="true" data-open="false"></div>';
$html[] = '<aside class="sg-card-list-page-drawer" aria-label="Neuen Markt anlegen" aria-hidden="true" data-market-definition-drawer="true" data-open="false"><div class="sg-card-list-page-drawer__content" data-market-definition-drawer-content><article class="sg-card sg-card--content-card" data-market-definition-create-card hidden><header class="sg-card-segment sg-card-segment--header sg-card-segment--darkgreen sg-object-card__header"><div class="sg-strong sg-text-on-dark">Neuen Markt anlegen</div></header><div class="sg-card-segment sg-card-segment--body sg-card-segment--gray"><div class="sg-form-sections-card-wrapper" data-pattern="form-sections"><form class="sg-form-sections-card" data-market-definition-form><div class="sg-form-sections-card__body" data-pattern-part="form-body"><div class="sg-form-sections-card__section"><div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Marktname<span class="market-required-field-indicator" aria-hidden="true">*</span></span><input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" name="name" required data-market-definition-name></label></div><div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Kategorie/Marktart<span class="market-required-field-indicator" aria-hidden="true">*</span></span><select class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable sg-pulldown" name="category_id" required data-market-definition-category><option value="">Bitte auswählen</option>';
$html[] = '<aside class="sg-card-list-page-drawer" aria-label="Markt-Details" aria-hidden="true" data-market-definition-drawer="true" data-open="false"><div class="sg-card-list-page-drawer__content" data-market-definition-drawer-content><article class="sg-card sg-card--content-card" data-market-definition-read-card hidden><header class="sg-card-segment sg-card-segment--header sg-card-segment--darkgreen sg-object-card__header"><h2 class="sg-strong sg-text-on-dark" data-market-definition-read-title>Markt</h2><button class="sg-interaction-element sg-button sg-button--active" type="button" data-market-definition-edit>Bearbeiten</button></header><div class="sg-card-segment sg-card-segment--body sg-card-segment--white"><div class="sg-form-sections-card__field-group"><div class="sg-labeled-input-row"><span class="sg-label">Marktname</span><span class="sg-body" data-market-definition-read-name></span></div></div><div class="sg-form-sections-card__field-group"><div class="sg-labeled-input-row"><span class="sg-label">Kategorie/Marktart</span><span class="sg-body" data-market-definition-read-category></span></div></div><div class="sg-form-sections-card__field-group"><div class="sg-labeled-input-row"><span class="sg-label">Website</span><span class="sg-body" data-market-definition-read-website></span></div></div></div></article><article class="sg-card sg-card--content-card" data-market-definition-create-card hidden><header class="sg-card-segment sg-card-segment--header sg-card-segment--darkgreen sg-object-card__header"><h2 class="sg-strong sg-text-on-dark" data-market-definition-form-title>Neuen Markt anlegen</h2></header><div class="sg-card-segment sg-card-segment--body sg-card-segment--gray"><div class="sg-form-sections-card-wrapper" data-pattern="form-sections"><form class="sg-form-sections-card" data-market-definition-form><div class="sg-form-sections-card__body" data-pattern-part="form-body"><div class="sg-form-sections-card__section"><div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Marktname<span class="market-required-field-indicator" aria-hidden="true">*</span></span><input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" name="name" required data-market-definition-name></label></div><div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Kategorie/Marktart<span class="market-required-field-indicator" aria-hidden="true">*</span></span><select class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable sg-pulldown" name="category_id" required data-market-definition-category><option value="">Bitte auswählen</option>';
foreach ($categories as $category) {
$html[] = '<option value="' . (int) ($category['id'] ?? 0) . '">' . auth_escape_html((string) ($category['name'] ?? $category['code'] ?? '')) . '</option>';
}
@@ -1193,17 +1195,22 @@ function render_auth_home_page(array $user, array $otcProducts = [], array $otcM
echo " const contentRoot = document.querySelector('[data-left-navigation-content-body]');";
echo " const definitionContent = contentRoot?.querySelector('[data-market-definitions-content]');";
echo " const drawer = definitionContent?.querySelector('[data-market-definition-drawer]');";
echo " const readCard = drawer?.querySelector('[data-market-definition-read-card]');";
echo " const card = drawer?.querySelector('[data-market-definition-create-card]');";
echo " const form = drawer?.querySelector('[data-market-definition-form]');";
echo " if (!contentRoot || !definitionContent || !drawer || !card || !form || definitionContent.dataset.marketDefinitionsBound === 'true') { return; }";
echo " const editButton = readCard?.querySelector('[data-market-definition-edit]');";
echo " if (!contentRoot || !definitionContent || !drawer || !readCard || !card || !form || !editButton || definitionContent.dataset.marketDefinitionsBound === 'true') { return; }";
echo " definitionContent.dataset.marketDefinitionsBound = 'true';";
echo " const setDrawerState = (open) => { drawer.dataset.open = String(open); drawer.setAttribute('aria-hidden', String(!open)); const trigger = definitionContent.querySelector('[data-market-definition-create]'); if (trigger) { trigger.setAttribute('aria-expanded', String(open)); } const backdrop = definitionContent.querySelector('[data-market-definition-drawer-backdrop]'); if (backdrop) { backdrop.dataset.open = String(open); backdrop.setAttribute('aria-hidden', String(!open)); } document.body.classList.toggle('sg-card-list-page-drawer-open', open); };";
echo " let activeMarket = null;";
echo " const setDrawerState = (open) => { drawer.dataset.open = String(open); drawer.setAttribute('aria-hidden', String(!open)); if (activeMarket?.trigger) { activeMarket.trigger.setAttribute('aria-expanded', String(open)); } const backdrop = definitionContent.querySelector('[data-market-definition-drawer-backdrop]'); if (backdrop) { backdrop.dataset.open = String(open); backdrop.setAttribute('aria-hidden', String(!open)); } document.body.classList.toggle('sg-card-list-page-drawer-open', open); };";
echo " const resetForm = () => { form.reset(); const status = form.querySelector('[data-market-definition-status]'); if (status) { status.textContent = ''; } };";
echo " const closeDrawer = () => { resetForm(); card.hidden = true; setDrawerState(false); };";
echo " const appendMarketRow = (market) => { const table = contentRoot.querySelector('[data-market-definitions-table]'); if (!table) { return; } const row = document.createElement('div'); row.className = 'sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row'; row.setAttribute('role', 'row'); row.dataset.componentPart = 'large-table-row'; const category = form.querySelector('[data-market-definition-category]')?.selectedOptions[0]?.textContent || ''; const website = market.website_url || 'Nicht hinterlegt'; [market.name, category, website, '0', 'Aktiv'].forEach((value) => { const cell = document.createElement('div'); cell.className = 'sg-large-table__cell'; cell.setAttribute('role', 'cell'); cell.textContent = value; row.appendChild(cell); }); table.appendChild(row); };";
echo " document.addEventListener('click', (event) => { if (event.target.closest('[data-market-definition-create]')) { event.preventDefault(); resetForm(); card.hidden = false; setDrawerState(true); form.querySelector('[data-market-definition-name]')?.focus(); return; } if (event.target.closest('[data-market-definition-cancel]') || event.target.closest('[data-market-definition-drawer-backdrop]')) { event.preventDefault(); closeDrawer(); } });";
echo " const closeDrawer = () => { resetForm(); readCard.hidden = true; card.hidden = true; activeMarket = null; setDrawerState(false); };";
echo " const showReadCard = (trigger) => { activeMarket = { id: trigger.dataset.marketDefinitionId || '', trigger }; readCard.querySelector('[data-market-definition-read-title]').textContent = trigger.dataset.marketDefinitionName || 'Markt'; readCard.querySelector('[data-market-definition-read-name]').textContent = trigger.dataset.marketDefinitionName || 'Nicht hinterlegt'; readCard.querySelector('[data-market-definition-read-category]').textContent = trigger.dataset.marketDefinitionCategoryName || 'Nicht hinterlegt'; readCard.querySelector('[data-market-definition-read-website]').textContent = trigger.dataset.marketDefinitionWebsite || 'Nicht hinterlegt'; readCard.hidden = false; card.hidden = true; setDrawerState(true); };";
echo " const openEditCard = () => { if (!activeMarket) { return; } form.querySelector('[data-market-definition-form-title]').textContent = 'Markt bearbeiten'; form.querySelector('[data-market-definition-name]').value = activeMarket.trigger.dataset.marketDefinitionName || ''; form.querySelector('[data-market-definition-category]').value = activeMarket.trigger.dataset.marketDefinitionCategoryId || ''; form.querySelector('[data-market-definition-website]').value = activeMarket.trigger.dataset.marketDefinitionWebsite === 'Nicht hinterlegt' ? '' : (activeMarket.trigger.dataset.marketDefinitionWebsite || ''); readCard.hidden = true; card.hidden = false; form.querySelector('[data-market-definition-name]')?.focus(); };";
echo " const appendMarketRow = (market) => { const table = contentRoot.querySelector('[data-market-definitions-table]'); if (!table) { return; } const row = document.createElement('div'); row.className = 'sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row'; row.setAttribute('role', 'row'); row.dataset.componentPart = 'large-table-row'; row.dataset.marketDefinitionRow = ''; row.dataset.marketDefinitionId = String(market.id || ''); const category = form.querySelector('[data-market-definition-category]')?.selectedOptions[0]?.textContent || ''; const website = market.website_url || 'Nicht hinterlegt'; const cells = document.createElement('div'); cells.className = 'sg-large-table__cell'; const trigger = document.createElement('button'); trigger.className = 'sg-interaction-element sg-hyperlink'; trigger.type = 'button'; trigger.setAttribute('aria-haspopup', 'dialog'); trigger.setAttribute('aria-expanded', 'false'); trigger.dataset.marketDefinitionOpen = ''; trigger.dataset.marketDefinitionId = String(market.id || ''); trigger.dataset.marketDefinitionName = market.name || ''; trigger.dataset.marketDefinitionCategoryId = String(market.category_id || ''); trigger.dataset.marketDefinitionCategoryName = category; trigger.dataset.marketDefinitionWebsite = website; trigger.textContent = market.name || ''; cells.appendChild(trigger); row.appendChild(cells); [category, website, '0', 'Aktiv'].forEach((value) => { const cell = document.createElement('div'); cell.className = 'sg-large-table__cell'; cell.setAttribute('role', 'cell'); cell.textContent = value; row.appendChild(cell); }); table.appendChild(row); };";
echo " document.addEventListener('click', (event) => { const openTrigger = event.target.closest('[data-market-definition-open]'); if (openTrigger) { event.preventDefault(); showReadCard(openTrigger); return; } if (event.target.closest('[data-market-definition-create]')) { event.preventDefault(); activeMarket = null; resetForm(); form.querySelector('[data-market-definition-form-title]').textContent = 'Neuen Markt anlegen'; readCard.hidden = true; card.hidden = false; setDrawerState(true); form.querySelector('[data-market-definition-name]')?.focus(); return; } if (event.target.closest('[data-market-definition-edit]')) { event.preventDefault(); openEditCard(); return; } if (event.target.closest('[data-market-definition-cancel]') || event.target.closest('[data-market-definition-drawer-backdrop]')) { event.preventDefault(); closeDrawer(); } });";
echo " document.addEventListener('keydown', (event) => { if (event.key === 'Escape' && drawer.dataset.open === 'true') { closeDrawer(); } });";
echo " form.addEventListener('submit', async (event) => { event.preventDefault(); const status = form.querySelector('[data-market-definition-status]'); const submit = form.querySelector('[type=submit]'); const fields = Object.fromEntries(new FormData(form).entries()); if (status) { status.textContent = 'Speichern läuft …'; } if (submit) { submit.disabled = true; } try { const response = await fetch('/api/market-definition.php', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': definitionContent.dataset.marketDefinitionsCsrfToken || '' }, body: JSON.stringify({ fields }) }); const result = await response.json(); if (!response.ok || !result.ok) { throw new Error(result.error || 'Speichern fehlgeschlagen.'); } appendMarketRow(result.market); closeDrawer(); } catch (error) { if (status) { status.textContent = error instanceof Error ? error.message : 'Speichern fehlgeschlagen.'; } } finally { if (submit) { submit.disabled = false; } } });";
echo " form.addEventListener('submit', async (event) => { event.preventDefault(); const status = form.querySelector('[data-market-definition-status]'); const submit = form.querySelector('[type=submit]'); const fields = Object.fromEntries(new FormData(form).entries()); const isUpdate = Boolean(activeMarket?.id); if (status) { status.textContent = 'Speichern läuft …'; } if (submit) { submit.disabled = true; } try { const response = await fetch('/api/market-definition.php', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': definitionContent.dataset.marketDefinitionsCsrfToken || '' }, body: JSON.stringify({ action: isUpdate ? 'update' : 'create', id: isUpdate ? activeMarket.id : null, fields }) }); const result = await response.json(); if (!response.ok || !result.ok) { throw new Error(result.error || 'Speichern fehlgeschlagen.'); } if (isUpdate) { const trigger = activeMarket.trigger; const category = form.querySelector('[data-market-definition-category]')?.selectedOptions[0]; const website = result.market.website_url || 'Nicht hinterlegt'; trigger.textContent = result.market.name; trigger.dataset.marketDefinitionName = result.market.name; trigger.dataset.marketDefinitionCategoryId = String(result.market.category_id); trigger.dataset.marketDefinitionCategoryName = category?.textContent || ''; trigger.dataset.marketDefinitionWebsite = website; showReadCard(trigger); } else { appendMarketRow(result.market); closeDrawer(); } } catch (error) { if (status) { status.textContent = error instanceof Error ? error.message : 'Speichern fehlgeschlagen.'; } } finally { if (submit) { submit.disabled = false; } } });";
echo "}";
echo "function initBestellungenBindings() {";
echo " const contentRoot = document.querySelector('[data-left-navigation-content-body]');";
+17 -5
View File
@@ -40,11 +40,23 @@ if (!is_array($payload)) {
try {
$fields = is_array($payload['fields'] ?? null) ? $payload['fields'] : [];
$market = market_management_create_market($pdo, [
'name' => $fields['name'] ?? null,
'category_id' => $fields['category_id'] ?? null,
'website_url' => $fields['website_url'] ?? null,
]);
if (($payload['action'] ?? 'create') === 'update') {
$marketId = (int) ($payload['id'] ?? 0);
if ($marketId < 1) {
throw new InvalidArgumentException('id ist erforderlich.');
}
$market = market_management_update_market($pdo, $marketId, [
'name' => $fields['name'] ?? null,
'category_id' => $fields['category_id'] ?? null,
'website_url' => $fields['website_url'] ?? null,
]);
} else {
$market = market_management_create_market($pdo, [
'name' => $fields['name'] ?? null,
'category_id' => $fields['category_id'] ?? null,
'website_url' => $fields['website_url'] ?? null,
]);
}
echo json_encode(['ok' => true, 'market' => $market], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
} catch (Throwable $error) {
http_response_code(422);