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,12 @@
<template>
<div>
<h2></h2>
</div>
</template>
<script>
export default {
name: 'ContactsContent',
};
</script>

View File

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

View File

@@ -0,0 +1,19 @@
<template>
<div>
<h1>Seite existiert nicht</h1>
<p>Leider existiert die aufgerufene Seite nicht.</p>
</div>
</template>
<script>
export default {
name: 'DefaultComponent'
};
</script>
<style scoped>
div {
padding: 20px;
}
</style>

View File

@@ -0,0 +1,46 @@
<template>
<div class="left-column">
<h2>Aktuelles</h2>
<p><a href="https://miriamgemeinde.de/wp-content/uploads/2024/04/GB.INT_.pdf"><strong>Hier finden Sie den aktuellen Gemeindebrief</strong></a></p>
<h3>Sommerfest</h3>
<p>Am Sonntag, den 09.06.2024 findet das ökumenische Sommerfest in Bonames statt.</p>
<h4>10:30 Uhr Musikalischer Gottestdienst</h4>
<p>mit der Kantorei St. Bonifatius, der Miriamkantorei und dem Gospelchor Chariots in der Katholischen Pfarrkirche St. Bonifatius, Oberer Kalbacher Weg 9</p>
<h4>Ab 12:00 Uhr Gemeinsames Fest</h4>
<p>am Evangelischen Gemeindezentrum Bonames, Kirchhofsweg 11<br>Begegnungen, Gespräche und Angebote für Kinder<br>Gegrilltes und Getränke, Kaffee und Kuchen<br>Bis 16:00 Uhr</p>
<h3>Ökumenisches Friedensgebet</h3>
<p>Jeden letzten Freitag im Monat um 18:00 Uhr<br>Evangelische Friedenskirche in Harheim</p>
<hr>
<h3>Miriamgemeinde auf <a href="https://www.youtube.com/channel/UCFWJZuXPKuTef9-NIo-vdPg">Youtube</a></h3>
<p>Gottesdienst-Aufzeichnungen von unseren Gottesdienstorten.</p>
<p>Bei Präsenzgottesdiensten finden Sie die Aufzeichnung erst am Sonntagnachmittag!</p>
<hr>
<h3>Youtube-Kanäle unserer Kindertagesstätten</h3>
<p><a href="https://www.youtube.com/channel/UCwDe0xnydn9xV-4MHjGhjWQ">KiTa Krambambuli</a></p>
<p><a href="https://www.youtube.com/channel/UC_Sj_yC__i91czlJUW4ylcg">KiTa Sternenzelt</a></p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
<p>lorem ipsum...</p>
</div>
</template>
<script>
export default {
name: 'HomeContent'
};
</script>

View File

@@ -0,0 +1,70 @@
<template>
<div class="right-column">
<img :src="currentImage" alt="Cross" />
</div>
</template>
<script>
import { menuData } from '../../config/menuData';
export default {
name: 'ImageContent',
data() {
return {
defaultImage: '/images/homepage1.png',
currentImage: '/images/homepage1.png'
};
},
watch: {
$route: {
immediate: true,
handler() {
this.updateImage();
}
}
},
methods: {
updateImage() {
const routePath = this.$route.path;
const menuItem = this.findMenuItemByPath(menuData, routePath);
if (menuItem && menuItem.image) {
this.currentImage = `/images/${menuItem.image}`;
} else {
this.currentImage = this.defaultImage;
}
},
findMenuItemByPath(menu, path) {
for (let item of menu) {
if (item.link === path) {
return item;
}
if (item.submenu) {
const subItem = this.findMenuItemByPath(item.submenu, path);
if (subItem) {
return subItem;
}
}
}
return null;
}
}
};
</script>
<style scoped>
.right-column {
background-color: #d9e2f3;
}
.right-column h2 {
text-align: center;
color: #000;
}
.right-column img {
display: block;
margin: 0 auto;
max-width: 100%;
height: auto;
}
</style>

View File

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

View File

