@@ -1202,6 +1202,9 @@ function render_auth_home_page(array $user, array $otcProducts = [], array $otcM
echo " const initializeMunicipalityFields = (scope) => { scope.querySelectorAll('select[name= \" municipality_reference_id \" ]').forEach((select) => { if (!select.querySelector('option[value= \" __new__ \" ]')) { const option = document.createElement('option'); option.value = '__new__'; option.textContent = 'Neue Gemeinde'; select.append(option); } const form = select.closest('form'); if (!form) { return; } let fields = form.querySelector('[data-market-new-municipality]'); if (!fields) { fields = document.createElement('div'); fields.className = 'sg-form-sections-card__field-group'; fields.dataset.marketNewMunicipality = ''; fields.hidden = true; fields.innerHTML = '<label class= \" sg-labeled-input-row \" ><span class= \" sg-label \" >Gemeinde</span><input class= \" sg-interaction-element sg-input-single-line \" type= \" text \" name= \" municipality_name \" data-market-new-municipality-name></label>'; select.closest('.sg-form-sections-card__field-group')?.after(fields); } const sync = () => { const visible = select.value === '__new__'; fields.hidden = !visible; const input = fields.querySelector('[data-market-new-municipality-name]'); if (input) { input.disabled = !visible; input.setAttribute('aria-disabled', String(!visible)); } }; if (select.dataset.municipalityBound !== 'true') { select.addEventListener('change', sync); select.dataset.municipalityBound = 'true'; } sync(); }); }; " ;
echo " const initializeMunicipalityFields = (scope) => { scope.querySelectorAll('select[name= \" municipality_reference_id \" ]').forEach((select) => { if (!select.querySelector('option[value= \" __new__ \" ]')) { const option = document.createElement('option'); option.value = '__new__'; option.textContent = 'Neue Gemeinde'; select.append(option); } const form = select.closest('form'); if (!form) { return; } let fields = form.querySelector('[data-market-new-municipality]'); if (!fields) { fields = document.createElement('div'); fields.className = 'sg-form-sections-card__field-group'; fields.dataset.marketNewMunicipality = ''; fields.hidden = true; fields.innerHTML = '<label class= \" sg-labeled-input-row \" ><span class= \" sg-label \" >Gemeinde</span><input class= \" sg-interaction-element sg-input-single-line \" type= \" text \" name= \" municipality_name \" data-market-new-municipality-name></label>'; select.closest('.sg-form-sections-card__field-group')?.after(fields); } const sync = () => { const visible = select.value === '__new__'; fields.hidden = !visible; const input = fields.querySelector('[data-market-new-municipality-name]'); if (input) { input.disabled = !visible; input.setAttribute('aria-disabled', String(!visible)); } }; if (select.dataset.municipalityBound !== 'true') { select.addEventListener('change', sync); select.dataset.municipalityBound = 'true'; } sync(); }); }; " ;
echo " const syncMunicipalityReadValue = (scope) => { const drawer = scope.querySelector('[data-market-drawer]'); if (!drawer?.dataset.marketPayload) { return; } let payload = { }; try { payload = JSON.parse(drawer.dataset.marketPayload); } catch (error) { return; } const value = payload.occurrence?.municipality_name || 'Nicht hinterlegt'; scope.querySelectorAll('.market-detail-row').forEach((row) => { if (row.querySelector('dt')?.textContent?.trim() !== 'Gemeinde') { return; } const output = row.querySelector('dd'); if (output && output.textContent !== value) { output.textContent = value; } }); }; " ;
echo " const syncMunicipalityReadValue = (scope) => { const drawer = scope.querySelector('[data-market-drawer]'); if (!drawer?.dataset.marketPayload) { return; } let payload = { }; try { payload = JSON.parse(drawer.dataset.marketPayload); } catch (error) { return; } const value = payload.occurrence?.municipality_name || 'Nicht hinterlegt'; scope.querySelectorAll('.market-detail-row').forEach((row) => { if (row.querySelector('dt')?.textContent?.trim() !== 'Gemeinde') { return; } const output = row.querySelector('dd'); if (output && output.textContent !== value) { output.textContent = value; } }); }; " ;
echo " const marketCard = (title, body, headerClass = 'sg-card-segment--darkgreen', actions = '', scope = '', id = '', values = null) => { const header = '<header class= \" sg-card-segment sg-card-segment--header ' + headerClass + ' sg-object-card__header \" data-component-part= \" card-header \" ><div class= \" sg-strong sg-text-on-dark \" >' + title + '</div>' + (actions ? '<div class= \" sg-component-row \" >' + actions + '</div>' : '') + '</header>'; return '<article class= \" sg-card sg-card--content-card market-detail-card \" data-component= \" content-card \" ' + (scope ? ' data-shared-editable-action-card' : '') + '>' + header + '<div class= \" sg-card-segment sg-card-segment--body \" data-component-part= \" card-body \" ' + (scope ? ' data-shared-editable-card-read' : '') + '>' + body + '</div>' + (scope ? '<div class= \" sg-card-segment sg-card-segment--body sg-card-segment--gray \" data-shared-editable-card-form hidden>' + marketEditForm(scope, id, values) + '</div>' : '') + '</article>'; }; " ;
echo " const marketCard = (title, body, headerClass = 'sg-card-segment--darkgreen', actions = '', scope = '', id = '', values = null) => { const header = '<header class= \" sg-card-segment sg-card-segment--header ' + headerClass + ' sg-object-card__header \" data-component-part= \" card-header \" ><div class= \" sg-strong sg-text-on-dark \" >' + title + '</div>' + (actions ? '<div class= \" sg-component-row \" >' + actions + '</div>' : '') + '</header>'; return '<article class= \" sg-card sg-card--content-card market-detail-card \" data-component= \" content-card \" ' + (scope ? ' data-shared-editable-action-card' : '') + '>' + header + '<div class= \" sg-card-segment sg-card-segment--body \" data-component-part= \" card-body \" ' + (scope ? ' data-shared-editable-card-read' : '') + '>' + body + '</div>' + (scope ? '<div class= \" sg-card-segment sg-card-segment--body sg-card-segment--gray \" data-shared-editable-card-form hidden>' + marketEditForm(scope, id, values) + '</div>' : '') + '</article>'; }; " ;
echo " const marketChecklistReadBody = (checklist) => { const items = Array.isArray(checklist.items) ? checklist.items : []; const rows = items.map((item, index) => '<div class= \" market-checklist-item \" ><button class= \" sg-checkbox-field sg-checkbox-field--on-grey' + (item.is_completed ? ' sg-form-active' : '') + ' \" type= \" button \" role= \" checkbox \" aria-checked= \" ' + (item.is_completed ? 'true' : 'false') + ' \" aria-label= \" Checklistenpunkt ' + (index + 1) + ' \" data-checklist-read-checkbox= \" ' + index + ' \" ><span class= \" sg-checkbox-field__mark \" aria-hidden= \" true \" >✓</span></button><span class= \" sg-body \" >' + marketEscape(item.label || '') + '</span></div>').join(''); return '<div class= \" market-checklist-list \" >' + rows + '</div><div class= \" market-checklist-comment \" ><div class= \" sg-strong \" >Kommentar</div><p class= \" sg-body \" >' + marketDisplay(checklist.comment) + '</p></div><p class= \" sg-body \" data-checklist-read-status aria-live= \" polite \" ></p>'; }; " ;
echo " const marketChecklistEditBody = (checklist) => { const items = Array.isArray(checklist.items) ? checklist.items : []; const rows = items.map((item) => '<div class= \" market-checklist-edit-item \" data-checklist-edit-item><button class= \" sg-checkbox-field sg-checkbox-field--on-grey' + (item.is_completed ? ' sg-form-active' : '') + ' \" type= \" button \" role= \" checkbox \" aria-checked= \" ' + (item.is_completed ? 'true' : 'false') + ' \" aria-label= \" Checklistenpunkt abhaken \" data-checklist-edit-checkbox><span class= \" sg-checkbox-field__mark \" aria-hidden= \" true \" >✓</span></button><input class= \" sg-interaction-element sg-input-single-line \" type= \" text \" value= \" ' + marketEscape(item.label || '') + ' \" data-checklist-label><button class= \" sg-interaction-element sg-button sg-button--warning market-checklist-delete \" type= \" button \" aria-label= \" Checklistenpunkt löschen \" data-checklist-delete-item>− </button></div>').join(''); return '<div class= \" market-checklist-edit-list \" data-checklist-edit-list>' + rows + '<div class= \" market-checklist-edit-item market-checklist-edit-item--trailing \" data-checklist-edit-item data-checklist-trailing-item><button class= \" sg-checkbox-field sg-checkbox-field--on-grey \" type= \" button \" role= \" checkbox \" aria-checked= \" false \" aria-label= \" Neuen Checklistenpunkt abhaken \" data-checklist-edit-checkbox><span class= \" sg-checkbox-field__mark \" aria-hidden= \" true \" >✓</span></button><input class= \" sg-interaction-element sg-input-single-line \" type= \" text \" value= \" \" aria-label= \" Neuer Checklistenpunkt \" data-checklist-label></div></div><label class= \" sg-labeled-input-row market-checklist-comment-field \" ><span class= \" sg-label \" >Kommentar</span><textarea class= \" sg-interaction-element sg-input-multi-line \" name= \" comment \" rows= \" 4 \" data-checklist-comment>' + marketEscape(checklist.comment || '') + '</textarea></label>'; }; " ;
echo " const marketChecklistCard = (id, checklist) => { const actions = '<button class= \" sg-interaction-element sg-button sg-button--active \" type= \" button \" data-checklist-open>Checkliste</button>' + marketEditButton('checklist', id); return '<article class= \" sg-card sg-card--content-card market-detail-card \" data-component= \" content-card \" data-shared-editable-action-card data-checklist-card><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 \" >Checkliste</div><div class= \" sg-component-row \" >' + actions + '</div></header><div class= \" sg-card-segment sg-card-segment--body sg-card-segment--gray \" data-shared-editable-card-read>' + marketChecklistReadBody(checklist) + '</div><div class= \" sg-card-segment sg-card-segment--body sg-card-segment--gray \" data-shared-editable-card-form hidden><form class= \" sg-form-sections-card market-checklist-form \" data-market-checklist-form data-market-checklist-id= \" ' + marketEscape(id) + ' \" ><div class= \" sg-form-sections-card__body \" data-pattern-part= \" form-body \" >' + marketChecklistEditBody(checklist) + '</div><footer class= \" sg-form-sections-card__actions-segment \" data-pattern-part= \" form-actions-segment \" ><div class= \" sg-form-sections-card__actions \" data-pattern-part= \" form-actions \" ><button class= \" sg-interaction-element sg-button sg-button--active sg-form-sections-card__action \" type= \" button \" data-shared-editable-card-cancel>Abbrechen</button><button class= \" sg-interaction-element sg-button sg-button--process sg-form-sections-card__action \" type= \" submit \" >Speichern</button></div></footer><p class= \" sg-body \" data-market-checklist-status aria-live= \" polite \" ></p></form></div></article>'; }; " ;
echo " const marketStatusCard = (id, values) => { const headerClass = marketStatusSegment(values.status); const textClass = headerClass === 'sg-card-segment--gray' ? '' : 'sg-text-on-dark'; const actions = marketEditButton('status', id); const header = '<header class= \" sg-card-segment sg-card-segment--header ' + headerClass + ' sg-object-card__header \" data-component-part= \" card-header \" ><div class= \" sg-strong ' + textClass + ' \" >Status: ' + marketEscape(marketStatusLabel(values.status)) + '</div><div class= \" sg-component-row \" >' + actions + '</div></header>'; return '<article class= \" sg-card sg-card--content-card market-detail-card \" data-component= \" content-card \" data-shared-editable-action-card>' + header + '<div class= \" sg-card-segment sg-card-segment--body sg-card-segment--gray \" data-shared-editable-card-form hidden>' + marketEditForm('status', id, values) + '</div></article>'; }; " ;
echo " const marketStatusCard = (id, values) => { const headerClass = marketStatusSegment(values.status); const textClass = headerClass === 'sg-card-segment--gray' ? '' : 'sg-text-on-dark'; const actions = marketEditButton('status', id); const header = '<header class= \" sg-card-segment sg-card-segment--header ' + headerClass + ' sg-object-card__header \" data-component-part= \" card-header \" ><div class= \" sg-strong ' + textClass + ' \" >Status: ' + marketEscape(marketStatusLabel(values.status)) + '</div><div class= \" sg-component-row \" >' + actions + '</div></header>'; return '<article class= \" sg-card sg-card--content-card market-detail-card \" data-component= \" content-card \" data-shared-editable-action-card>' + header + '<div class= \" sg-card-segment sg-card-segment--body sg-card-segment--gray \" data-shared-editable-card-form hidden>' + marketEditForm('status', id, values) + '</div></article>'; }; " ;
echo " const marketEditButton = () => '<button class= \" sg-interaction-element sg-button sg-button--active \" type= \" button \" data-shared-editable-card-edit>Bearbeiten</button>'; " ;
echo " const marketEditButton = () => '<button class= \" sg-interaction-element sg-button sg-button--active \" type= \" button \" data-shared-editable-card-edit>Bearbeiten</button>'; " ;
echo " const marketHumanizeError = (error) => { const message = error instanceof Error ? error.message : 'Speichern fehlgeschlagen.'; const labels = { table_available: 'Tisch vorhanden', table_rentable: 'Tisch mietbar', own_table_required: 'Eigener Tisch erforderlich', shelter_available: 'Überdachung', power_available: 'Strom', water_available: 'Wasser', lighting_available: 'Beleuchtung', direct_unload_possible: 'Direktes Entladen' }; const match = message.match(/^([a-z_]+) muss boolean sein \\ . $ /); return match && labels[match[1]] ? labels[match[1]] + ' muss Ja oder Nein sein.' : message; }; " ;
echo " const marketHumanizeError = (error) => { const message = error instanceof Error ? error.message : 'Speichern fehlgeschlagen.'; const labels = { table_available: 'Tisch vorhanden', table_rentable: 'Tisch mietbar', own_table_required: 'Eigener Tisch erforderlich', shelter_available: 'Überdachung', power_available: 'Strom', water_available: 'Wasser', lighting_available: 'Beleuchtung', direct_unload_possible: 'Direktes Entladen' }; const match = message.match(/^([a-z_]+) muss boolean sein \\ . $ /); return match && labels[match[1]] ? labels[match[1]] + ' muss Ja oder Nein sein.' : message; }; " ;
@@ -1232,9 +1235,15 @@ function render_auth_home_page(array $user, array $otcProducts = [], array $otcM
echo " const addMarketDayDraft = () => { const drawer = getMarketDrawer(); const payload = drawer?.dataset.marketPayload ? JSON.parse(drawer.dataset.marketPayload) : null; if (!payload?.occurrence) { return; } const days = Array.isArray(payload.occurrence.days) ? payload.occurrence.days : []; if (days.some((day) => day.__draft)) { return; } days.push( { id: 'draft-' + Date.now(), date: '', __draft: true }); payload.occurrence.days = days; rerenderMarketDetail(payload); const draftEdit = contentRoot.querySelector('[data-market-edit-form][data-market-edit-draft= \" true \" ]')?.closest('[data-shared-editable-action-card]')?.querySelector('[data-shared-editable-card-edit]'); draftEdit?.click(); window.setTimeout(() => syncMarketDayAddButton(contentRoot), 0); }; " ;
echo " const addMarketDayDraft = () => { const drawer = getMarketDrawer(); const payload = drawer?.dataset.marketPayload ? JSON.parse(drawer.dataset.marketPayload) : null; if (!payload?.occurrence) { return; } const days = Array.isArray(payload.occurrence.days) ? payload.occurrence.days : []; if (days.some((day) => day.__draft)) { return; } days.push( { id: 'draft-' + Date.now(), date: '', __draft: true }); payload.occurrence.days = days; rerenderMarketDetail(payload); const draftEdit = contentRoot.querySelector('[data-market-edit-form][data-market-edit-draft= \" true \" ]')?.closest('[data-shared-editable-action-card]')?.querySelector('[data-shared-editable-card-edit]'); draftEdit?.click(); window.setTimeout(() => syncMarketDayAddButton(contentRoot), 0); }; " ;
echo " const discardMarketDayDraft = () => { const drawer = getMarketDrawer(); const payload = drawer?.dataset.marketPayload ? JSON.parse(drawer.dataset.marketPayload) : null; if (!payload?.occurrence || !Array.isArray(payload.occurrence.days)) { return; } const days = payload.occurrence.days.filter((day) => !day.__draft); if (days.length === payload.occurrence.days.length) { return; } payload.occurrence.days = days; rerenderMarketDetail(payload); }; " ;
echo " const discardMarketDayDraft = () => { const drawer = getMarketDrawer(); const payload = drawer?.dataset.marketPayload ? JSON.parse(drawer.dataset.marketPayload) : null; if (!payload?.occurrence || !Array.isArray(payload.occurrence.days)) { return; } const days = payload.occurrence.days.filter((day) => !day.__draft); if (days.length === payload.occurrence.days.length) { return; } payload.occurrence.days = days; rerenderMarketDetail(payload); }; " ;
echo " const closeMarketDrawer = () => { setMarketDrawerState(false); contentRoot.querySelectorAll('[data-market-drawer-open]').forEach((button) => button.setAttribute('aria-expanded', 'false')); }; " ;
echo " const closeMarketDrawer = () => { setMarketDrawerState(false); contentRoot.querySelectorAll('[data-market-drawer-open]').forEach((button) => button.setAttribute('aria-expanded', 'false')); }; " ;
echo " const renderMarketDetail = (payload) => { const market = payload.market || { }; const occurrence = payload.occurrence || { }; const days = Array.isArray(occurrence.days) ? occurrence.days : []; const hasDraftDay = days.some((day) => day.__draft); const organizer = occurrence.organizer || { }; const organization = organizer.organization || { }; const contactPerson = organizer.contact_person || { }; const website = market.website_url ? '<a class= \" sg-hyperlink \" href= \" ' + marketEscape(market.website_url) + ' \" target= \" _blank \" rel= \" noopener \" >' + marketEscape(market.website_url) + '</a>' : 'Nicht hinterlegt'; const contract = occurrence.contract_folder_url ? '<a class= \" sg-hyperlink \" href= \" ' + marketEscape(occurrence.contract_folder_url) + ' \" target= \" _blank \" rel= \" noopener \" >Vertragsordner öffnen</a>' : 'Nicht hinterlegt'; const overview = marketRow('Markt', market.name) + marketRow('Kategorie', market.category_name || market.category_code) + '<div class= \" market-detail-row \" ><dt>Website</dt><dd>' + website + '</dd></div>' + marketRow('Ort', occurrence.place) + marketRow('Adresse', occurrence.address) + marketRow('Gemeinde', occurrence.municipality_reference_id) + marketRow('Veranstalter', organization.name) + marketRow('Kontaktperson', marketContactName(contactPerson)) + marketRow('Kontakt E-Mail', contactPerson.email) + marketRow('Kontakt Telefon', contactPerson.phone); const dates = days.map((day) => marketDate(day.date)).filter((date) => date !== 'Nicht hinterlegt').join(' – '); const costSummary = occurrence.cost_summary || { }; const participation = marketRow('Anmeldung / Anfrage', occurrence.request_or_registration_date) + marketRow('Hinweis Anmeldung', occurrence.registration_note) + marketRow('Anmeldefrist', occurrence.registration_deadline) + marketRow('Bestätigung', occurrence.confirmation_date) + marketRow('Zahlungsfrist', occurrence.payment_deadline) + marketRow('Zahlungsstatus', occurrence.payment_status) + marketRow('Zahlungsdatum', occurrence.payment_date) + marketRow('Bezahlter Betrag', marketMoney(occurrence.paid_amount)) + marketRow('Zahlungsart', occurrence.payment_method_code) + marketRow('Gesamtkosten brutto', marketMoney(costSummary.gross_amount)) + marketRow('Gesamtkosten netto', marketMoney(costSummary.net_amount)) + marketRow('Steuern', marketMoney(costSummary.tax_amount)) + marketRow('Offener Betrag', marketMoney(costSummary.open_amount)) + '<div class= \" market-detail-row \" ><dt>Kostenpositionen</dt><dd>' + marketDisplay(occurrence.cost_items_text) + '</dd></div>'; const infrastructure = marketRow('Standgrösse', occurrence.stand_size) + marketRow('Tisch vorhanden', marketBoolean(occurrence.table_available)) + marketRow('Tisch mietbar', marketBoolean(occurrence.table_rentable)) + marketRow('Eigener Tisch erforderlich', marketBoolean(occurrence.own_table_required)) + marketRow('Überdachung', marketBoolean(occurrence.shelter_available)) + marketRow('Strom', marketBoolean(occurrence.power_available)) + marketRow('Wasser', marketBoolean(occurrence.water_available)) + marketRow('Beleuchtung', marketBoolean(occurrence.lighting_available)) + marketRow('Weitere Infrastruktur', occurrence.other_infrastructure) + marketRow('Anforderungen an den eigenen Stand', occurrence.own_stand_requirements); const travel = marketRow('Reiseadresse', occurrence.travel_address) + marketRow('Distanz (km)', occurrence.travel_distance_km) + marketRow('Parkmöglichkeiten', occurrence.parking_options) + marketRow('Anlieferung', occurrence.delivery_access) + marketRow('Direktes Entladen', marketBoolean(occurrence.direct_unload_possible)) + marketRow('Lagerung', occurrence.storage_options) + marketRow('Besondere Anreisehinweise', occurrence.travel_notes); const notes = marketRow('Teilnahmebedingungen', occurrence.other_participation_conditions) + marketRow('Rücktrittsbedingungen', occurrence.cancellation_terms) + marketRow('Umsatzbeteiligung', occurrence.revenue_share_terms) + marketRow('Notizen', occurrence.notes) + '<div class= \" market-detail-row \" ><dt>Vertragsordner</dt><dd>' + contract + '</dd></div>'; const salesSummary = occurrence.sales_summary || { }; const dayTabs = days.map((day, index) => { const label = day.__draft ? 'Neuer Tag' : marketDate(day.date); const selected = day.__draft || (!hasDraftDay && index === 0); return '<button class= \" sg-interaction-element sg-button sg-button--active sg-tab-button \" type= \" button \" role= \" tab \" aria-selected= \" ' + (selected ? 'true' : 'false') + ' \" aria-controls= \" market-day-panel-' + day.id + ' \" id= \" market-day-tab-' + day.id + ' \" data-market-day-tab= \" true \" >' + label + '</button>'; }).join(''); const addDayTab = '<button class= \" sg-interaction-element sg-button sg-button--active sg-tab-button market-day-add-button \" type= \" button \" data-market-day-add= \" true \" aria-label= \" Markttag hinzufügen \" title= \" Markttag hinzufügen \" >+</button>'; const dayPanels = days.map((day, index) => { const label = day.__draft ? 'Neuer Tag' : marketDate(day.da
Line truncated
echo " const renderMarketDetail = (payload) => { const market = payload.market || { }; const occurrence = payload.occurrence || { }; const days = Array.isArray(occurrence.days) ? occurrence.days : []; const hasDraftDay = days.some((day) => day.__draft); const organizer = occurrence.organizer || { }; const organization = organizer.organization || { }; const contactPerson = organizer.contact_person || { }; const website = market.website_url ? '<a class= \" sg-hyperlink \" href= \" ' + marketEscape(market.website_url) + ' \" target= \" _blank \" rel= \" noopener \" >' + marketEscape(market.website_url) + '</a>' : 'Nicht hinterlegt'; const contract = occurrence.contract_folder_url ? '<a class= \" sg-hyperlink \" href= \" ' + marketEscape(occurrence.contract_folder_url) + ' \" target= \" _blank \" rel= \" noopener \" >Vertragsordner öffnen</a>' : 'Nicht hinterlegt'; const overview = marketRow('Markt', market.name) + marketRow('Kategorie', market.category_name || market.category_code) + '<div class= \" market-detail-row \" ><dt>Website</dt><dd>' + website + '</dd></div>' + marketRow('Ort', occurrence.place) + marketRow('Adresse', occurrence.address) + marketRow('Gemeinde', occurrence.municipality_reference_id) + marketRow('Veranstalter', organization.name) + marketRow('Kontaktperson', marketContactName(contactPerson)) + marketRow('Kontakt E-Mail', contactPerson.email) + marketRow('Kontakt Telefon', contactPerson.phone); const dates = days.map((day) => marketDate(day.date)).filter((date) => date !== 'Nicht hinterlegt').join(' – '); const costSummary = occurrence.cost_summary || { }; const participation = marketRow('Anmeldung / Anfrage', occurrence.request_or_registration_date) + marketRow('Hinweis Anmeldung', occurrence.registration_note) + marketRow('Anmeldefrist', occurrence.registration_deadline) + marketRow('Bestätigung', occurrence.confirmation_date) + marketRow('Zahlungsfrist', occurrence.payment_deadline) + marketRow('Zahlungsstatus', occurrence.payment_status) + marketRow('Zahlungsdatum', occurrence.payment_date) + marketRow('Bezahlter Betrag', marketMoney(occurrence.paid_amount)) + marketRow('Zahlungsart', occurrence.payment_method_code) + marketRow('Gesamtkosten brutto', marketMoney(costSummary.gross_amount)) + marketRow('Gesamtkosten netto', marketMoney(costSummary.net_amount)) + marketRow('Steuern', marketMoney(costSummary.tax_amount)) + marketRow('Offener Betrag', marketMoney(costSummary.open_amount)) + '<div class= \" market-detail-row \" ><dt>Kostenpositionen</dt><dd>' + marketDisplay(occurrence.cost_items_text) + '</dd></div>'; const infrastructure = marketRow('Standgrösse', occurrence.stand_size) + marketRow('Tisch vorhanden', marketBoolean(occurrence.table_available)) + marketRow('Tisch mietbar', marketBoolean(occurrence.table_rentable)) + marketRow('Eigener Tisch erforderlich', marketBoolean(occurrence.own_table_required)) + marketRow('Überdachung', marketBoolean(occurrence.shelter_available)) + marketRow('Strom', marketBoolean(occurrence.power_available)) + marketRow('Wasser', marketBoolean(occurrence.water_available)) + marketRow('Beleuchtung', marketBoolean(occurrence.lighting_available)) + marketRow('Weitere Infrastruktur', occurrence.other_infrastructure) + marketRow('Anforderungen an den eigenen Stand', occurrence.own_stand_requirements); const travel = marketRow('Reiseadresse', occurrence.travel_address) + marketRow('Distanz (km)', occurrence.travel_distance_km) + marketRow('Parkmöglichkeiten', occurrence.parking_options) + marketRow('Anlieferung', occurrence.delivery_access) + marketRow('Direktes Entladen', marketBoolean(occurrence.direct_unload_possible)) + marketRow('Lagerung', occurrence.storage_options) + marketRow('Besondere Anreisehinweise', occurrence.travel_notes); const notes = marketRow('Teilnahmebedingungen', occurrence.other_participation_conditions) + marketRow('Rücktrittsbedingungen', occurrence.cancellation_terms) + marketRow('Umsatzbeteiligung', occurrence.revenue_share_terms) + marketRow('Notizen', occurrence.notes) + '<div class= \" market-detail-row \" ><dt>Vertragsordner</dt><dd>' + contract + '</dd></div>'; const salesSummary = occurrence.sales_summary || { }; const dayTabs = days.map((day, index) => { const label = day.__draft ? 'Neuer Tag' : marketDate(day.date); const selected = day.__draft || (!hasDraftDay && index === 0); return '<button class= \" sg-interaction-element sg-button sg-button--active sg-tab-button \" type= \" button \" role= \" tab \" aria-selected= \" ' + (selected ? 'true' : 'false') + ' \" aria-controls= \" market-day-panel-' + day.id + ' \" id= \" market-day-tab-' + day.id + ' \" data-market-day-tab= \" true \" >' + label + '</button>'; }).join(''); const addDayTab = '<button class= \" sg-interaction-element sg-button sg-button--active sg-tab-button market-day-add-button \" type= \" button \" data-market-day-add= \" true \" aria-label= \" Markttag hinzufügen \" title= \" Markttag hinzufügen \" >+</button>'; const dayPanels = days.map((day, index) => { const label = day.__draft ? 'Neuer Tag' : marketDate(day.da
Line truncated
echo " const reorderMarketStatusCard = (html) => { const template = document.createElement('template'); template.innerHTML = html; const target = template.content.querySelector('[data-market-delete-occurrence-id]'); const cards = target ? Array.from(target.children).filter((child) => child.matches('.market-detail-card')) : []; if (cards.length > 1) { target.insertBefore(cards[0], cards[1].nextSibling); } return template.innerHTML; }; " ;
echo " const reorderMarketStatusCard = (html) => { const template = document.createElement('template'); template.innerHTML = html; const target = template.content.querySelector('[data-market-delete-occurrence-id]'); const cards = target ? Array.from(target.children).filter((child) => child.matches('.market-detail-card')) : []; if (cards.length > 1) { target.insertBefore(cards[0], cards[1].nextSibling); } return template.innerHTML; }; " ;
echo " const renderMarketDetailWithActions = (payload) => reorderMarketStatusCard(marketDeletePatternWithTitleAndDays(payload.occurrence?.id || '', marketDrawerTitle(payload), renderMarketDetail(payload))); " ;
echo " const renderMarketDetailWithActions = (payload) => reorderMarketStatusCard(marketDeletePatternWithTitleAndDays(payload.occurrence?.id || '', marketDrawerTitle(payload), renderMarketDetail(payload))); " ;
echo " const ensureChecklistTrailingItem = (form) => { const list = form?.querySelector('[data-checklist-edit-list]'); if (!list) { return; } const trailing = list.querySelector('[data-checklist-trailing-item]'); if (!trailing || (trailing.querySelector('[data-checklist-label]')?.value || '').trim() !== '') { const item = document.createElement('div'); item.className = 'market-checklist-edit-item market-checklist-edit-item--trailing'; item.dataset.checklistEditItem = ''; item.dataset.checklistTrailingItem = ''; item.innerHTML = '<button class= \" sg-checkbox-field sg-checkbox-field--on-grey \" type= \" button \" role= \" checkbox \" aria-checked= \" false \" aria-label= \" Neuen Checklistenpunkt abhaken \" data-checklist-edit-checkbox><span class= \" sg-checkbox-field__mark \" aria-hidden= \" true \" >✓</span></button><input class= \" sg-interaction-element sg-input-single-line \" type= \" text \" value= \" \" aria-label= \" Neuer Checklistenpunkt \" data-checklist-label>'; list.append(item); } }; " ;
echo " const setChecklistCheckbox = (button, checked) => { if (!button) { return; } button.setAttribute('aria-checked', String(checked)); button.classList.toggle('sg-form-active', checked); }; " ;
echo " const persistChecklistReadToggle = async (button) => { const drawer = getMarketDrawer(); const card = button.closest('[data-checklist-card]'); const status = card?.querySelector('[data-checklist-read-status]'); const index = Number(button.dataset.checklistReadCheckbox); let payload = { }; try { payload = drawer?.dataset.marketPayload ? JSON.parse(drawer.dataset.marketPayload) : { }; } catch (error) { return; } const items = Array.isArray(payload.occurrence?.checklist?.items) ? payload.occurrence.checklist.items : []; if (!items[index]) { return; } const previous = Boolean(items[index].is_completed); const next = !previous; items[index].is_completed = next; setChecklistCheckbox(button, next); button.disabled = true; if (status) { status.textContent = 'Speichern läuft …'; } try { const response = await fetch('/api/market-occurrence.php', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': contentRoot.querySelector('[data-market-csrf-token]')?.dataset.marketCsrfToken || '' }, body: JSON.stringify( { action: 'update_checklist', id: payload.occurrence.id, items: items.map((item) => ( { label: item.label || '', is_completed: Boolean(item.is_completed) })), comment: payload.occurrence.checklist.comment || '' }) }); const result = await response.json(); if (!response.ok || !result.ok) { throw new Error(result.error || 'Speichern fehlgeschlagen.'); } payload.occurrence.checklist = result.checklist; if (drawer) { drawer.dataset.marketPayload = JSON.stringify(payload); } if (status) { status.textContent = ''; } } catch (error) { items[index].is_completed = previous; setChecklistCheckbox(button, previous); if (status) { status.textContent = error instanceof Error ? error.message : 'Speichern fehlgeschlagen.'; } } finally { button.disabled = false; } }; " ;
echo " document.addEventListener('click', (event) => { const checklistOpen = event.target.closest('[data-checklist-open]'); if (checklistOpen) { checklistOpen.closest('[data-checklist-card]')?.querySelector('[data-checklist-read-checkbox]')?.focus(); return; } const checkbox = event.target.closest('[data-checklist-edit-checkbox]'); if (checkbox) { event.preventDefault(); setChecklistCheckbox(checkbox, checkbox.getAttribute('aria-checked') !== 'true'); return; } const readCheckbox = event.target.closest('[data-checklist-read-checkbox]'); if (readCheckbox) { event.preventDefault(); void persistChecklistReadToggle(readCheckbox); return; } const deleteItem = event.target.closest('[data-checklist-delete-item]'); if (deleteItem) { deleteItem.closest('[data-checklist-edit-item]')?.remove(); ensureChecklistTrailingItem(deleteItem.closest('[data-checklist-form]') || deleteItem.closest('[data-market-checklist-form]')); } }); " ;
echo " document.addEventListener('input', (event) => { const input = event.target.closest('[data-market-checklist-form] [data-checklist-label]'); if (!input) { return; } const form = input.closest('[data-market-checklist-form]'); const item = input.closest('[data-checklist-edit-item]'); if (item?.hasAttribute('data-checklist-trailing-item') && input.value.trim() !== '') { item.removeAttribute('data-checklist-trailing-item'); } ensureChecklistTrailingItem(form); }); " ;
echo " document.addEventListener('submit', async (event) => { const form = event.target.closest('[data-market-checklist-form]'); if (!form) { return; } event.preventDefault(); event.stopImmediatePropagation(); const status = form.querySelector('[data-market-checklist-status]'); const items = Array.from(form.querySelectorAll('[data-checklist-edit-item]')).filter((item) => !item.hasAttribute('data-checklist-trailing-item')).map((item) => ( { label: item.querySelector('[data-checklist-label]')?.value || '', is_completed: item.querySelector('[data-checklist-edit-checkbox]')?.getAttribute('aria-checked') === 'true' })); if (status) { status.textContent = 'Speichern läuft …'; } try { const response = await fetch('/api/market-occurrence.php', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': contentRoot.querySelector('[data-market-csrf-token]')?.dataset.marketCsrfToken || '' }, body: JSON.stringify( { action: 'update_checklist', id: form.dataset.marketChecklistId, items, comment: form.querySelector('[data-checklist-comment]')?.value || '' }) }); const result = await response.json(); if (!response.ok || !result.ok) { throw new Error(result.error || 'Speichern fehlgeschlagen.'); } const trigger = contentRoot.querySelector('[data-market-drawer-open][aria-expanded= \" true \" ]'); if (trigger) { await openMarketDrawer(trigger); } } catch (error) { if (status) { status.textContent = error instanceof Error ? error.message : 'Speichern fehlgeschlagen.'; } } }); " ;
echo " const marketDrawerTitle = (payload) => { const marketName = payload.market?.name || 'Marktdurchführung'; const dates = (Array.isArray(payload.occurrence?.days) ? payload.occurrence.days : []).map((day) => marketDate(day.date)).filter(Boolean); return dates.length ? marketName + ', Marktdurchführung ' + dates.join(', ') : marketName; }; " ;
echo " const marketDrawerTitle = (payload) => { const marketName = payload.market?.name || 'Marktdurchführung'; const dates = (Array.isArray(payload.occurrence?.days) ? payload.occurrence.days : []).map((day) => marketDate(day.date)).filter(Boolean); return dates.length ? marketName + ', Marktdurchführung ' + dates.join(', ') : marketName; }; " ;
echo " const openMarketDrawer = async (trigger) => { const drawer = getMarketDrawer(); if (!drawer) { return; } const title = drawer.querySelector('[data-market-drawer-title]'); const content = drawer.querySelector('[data-market-drawer-content]'); setMarketDrawerState(true); if (title) { title.textContent = 'Marktdurchführung'; } if (content) { content.innerHTML = '<p class= \" sg-body \" >Marktdetails werden geladen …</p>'; } try { const response = await fetch('/api/market-occurrence.php?id=' + encodeURIComponent(trigger.dataset.marketOccurrenceId || ''), { credentials: 'same-origin' }); const payload = await response.json(); if (!response.ok || !payload.ok) { throw new Error(payload.error || 'Marktdetails konnten nicht geladen werden.'); } drawer.dataset.marketPayload = JSON.stringify(payload); if (title) { title.textContent = marketDrawerTitle(payload); } if (content) { content.innerHTML = renderMarketDetailWithActions(payload); applyMarketTabs(content); syncMarketDayAddButton(content); } } catch (error) { if (content) { content.innerHTML = '<p class= \" sg-body \" >' + marketEscape(error.message) + '</p>'; } } contentRoot.querySelectorAll('[data-market-drawer-open]').forEach((button) => button.setAttribute('aria-expanded', String(button === trigger))); }; " ;
echo " const openMarketDrawer = async (trigger) => { const drawer = getMarketDrawer(); if (!drawer) { return; } const title = drawer.querySelector('[data-market-drawer-title]'); const content = drawer.querySelector('[data-market-drawer-content]'); setMarketDrawerState(true); if (title) { title.textContent = 'Marktdurchführung'; } if (content) { content.innerHTML = '<p class= \" sg-body \" >Marktdetails werden geladen …</p>'; } try { const response = await fetch('/api/market-occurrence.php?id=' + encodeURIComponent(trigger.dataset.marketOccurrenceId || ''), { credentials: 'same-origin' }); const payload = await response.json(); if (!response.ok || !payload.ok) { throw new Error(payload.error || 'Marktdetails konnten nicht geladen werden.'); } drawer.dataset.marketPayload = JSON.stringify(payload); if (title) { title.textContent = marketDrawerTitle(payload); } if (content) { content.innerHTML = renderMarketDetailWithActions(payload); applyMarketTabs(content); syncMarketDayAddButton(content); } } catch (error) { if (content) { content.innerHTML = '<p class= \" sg-body \" >' + marketEscape(error.message) + '</p>'; } } contentRoot.querySelectorAll('[data-market-drawer-open]').forEach((button) => button.setAttribute('aria-expanded', String(button === trigger))); }; " ;
echo " const openNewMarketDrawer = async () => { const drawer = getMarketDrawer(); if (!drawer) { return; } const title = drawer.querySelector('[data-market-drawer-title]'); const content = drawer.querySelector('[data-market-drawer-content]'); setMarketDrawerState(true); if (title) { title.textContent = 'Neue Marktdurchführung'; } if (content) { content.innerHTML = '<p class= \" sg-body \" >Pflichtangaben werden geladen …</p>'; } try { const response = await fetch('/api/market-occurrence.php?action=create_options', { credentials: 'same-origin' }); const payload = await response.json(); if (!response.ok || !payload.ok) { throw new Error(payload.error || 'Pflichtangaben konnten nicht geladen werden.'); } if (content) { content.innerHTML = marketCreateForm(payload.market_definitions || []); } } catch (error) { if (content) { content.innerHTML = '<p class= \" sg-body \" >' + marketEscape(error.message) + '</p>'; } } }; " ;
echo " const openNewMarketDrawer = async () => { const drawer = getMarketDrawer(); if (!drawer) { return; } const title = drawer.querySelector('[data-market-drawer-title]'); const content = drawer.querySelector('[data-market-drawer-content]'); setMarketDrawerState(true); if (title) { title.textContent = 'Neue Marktdurchführung'; } if (content) { content.innerHTML = '<p class= \" sg-body \" >Pflichtangaben werden geladen …</p>'; } try { const response = await fetch('/api/market-occurrence.php?action=create_options', { credentials: 'same-origin' }); const payload = await response.json(); if (!response.ok || !payload.ok) { throw new Error(payload.error || 'Pflichtangaben konnten nicht geladen werden.'); } if (content) { content.innerHTML = marketCreateForm(payload.market_definitions || []); } } catch (error) { if (content) { content.innerHTML = '<p class= \" sg-body \" >' + marketEscape(error.message) + '</p>'; } } }; " ;