inital commit

This commit is contained in:
Torsten Schulz
2024-06-15 23:01:46 +02:00
parent 1b7fefe381
commit 61653ff407
105 changed files with 7805 additions and 524 deletions

View File

@@ -0,0 +1,207 @@
<template>
<div class="admin-menu-management">
<h2>Menüverwaltung</h2>
<div>
<h3>Neuen Menüpunkt hinzufügen</h3>
<form @submit.prevent="addMenuItem">
<label for="name">Name:</label>
<input type="text" v-model="newItem.name" required />
<label for="link">Link:</label>
<input type="text" v-model="newItem.link" required />
<label for="component">Component:</label>
<input type="text" v-model="newItem.component" required />
<label for="showInMenu">Im Menü anzeigen:</label>
<input type="checkbox" v-model="newItem.showInMenu" />
<label for="requiresAuth">Authentifizierung erforderlich:</label>
<input type="checkbox" v-model="newItem.requiresAuth" />
<label for="image">Bild:</label>
<input type="text" v-model="newItem.image" />
<label for="parentId">Eltern-Menüpunkt:</label>
<select v-model="newItem.parentId">
<option :value="null">Kein Eltern-Menüpunkt</option>
<option v-for="item in menuItems" :key="item.id" :value="item.id">
{{ item.name }}
</option>
</select>
<button type="submit">Hinzufügen</button>
</form>
</div>
<div>
<h3>Menüpunkte bearbeiten</h3>
<ul>
<li v-for="item in menuItems" :key="item.id">
{{ item.name }}
<button @click="editMenuItem(item)">Bearbeiten</button>
<button @click="deleteMenuItem(item.id)">Löschen</button>
</li>
</ul>
</div>
<div v-if="editingItem">
<h3>Menüpunkt bearbeiten</h3>
<form @submit.prevent="updateMenuItem">
<label for="editName">Name:</label>
<input type="text" v-model="editingItem.name" required />
<label for="editLink">Link:</label>
<input type="text" v-model="editingItem.link" required />
<label for="editComponent">Component:</label>
<input type="text" v-model="editingItem.component" required />
<label for="editShowInMenu">Im Menü anzeigen:</label>
<input type="checkbox" v-model="editingItem.showInMenu" />
<label for="editRequiresAuth">Authentifizierung erforderlich:</label>
<input type="checkbox" v-model="editingItem.requiresAuth" />
<label for="editImage">Bild:</label>
<input type="text" v-model="editingItem.image" />
<label for="editParentId">Eltern-Menüpunkt:</label>
<select v-model="editingItem.parentId">
<option :value="null">Kein Eltern-Menüpunkt</option>
<option v-for="item in menuItems" :key="item.id" :value="item.id">
{{ item.name }}
</option>
</select>
<button type="submit">Aktualisieren</button>
<button @click="cancelEdit">Abbrechen</button>
</form>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
name: 'AdminMenuManagement',
data() {
return {
newItem: {
name: '',
link: '',
component: '',
showInMenu: false,
requiresAuth: false,
image: '',
parentId: null
},
editingItem: null
};
},
computed: {
...mapState(['menuData']),
menuItems() {
return this.menuData;
}
},
methods: {
...mapActions(['loadMenuData']),
async addMenuItem() {
this.menuData.push(this.newItem);
await this.saveMenuData();
this.resetNewItem();
},
editMenuItem(item) {
this.editingItem = { ...item };
},
async updateMenuItem() {
const index = this.menuData.findIndex(item => item.id === this.editingItem.id);
if (index !== -1) {
this.menuData.splice(index, 1, this.editingItem);
await this.saveMenuData();
this.cancelEdit();
}
},
async deleteMenuItem(id) {
this.menuData = this.menuData.filter(item => item.id !== id);
await this.saveMenuData();
},
cancelEdit() {
this.editingItem = null;
},
resetNewItem() {
this.newItem = {
name: '',
link: '',
component: '',
showInMenu: false,
requiresAuth: false,
image: '',
parentId: null
};
},
async saveMenuData() {
try {
await fetch('http://localhost:3000/api/menu-data', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(this.menuData)
});
await this.loadMenuData();
} catch (error) {
console.error('Fehler beim Speichern der Menü-Daten:', error);
}
}
},
created() {
this.loadMenuData();
}
};
</script>
<style scoped>
.admin-menu-management {
padding: 20px;
}
form {
margin-bottom: 20px;
}
form label {
display: block;
margin-top: 10px;
}
form input,
form select {
width: 100%;
padding: 5px;
margin-top: 5px;
}
button {
margin-top: 10px;
padding: 5px 10px;
cursor: pointer;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin: 10px 0;
display: flex;
justify-content: space-between;
align-items: center;
}
li button {
margin-left: 10px;
}
</style>

