Files
miriamgemeinde/src/content/admin/EventManagement.vue

292 lines
8.0 KiB
Vue

<template>
<div class="event-management">
<h2>Veranstaltungen</h2>
<button v-if="hasNewsletterPreview" @click="goBackToNewsletterImport">Zurück zum Gemeindebrief-Import</button>
<button @click="createEvent">Neue Veranstaltung</button>
<EventForm v-if="showForm"
ref="eventForm"
:event="selectedEvent"
:institutions="institutions"
:eventPlaces="eventPlaces"
:contactPersons="contactPersons"
@saved="handleEventSaved"
@cancelled="handleEventCancelled" />
<div class="filter-section">
<input
v-model="searchQuery"
type="text"
placeholder="Suche nach Name, Typ, Beschreibung..."
class="search-input"
/>
<label class="checkbox-label">
<input
v-model="showPastEvents"
type="checkbox"
/>
Vergangene Events anzeigen
</label>
</div>
<table>
<thead>
<tr>
<th>Name</th>
<th>Typ</th>
<th>Datum</th>
<th>Uhrzeit</th>
<th>Wochentag</th>
<th>Beschreibung</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
<tr v-for="event in filteredEvents" :key="event.id">
<td>{{ event.name }}</td>
<td>{{ getEventTypeCaption(event.eventTypeId) }}</td>
<td>{{ event.date }}</td>
<td>{{ formatTime(event.time) }}<span v-if="event.endTime"> - {{ formatTime(event.endTime) }}</span></td>
<td>{{ getWeekdayName(event.dayOfWeek) }}</td>
<td>{{ event.description }}</td>
<td>
<button @click="editEvent(event)">Bearbeiten</button>
<button @click="deleteEvent(event.id)">Löschen</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import axios from 'axios';
import EventForm from '@/components/EventForm.vue';
import { formatTime } from '../../utils/strings';
export default {
components: { EventForm },
data() {
return {
events: [],
institutions: [],
eventPlaces: [],
contactPersons: [],
eventTypes: [],
selectedEvent: null,
showForm: false,
searchQuery: '',
showPastEvents: false,
hasNewsletterPreview: false,
};
},
computed: {
filteredEvents() {
let filtered = this.events;
// Filter vergangene Events aus
if (!this.showPastEvents) {
const today = new Date();
today.setHours(0, 0, 0, 0);
filtered = filtered.filter(event => {
// Events mit Wochentag (ohne festes Datum) immer anzeigen
if (event.dayOfWeek !== null && event.dayOfWeek !== undefined && !event.date) {
return true;
}
// Events mit Datum: nur zukünftige oder heutige anzeigen
if (event.date) {
const eventDate = new Date(event.date);
eventDate.setHours(0, 0, 0, 0);
return eventDate >= today;
}
// Events ohne Datum und ohne Wochentag anzeigen
return true;
});
}
// Suchfilter anwenden
if (this.searchQuery.trim()) {
const query = this.searchQuery.toLowerCase();
filtered = filtered.filter(event => {
const name = event.name ? event.name.toLowerCase() : '';
const description = event.description ? event.description.toLowerCase() : '';
const eventType = this.getEventTypeCaption(event.eventTypeId).toLowerCase();
return name.includes(query) ||
description.includes(query) ||
eventType.includes(query);
});
}
return filtered;
}
},
async created() {
await this.fetchData();
this.hasNewsletterPreview = !!localStorage.getItem('newsletter_import_last_result');
this.applyNewsletterDraft();
},
methods: {
formatTime,
async fetchData() {
try {
const [eventResponse, institutionResponse, eventPlaceResponse, contactPersonResponse, eventTypeResponse] = await Promise.all([
axios.get('/events'),
axios.get('/institutions'),
axios.get('/event-places'),
axios.get('/contact-persons'),
axios.get('/event-types')
]);
this.events = eventResponse.data;
this.institutions = institutionResponse.data;
this.eventPlaces = eventPlaceResponse.data;
this.contactPersons = contactPersonResponse.data;
this.eventTypes = eventTypeResponse.data;
} catch (error) {
console.error('Fehler beim Abrufen der Daten:', error);
}
},
createEvent() {
this.selectedEvent = {};
this.showForm = true;
this.scrollToFormAndFocus();
},
goBackToNewsletterImport() {
this.$router.push('/admin/newsletter-import');
},
applyNewsletterDraft() {
const raw = localStorage.getItem('newsletter_import_event_draft');
if (!raw) return;
localStorage.removeItem('newsletter_import_event_draft');
try {
const draft = JSON.parse(raw);
const resolvedEventPlace =
this.eventPlaces.find((place) => place.id === draft?.event_place_id) ||
this.eventPlaces.find((place) =>
draft?.event_place_name &&
String(place?.name || '').toLowerCase().includes(String(draft.event_place_name).toLowerCase())
) ||
null;
this.selectedEvent = {
name: draft?.name || '',
description: '',
date: draft?.date || '',
time: draft?.time || '',
eventTypeId: draft?.eventTypeId ?? null,
event_place_id: resolvedEventPlace?.id ?? draft?.event_place_id ?? null,
eventPlace: resolvedEventPlace,
__newsletterDateMode: draft?.dateMode || null,
__newsletterBulkDates: draft?.bulkDates || '',
};
this.showForm = true;
this.scrollToFormAndFocus();
} catch (error) {
console.error('Fehler beim Übernehmen des Gemeindebrief-Entwurfs (Event):', error);
}
},
editEvent(event) {
this.selectedEvent = { ...event };
this.showForm = true;
this.scrollToFormAndFocus();
},
scrollToFormAndFocus() {
// Wartet auf das Rendern des Formulars und scrollt dann nach oben
this.$nextTick(() => {
// Nach oben scrollen
window.scrollTo({ top: 0, behavior: 'smooth' });
// Das erste Feld fokussieren
if (this.$refs.eventForm) {
this.$refs.eventForm.focusFirstField();
}
});
},
async deleteEvent(id) {
try {
await axios.delete(`/events/${id}`);
this.fetchData();
} catch (error) {
console.error('Fehler beim Löschen der Veranstaltung:', error);
}
},
handleEventSaved() {
this.showForm = false;
this.fetchData();
},
handleEventCancelled() {
this.showForm = false;
},
getEventTypeCaption(eventTypeId) {
const eventType = this.eventTypes.find(type => type.id === eventTypeId);
return eventType ? eventType.caption : 'Unbekannt';
},
getWeekdayName(dayOfWeek) {
const weekdays = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
return weekdays[dayOfWeek];
},
}
};
</script>
<style scoped>
.event-management {
max-width: 1200px;
margin: 0 auto;
}
.filter-section {
margin: 20px 0;
display: flex;
gap: 20px;
align-items: center;
flex-wrap: wrap;
}
.search-input {
flex: 1;
min-width: 250px;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.search-input:focus {
outline: none;
border-color: #4CAF50;
}
.checkbox-label {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
user-select: none;
}
.checkbox-label input[type="checkbox"] {
cursor: pointer;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th,
td {
border: 1px solid #ddd;
padding: 8px;
}
th {
background-color: #f2f2f2;
}
button {
margin: 5px;
}
</style>