adsad
All checks were successful
Deploy / deploy (push) Successful in 1m2s

This commit is contained in:
2026-08-04 22:07:29 +02:00
parent ac32727dc6
commit 565d197bb2
6 changed files with 143 additions and 103 deletions

View File

@@ -921,6 +921,9 @@ if (!empty($canManageSystemSettings)) {
</p>
</div>
<?php endif; ?>
<div class="card" id="entryKindQuickGuide">
<p class="muted small" style="margin:0;">Trage zuerst nur die wichtigsten Angaben ein. Alles Weitere ist optional und unten einklappbar.</p>
</div>
<div class="stack gap-6">
<label class="label" for="evTitle">Titel</label>
<input id="evTitle" name="title" class="input" placeholder="z. B. Väter-Kaffee im Park" required value="<?= htmlspecialchars($titleValue, ENT_QUOTES) ?>">
@@ -947,20 +950,16 @@ if (!empty($canManageSystemSettings)) {
<input id="categoryCustomTitle" name="category_custom_title" class="input" placeholder="z. B. Tierpark">
</div>
</div>
<div class="stack gap-6" id="placeLookupWrap">
<label class="label" for="existingPlaceLookup">Vorhandenen Ort suchen (optional)</label>
<div class="flex gap-8" style="flex-wrap:wrap;">
<input id="existingPlaceLookup" class="input" list="existingPlacesList" placeholder="z. B. Tierpark, Café, Spielplatz" style="flex:1;">
<button class="btn ghost" type="button" id="btnUseExistingPlace">Ort übernehmen</button>
<details id="placeLookupWrap" class="card">
<summary style="cursor:pointer; font-weight:600;">Vorhandenen Ort übernehmen</summary>
<div class="stack gap-6" style="margin-top:12px;">
<label class="label" for="existingPlaceLookup">Vorhandenen Ort suchen (optional)</label>
<div class="flex gap-8" style="flex-wrap:wrap;">
<input id="existingPlaceLookup" class="input" list="existingPlacesList" placeholder="z. B. Tierpark, Café, Spielplatz" style="flex:1;">
<button class="btn ghost" type="button" id="btnUseExistingPlace">Ort übernehmen</button>
</div>
</div>
</div>
<div class="stack gap-6">
<label class="label" for="imageFile">Bild (optional)</label>
<input id="imageFile" name="image_file" class="input" type="file" accept="image/jpeg,image/png,image/webp">
<?php if ($imagePathValue !== ''): ?>
<div class="muted small">Aktuelles Bild: <a href="<?= htmlspecialchars($imagePathValue, ENT_QUOTES) ?>" target="_blank" rel="noopener">Ansehen</a></div>
<?php endif; ?>
</div>
</details>
<div class="form-grid" id="eventDateRow">
<div class="stack gap-6">
<label class="label" for="evDate">Start / Termin</label>
@@ -1030,14 +1029,36 @@ if (!empty($canManageSystemSettings)) {
<div class="flex gap-8" style="flex-wrap:wrap; align-items:center;">
<button class="btn ghost" type="button" id="btnEventAddressSearch">Adresse suchen</button>
<button class="btn ghost" type="button" id="btnEventBrowserLocation">Browser-Adresse übernehmen</button>
<button class="btn ghost" type="button" id="btnAddrToMap">Adresse auf Karte setzen</button>
<span class="muted small">Hält Karte und Adresse synchron.</span>
</div>
<div id="eventAddressStatus" class="muted small" style="margin:0;"></div>
<input type="hidden" id="evLat" name="lat" value="<?= htmlspecialchars($latValue, ENT_QUOTES) ?>">
<input type="hidden" id="evLng" name="lng" value="<?= htmlspecialchars($lngValue, ENT_QUOTES) ?>">
<div class="stack gap-6" id="placeContactWrap">
<div class="form-grid">
<details class="card" id="mapDetails">
<summary style="cursor:pointer; font-weight:600;">Adresse auf Karte wählen</summary>
<div class="stack gap-6" style="margin-top:12px;">
<div class="flex gap-8" style="flex-wrap:wrap; align-items:center;">
<button class="btn ghost" type="button" id="btnAddrToMap">Adresse auf Karte setzen</button>
<span class="muted small">Hält Karte und Adresse synchron.</span>
</div>
<div class="stack gap-6">
<button class="btn ghost" type="button" id="btnMap">Auf Karte suchen</button>
<div id="mapWrapper" class="map-wrapper" hidden>
<div class="form-row">
<label class="label" for="mapSearch">Adresse suchen (optional)</label>
<div class="flex gap-8">
<input id="mapSearch" class="input" placeholder="Straße, PLZ, Ort">
<button class="btn ghost" type="button" id="btnMapSearch">Suchen</button>
</div>
<p class="muted small">Klick auf die Karte setzt den Treffpunkt. Zoom/Scroll möglich.</p>
</div>
<div id="mapContainer" class="map-container"></div>
</div>
</div>
</div>
</details>
<details class="card" id="placeContactWrap">
<summary style="cursor:pointer; font-weight:600;">Kontaktangaben</summary>
<div class="form-grid" style="margin-top:12px;">
<div class="stack gap-6">
<label class="label" for="placePhone">Telefon (optional)</label>
<input id="placePhone" name="phone" class="input" value="<?= htmlspecialchars($phoneValue, ENT_QUOTES) ?>">
@@ -1047,87 +1068,92 @@ if (!empty($canManageSystemSettings)) {
<input id="placeWebsite" name="website_url" class="input" type="url" placeholder="https://..." value="<?= htmlspecialchars($websiteValue, ENT_QUOTES) ?>">
</div>
</div>
</div>
<div class="stack gap-6" id="placeOpeningHoursWrap">
<div class="flex between center-y">
<label class="label" for="openingHoursNote">Öffnungszeiten / Zeitfenster</label>
<button class="btn ghost" type="button" id="btnAddOpeningRow">Zeit hinzufügen</button>
</div>
<div id="openingHoursRows" class="stack gap-8">
<?php foreach ($openingHoursRows as $openingRow): ?>
<div class="form-grid opening-row">
<input name="opening_day_label[]" class="input" placeholder="z. B. Montag oder täglich" value="<?= htmlspecialchars((string)($openingRow['day_label'] ?? ''), ENT_QUOTES) ?>">
<input name="opening_time_from[]" class="input" type="time" value="<?= htmlspecialchars((string)($openingRow['time_from'] ?? ''), ENT_QUOTES) ?>">
<input name="opening_time_to[]" class="input" type="time" value="<?= htmlspecialchars((string)($openingRow['time_to'] ?? ''), ENT_QUOTES) ?>">
<input name="opening_note[]" class="input" placeholder="Hinweis" value="<?= htmlspecialchars((string)($openingRow['note'] ?? ''), ENT_QUOTES) ?>">
</div>
<?php endforeach; ?>
</div>
<textarea id="openingHoursNote" name="opening_hours_note" class="textarea" rows="2" placeholder="Freitext-Hinweis zu Öffnungszeiten oder Besonderheiten"><?= htmlspecialchars($openingHoursValue, ENT_QUOTES) ?></textarea>
</div>
<div class="stack gap-6">
<button class="btn ghost" type="button" id="btnMap">Auf Karte suchen</button>
<div id="mapWrapper" class="map-wrapper" hidden>
<div class="form-row">
<label class="label" for="mapSearch">Adresse suchen (optional)</label>
<div class="flex gap-8">
<input id="mapSearch" class="input" placeholder="Straße, PLZ, Ort">
<button class="btn ghost" type="button" id="btnMapSearch">Suchen</button>
</div>
<p class="muted small">Klick auf die Karte setzt den Treffpunkt. Zoom/Scroll möglich.</p>
</details>
<details class="card" id="placeOpeningHoursWrap">
<summary style="cursor:pointer; font-weight:600;">Öffnungszeiten / Zeitfenster</summary>
<div class="stack gap-6" style="margin-top:12px;">
<div class="flex between center-y">
<label class="label" for="openingHoursNote">Öffnungszeiten / Zeitfenster</label>
<button class="btn ghost" type="button" id="btnAddOpeningRow">Zeit hinzufügen</button>
</div>
<div id="mapContainer" class="map-container"></div>
</div>
</div>
<div class="form-grid">
<div class="stack gap-6">
<label class="label" for="evVis">Sichtbarkeit</label>
<select id="evVis" name="visibility" class="select">
<option value="public" <?= $visibilityValue === 'public' ? 'selected' : '' ?>>Öffentlich</option>
<option value="members" <?= $visibilityValue === 'members' ? 'selected' : '' ?>>Nur Mitglieder</option>
</select>
</div>
</div>
<div class="stack gap-10" id="eventPricingWrap">
<div class="flex between center-y">
<label class="label">Eintritt / Kosten</label>
<button class="btn ghost" type="button" id="btnAddPriceRow">Preisregel hinzufügen</button>
</div>
<div id="priceRows" class="stack gap-8">
<?php foreach ($priceRows as $priceRow): ?>
<div class="stack gap-8 price-row card">
<div class="form-grid">
<input name="price_label[]" class="input" placeholder="z. B. Kinder 4-7" value="<?= htmlspecialchars((string)($priceRow['label'] ?? ''), ENT_QUOTES) ?>">
<select name="price_audience[]" class="select">
<?php foreach (['general' => 'Allgemein', 'child' => 'Kinder', 'adult' => 'Erwachsene', 'family' => 'Familie', 'group' => 'Gruppe'] as $audienceValue => $audienceLabel): ?>
<option value="<?= htmlspecialchars($audienceValue, ENT_QUOTES) ?>" <?= (string)($priceRow['audience'] ?? 'general') === $audienceValue ? 'selected' : '' ?>><?= htmlspecialchars($audienceLabel, ENT_QUOTES) ?></option>
<?php endforeach; ?>
</select>
<div id="openingHoursRows" class="stack gap-8">
<?php foreach ($openingHoursRows as $openingRow): ?>
<div class="form-grid opening-row">
<input name="opening_day_label[]" class="input" placeholder="z. B. Montag oder täglich" value="<?= htmlspecialchars((string)($openingRow['day_label'] ?? ''), ENT_QUOTES) ?>">
<input name="opening_time_from[]" class="input" type="time" value="<?= htmlspecialchars((string)($openingRow['time_from'] ?? ''), ENT_QUOTES) ?>">
<input name="opening_time_to[]" class="input" type="time" value="<?= htmlspecialchars((string)($openingRow['time_to'] ?? ''), ENT_QUOTES) ?>">
<input name="opening_note[]" class="input" placeholder="Hinweis" value="<?= htmlspecialchars((string)($openingRow['note'] ?? ''), ENT_QUOTES) ?>">
</div>
<div class="form-grid">
<select name="price_type[]" class="select">
<?php foreach (['free' => 'Frei', 'fixed' => 'Fester Preis', 'from' => 'Preis ab', 'up_to' => 'Preis bis', 'range' => 'Preisspanne', 'request' => 'Auf Anfrage'] as $typeValue => $typeLabel): ?>
<option value="<?= htmlspecialchars($typeValue, ENT_QUOTES) ?>" <?= (string)($priceRow['price_type'] ?? 'fixed') === $typeValue ? 'selected' : '' ?>><?= htmlspecialchars($typeLabel, ENT_QUOTES) ?></option>
<?php endforeach; ?>
</select>
<input name="price_amount[]" class="input" inputmode="decimal" placeholder="Preis" value="<?= htmlspecialchars((string)($priceRow['amount'] ?? ''), ENT_QUOTES) ?>">
</div>
<div class="form-grid">
<input name="price_amount_secondary[]" class="input" inputmode="decimal" placeholder="Zweiter Preis bei Spanne" value="<?= htmlspecialchars((string)($priceRow['amount_secondary'] ?? ''), ENT_QUOTES) ?>">
<input name="price_note[]" class="input" placeholder="Hinweis" value="<?= htmlspecialchars((string)($priceRow['note'] ?? ''), ENT_QUOTES) ?>">
</div>
<div class="form-grid">
<input name="price_age_from[]" class="input" type="number" min="0" max="99" placeholder="Alter von" value="">
<input name="price_age_to[]" class="input" type="number" min="0" max="99" placeholder="Alter bis" value="">
</div>
</div>
<?php endforeach; ?>
<?php endforeach; ?>
</div>
<textarea id="openingHoursNote" name="opening_hours_note" class="textarea" rows="2" placeholder="Freitext-Hinweis zu Öffnungszeiten oder Besonderheiten"><?= htmlspecialchars($openingHoursValue, ENT_QUOTES) ?></textarea>
</div>
<div class="stack gap-6">
<label class="label" for="specialConditionsNote">Sonderkonditionen</label>
<textarea id="specialConditionsNote" name="special_conditions_note" class="textarea" rows="2" placeholder="z. B. Sonderkonditionen für Senioren oder Menschen mit Behinderung vorhanden"><?= htmlspecialchars($specialConditionsValue, ENT_QUOTES) ?></textarea>
</details>
<details class="card" id="visibilityDetails">
<summary style="cursor:pointer; font-weight:600;">Weitere Optionen</summary>
<div class="form-grid" style="margin-top:12px;">
<div class="stack gap-6">
<label class="label" for="evVis">Sichtbarkeit</label>
<select id="evVis" name="visibility" class="select">
<option value="public" <?= $visibilityValue === 'public' ? 'selected' : '' ?>>Öffentlich</option>
<option value="members" <?= $visibilityValue === 'members' ? 'selected' : '' ?>>Nur Mitglieder</option>
</select>
</div>
</div>
</div>
</details>
<details class="card">
<summary style="cursor:pointer; font-weight:600;">Bild hinzufügen</summary>
<div class="stack gap-6" style="margin-top:12px;">
<label class="label" for="imageFile">Bild (optional)</label>
<input id="imageFile" name="image_file" class="input" type="file" accept="image/jpeg,image/png,image/webp">
<?php if ($imagePathValue !== ''): ?>
<div class="muted small">Aktuelles Bild: <a href="<?= htmlspecialchars($imagePathValue, ENT_QUOTES) ?>" target="_blank" rel="noopener">Ansehen</a></div>
<?php endif; ?>
</div>
</details>
<details class="card" id="eventPricingWrap">
<summary style="cursor:pointer; font-weight:600;">Eintritt / Kosten</summary>
<div class="stack gap-10" style="margin-top:12px;">
<div class="flex between center-y">
<label class="label">Preisregeln</label>
<button class="btn ghost" type="button" id="btnAddPriceRow">Preisregel hinzufügen</button>
</div>
<div id="priceRows" class="stack gap-8">
<?php foreach ($priceRows as $priceRow): ?>
<div class="stack gap-8 price-row card">
<div class="form-grid">
<input name="price_label[]" class="input" placeholder="z. B. Kinder 4-7" value="<?= htmlspecialchars((string)($priceRow['label'] ?? ''), ENT_QUOTES) ?>">
<select name="price_audience[]" class="select">
<?php foreach (['general' => 'Allgemein', 'child' => 'Kinder', 'adult' => 'Erwachsene', 'family' => 'Familie', 'group' => 'Gruppe'] as $audienceValue => $audienceLabel): ?>
<option value="<?= htmlspecialchars($audienceValue, ENT_QUOTES) ?>" <?= (string)($priceRow['audience'] ?? 'general') === $audienceValue ? 'selected' : '' ?>><?= htmlspecialchars($audienceLabel, ENT_QUOTES) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-grid">
<select name="price_type[]" class="select">
<?php foreach (['free' => 'Frei', 'fixed' => 'Fester Preis', 'from' => 'Preis ab', 'up_to' => 'Preis bis', 'range' => 'Preisspanne', 'request' => 'Auf Anfrage'] as $typeValue => $typeLabel): ?>
<option value="<?= htmlspecialchars($typeValue, ENT_QUOTES) ?>" <?= (string)($priceRow['price_type'] ?? 'fixed') === $typeValue ? 'selected' : '' ?>><?= htmlspecialchars($typeLabel, ENT_QUOTES) ?></option>
<?php endforeach; ?>
</select>
<input name="price_amount[]" class="input" inputmode="decimal" placeholder="Preis" value="<?= htmlspecialchars((string)($priceRow['amount'] ?? ''), ENT_QUOTES) ?>">
</div>
<div class="form-grid">
<input name="price_amount_secondary[]" class="input" inputmode="decimal" placeholder="Zweiter Preis bei Spanne" value="<?= htmlspecialchars((string)($priceRow['amount_secondary'] ?? ''), ENT_QUOTES) ?>">
<input name="price_note[]" class="input" placeholder="Hinweis" value="<?= htmlspecialchars((string)($priceRow['note'] ?? ''), ENT_QUOTES) ?>">
</div>
<div class="form-grid">
<input name="price_age_from[]" class="input" type="number" min="0" max="99" placeholder="Alter von" value="">
<input name="price_age_to[]" class="input" type="number" min="0" max="99" placeholder="Alter bis" value="">
</div>
</div>
<?php endforeach; ?>
</div>
<div class="stack gap-6">
<label class="label" for="specialConditionsNote">Sonderkonditionen</label>
<textarea id="specialConditionsNote" name="special_conditions_note" class="textarea" rows="2" placeholder="z. B. Sonderkonditionen für Senioren oder Menschen mit Behinderung vorhanden"><?= htmlspecialchars($specialConditionsValue, ENT_QUOTES) ?></textarea>
</div>
</div>
</details>
<div class="flex gap-12">
<button class="btn ghost" type="button" data-modal-close>Abbrechen</button>
<button class="btn" type="submit"><?= htmlspecialchars($submitLabel, ENT_QUOTES) ?></button>
@@ -1229,6 +1255,15 @@ if (!empty($canManageSystemSettings)) {
};
}
function setSectionState(element, visible) {
if (!element) return;
element.hidden = !visible;
element.querySelectorAll('input, select, textarea, button').forEach((field) => {
if (field.type === 'hidden') return;
field.disabled = !visible;
});
}
function syncEventEntryKind(nextKind) {
const kind = nextKind || entryKindInput?.value || 'event';
if (entryKindInput) entryKindInput.value = kind;
@@ -1249,17 +1284,17 @@ if (!empty($canManageSystemSettings)) {
}
}
if (eventDateRow) eventDateRow.hidden = kind === 'place';
setSectionState(eventDateRow, kind !== 'place');
if (eventDateInput) eventDateInput.required = kind !== 'place';
if (eventLocationLabelWrap) eventLocationLabelWrap.hidden = kind !== 'event';
setSectionState(eventLocationLabelWrap, kind === 'event');
if (categorySelect) categorySelect.required = true;
if (eventChildrenWrap) eventChildrenWrap.hidden = kind === 'place';
if (eventCapacityWrap) eventCapacityWrap.hidden = kind !== 'event';
if (eventPricingWrap) eventPricingWrap.hidden = kind === 'event';
if (placeLookupWrap) placeLookupWrap.hidden = kind === 'event';
if (placeContactWrap) placeContactWrap.hidden = kind === 'event';
if (placeOpeningHoursWrap) placeOpeningHoursWrap.hidden = kind === 'event';
if (eventRecurrenceWrap) eventRecurrenceWrap.hidden = kind !== 'editorial_event';
setSectionState(eventChildrenWrap, kind === 'event' || kind === 'editorial_event');
setSectionState(eventCapacityWrap, kind === 'event');
setSectionState(eventPricingWrap, kind === 'place' || kind === 'editorial_event');
setSectionState(placeLookupWrap, kind === 'place' || kind === 'editorial_event');
setSectionState(placeContactWrap, kind === 'place' || kind === 'editorial_event');
setSectionState(placeOpeningHoursWrap, kind === 'place' || kind === 'editorial_event');
setSectionState(eventRecurrenceWrap, kind === 'editorial_event');
syncRecurrenceVisibility();
}