View File

@@ -0,0 +1,12 @@
<template>
<div>
<h2></h2>
</div>
</template>
<script>
export default {
name: 'AdminWorshipService',
};
</script>

View File

@@ -0,0 +1,83 @@
<template>
<div>
<h1>Kontaktpersonen Verwaltung</h1>
<ContactPersonForm
:contactPerson="selectedContactPerson"
:positions="positions"
@contactPersonSaved="fetchContactPersons"
/>
<ul>
<li v-for="contactPerson in contactPersons" :key="contactPerson.id" @click="selectContactPerson(contactPerson)">
{{ contactPerson.name }}
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
import ContactPersonForm from '../../components/ContactPersonForm.vue';
export default {
name: 'ContactPersonManagement',
components: {
ContactPersonForm
},
data() {
return {
contactPersons: [],
selectedContactPerson: {
name: '',
phone: '',
street: '',
zipcode: '',
city: '',
email: '',
positions: []
},
positions: []
};
},
created() {
this.fetchContactPersons();
this.fetchPositions();
},
methods: {
async fetchContactPersons() {
try {
const response = await axios.get('http://localhost:3000/api/contact-persons');
this.contactPersons = response.data;
} catch (error) {
console.error('Fehler beim Abrufen der Kontaktpersonen:', error);
}
},
async fetchPositions() {
try {
const response = await axios.get('http://localhost:3000/api/positions');
this.positions = response.data;
} catch (error) {
console.error('Fehler beim Abrufen der Positionen:', error);
}
},
selectContactPerson(contactPerson) {
this.selectedContactPerson = contactPerson;
}
}
};
</script>
<style scoped>
ul {
list-style-type: none;
padding: 0;
}
li {
cursor: pointer;
padding: 5px;
margin: 5px 0;
background-color: #f0f0f0;
}
li:hover {
background-color: #e0e0e0;
}
</style>

View File

