Add worship leaders functionality: Introduce worship leaders management by adding routes, controllers, and CSV import capabilities. Update worship management UI to support .csv file uploads for worship services, enhancing data handling and user experience.
All checks were successful
Deploy miriamgemeinde / deploy (push) Successful in 7s
All checks were successful
Deploy miriamgemeinde / deploy (push) Successful in 7s
This commit is contained in:
126
src/content/admin/WorshipLeaderAdministration.vue
Normal file
126
src/content/admin/WorshipLeaderAdministration.vue
Normal file
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div class="worship-leader-admin">
|
||||
<h1>Gestalter (Kürzel)</h1>
|
||||
|
||||
<h2>{{ formTitle }}</h2>
|
||||
<form @submit.prevent="saveLeader">
|
||||
<label for="code">Kürzel (z.B. "Eif"):</label>
|
||||
<input id="code" v-model="currentLeader.code" required />
|
||||
|
||||
<label for="name">Name (wird als Gestalter gespeichert):</label>
|
||||
<input id="name" v-model="currentLeader.name" required />
|
||||
|
||||
<label for="aliases">Aliase (kommagetrennt):</label>
|
||||
<input id="aliases" v-model="currentLeader.aliases" />
|
||||
|
||||
<div class="row">
|
||||
<label for="active">Aktiv:</label>
|
||||
<input id="active" v-model="currentLeader.active" type="checkbox" />
|
||||
</div>
|
||||
|
||||
<button type="submit">{{ isCreating ? 'Erstellen' : 'Aktualisieren' }}</button>
|
||||
<button v-if="!isCreating" type="button" @click="resetForm">Abbrechen</button>
|
||||
</form>
|
||||
|
||||
<div class="list">
|
||||
<h2>Vorhandene Kürzel</h2>
|
||||
<div class="tools">
|
||||
<label><input type="checkbox" v-model="includeInactive" @change="fetchLeaders" /> Inaktive anzeigen</label>
|
||||
</div>
|
||||
<ul v-if="leaders.length">
|
||||
<li v-for="leader in leaders" :key="leader.id" class="item">
|
||||
<button type="button" class="link" @click="editLeader(leader)">
|
||||
<strong>{{ leader.code }}</strong> – {{ leader.name }}
|
||||
<span v-if="leader.aliases"> ({{ leader.aliases }})</span>
|
||||
<span v-if="!leader.active"> [inaktiv]</span>
|
||||
</button>
|
||||
<button type="button" class="danger" @click="deleteLeader(leader)">Löschen</button>
|
||||
</li>
|
||||
</ul>
|
||||
<p v-else>Keine Einträge.</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from '@/axios';
|
||||
|
||||
export default {
|
||||
name: 'WorshipLeaderAdministration',
|
||||
data() {
|
||||
return {
|
||||
leaders: [],
|
||||
includeInactive: false,
|
||||
currentLeader: {
|
||||
code: '',
|
||||
name: '',
|
||||
aliases: '',
|
||||
active: true,
|
||||
},
|
||||
isCreating: true,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
formTitle() {
|
||||
return this.isCreating ? 'Kürzel anlegen' : 'Kürzel bearbeiten';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async fetchLeaders() {
|
||||
try {
|
||||
const response = await axios.get('/worship-leaders', {
|
||||
params: { includeInactive: this.includeInactive ? 1 : 0 },
|
||||
});
|
||||
this.leaders = response.data || [];
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Kürzel:', error);
|
||||
}
|
||||
},
|
||||
async saveLeader() {
|
||||
try {
|
||||
if (this.isCreating) {
|
||||
await axios.post('/worship-leaders', this.currentLeader);
|
||||
} else {
|
||||
await axios.put(`/worship-leaders/${this.currentLeader.id}`, this.currentLeader);
|
||||
}
|
||||
this.resetForm();
|
||||
await this.fetchLeaders();
|
||||
} catch (error) {
|
||||
const msg = error.response?.data?.message || error.message;
|
||||
alert(`Fehler: ${msg}`);
|
||||
}
|
||||
},
|
||||
editLeader(leader) {
|
||||
this.currentLeader = { ...leader };
|
||||
this.isCreating = false;
|
||||
},
|
||||
async deleteLeader(leader) {
|
||||
if (!confirm(`Kürzel "${leader.code}" wirklich löschen?`)) return;
|
||||
try {
|
||||
await axios.delete(`/worship-leaders/${leader.id}`);
|
||||
await this.fetchLeaders();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Löschen:', error);
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
this.currentLeader = { code: '', name: '', aliases: '', active: true };
|
||||
this.isCreating = true;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchLeaders();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.worship-leader-admin { padding: 20px; }
|
||||
form { display: grid; gap: 8px; max-width: 520px; }
|
||||
.row { display: flex; align-items: center; gap: 10px; }
|
||||
.list { margin-top: 18px; }
|
||||
.tools { margin: 8px 0; }
|
||||
.item { display: flex; align-items: center; gap: 10px; margin: 6px 0; }
|
||||
.link { background: none; border: none; padding: 0; color: #1a73e8; cursor: pointer; text-align: left; }
|
||||
.danger { background: #c62828; color: #fff; border: none; padding: 4px 8px; border-radius: 4px; cursor: pointer; }
|
||||
</style>
|
||||
@@ -15,13 +15,13 @@
|
||||
<div v-if="showImportSection" class="import-section">
|
||||
<h3>Gottesdienste importieren</h3>
|
||||
<div class="import-content">
|
||||
<label for="import-file">Datei auswählen (.doc, .docx):</label>
|
||||
<label for="import-file">Datei auswählen (.doc, .docx, .csv):</label>
|
||||
<input
|
||||
type="file"
|
||||
id="import-file"
|
||||
ref="fileInput"
|
||||
@change="handleFileSelect"
|
||||
accept=".doc,.docx"
|
||||
accept=".doc,.docx,.csv"
|
||||
/>
|
||||
<div v-if="selectedFile" class="selected-file">
|
||||
Ausgewählte Datei: {{ selectedFile.name }}
|
||||
@@ -730,13 +730,13 @@ export default {
|
||||
handleFileSelect(event) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
// Validierung: Nur .doc und .docx Dateien erlauben
|
||||
const allowedExtensions = ['.doc', '.docx'];
|
||||
// Validierung: .docx (alt) oder .csv (neu) erlauben
|
||||
const allowedExtensions = ['.doc', '.docx', '.csv'];
|
||||
const fileName = file.name.toLowerCase();
|
||||
const isValidFile = allowedExtensions.some(ext => fileName.endsWith(ext));
|
||||
|
||||
if (!isValidFile) {
|
||||
alert('Bitte wählen Sie nur .doc oder .docx Dateien aus.');
|
||||
alert('Bitte wählen Sie eine .doc/.docx oder .csv Datei aus.');
|
||||
event.target.value = '';
|
||||
this.selectedFile = null;
|
||||
return;
|
||||
@@ -758,7 +758,12 @@ export default {
|
||||
formData.append('file', this.selectedFile);
|
||||
|
||||
try {
|
||||
const response = await axios.post('/worships/import', formData, {
|
||||
const fileName = this.selectedFile.name.toLowerCase();
|
||||
const endpoint = fileName.endsWith('.csv')
|
||||
? '/worships/import/nbr-csv'
|
||||
: '/worships/import';
|
||||
|
||||
const response = await axios.post(endpoint, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
|
||||
@@ -5,6 +5,7 @@ const ROUTE_NAMES = {
|
||||
ADMIN_EDIT_PAGES: 'admin-edit-pages',
|
||||
ADMIN_FILE_UPLOAD: 'admin-file-upload',
|
||||
ADMIN_NEWSLETTER_IMPORT: 'admin-newsletter-import',
|
||||
ADMIN_WORSHIP_LEADERS: 'admin-worship-leaders',
|
||||
REGISTER: 'register',
|
||||
FORGOT_PASSWORD: 'forgot-password',
|
||||
RESET_PASSWORD: 'reset-password',
|
||||
@@ -219,6 +220,21 @@ function addNewsletterImportRoute() {
|
||||
});
|
||||
}
|
||||
|
||||
function addWorshipLeadersRoute() {
|
||||
if (router.hasRoute(ROUTE_NAMES.ADMIN_WORSHIP_LEADERS)) {
|
||||
router.removeRoute(ROUTE_NAMES.ADMIN_WORSHIP_LEADERS);
|
||||
}
|
||||
router.addRoute({
|
||||
path: '/admin/worship-leaders',
|
||||
meta: { requiresAuth: true },
|
||||
components: {
|
||||
default: loadComponent('admin/WorshipLeaderAdministration'),
|
||||
rightColumn: loadComponent('ImageContent')
|
||||
},
|
||||
name: ROUTE_NAMES.ADMIN_WORSHIP_LEADERS
|
||||
});
|
||||
}
|
||||
|
||||
function addRegisterRoute() {
|
||||
if (router.hasRoute(ROUTE_NAMES.REGISTER)) {
|
||||
router.removeRoute(ROUTE_NAMES.REGISTER);
|
||||
@@ -335,6 +351,7 @@ function ensureCoreRoutes() {
|
||||
if (!router.hasRoute(ROUTE_NAMES.ADMIN_EDIT_PAGES)) addEditPagesRoute();
|
||||
if (!router.hasRoute(ROUTE_NAMES.ADMIN_FILE_UPLOAD)) addFileUploadRoute();
|
||||
if (!router.hasRoute(ROUTE_NAMES.ADMIN_NEWSLETTER_IMPORT)) addNewsletterImportRoute();
|
||||
if (!router.hasRoute(ROUTE_NAMES.ADMIN_WORSHIP_LEADERS)) addWorshipLeadersRoute();
|
||||
if (!router.hasRoute(ROUTE_NAMES.REGISTER)) addRegisterRoute();
|
||||
if (!router.hasRoute(ROUTE_NAMES.FORGOT_PASSWORD)) addForgotPasswordRoute();
|
||||
if (!router.hasRoute(ROUTE_NAMES.RESET_PASSWORD)) addResetPasswordRoute();
|
||||
@@ -348,6 +365,7 @@ function ensureCoreRoutes() {
|
||||
addEditPagesRoute();
|
||||
addFileUploadRoute();
|
||||
addNewsletterImportRoute();
|
||||
addWorshipLeadersRoute();
|
||||
addRegisterRoute();
|
||||
addForgotPasswordRoute();
|
||||
addResetPasswordRoute();
|
||||
|
||||
Reference in New Issue
Block a user