@@ -0,0 +1,11 @@
<template>
<div>
<h2>Miriams Wunderkiste</h2>
</div>
</template>
<script>
export default {
name: 'MiriamsWonderboxContent',
};
</script>

View File

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

View File

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

View File

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

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>

View File

@@ -0,0 +1,40 @@
<template>
<div class="forgot-password">
<h2>Passwort vergessen</h2>
<form>
<label for="email">Email-Adresse:</label>
<input type="email" id="email" required>
<button type="submit">Link zum Zurücksetzen senden</button>
</form>
<p>
<router-link to="/login">Login</router-link>
</p>
<p>
<router-link to="/register">Registrieren</router-link>
</p>
</div>
</template>
<script>
export default {
name: 'ForgotPassword'
};
</script>
<style scoped>
.forgot-password {
max-width: 400px;
margin: auto;
}
form {
display: flex;
flex-direction: column;
}
label {
margin-top: 10px;
}
button {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,106 @@
<template>
<div class="login">
<h2>Login</h2>
<form @submit.prevent="runLogin">
<label for="email">Email-Adresse:</label>
<input type="email" id="email" v-model="email" required>
<label for="password">Passwort:</label>
<input type="password" id="password" v-model="password" required>
<button type="submit">Login</button>
</form>
<p>
<router-link to="/register">Registrieren</router-link>
</p>
<p>
<router-link to="/forgot-password">Passwort vergessen?</router-link>
</p>
<DialogComponent
:title="dialogTitle"
:message="dialogMessage"
v-model="dialogVisible"
@close="closeDialog"
/>
</div>
</template>
<script>
import axios from 'axios';
import DialogComponent from '../../common/components/DialogComponent.vue';
import { mapActions } from 'vuex';
export default {
name: 'LoginComponent',
components: {
DialogComponent
},
data() {
return {
email: '',
password: '',
dialogTitle: '',
dialogMessage: '',
dialogVisible: false
};
},
methods: {
...mapActions(['login']),
async runLogin() {
try {
const response = await axios.post('http://localhost:3000/api/auth/login', {
email: this.email,
password: this.password
});
console.log(1);
const token = response.data.token;
console.log(2);
const data = response.data;
console.log(3);
localStorage.setItem('token', token);
console.log(4);
console.log(data);
this.login(data.user);
console.log(5);
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
console.log(6);
this.$router.push('/admin');
} catch (error) {
if (error.response) {
this.showDialog('Fehler', error.response.data.message);
} else {
this.showDialog('Ein Fehler ist aufgetreten', error.message);
}
}
},
showDialog(title, message) {
this.dialogTitle = title;
this.dialogMessage = message;
this.dialogVisible = true;
},
closeDialog() {
this.dialogVisible = false;
}
}
};
</script>
<style scoped>
.login {
max-width: 400px;
margin: auto;
}
form {
display: flex;
flex-direction: column;
}
label {
margin-top: 10px;
}
button {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,90 @@
<template>
<div class="register">
<h2>Registrieren</h2>
<form @submit.prevent="register">
<label for="name">Name:</label>
<input type="text" id="name" v-model="name" required>
<label for="email">Email-Adresse:</label>
<input type="email" id="email" v-model="email" required>
<label for="password">Passwort:</label>
<input type="password" id="password" v-model="password" required>
<button type="submit">Registrieren</button>
</form>
<p>
<router-link to="/login">Login</router-link>
</p>
<p>
<router-link to="/forgot-password">Passwort vergessen?</router-link>
</p>
</div>
</template>
<script>
export default {
name: 'RegisterComponent',
components: {
},
data() {
return {
name: '',
email: '',
password: '',
dialogTitle: '',
dialogMessage: '',
dialogVisible: false
};
},
methods: {
async register() {
try {
const response = await fetch('http://localhost:3000/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: this.name,
email: this.email,
password: this.password
})
});
if (response.ok) {
await response.json();
this.showDialog('Registrierung erfolgreich', 'Ihr Konto wurde erfolgreich erstellt.');
} else {
const error = await response.json();
this.showDialog('Fehler', error.message);
}
} catch (err) {
this.showDialog('Ein Fehler ist aufgetreten', err.message);
}
},
showDialog(title, message) {
this.dialogTitle = title;
this.dialogMessage = message;
this.dialogVisible = true;
}
}
};
</script>
<style scoped>
.register {
max-width: 400px;
margin: auto;
}
form {
display: flex;
flex-direction: column;
}
label {
margin-top: 10px;
}
button {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,143 @@
<template>
<div class="privacy-policy">
<h1>Datenschutzerklärung der Miriamgemeinde Frankfurt am Main</h1>
<p>
Die Miriamgemeinde Frankfurt am Main nimmt den Schutz Ihrer persönlichen Daten sehr ernst und behandelt Ihre personenbezogenen Daten vertraulich und entsprechend der kirchlichen Datenschutzgesetze sowie dieser Datenschutzerklärung. Die Sicherheit Ihrer Daten steht für uns an erster Stelle.
</p>
<h2>Anbieter:</h2>
<p>
Miriamgemeinde Frankfurt am Main, Gemeindebüro Bonames<br />
Kirchhofsweg 5, 60437 Frankfurt, Tel.: 50 14 17, Fax: 50 93 0148,<br />
Email: <a href="mailto:Ev.Kirche-Bonames@t-online.de">Ev.Kirche-Bonames@t-online.de</a><br />
Inhaltlich Verantwortlicher gemäß § 6 MDStV: Sabine Mentrup
</p>
<p>
Die Nutzung der Webseite der Miriamgemeinde Frankfurt am Main ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf unseren Seiten personenbezogene Daten (beispielsweise Name, Anschrift oder E-Mail-Adressen) erhoben werden, erfolgt dies, soweit möglich, stets auf freiwilliger Basis. Diese Daten werden ohne Ihre ausdrückliche Zustimmung nicht an Dritte weitergegeben. Die nachfolgende Erklärung gibt Ihnen einen Überblick darüber, wie dieser Schutz gewährleistet werden soll und welche Art von Daten zu welchem Zweck von Ihnen erhoben werden.
</p>
<p>
Die Miriamgemeinde Frankfurt am Main weist darauf hin, dass die Datenübertragung im Internet (z.B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich.
</p>
<h2>Datenverarbeitung auf dieser Internetseite</h2>
<h3>Server-Log-Files</h3>
<p>
Im Allgemeinen ist es für die Nutzung der Internetseite Miriamgemeinde Frankfurt am Main nicht erforderlich, dass Sie personenbezogene Daten angeben. Um die Zugriffs-Statistik auf die Internetseite zu erheben, werden folgende Daten automatisch in Log-Files des Servers erhoben und 60 Tage lang gespeichert, die der Browser übermittelt. Diese sind:
</p>
<ul>
<li>IP-Adresse (anonymisiert)</li>
<li>Betriebssystem</li>
<li>Browser-Typ / -Version / -Sprache</li>
<li>Datum und Uhrzeit der Server-Anfrage mit Angabe der Zeitzone</li>
<li>Sofern Sie Seiten mit Passwortschutz besuchen: verwendeter Benutzername</li>
<li>Webseiten, die Sie bei uns besuchen.</li>
</ul>
<p>
Diese Daten sind nicht bestimmten Personen zuordenbar. Eine Zusammenführung dieser Daten mit anderen Datenquellen wird nicht vorgenommen.
</p>
<h3>Verwendung von Cookies</h3>
<p>
Die Internetseiten der Miriamgemeinde Frankfurt am Main verwenden teilweise sogenannte Cookies. Cookies richten auf Ihrem Rechner keinen Schaden an und enthalten keine Viren. Cookies dienen dazu, unser Angebot nutzerfreundlicher, effektiver und sicherer zu machen. Cookies sind kleine Textdateien, die auf Ihrem Rechner abgelegt werden und die Ihr Browser speichert.
</p>
<p>
Die meisten der von uns verwendeten Cookies sind sogenannte Session-Cookies. Sie werden nach Ende Ihres Besuchs automatisch gelöscht. Andere Cookies bleiben auf Ihrem Endgerät gespeichert, bis Sie diese löschen. Diese Cookies ermöglichen es uns, Ihren Browser beim nächsten Besuch wiederzuerkennen.
</p>
<p>
Sie können Ihren Browser so einstellen, dass Sie über das Setzen von Cookies informiert werden und Cookies nur im Einzelfall erlauben, die Annahme von Cookies für bestimmte Fälle oder generell ausschließen sowie das automatische Löschen der Cookies beim Schließen des Browsers aktivieren. Bei der Deaktivierung von Cookies kann die Funktionalität dieser Website eingeschränkt sein.
</p>
<h3>Kommentarfunktion</h3>
<p>
Die Kommentarfunktion auf dieser Webseite ist aktuell nicht aktiviert. Bei aktivierter Kommentarfunktion gilt: Wenn Sie einen Kommentar auf unserer Website schreiben, kann das eine Einwilligung sein, Ihren Namen, E-Mail-Adresse und Website in Cookies zu speichern. Dies ist eine Komfortfunktion, damit Sie nicht, wenn Sie einen weiteren Kommentar schreiben, all diese Daten erneut eingeben müssen. Diese Cookies werden ein Jahr lang gespeichert.
</p>
<h3>Angemeldete Nutzer</h3>
<p>
Falls Sie ein Konto haben und sich auf dieser Website anmelden, werden wir ein temporäres Cookie setzen, um festzustellen, ob Ihr Browser Cookies akzeptiert. Dieses Cookie enthält keine personenbezogenen Daten und wird verworfen, wenn Sie den Browser schließen.
</p>
<p>
Wenn Sie sich anmelden, werden wir einige Cookies einrichten, um Ihre Anmeldeinformationen und Anzeigeoptionen zu speichern. Anmelde-Cookies verfallen nach zwei Tagen und Cookies für die Anzeigeoptionen nach einem Jahr. Falls Sie bei der Anmeldung Angemeldet bleiben auswählen, wird Ihre Anmeldung zwei Wochen lang aufrechterhalten. Mit der Abmeldung aus Ihrem Konto werden die Anmelde-Cookies gelöscht.
</p>
<p>
Wenn Sie einen Artikel bearbeiten oder veröffentlichen, wird ein zusätzlicher Cookie in Ihrem Browser gespeichert. Dieser Cookie enthält keine personenbezogenen Daten und verweist nur auf die Beitrags-ID des Artikels, den Sie gerade bearbeitet haben. Der Cookie verfällt nach einem Tag.
</p>
<h3>Links zu Webseiten anderer Anbieter</h3>
<p>
Unser Online-Angebot enthält Links zu Webseiten anderer Anbieter. Wir haben keinen Einfluss darauf, dass diese Anbieter die Datenschutzbestimmungen einhalten.
</p>
<h3>Ihr Recht auf Auskunft, Löschung, Sperrung</h3>
<p>
Sie haben als Nutzer das Recht, Auskunft darüber zu verlangen, welche Daten über Sie bei uns gespeichert sind und zu welchem Zweck diese Speicherung erfolgt. Darüber hinaus können Sie unrichtige Daten berichtigen oder solche Daten löschen lassen, deren Speicherung unzulässig oder nicht mehr erforderlich ist. Sie haben die Rechte auf Datenübertragbarkeit, Einschränkung der Verarbeitung und Widerspruch. Außerdem haben Sie das Recht, sich bei der Aufsichtsbehörde über die stattfindende Datenverarbeitung zu beschweren. Zuständige Aufsichtsbehörde ist Der Beauftragte für den Datenschutz der EKD Adresse siehe unten.
</p>
<p>
Sie erhalten jederzeit ohne Angabe von Gründen kostenfrei Auskunft über Ihre bei uns gespeicherten Daten. Sie können jederzeit Ihre bei uns erhobenen Daten sperren, berichtigen oder löschen lassen. Auch können Sie jederzeit die uns erteilte Einwilligung zur Datenerhebung und Verwendung ohne Angaben von Gründen widerrufen. Wenden Sie sich hierzu bitte an die auf dieser Seite angegebene Kontaktadresse des Datenschutzbeauftragten. Wir stehen Ihnen jederzeit gern für weitergehende Fragen zu unserem Hinweisen zum Datenschutz und zur Verarbeitung Ihrer persönlichen Daten zur Verfügung.
</p>
<h3>Der Datenschutzbeauftragte für den Datenschutz der Evangelischen Kirchen in Deutschland</h3>
<p>
Die Aufsicht über die Einhaltung der Vorschriften zum Datenschutz obliegt im kirchlichen Bereich dem Beauftragten für den Datenschutz der EKD. Für den Bereich der Evangelischen Kirche in Hessen und Nassau (EKHN) ist zuständig die Außenstelle Dortmund für die Datenschutzregion Mitte-West
</p>
<p>
Friedhof 4<br />
44135 Dortmund<br />
Tel: 0231 / 533827-0<br />
Fax: 0231 / 533827-20<br />
E-Mail: <a href="mailto:mitte-west@datenschutz.ekd.de">mitte-west@datenschutz.ekd.de</a>
</p>
<h3>E-Mails / Formulare</h3>
<p>
Aus technischen oder betrieblichen Gründen kann der Empfang von E-Mail-Kommunikation gestört sein und / oder nicht rechtzeitig den Empfänger erreichen. Daher hat die Versendung von E-Mails an uns keine fristwahrende Wirkung und kann Fristen nicht rechtsverbindlich setzen. Wir empfehlen, zeitkritische oder eilige Nachrichten zusätzlich per Post, Kurier oder Telefax zu übersenden.
</p>
<p>
Falls Sie sicher sein wollen, dass Ihre E-Mail ordnungsgemäß empfangen worden ist, fordern Sie bitte von dem Empfänger eine schriftliche Empfangsbestätigung an. Wir unternehmen alle vernünftigerweise zu erwartenden Vorsichtsmaßnahmen, um das Risiko einer Übertragung von Computerviren zu verhindern. Wir sind jedoch nicht haftbar für Schäden, die durch Computerviren entstehen.
</p>
<p>
Bitte führen Sie selber Überprüfungen auf Computerviren durch, bevor Sie E-Mails lesen, insbesondere bevor Sie Anhänge zu E-Mails öffnen. Die Kommunikation per E-Mail ist unsicher, da grundsätzlich die Möglichkeit der Kenntnisnahme und Manipulation durch Dritte besteht. Wir empfehlen, keine vertraulichen Daten unverschlüsselt per E-Mail zu versenden.
</p>
<h3>Änderungen</h3>
<p>
Wir behalten uns vor, die Datenschutzerklärung zu ändern, um sie an geänderte Rechtslagen, oder bei Änderungen des Dienstes sowie der Datenverarbeitung anzupassen. Dies gilt jedoch nur im Hinblick auf Erklärungen zur Datenverarbeitung. Sofern Einwilligungen der Nutzer erforderlich sind oder Bestandteile der Datenschutzerklärung Regelungen des Vertragsverhältnisses mit den Nutzern enthalten, erfolgen die Änderungen nur mit Zustimmung der Nutzer.
</p>
<p>
Die Nutzer werden gebeten, sich regelmäßig über den Inhalt der Datenschutzerklärung zu informieren.
</p>
<p>Stand: 24. Mai 2018</p>
</div>
</template>
<script>
export default {
name: 'PrivacyPolicyComponent'
};
</script>
<style scoped>
.privacy-policy {
max-width: 800px;
margin: auto;
padding: 20px;
}
h1, h2, h3, h4, h5 {
margin-top: 20px;
color: #333;
}
p {
line-height: 1.6;
}
ul {
margin: 10px 0;
padding-left: 20px;
}
ul li {
list-style-type: disc;
}
a {
color: #007BFF;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>

View File

@@ -0,0 +1,97 @@
<template>
<div class="impressum">
<h1>Evangelische Miriamgemeinde Frankfurt</h1>
<section>
<h2>Gemeindebüro Bonames</h2>
<p>Kirchhofsweg 5<br />
60437 Frankfurt<br />
Tel.: 50 14 17, Fax: 50 93 0148<br />
Gemeindesekretärin: Angela Kehl<br />
Bürozeiten:<br />
Di. 9.00 - 12.00 Uhr<br />
Email: <a href="mailto:Ev.Kirche-Bonames@t-online.de">Ev.Kirche-Bonames@t-online.de</a>
</p>
</section>
<section>
<h2>Gemeindebüro Kalbach</h2>
<p>An der Grünhohl 9<br />
60437 Frankfurt<br />
Tel.: 50 25 78, Fax: 50 49 39<br />
Gemeindesekretärin: Angela Kehl<br />
Bürozeiten:<br />
Mo. 9.00 - 12.00 Uhr<br />
Email: <a href="mailto:ev-kirchengemeinde-kalbach@t-online.de">ev-kirchengemeinde-kalbach@t-online.de</a>
</p>
</section>
<section>
<h3>Inhaltlich Verantwortlicher gemäß § 6 MDStV:</h3>
<p>Torsten Schulz</p>
</section>
<section>
<h3>Haftungsausschluss</h3>
<h4>1. Inhalt des Onlineangebotes</h4>
<p>
Der Autor übernimmt keinerlei Gewähr für die Aktualität, Korrektheit, Vollständigkeit oder Qualität der bereitgestellten Informationen. Haftungsansprüche gegen den Autor, welche sich auf Schäden materieller oder ideeller Art beziehen, die durch die Nutzung oder Nichtnutzung der dargebotenen Informationen bzw. durch die Nutzung fehlerhafter und unvollständiger Informationen verursacht wurden, sind grundsätzlich ausgeschlossen, sofern seitens des Autors kein nachweislich vorsätzliches oder grob fahrlässiges Verschulden vorliegt.
Alle Angebote sind freibleibend und unverbindlich. Der Autor behält es sich ausdrücklich vor, Teile der Seiten oder das gesamte Angebot ohne gesonderte Ankündigung zu verändern, zu ergänzen, zu löschen oder die Veröffentlichung zeitweise oder endgültig einzustellen.
</p>
<h4>2. Verweise und Links</h4>
<p>
Bei direkten oder indirekten Verweisen auf fremde Webseiten ("Hyperlinks"), die außerhalb des Verantwortungsbereiches des Autors liegen, würde eine Haftungsverpflichtung ausschließlich in dem Fall in Kraft treten, in dem der Autor von den Inhalten Kenntnis hat und es ihm technisch möglich und zumutbar wäre, die Nutzung im Falle rechtswidriger Inhalte zu verhindern.
Der Autor erklärt hiermit ausdrücklich, dass zum Zeitpunkt der Linksetzung keine illegalen Inhalte auf den zu verlinkenden Seiten erkennbar waren. Auf die aktuelle und zukünftige Gestaltung, die Inhalte oder die Urheberschaft der verlinkten/verknüpften Seiten hat der Autor keinerlei Einfluss. Deshalb distanziert er sich hiermit ausdrücklich von allen Inhalten aller verlinkten/verknüpften Seiten, die nach der Linksetzung verändert wurden. Diese Feststellung gilt für alle innerhalb des eigenen Internetangebotes gesetzten Links und Verweise sowie für Fremdeinträge in vom Autor eingerichteten Gästebüchern, Diskussionsforen, Linkverzeichnissen, Mailinglisten und in allen anderen Formen von Datenbanken, auf deren Inhalt externe Schreibzugriffe möglich sind. Für illegale, fehlerhafte oder unvollständige Inhalte und insbesondere für Schäden, die aus der Nutzung oder Nichtnutzung solcherart dargebotener Informationen entstehen, haftet allein der Anbieter der Seite, auf welche verwiesen wurde, nicht derjenige, der über Links auf die jeweilige Veröffentlichung lediglich verweist.
</p>
<h4>3. Urheber- und Kennzeichenrecht</h4>
<p>
Der Autor ist bestrebt, in allen Publikationen die Urheberrechte der verwendeten Grafiken, Tondokumente, Videosequenzen und Texte zu beachten, von ihm selbst erstellte Grafiken, Tondokumente, Videosequenzen und Texte zu nutzen oder auf lizenzfreie Grafiken, Tondokumente, Videosequenzen und Texte zurückzugreifen.
Alle innerhalb des Internetangebotes genannten und ggf. durch Dritte geschützten Marken- und Warenzeichen unterliegen uneingeschränkt den Bestimmungen des jeweils gültigen Kennzeichenrechts und den Besitzrechten der jeweiligen eingetragenen Eigentümer. Allein aufgrund der bloßen Nennung ist nicht der Schluss zu ziehen, dass Markenzeichen nicht durch Rechte Dritter geschützt sind!
Das Copyright für veröffentlichte, vom Autor selbst erstellte Objekte bleibt allein beim Autor der Seiten. Eine Vervielfältigung oder Verwendung solcher Grafiken, Tondokumente, Videosequenzen und Texte in anderen elektronischen oder gedruckten Publikationen ist ohne ausdrückliche Zustimmung des Autors nicht gestattet.
</p>
<h4>4. Datenschutz</h4>
<p>
Sofern innerhalb des Internetangebotes die Möglichkeit zur Eingabe persönlicher oder geschäftlicher Daten (Emailadressen, Namen, Anschriften) besteht, so erfolgt die Preisgabe dieser Daten seitens des Nutzers auf ausdrücklich freiwilliger Basis. Die Inanspruchnahme und Bezahlung aller angebotenen Dienste ist - soweit technisch möglich und zumutbar - auch ohne Angabe solcher Daten bzw. unter Angabe anonymisierter Daten oder eines Pseudonyms gestattet. Die Nutzung der im Rahmen des Impressums oder vergleichbarer Angaben veröffentlichten Kontaktdaten wie Postanschriften, Telefon- und Faxnummern sowie Emailadressen durch Dritte zur Übersendung von nicht ausdrücklich angeforderten Informationen ist nicht gestattet. Rechtliche Schritte gegen die Versender von sogenannten Spam-Mails bei Verstößen gegen dieses Verbot sind ausdrücklich vorbehalten.
Bitte beachten Sie unsere <router-link to="/privacy-policy">Datenschutzerklärung</router-link>.
</p>
<h4>5. Rechtswirksamkeit dieses Haftungsausschlusses</h4>
<p>
Dieser Haftungsausschluss ist als Teil des Internetangebotes zu betrachten, von dem aus auf diese Seite verwiesen wurde. Sofern Teile oder einzelne Formulierungen dieses Textes der geltenden Rechtslage nicht, nicht mehr oder nicht vollständig entsprechen sollten, bleiben die übrigen Teile des Dokumentes in ihrem Inhalt und ihrer Gültigkeit davon unberührt.
</p>
<h4>6. Schlussbestimmungen</h4>
<p>
Es gilt das Recht der Bundesrepublik Deutschland.
Ausschließlicher Gerichtsstand für Rechtsstreitigkeiten aus dem Nutzungsverhältnis ist Frankfurt.
Änderungen der Nutzungsbedingungen bedürfen der Schriftform (kein E-Mail). Dies gilt auch für die Aufhebung oder Änderung dieser Schriftklausel.
</p>
</section>
</div>
</template>
<script>
export default {
name: 'ImpressumComponent'
};
</script>
<style scoped>
.impressum {
max-width: 800px;
margin: auto;
padding: 20px;
}
h1, h2, h3, h4 {
margin-top: 20px;
color: #333;
}
p {
line-height: 1.6;
}
a {
color: #007BFF;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>

View File

@@ -0,0 +1,11 @@
<template>
<div>
<h2>Gottesdienste in unserer Gemeinde</h2>
</div>
</template>
<script>
export default {
name: 'AllWorshipsContent',
};
</script>

View File

@@ -0,0 +1,11 @@
<template>
<div>
<h2>Gottesdienste in Bonames</h2>
</div>
</template>
<script>
export default {
name: 'BonamesContent',
};
</script>