@@ -0,0 +1,202 @@
<template>
<div class="edit-pages">
<h2>Webseiten bearbeiten</h2>
<div>
<label for="page-select">Wähle eine Seite:</label>
<select id="page-select" v-model="selectedPage" @change="loadPageContent">
<option v-for="page in pages" :key="page.link" :value="page.link">{{ page.name }}</option>
</select>
</div>
<div class="toolbar">
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()">H1</button>
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()">H2</button>
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()">H3</button>
<button @click="editor.chain().focus().toggleBold().run()">Fett</button>
<button @click="editor.chain().focus().toggleItalic().run()">Kursiv</button>
<button @click="editor.chain().focus().toggleUnderline().run()">Unterstrichen</button>
<button @click="editor.chain().focus().toggleStrike().run()">Durchgestrichen</button>
<button
@click="editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()">Tabelle</button>
<button @click="editor.chain().focus().toggleBulletList().run()">Liste</button>
<button @click="editor.chain().focus().toggleOrderedList().run()">Nummerierte Liste</button>
</div>
<div class="table-toolbar">
<button @click="editor.chain().focus().addColumnBefore().run()">Spalte davor einfügen</button>
<button @click="editor.chain().focus().addColumnAfter().run()">Spalte danach einfügen</button>
<button @click="editor.chain().focus().addRowBefore().run()">Zeile davor einfügen</button>
<button @click="editor.chain().focus().addRowAfter().run()">Zeile danach einfügen</button>
<button @click="editor.chain().focus().deleteColumn().run()">Spalte löschen</button>
<button @click="editor.chain().focus().deleteRow().run()">Zeile löschen</button>
<button @click="editor.chain().focus().toggleHeaderColumn().run()">Header-Spalte umschalten</button>
<button @click="editor.chain().focus().toggleHeaderRow().run()">Header-Zeile umschalten</button>
<button @click="editor.chain().focus().toggleHeaderCell().run()">Header-Zelle umschalten</button>
</div>
<div class="additional-toolbar">
<button>Events</button>
<button>Kontaktpersonen</button>
<button>Institutionen</button>
<button>Gottesdienste</button>
</div>
<div :class="['htmleditor']">
<EditorContent :editor="editor" />
</div>
<button @click="savePageContent">Speichern</button>
</div>
</template>
<script>
import { ref, computed, onMounted } from 'vue';
import { useStore } from 'vuex';
import axios from '../../axios';
import { EditorContent, useEditor } from '@tiptap/vue-3';
import StarterKit from '@tiptap/starter-kit';
import Table from '@tiptap/extension-table';
import TableRow from '@tiptap/extension-table-row';
import Bold from '@tiptap/extension-bold';
import Italic from '@tiptap/extension-italic';
import Underline from '@tiptap/extension-underline';
import Strike from '@tiptap/extension-strike';
import BulletList from '@tiptap/extension-bullet-list';
import OrderedList from '@tiptap/extension-ordered-list';
import Heading from '@tiptap/extension-heading';
import { CustomTableCell, CustomTableHeader } from '../../extensions/CustomTableCell'; // Importiere die angepasste Erweiterung
export default {
name: 'EditPagesComponent',
components: {
EditorContent,
},
setup() {
const store = useStore();
const pages = ref([]);
const selectedPage = ref('');
const pageHtmlContent = computed(() => store.state.pageContent);
const editor = useEditor({
extensions: [
StarterKit,
Table.configure({
resizable: true,
}),
TableRow,
CustomTableCell,
CustomTableHeader,
Bold,
Italic,
Underline,
Strike,
BulletList,
OrderedList,
Heading.configure({
levels: [1, 2, 3],
}),
],
content: '',
onUpdate: ({ editor }) => {
store.commit('UPDATE_PAGE_CONTENT', editor.getHTML());
},
});
const fetchPages = async () => {
try {
const response = await axios.get('http://localhost:3000/api/menu-data');
pages.value = response.data;
} catch (error) {
console.error('Fehler beim Abrufen der Seiten:', error);
}
};
const loadPageContent = async () => {
try {
await store.dispatch('loadPageContent', selectedPage.value);
const content = store.getters.pageContent;
const setEditorContent = () => {
if (editor.value && editor.value.commands) {
editor.value.commands.setContent(content, false);
} else {
setTimeout(setEditorContent, 100); // Try again after 100ms if not ready
}
};
setEditorContent();
} catch (error) {
console.error('Fehler beim Laden des Seiteninhalts:', error);
}
};
const savePageContent = async () => {
try {
const selectedPageName = pages.value.find(page => page.link === selectedPage.value)?.name || '';
if (!selectedPageName) {
return;
}
const contentToSave = editor.value.getHTML();
store.commit('SET_PAGE_CONTENT', contentToSave);
await store.dispatch('savePageContent', {
link: selectedPage.value,
name: selectedPageName,
});
} catch (error) {
console.error('Fehler beim Speichern des Seiteninhalts:', error);
}
};
onMounted(fetchPages);
return {
pages,
selectedPage,
editor,
loadPageContent,
savePageContent,
pageHtmlContent,
};
},
};
</script>
<style scoped>
.edit-pages {
width: 100%;
margin: auto;
}
#page-select {
margin-bottom: 20px;
}
.toolbar {
margin-bottom: 10px;
}
.toolbar button {
margin-right: 5px;
}
.table-toolbar {
margin-bottom: 10px;
}
.table-toolbar button {
margin-right: 5px;
}
.additional-toolbar {
margin-bottom: 10px;
}
.additional-toolbar button {
margin-right: 5px;
}
.ql-container {
background-color: #fff !important;
}
.ql-editor {
background-color: #fff !important;
}
</style>

