Implement date filtering for worship imports in WorshipManagement.vue: Add date range filter inputs, enhance worship list display with filtered results, and improve data handling for imported worships, ensuring better user experience during worship management.
All checks were successful
Deploy miriamgemeinde / deploy (push) Successful in 7s

This commit is contained in:
Torsten Schulz (local)
2026-04-30 09:32:56 +02:00
parent 22f882d9d2
commit 181257ad26

View File

@@ -72,8 +72,29 @@
<li v-for="(error, index) in importErrors" :key="index">{{ error }}</li>
</ul>
</div>
<div class="import-filter-bar">
<p class="import-range">
Importierter Zeitraum: {{ importedDateRangeLabel }}
</p>
<div class="import-filter-fields">
<label>
Von:
<input type="date" v-model="importFilterFrom" />
</label>
<label>
Bis:
<input type="date" v-model="importFilterTo" />
</label>
<button type="button" class="clear-button" @click="clearImportDateFilter">
Filter zurücksetzen
</button>
</div>
<p class="import-range">
Angezeigt: {{ filteredImportedWorships.length }} von {{ importedWorships.length }}
</p>
</div>
<div class="imported-worships-list">
<div v-for="(worship, index) in importedWorships" :key="index" class="imported-worship-item">
<div v-for="(worship, index) in filteredImportedWorships" :key="worship._tempId || index" class="imported-worship-item">
<h4>
Gottesdienst {{ index + 1 }}
<span v-if="worship._isNew" class="new-badge">NEU</span>
@@ -197,7 +218,7 @@
Selbstinformation
</label>
</div>
<button type="button" @click="removeWorship(index)" class="remove-button">Entfernen</button>
<button type="button" @click="removeWorship(worship)" class="remove-button">Entfernen</button>
</div>
</div>
</div>
@@ -373,6 +394,8 @@ export default {
importedWorships: [],
importErrors: [],
hasNewsletterPreview: false,
importFilterFrom: '',
importFilterTo: '',
};
},
computed: {
@@ -410,6 +433,34 @@ export default {
}
return filtered;
},
filteredImportedWorships() {
return this.importedWorships.filter((w) => {
const dateValue = this.normalizeDateOnly(w.date);
if (!dateValue) return false;
// 1) Vergangene Termine grundsätzlich ausblenden.
const today = new Date();
today.setHours(0, 0, 0, 0);
const worshipDate = new Date(dateValue);
worshipDate.setHours(0, 0, 0, 0);
if (worshipDate < today) return false;
// 2) Zusätzlicher Von/Bis-Filter.
if (this.importFilterFrom && dateValue < this.importFilterFrom) return false;
if (this.importFilterTo && dateValue > this.importFilterTo) return false;
return true;
});
},
importedDateRangeLabel() {
const dates = this.importedWorships
.map((w) => this.normalizeDateOnly(w.date))
.filter(Boolean)
.sort();
if (dates.length === 0) return '-';
const from = dates[0];
const to = dates[dates.length - 1];
return `${this.formatDate(from)} bis ${this.formatDate(to)}`;
}
},
watch: {
@@ -430,6 +481,20 @@ export default {
this.applyNewsletterDraft();
},
methods: {
normalizeDateOnly(value) {
if (!value) return '';
if (typeof value === 'string') return value.split('T')[0];
const date = new Date(value);
if (Number.isNaN(date.getTime())) return '';
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, '0');
const d = String(date.getDate()).padStart(2, '0');
return `${y}-${m}-${d}`;
},
clearImportDateFilter() {
this.importFilterFrom = '';
this.importFilterTo = '';
},
goBackToNewsletterImport() {
this.$router.push('/admin/newsletter-import');
},
@@ -459,6 +524,7 @@ export default {
_oldValues: {},
_isUpdate: false,
_isNew: true,
_tempId: `bulk-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
};
});
this.importErrors = [];
@@ -904,6 +970,7 @@ export default {
_importChoice: w._importChoice || (w._hasDayPlaceConflict ? 'keepExisting' : 'import'),
neighborInvitation: !!w.neighborInvitation,
selfInformation: !!w.selfInformation,
_tempId: `imp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
_selectedOrganizer: this.resolveImportOrganizerOption(w.organizer || '')
};
});
@@ -924,13 +991,17 @@ export default {
this.showImportDialog = false;
this.importedWorships = [];
this.importErrors = [];
this.clearImportDateFilter();
this.selectedFile = null;
if (this.$refs.fileInput) {
this.$refs.fileInput.value = '';
}
},
removeWorship(index) {
this.importedWorships.splice(index, 1);
removeWorship(worshipToRemove) {
const index = this.importedWorships.findIndex((w) => w === worshipToRemove || (w._tempId && w._tempId === worshipToRemove._tempId));
if (index >= 0) {
this.importedWorships.splice(index, 1);
}
},
handleImportNeighborInvitationChange(worship) {
if (worship?.neighborInvitation) {
@@ -938,12 +1009,13 @@ export default {
}
},
async saveImportedWorships() {
if (this.importedWorships.length === 0) {
const worshipsForSave = this.filteredImportedWorships;
if (worshipsForSave.length === 0) {
alert('Keine Gottesdienste zum Speichern vorhanden.');
return;
}
const invalidWorship = this.importedWorships.find(w => {
const invalidWorship = worshipsForSave.find(w => {
if (w._hasDayPlaceConflict && w._importChoice === 'keepExisting') {
return false;
}
@@ -958,7 +1030,7 @@ export default {
this.isImporting = true;
// Daten für das Backend vorbereiten
const worshipsToSave = this.importedWorships.map(w => {
const worshipsToSave = worshipsForSave.map(w => {
// Stelle sicher, dass das Datum im richtigen Format ist (YYYY-MM-DD)
let dateStr = w.date;
if (w.date instanceof Date) {