View File

@@ -0,0 +1,144 @@
<template>
<div class="event-management">
<h2>Veranstaltungen</h2>
<button @click="createEvent">Neue Veranstaltung</button>
<EventForm v-if="showForm"
:event="selectedEvent"
:institutions="institutions"
:eventPlaces="eventPlaces"
:contactPersons="contactPersons"
@saved="handleEventSaved"
@cancelled="handleEventCancelled" />
<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 events" :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,
};
},
async created() {
await this.fetchData();
},
methods: {
formatTime,
async fetchData() {
try {
const [eventResponse, institutionResponse, eventPlaceResponse, contactPersonResponse, eventTypeResponse] = await Promise.all([
axios.get('http://localhost:3000/api/events'),
axios.get('http://localhost:3000/api/institutions'),
axios.get('http://localhost:3000/api/event-places'),
axios.get('http://localhost:3000/api/contact-persons'),
axios.get('http://localhost:3000/api/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;
},
editEvent(event) {
this.selectedEvent = { ...event };
this.showForm = true;
},
async deleteEvent(id) {
try {
await axios.delete(`http://localhost:3000/api/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 - 1];
},
}
};
</script>
<style scoped>
.event-management {
max-width: 1200px;
margin: 0 auto;
}
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>

View File

@@ -0,0 +1,147 @@
<template>
<div class="event-places-management">
<h2>Veranstaltungsorte verwalten</h2>
<form @submit.prevent="addEventPlace">
<label for="name">Name:</label>
<input type="text" id="name" v-model="newEventPlace.name" placeholder="Name" required>
<label for="street">Straße:</label>
<input type="text" id="street" v-model="newEventPlace.street" placeholder="Straße" required>
<label for="zipcode">PLZ:</label>
<input type="text" id="zipcode" v-model="newEventPlace.zipcode" placeholder="PLZ" required>
<label for="city">Stadt:</label>
<input type="text" id="city" v-model="newEventPlace.city" placeholder="Stadt" required>
<label for="backgroundColor">Hintergrundfarbe:</label>
<input type="color" id="backgroundColor" v-model="newEventPlace.backgroundColor">
<button type="submit">Speichern</button>
<button type="button" v-if="editMode" @click="resetForm">Neuen Veranstaltungsort erstellen</button>
</form>
<table>
<thead>
<tr>
<th>Name</th>
<th>Bearbeiten</th>
<th>Löschen</th>
</tr>
</thead>
<tbody>
<tr v-for="eventPlace in eventPlaces" :key="eventPlace.id">
<td>{{ eventPlace.name }}</td>
<td><button @click="editEventPlace(eventPlace)">Bearbeiten</button></td>
<td><button @click="deleteEventPlace(eventPlace.id)">Löschen</button></td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
eventPlaces: [],
newEventPlace: {
name: '',
street: '',
zipcode: '',
city: '',
backgroundColor: '#ffffff'
},
editMode: false,
editId: null
};
},
methods: {
async fetchEventPlaces() {
const response = await axios.get('http://localhost:3000/api/event-places');
this.eventPlaces = response.data;
},
async addEventPlace() {
if (this.editMode) {
await axios.put(`http://localhost:3000/api/event-places/${this.editId}`, this.newEventPlace);
} else {
const response = await axios.post('http://localhost:3000/api/event-places', this.newEventPlace);
this.eventPlaces.push(response.data);
}
this.resetForm();
await this.fetchEventPlaces();
},
async updateEventPlace(eventPlace) {
await axios.put(`http://localhost:3000/api/event-places/${eventPlace.id}`, eventPlace);
this.fetchEventPlaces(); // Refresh the list
},
async deleteEventPlace(id) {
await axios.delete(`http://localhost:3000/api/event-places/${id}`);
this.fetchEventPlaces(); // Refresh the list
},
editEventPlace(eventPlace) {
this.newEventPlace = { ...eventPlace };
this.editMode = true;
this.editId = eventPlace.id;
},
resetForm() {
this.newEventPlace = {
name: '',
street: '',
zipcode: '',
city: '',
backgroundColor: '#ffffff'
};
this.editMode = false;
this.editId = null;
}
},
created() {
this.fetchEventPlaces();
}
};
</script>
<style scoped>
.event-places-management {
max-width: 600px;
margin: auto;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
}
form {
display: flex;
flex-direction: column;
margin-bottom: 20px;
}
label {
margin-top: 10px;
}
input {
margin-top: 5px;
margin-bottom: 10px;
padding: 8px;
}
button {
margin-top: 10px;
padding: 10px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th, td {
border: 1px solid #ccc;
padding: 10px;
text-align: left;
}
th {
background-color: #f4f4f4;
}
</style>

View File

@@ -0,0 +1,132 @@
<template>
<div class="event-types-management">
<h2>Event-Typen Verwaltung</h2>
<form @submit.prevent="saveEventType">
<label for="newEventType">Event-Typ:</label>
<input type="text" id="newEventType" v-model="eventTypeData.caption" placeholder="Event-Typ" required>
<button type="submit">{{ editMode ? 'Aktualisieren' : 'Hinzufügen' }}</button>
<button type="button" v-if="editMode" @click="resetForm">Abbrechen</button>
</form>
<table>
<tr v-for="eventType in eventTypes" :key="eventType.id">
<td>{{ eventType.caption }}</td>
<td><button @click="editEventType(eventType)">Bearbeiten</button></td>
<td><button @click="deleteEventType(eventType.id)">Löschen</button></td>
</tr>
</table>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
eventTypes: [],
eventTypeData: {
caption: ''
},
editMode: false,
editId: null
};
},
methods: {
async fetchEventTypes() {
try {
const response = await axios.get('http://localhost:3000/api/event-types');
this.eventTypes = response.data;
} catch (error) {
console.error('Fehler beim Abrufen der Event-Typen:', error);
}
},
async saveEventType() {
try {
if (this.editMode) {
await axios.put(`http://localhost:3000/api/event-types/${this.editId}`, this.eventTypeData);
} else {
const response = await axios.post('http://localhost:3000/api/event-types', this.eventTypeData);
this.eventTypes.push(response.data);
}
this.resetForm();
await this.fetchEventTypes();
} catch (error) {
console.error('Fehler beim Speichern des Event-Typs:', error);
}
},
editEventType(eventType) {
this.eventTypeData = { ...eventType };
this.editMode = true;
this.editId = eventType.id;
},
async deleteEventType(id) {
try {
await axios.delete(`http://localhost:3000/api/event-types/${id}`);
await this.fetchEventTypes();
} catch (error) {
console.error('Fehler beim Löschen des Event-Typs:', error);
}
},
resetForm() {
this.eventTypeData = {
caption: ''
};
this.editMode = false;
this.editId = null;
}
},
async created() {
await this.fetchEventTypes();
}
};
</script>
<style scoped>
@import 'vue-multiselect/dist/vue-multiselect.css';
.event-types-management {
max-width: 600px;
margin: 0 auto;
display: flex;
flex-direction: column;
}
form {
display: flex;
flex-direction: column;
margin-bottom: 20px;
}
label {
margin-top: 10px;
}
input {
margin-top: 10px;
padding: 5px;
}
button {
margin-top: 20px;
padding: 10px;
}
ul {
margin-top: 20px;
}
li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border-bottom: 1px solid rgba(224, 224, 224, 0.9);
position: relative;
}
button {
margin-left: 10px;
}
</style>

View File

@@ -0,0 +1,19 @@
<template>
<div>
<h1>Administration</h1>
<p>Hier kommt eine Navigation hin.</p>
</div>
</template>
<script>
export default {
name: 'DefaultComponent'
};
</script>
<style scoped>
div {
padding: 20px;
}
</style>

View File

@@ -0,0 +1,189 @@
<template>
<div class="institution-management">
<h2>Institutionenverwaltung</h2>
<form @submit.prevent="saveInstitution">
<label for="name">Name:</label>
<input type="text" id="name" v-model="institutionData.name" required>
<label for="street">Straße:</label>
<input type="text" id="street" v-model="institutionData.street">
<label for="zipcode">PLZ:</label>
<input type="text" id="zipcode" v-model="institutionData.zipcode">
<label for="city">Stadt:</label>
<input type="text" id="city" v-model="institutionData.city">
<label for="phone">Telefon:</label>
<input type="text" id="phone" v-model="institutionData.phone">
<label for="fax">Fax:</label>
<input type="text" id="fax" v-model="institutionData.fax">
<label for="email">Email:</label>
<input type="email" id="email" v-model="institutionData.email">
<button type="submit">Speichern</button>
<button type="button" @click="resetForm" v-if="editMode">Neue Institution erstellen</button>
</form>
<table>
<thead>
<tr>
<th>Name</th>
<th>Bearbeiten</th>
<th>Löschen</th>
</tr>
</thead>
<tbody>
<tr v-for="institution in institutions" :key="institution.id">
<td>{{ institution.name }}</td>
<td><button @click="editInstitution(institution)">Bearbeiten</button></td>
<td><button @click="deleteInstitution(institution.id)">Löschen</button></td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'InstitutionManagement',
data() {
return {
institutions: [],
contactPersons: [],
institutionData: {
name: '',
street: '',
zipcode: '',
city: '',
phone: '',
fax: '',
email: ''
},
selectedInstitution: null,
showForm: false,
editMode: false,
editId: null
};
},
created() {
this.fetchInstitutions();
this.fetchContactPersons();
},
methods: {
async fetchInstitutions() {
try {
const response = await axios.get('http://localhost:3000/api/institutions');
this.institutions = response.data;
} catch (error) {
console.error('Fehler beim Abrufen der Institutionen:', error);
}
},
async fetchContactPersons() {
try {
const response = await axios.get('http://localhost:3000/api/contact-persons');
this.contactPersons = response.data;
} catch (error) {
console.error('Fehler beim Abrufen der Kontaktpersonen:', error);
}
},
async saveInstitution() {
try {
if (this.editMode) {
await axios.put(`http://localhost:3000/api/institutions/${this.editId}`, this.institutionData);
} else {
const response = await axios.post('http://localhost:3000/api/institutions', this.institutionData);
this.institutions.push(response.data);
}
this.resetForm();
await this.fetchInstitutions();
} catch (error) {
console.error('Fehler beim Speichern der Institution:', error);
}
},
editInstitution(institution) {
this.institutionData = { ...institution };
this.editMode = true;
this.editId = institution.id;
this.showForm = true;
},
async deleteInstitution(id) {
try {
await axios.delete(`http://localhost:3000/api/institutions/${id}`);
this.fetchInstitutions();
} catch (error) {
console.error('Fehler beim Löschen der Institution:', error);
}
},
resetForm() {
this.institutionData = {
name: '',
street: '',
zipcode: '',
city: '',
phone: '',
fax: '',
email: ''
};
this.editMode = false;
this.editId = null;
this.showForm = false;
},
showCreateForm() {
this.resetForm();
this.showForm = true;
}
}
};
</script>
<style scoped>
.institution-management {
max-width: 600px;
margin: auto;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
}
form {
display: flex;
flex-direction: column;
margin-bottom: 20px;
}
label {
margin-top: 10px;
}
input {
margin-top: 5px;
margin-bottom: 10px;
padding: 8px;
}
button {
margin-top: 10px;
padding: 10px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th, td {
border: 1px solid #ccc;
padding: 10px;
text-align: left;
}
th {
background-color: #f4f4f4;
}
</style>

View File

@@ -0,0 +1,35 @@
<template>
<div>
<div class="previewinfo">Dies ist eine Vorschau.</div>
<div v-html="content"></div>
</div>
</template>
<script>
import { computed } from 'vue';
import { useStore } from 'vuex';
export default {
name: 'PagePreview',
setup() {
const store = useStore();
const content = computed(() => store.state.pageContent);
return {
content,
};
},
};
</script>
<style scoped>
.previewinfo {
background-color: black;
color: #d00000;
position: absolute;
top: 93px;
left: 0;
padding: 2px 10px;
font-weight: bold;
}
</style>

View File

@@ -0,0 +1,131 @@
<template>
<div class="position-management">
<h2>Verwalten der Rollen</h2>
<form @submit.prevent="addPosition">
<label for="caption">Rollenbezeichnung:</label>
<input type="text" id="caption" v-model="newPosition.caption" placeholder="Rollenbezeichnung" required>
<button type="submit">Speichern</button>
<button type="button" v-if="editMode" @click="resetForm">Neue Rolle erstellen</button>
</form>
<table>
<thead>
<tr>
<th>Rollenbezeichnung</th>
<th>Bearbeiten</th>
<th>Löschen</th>
</tr>
</thead>
<tbody>
<tr v-for="position in positions" :key="position.id">
<td>{{ position.caption }}</td>
<td><button @click="editPosition(position)">Bearbeiten</button></td>
<td><button @click="deletePosition(position.id)">Löschen</button></td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
positions: [],
newPosition: {
caption: ''
},
editMode: false,
editId: null
};
},
methods: {
async fetchPositions() {
const response = await axios.get('http://localhost:3000/api/positions');
this.positions = response.data;
},
async addPosition() {
if (this.editMode) {
await axios.put(`http://localhost:3000/api/positions/${this.editId}`, this.newPosition);
} else {
const response = await axios.post('http://localhost:3000/api/positions', this.newPosition);
this.positions.push(response.data);
}
this.resetForm();
await this.fetchPositions();
},
async updatePosition(position) {
await axios.put(`http://localhost:3000/api/positions/${position.id}`, position);
this.fetchPositions(); // Refresh the list
},
async deletePosition(id) {
await axios.delete(`http://localhost:3000/api/positions/${id}`);
this.fetchPositions(); // Refresh the list
},
editPosition(position) {
this.newPosition = { ...position };
this.editMode = true;
this.editId = position.id;
},
resetForm() {
this.newPosition = {
caption: ''
};
this.editMode = false;
this.editId = null;
}
},
created() {
this.fetchPositions();
}
};
</script>
<style scoped>
.position-management {
max-width: 600px;
margin: auto;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
}
form {
display: flex;
flex-direction: column;
margin-bottom: 20px;
}
label {
margin-top: 10px;
}
input {
margin-top: 5px;
margin-bottom: 10px;
padding: 8px;
}
button {
margin-top: 10px;
padding: 10px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th, td {
border: 1px solid #ccc;
padding: 10px;
text-align: left;
}
th {
background-color: #f4f4f4;
}
</style>

View File

@@ -0,0 +1,228 @@
<template>
<div class="worship-management">
<h2>Gottesdienst Verwaltung</h2>
<form @submit.prevent="saveWorship">
<label for="eventPlaceId">Veranstaltungsort:</label>
<multiselect v-model="selectedEventPlace" :options="eventPlaces" label="name" track-by="id"
placeholder="Veranstaltungsort wählen"></multiselect>
<label for="date">Datum:</label>
<input type="date" id="date" v-model="worshipData.date" required>
<label for="time">Uhrzeit:</label>
<input type="time" id="time" v-model="worshipData.time" required>
<label for="title">Titel:</label>
<input type="text" id="title" v-model="worshipData.title" required>
<label for="organizer">Gestalter:</label>
<input type="text" id="organizer" v-model="worshipData.organizer">
<label for="collection">Kollekte:</label>
<input type="text" id="collection" v-model="worshipData.collection">
<label for="address">Adresse:</label>
<input type="text" id="address" v-model="worshipData.address">
<label for="selfInformation">Selbstinformation:</label>
<input type="checkbox" id="selfInformation" v-model="worshipData.selfInformation">
<label for="highlightTime">Uhrzeit hervorheben:</label>
<input type="checkbox" id="highlightTime" v-model="worshipData.highlightTime">
<label for="neighborInvitation">Einladung zum Nachbarschaftsraum:</label>
<input type="checkbox" id="neighborInvitation" v-model="worshipData.neighborInvitation">
<label for="introLine">Einleitungszeile:</label>
<input type="text" id="introLine" v-model="worshipData.introLine">
<button type="submit">Speichern</button>
<button type="button" @click="resetForm">Neuer Gottesdienst</button>
</form>
<ul>
<li v-for="worship in worships" :key="worship.id">
<span>{{ worship.title }} - {{ formatDate(worship.date) }}, {{ formatTime(worship.time) }}</span>
<button @click="editWorship(worship)">Bearbeiten</button>
<button @click="deleteWorship(worship.id)">Löschen</button>
<div class="tooltip">{{ getEventPlaceName(worship.eventPlaceId) }}</div>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
import Multiselect from 'vue-multiselect';
import { formatTime, formatDate } from '../../utils/strings'; // Importieren der Methode
export default {
name: 'WorshipManagement',
components: { Multiselect },
data() {
return {
worships: [],
eventPlaces: [],
worshipData: {
eventPlaceId: null,
date: '',
time: '',
title: '',
organizer: '',
collection: '',
address: '',
selfInformation: false,
highlightTime: false,
neighborInvitation: false,
introLine: ''
},
selectedEventPlace: null,
editMode: false,
editId: null
};
},
async created() {
await this.fetchEventPlaces();
await this.fetchWorships();
},
methods: {
formatTime,
formatDate,
async fetchWorships() {
try {
const response = await axios.get('http://localhost:3000/api/worships');
this.worships = response.data;
} catch (error) {
console.error('Fehler beim Abrufen der Gottesdienste:', error);
}
},
async fetchEventPlaces() {
try {
const response = await axios.get('http://localhost:3000/api/event-places');
this.eventPlaces = response.data;
} catch (error) {
console.error('Fehler beim Abrufen der Veranstaltungsorte:', error);
}
},
async saveWorship() {
try {
const payload = {
...this.worshipData,
eventPlaceId: this.selectedEventPlace ? this.selectedEventPlace.id : null
};
if (this.editMode) {
await axios.put(`http://localhost:3000/api/worships/${this.editId}`, payload);
} else {
await axios.post('http://localhost:3000/api/worships', payload);
}
this.resetForm();
await this.fetchWorships();
} catch (error) {
console.error('Fehler beim Speichern des Gottesdienstes:', error);
}
},
editWorship(worship) {
this.worshipData = { ...worship };
this.selectedEventPlace = this.eventPlaces.find(ep => ep.id === worship.eventPlaceId);
this.editMode = true;
this.editId = worship.id;
},
async deleteWorship(id) {
try {
await axios.delete(`http://localhost:3000/api/worships/${id}`);
await this.fetchWorships();
} catch (error) {
console.error('Fehler beim Löschen des Gottesdienstes:', error);
}
},
resetForm() {
this.worshipData = {
eventPlaceId: null,
date: '',
time: '',
title: '',
organizer: '',
collection: '',
address: '',
selfInformation: false,
highlightTime: false,
neighborInvitation: false,
introLine: ''
};
this.selectedEventPlace = null;
this.editMode = false;
this.editId = null;
},
getEventPlaceName(eventPlaceId) {
const place = this.eventPlaces.find(place => place.id === eventPlaceId);
return place ? place.name : 'Unbekannter Ort';
}
}
};
</script>
<style scoped>
@import 'vue-multiselect/dist/vue-multiselect.css';
.worship-management {
max-width: 600px;
margin: 0 auto;
display: flex;
flex-direction: column;
}
form {
display: flex;
flex-direction: column;
}
label {
margin-top: 10px;
}
button {
margin-top: 20px;
}
ul {
margin-top: 20px;
}
li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border-bottom: 1px solid rgba(224, 224, 224, 0.9);
position: relative;
}
button {
margin-left: 10px;
}
.tooltip {
visibility: hidden;
width: auto;
background-color: rgba(224, 224, 224, 0.6);
color: #000;
text-align: center;
padding: 5px 0;
position: absolute;
z-index: 1;
bottom: 75%;
left: 50%;
margin-left: -100px;
padding: 5px;
border: 1px solid #000;
opacity: 0;
transition: opacity 0.2s;
}
li:hover .tooltip {
visibility: visible;
opacity: 1;
}
</style>