Fixed format of events

This commit is contained in:
Torsten Schulz
2024-06-23 17:32:45 +02:00
parent 692e989861
commit 8b89d8b800
26 changed files with 455 additions and 157 deletions

View File

@@ -21,7 +21,7 @@ const getAllEvents = async (req, res) => {
const filterEvents = async (req, res) => { const filterEvents = async (req, res) => {
try { try {
const { id, 'event-places': eventPlaces, 'event-types': eventTypes, display } = req.query; const request = req.body;
const where = { const where = {
[Op.or]: [ [Op.or]: [
{ {
@@ -36,7 +36,7 @@ const filterEvents = async (req, res) => {
] ]
}; };
if (id === 'all') { if (request.id === 'all') {
const events = await Event.findAll({ const events = await Event.findAll({
where, where,
include: [ include: [
@@ -49,7 +49,7 @@ const filterEvents = async (req, res) => {
return res.json({ events }); return res.json({ events });
} }
if (id === 'home') { if (request.id === 'home') {
const events = await Event.findAll({ const events = await Event.findAll({
where: { where: {
alsoOnHomepage: 1, alsoOnHomepage: 1,
@@ -65,23 +65,23 @@ const filterEvents = async (req, res) => {
return res.json({ events }); return res.json({ events });
} }
if (!id && !eventPlaces && !eventTypes) { if (!request.id && !request.places && !request.types) {
return res.json({ events: [], eventPlaces: [], eventTypes: [], contactPersons: [] }); return res.json({ events: [], places: [], types: [], contactPersons: [] });
} }
if (id) { if (request.id) {
where.id = id; where.id = request.id;
} }
if (eventPlaces) { if (request.places && request.places.length > 0) {
where.event_place_id = { where.event_place_id = {
[Op.in]: eventPlaces.split('|').map(id => parseInt(id)) [Op.in]: request.places.map(id => parseInt(id))
}; };
} }
if (eventTypes) { if (request.types && request.types.length > 0) {
where.eventTypeId = { where.eventTypeId = {
[Op.in]: eventTypes.split('|').map(id => parseInt(id)) [Op.in]: request.types.map(id => parseInt(id))
}; };
} }
@@ -94,8 +94,7 @@ const filterEvents = async (req, res) => {
{ model: ContactPerson, as: 'contactPersons', through: { attributes: [] } } { model: ContactPerson, as: 'contactPersons', through: { attributes: [] } }
] ]
}); });
const displayFields = request.display ? request.display : [];
const displayFields = display ? display.split('|') : [];
const filteredEvents = events.map(event => { const filteredEvents = events.map(event => {
const filteredEvent = { ...event.toJSON() }; const filteredEvent = { ...event.toJSON() };

View File

@@ -18,6 +18,28 @@ const getAllInstitutions = async (req, res) => {
} }
}; };
const getInstitutionById = async (req, res) => {
try {
const { id } = req.params;
const institution = await Institution.findByPk(id, {
include: [
{
model: ContactPerson,
as: 'contactPersons',
through: { attributes: [] }
}
]
});
if (!institution) {
return res.status(404).json({ error: 'Institution not found' });
}
res.json(institution);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch institution' });
console.error(error);
}
};
const createInstitution = async (req, res) => { const createInstitution = async (req, res) => {
try { try {
const { contactPersonIds, ...institutionData } = req.body; const { contactPersonIds, ...institutionData } = req.body;
@@ -70,6 +92,7 @@ const deleteInstitution = async (req, res) => {
module.exports = { module.exports = {
getAllInstitutions, getAllInstitutions,
getInstitutionById,
createInstitution, createInstitution,
updateInstitution, updateInstitution,
deleteInstitution deleteInstitution

View File

@@ -49,24 +49,21 @@ exports.deleteWorship = async (req, res) => {
}; };
exports.getFilteredWorships = async (req, res) => { exports.getFilteredWorships = async (req, res) => {
const { location, orderBy } = req.query; const { location, order } = req.query;
const where = {}; const where = {};
if (location && location !== '-1') { const locations = JSON.parse(location);
if (location.includes('|')) { if (location && locations.length > 0) {
const locationsArray = location.split('|');
where.eventPlaceId = { where.eventPlaceId = {
[Sequelize.Op.in]: locationsArray [Sequelize.Op.in]: locations
} }
} else {
where.eventPlaceId = location;
}
} }
where.date = { where.date = {
[Op.gte]: new Date(), // Only include events from today onwards [Op.gte]: new Date(), // Only include events from today onwards
}; };
console.log(where, order);
try { try {
const worships = await Worship.findAll({ const worships = await Worship.findAll({
where, where,
@@ -74,7 +71,7 @@ exports.getFilteredWorships = async (req, res) => {
model: EventPlace, model: EventPlace,
as: 'eventPlace', as: 'eventPlace',
}, },
order: [orderBy.split(' ')], order: [order.split(' ')],
}); });
res.status(200).json(worships); res.status(200).json(worships);
} catch (error) { } catch (error) {

View File

@@ -26,7 +26,7 @@ module.exports = (sequelize) => {
pageId: { pageId: {
type: DataTypes.UUID, type: DataTypes.UUID,
allowNull: true allowNull: true
} },
}, { }, {
tableName: 'images', tableName: 'images',
timestamps: false timestamps: false

View File

@@ -37,7 +37,11 @@ module.exports = (sequelize) => {
page_title: { page_title: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true allowNull: true
} },
image: {
type: DataTypes.STRING,
allowNull: true,
},
}, { }, {
tableName: 'menu_items', tableName: 'menu_items',
timestamps: false timestamps: false

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 KiB

View File

@@ -7,6 +7,6 @@ router.get('/', authMiddleware, getAllEvents);
router.post('/', authMiddleware, createEvent); router.post('/', authMiddleware, createEvent);
router.put('/:id', authMiddleware, updateEvent); router.put('/:id', authMiddleware, updateEvent);
router.delete('/:id', authMiddleware, deleteEvent); router.delete('/:id', authMiddleware, deleteEvent);
router.get('/filter', filterEvents); router.post('/filter', filterEvents);
module.exports = router; module.exports = router;

View File

@@ -1,9 +1,10 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const institutionController = require('../controllers/institutionController'); const institutionController = require('../controllers/institutionController');
const authMiddleware = require('../middleware/authMiddleware') const authMiddleware = require('../middleware/authMiddleware');
router.get('/', authMiddleware, institutionController.getAllInstitutions); router.get('/', institutionController.getAllInstitutions);
router.get('/:id', institutionController.getInstitutionById); // Neuer Endpunkt
router.post('/', authMiddleware, institutionController.createInstitution); router.post('/', authMiddleware, institutionController.createInstitution);
router.put('/:id', authMiddleware, institutionController.updateInstitution); router.put('/:id', authMiddleware, institutionController.updateInstitution);
router.delete('/:id', authMiddleware, institutionController.deleteInstitution); router.delete('/:id', authMiddleware, institutionController.deleteInstitution);

View File

@@ -24,10 +24,12 @@ export default {
await this.loadMenuData(); await this.loadMenuData();
this.$router.push({ path: '/' }); // Zurück zur Startseite oder eine andere Seite, um sicherzustellen, dass der Router neu geladen wird this.$router.push({ path: '/' }); // Zurück zur Startseite oder eine andere Seite, um sicherzustellen, dass der Router neu geladen wird
const routes = this.$store.state.menuData.map(item => { const routes = this.$store.state.menuData.map(item => {
return { if (item.component) {
path: item.link, return {
component: () => import(`../components/${item.component}.vue`) path: item.link,
}; component: () => import(`../components/${item.component}.vue`)
};
}
}); });
routes.forEach(route => router.addRoute(route)); // Neue Routen hinzufügen routes.forEach(route => router.addRoute(route)); // Neue Routen hinzufügen
} }

View File

@@ -18,6 +18,11 @@
<multiselect id="types-select" v-model="selectedEventTypes" :options="eventTypes" :multiple="true" <multiselect id="types-select" v-model="selectedEventTypes" :options="eventTypes" :multiple="true"
label="caption" track-by="id" /> label="caption" track-by="id" />
</div> </div>
<div v-if="selectedTypes.some(type => type.id === 'position')">
<label for="contact-select">Wählen Sie eine Position:</label>
<multiselect id="contact-select" v-model="selectedPositions" :options="positions" :multiple="false"
label="caption" track-by="id" />
</div>
<div v-if="selectedTypes.some(type => type.id === 'specific')"> <div v-if="selectedTypes.some(type => type.id === 'specific')">
<label for="contact-select">Wählen Sie eine Kontaktperson:</label> <label for="contact-select">Wählen Sie eine Kontaktperson:</label>
<multiselect id="contact-select" v-model="selectedContact" :options="contacts" :multiple="false" <multiselect id="contact-select" v-model="selectedContact" :options="contacts" :multiple="false"
@@ -66,9 +71,11 @@ export default {
const contacts = ref([]); const contacts = ref([]);
const eventTypes = ref([]); const eventTypes = ref([]);
const places = ref([]); const places = ref([]);
const positions = ref([]);
const selectedContact = ref(null); const selectedContact = ref(null);
const selectedTypes = ref([]); const selectedTypes = ref([]);
const selectedEventTypes = ref([]); const selectedEventTypes = ref([]);
const selectedPositions = ref([]);
const selectedPlaces = ref([]); const selectedPlaces = ref([]);
const displayStyle = ref('float'); const displayStyle = ref('float');
@@ -86,6 +93,7 @@ export default {
{ id: 'specific', caption: 'Eine Person' }, { id: 'specific', caption: 'Eine Person' },
{ id: 'places', caption: 'Für bestimmte Orte' }, { id: 'places', caption: 'Für bestimmte Orte' },
{ id: 'types', caption: 'Für bestimmte Typen' }, { id: 'types', caption: 'Für bestimmte Typen' },
{ id: 'position', caption: 'Für bestimmte Positionen'}
]); ]);
const displayStyles = ref([ const displayStyles = ref([
@@ -98,6 +106,7 @@ export default {
fetchContacts(); fetchContacts();
fetchEventTypes(); fetchEventTypes();
fetchPlaces(); fetchPlaces();
fetchPositions();
}; };
const closeAddContactDialog = () => { const closeAddContactDialog = () => {
@@ -110,16 +119,18 @@ export default {
selectedContact.value = null; selectedContact.value = null;
selectedEventTypes.value = []; selectedEventTypes.value = [];
selectedPlaces.value = []; selectedPlaces.value = [];
selectedPositions.value = [];
} else if (selectedTypes.value.some(type => type.id === 'specific')) { } else if (selectedTypes.value.some(type => type.id === 'specific')) {
selectedTypes.value = [{ id: 'specific', caption: 'Eine Person' }]; selectedTypes.value = [{ id: 'specific', caption: 'Eine Person' }];
selectedEventTypes.value = []; selectedEventTypes.value = [];
selectedPlaces.value = []; selectedPlaces.value = [];
selectedPositions.value = [];
} else if (selectedTypes.value.some(type => type.id === 'places')) { } else if (selectedTypes.value.some(type => type.id === 'places')) {
selectedContact.value = null; selectedContact.value = null;
selectedEventTypes.value = [];
} else if (selectedTypes.value.some(type => type.id === 'types')) { } else if (selectedTypes.value.some(type => type.id === 'types')) {
selectedContact.value = null; selectedContact.value = null;
selectedPlaces.value = []; } else if (selectedPositions.value.some(type => type.id === 'position')) {
selectedContact.value = null;
} }
}; };
@@ -132,8 +143,9 @@ export default {
} else if (selectedTypes.value.some(type => type.id === 'specific') && selectedContact.value) { } else if (selectedTypes.value.some(type => type.id === 'specific') && selectedContact.value) {
selection['id'] = selectedContact.value.id; selection['id'] = selectedContact.value.id;
} else { } else {
selection['types'] = selectedEventTypes.value.map((type) => type.id).join('|'); selection['types'] = selectedEventTypes.value.map((type) => type.id);
selection['places'] = selectedPlaces.value.map((place) => place.id).join('|'); selection['places'] = selectedPlaces.value.map((place) => place.id);
selection['positions'] = selectedPositions.value((postion) => postion.id);
} }
const contact = { const contact = {
selection: selection, selection: selection,
@@ -166,13 +178,21 @@ export default {
const fetchPlaces = async () => { const fetchPlaces = async () => {
try { try {
const response = await axios.get('/event-places'); const response = await axios.get('/event-places');
console.log(response);
places.value = response.data; places.value = response.data;
} catch (error) { } catch (error) {
console.error('Fehler beim Laden der Orte:', error); console.error('Fehler beim Laden der Orte:', error);
} }
}; };
const fetchPositions = async () => {
try {
const response = await axios.get('/positions');
positions.value = response.data;
} catch (error) {
console.error('Fehler beim Laden der Positionen:', error)
}
}
return { return {
isOpen, isOpen,
contacts, contacts,
@@ -190,6 +210,8 @@ export default {
onTypeSelect, onTypeSelect,
places, places,
eventTypes, eventTypes,
positions,
selectedPositions,
}; };
}, },
}; };

View File

@@ -50,7 +50,8 @@
}, },
confirm() { confirm() {
if (this.selectedFile) { if (this.selectedFile) {
this.$emit('confirm', this.selectedFile.hash); console.log(this.selectedFile.hash);
this.$emit('confirm', { hash: this.selectedFile.hash });
this.closeDialog(); this.closeDialog();
} else { } else {
alert('Bitte wählen Sie eine Datei aus.'); alert('Bitte wählen Sie eine Datei aus.');

View File

@@ -102,23 +102,21 @@ export default {
}; };
const confirmAddEventConfiguration = () => { const confirmAddEventConfiguration = () => {
let configString = ''; const event = {};
const displayString = Object.keys(displayOptions.value) event.display = Object.keys(displayOptions.value)
.filter(key => displayOptions.value[key]) .filter(key => displayOptions.value[key]);
.join('|');
if (isHomepage.value) { if (isHomepage.value) {
configString = `{{ events:id=home,display=${displayString} }}` event.id = "home";
} else if (selectedTypes.value.includes('Alle')) { } else if (selectedTypes.value.includes('Alle')) {
configString = `{{ events:id=all,display=${displayString} }}`; event.id = "all"
} else if (selectedTypes.value.includes('Ein bestimmtes')) { } else if (selectedTypes.value.includes('Ein bestimmtes')) {
configString = `{{ events:id=${selectedEvent.value.id},display=${displayString} }}`; event.id = selectedEvent.value.id;
} else { } else {
const placesString = selectedPlaces.value.map(place => place.id).join('|'); event.types = selectedEventTypes.value.map(eventType => eventType.id);
const eventTypesString = selectedEventTypes.value.map(eventType => eventType.id).join('|'); event.places = selectedPlaces.value.map(place => place.id);
configString = `{{ events:${placesString ? `event-places=${placesString},` : ''}${eventTypesString ? `event-types=${eventTypesString},` : ''}display=${displayString} }}`;
} }
emit('confirm', configString); emit('confirm', '{{ events:' + JSON.stringify(event) + ' }}');
closeAddEventDialog(); closeAddEventDialog();
}; };

View File

@@ -42,7 +42,6 @@ export default {
const confirmAddImageConfiguration = () => { const confirmAddImageConfiguration = () => {
if (selectedImage.value) { if (selectedImage.value) {
console.log('->', selectImage.value);
emit('confirm', `${selectedImage.value.id}`); emit('confirm', `${selectedImage.value.id}`);
} }
closeAddImageDialog(); closeAddImageDialog();

View File

@@ -0,0 +1,154 @@
<template>
<div>
<div v-if="isOpen" class="dialog-overlay">
<div class="dialog-content">
<h3>Institution hinzufügen</h3>
<div>
<label for="institution-select">Wählen Sie eine Institution:</label>
<multiselect id="institution-select" v-model="selectedInstitution" :options="institutionOptions" :multiple="false" label="name" track-by="id" @select="onInstitutionSelect" />
</div>
<div>
<label>Wählen Sie welche Elemente angezeigt werden sollen:</label>
<div class="display-options">
<label><input type="checkbox" v-model="displayOptions.street" /> Straße</label>
<label><input type="checkbox" v-model="displayOptions.zipcode" /> Postleitzahl</label>
<label><input type="checkbox" v-model="displayOptions.city" /> Stadt</label>
<label><input type="checkbox" v-model="displayOptions.phone" /> Telefon</label>
<label><input type="checkbox" v-model="displayOptions.fax" /> Fax</label>
<label><input type="checkbox" v-model="displayOptions.email" /> E-Mail</label>
</div>
<div>
<label for="displayStyle">Anzeigen als</label>
<select id="displayStyle" v-model="displayStyle">
<option v-for="style in displayStyles" :value="style.id" :key="style.id">{{ style.label }}</option>
</select>
</div>
</div>
<div>
<button @click="confirmAddInstitutionConfiguration">Bestätigen</button>
<button @click="closeAddInstitutionDialog">Schließen</button>
</div>
</div>
</div>
</div>
</template>
<script>
import { ref } from 'vue';
import axios from '@/axios';
import Multiselect from 'vue-multiselect';
export default {
name: 'AddInstitutionDialog',
components: {
Multiselect,
},
emits: ['confirm'],
setup(props, { emit }) {
const isOpen = ref(false);
const institutions = ref([]);
const selectedInstitution = ref(null);
const displayStyle = ref('float');
const displayOptions = ref({
street: false,
zipcode: false,
city: false,
phone: false,
fax: false,
email: false,
});
const institutionOptions = ref([
{ id: 'all', name: 'Alle' },
...institutions.value,
]);
const displayStyles = ref([
{ id: 'float', label: 'Durchlaufender Text' },
{ id: 'box', label: 'Textbox' },
]);
const openAddInstitutionDialog = () => {
isOpen.value = true;
fetchInstitutions();
};
const closeAddInstitutionDialog = () => {
isOpen.value = false;
};
const onInstitutionSelect = () => {
if (selectedInstitution.value && selectedInstitution.value.id === 'all') {
institutionOptions.value = [{ id: 'all', name: 'Alle' }];
selectedInstitution.value = { id: 'all', name: 'Alle' };
}
};
const confirmAddInstitutionConfiguration = () => {
const displayArray = Object.keys(displayOptions.value).filter((key) => displayOptions.value[key]);
const institutionConfig = {
id: selectedInstitution.value.id,
display: displayArray,
style: displayStyle.value
};
const configString = `{{ institution:${JSON.stringify(institutionConfig)} }}`;
emit('confirm', configString);
closeAddInstitutionDialog();
};
const fetchInstitutions = async () => {
try {
const response = await axios.get('/institutions');
institutions.value = response.data;
institutionOptions.value = [{ id: 'all', name: 'Alle' }, ...institutions.value];
} catch (error) {
console.error('Fehler beim Laden der Institutionen:', error);
}
};
return {
isOpen,
institutions,
selectedInstitution,
displayOptions,
displayStyle,
displayStyles,
institutionOptions,
openAddInstitutionDialog,
closeAddInstitutionDialog,
confirmAddInstitutionConfiguration,
onInstitutionSelect,
};
},
};
</script>
<style scoped>
.dialog-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
}
.dialog-content {
background: white;
padding: 20px;
border-radius: 8px;
}
.multiselect {
width: 100%;
}
.display-options label {
display: block;
}
</style>

View File

@@ -46,15 +46,11 @@ export default {
}, },
async created() { async created() {
try { try {
console.log('Initial config:', JSON.stringify(this.config));
this.displayOptions = this.config.display || []; this.displayOptions = this.config.display || [];
console.log('Display options:', this.displayOptions);
const response = await axios.post('/contact-persons/filter', { const response = await axios.post('/contact-persons/filter', {
config: JSON.stringify(this.config), config: JSON.stringify(this.config),
}); });
this.contacts = response.data; this.contacts = response.data;
console.log('Fetched contacts:', JSON.stringify(this.contacts));
console.log('Config style:', this.config.style);
this.loading = false; this.loading = false;
} catch (error) { } catch (error) {
console.error('Error loading contacts:', error); console.error('Error loading contacts:', error);

View File

@@ -1,5 +1,5 @@
<template> <template>
<span @click="downloadFile">{{ title }}</span> <span v-if="title" @click="downloadFile">{{ title }}</span>
</template> </template>
<script> <script>
@@ -8,20 +8,33 @@ import axios from 'axios';
export default { export default {
name: 'DownloadLink', name: 'DownloadLink',
props: { props: {
title: {
type: String,
required: true,
},
hash: { hash: {
type: String, type: String,
required: true, required: true,
}, },
extension: { },
type: String, data() {
required: true, return {
}, title: '',
link: '',
};
},
async created() {
await this.fetchFile();
}, },
methods: { methods: {
async fetchFile() {
try {
console.log(this.hash);
const response = await axios.get('/files/hash/' + this.hash);
this.title = response.data.title;
console.log('Fetched files:', response.data.events);
this.events = response.data.events;
} catch (error) {
console.error('Fehler beim Abrufen der Events', error);
}
},
async downloadFile() { async downloadFile() {
const response = await axios.get(`/files/download/${this.hash}`, { const response = await axios.get(`/files/download/${this.hash}`, {
responseType: 'blob' responseType: 'blob'

View File

@@ -49,19 +49,18 @@ export default {
}, },
methods: { methods: {
async fetchEvents() { async fetchEvents() {
console.log(this.config);
try { try {
const response = await axios.get('/events/filter', { const response = await axios.post('/events/filter',
params: this.config this.config
}); );
console.log('Fetched events:', response.data.events);
this.events = response.data.events; this.events = response.data.events;
} catch (error) { } catch (error) {
console.error('Fehler beim Abrufen der Events', error); console.error('Fehler beim Abrufen der Events', error);
} }
}, },
shouldDisplay(field) { shouldDisplay(field) {
const displayFields = this.config.display.split('|'); return this.config.display.includes(field);
return displayFields.includes(field);
}, },
formatDateOrDay(date, dayOfWeek) { formatDateOrDay(date, dayOfWeek) {
if (date) { if (date) {

View File

@@ -0,0 +1,64 @@
<template>
<div v-if="config && config.style === 'box' && institution">
<h3>{{ institution.name }}</h3>
<span v-if="displayOptions.includes('street')">Straße: {{ institution.street }}<br></span>
<span v-if="displayOptions.includes('zipcode')">Postleitzahl: {{ institution.zipcode }}<br></span>
<span v-if="displayOptions.includes('city')">Stadt: {{ institution.city }}<br></span>
<span v-if="displayOptions.includes('email')">E-Mail: {{ institution.email }}<br></span>
<span v-if="displayOptions.includes('phone')">Telefon: {{ institution.phone }}<br></span>
</div>
<span v-else-if="config.style === 'float' && institution">
{{ institution.name }}
<span v-if="displayOptions.includes('street')">, Straße: {{ institution.street }}</span>
<span v-if="displayOptions.includes('zipcode')">, Postleitzahl: {{ institution.zipcode }}</span>
<span v-if="displayOptions.includes('city')">, Stadt: {{ institution.city }}</span>
<span v-if="displayOptions.includes('email')">, E-Mail: {{ institution.email }}</span>
<span v-if="displayOptions.includes('phone')">, Telefon: {{ institution.phone }}</span>
</span>
<span v-else>
{{ config }}<br/>
---
{{ institution }}
</span>
</template>
<script>
import axios from '@/axios';
export default {
name: 'InstitutionRender',
props: {
config: {
type: Object,
required: true,
},
},
data() {
return {
institution: null,
loading: true,
error: null,
displayOptions: [],
};
},
async created() {
try {
this.displayOptions = this.config.display || [];
const response = await axios.get('/institutions/' + this.config.id, {
config: JSON.stringify(this.config),
});
this.institution = response.data;
this.loading = false;
} catch (error) {
console.error('Error loading institutions:', error);
this.error = 'Fehler beim Laden der Institutionen';
this.loading = false;
}
},
};
</script>
<style scoped>
/* Add styles if needed */
</style>

View File

@@ -7,7 +7,9 @@ import { createApp, h, ref, watch } from 'vue';
import WorshipRender from './WorshipRender.vue'; import WorshipRender from './WorshipRender.vue';
import ImageRender from './ImageRender.vue'; import ImageRender from './ImageRender.vue';
import EventRender from './EventRender.vue'; import EventRender from './EventRender.vue';
import ContactRender from './ContactRender.vue'; // Neue Komponente importieren import ContactRender from './ContactRender.vue'; // Importiere die neue Komponente
import InstitutionRender from './InstitutionRender.vue'; // Importiere die neue Komponente
import DownloadLink from './DownloadLink.vue';
export default { export default {
name: 'RenderContentComponent', name: 'RenderContentComponent',
@@ -23,8 +25,10 @@ export default {
const renderContent = (content) => { const renderContent = (content) => {
let result = renderWorship(content); let result = renderWorship(content);
result = renderImage(result); result = renderImage(result);
result = renderDownload(result);
result = renderEvent(result); result = renderEvent(result);
result = renderContact(result); // Neuer Filter result = renderContact(result);
result = renderInstitution(result);
return result; return result;
}; };
@@ -32,14 +36,13 @@ export default {
const worshipsPattern = /{{ worshipslist:(.*?) }}/g; const worshipsPattern = /{{ worshipslist:(.*?) }}/g;
let result = content; let result = content;
result = result.replace(worshipsPattern, (match, config) => { result = result.replace(worshipsPattern, (match, config) => {
const props = parseConfig(config);
const placeholderId = `worship-render-placeholder-${Math.random().toString(36).substr(2, 9)}`; const placeholderId = `worship-render-placeholder-${Math.random().toString(36).substr(2, 9)}`;
setTimeout(() => { setTimeout(() => {
const placeholder = document.getElementById(placeholderId); const placeholder = document.getElementById(placeholderId);
if (placeholder) { if (placeholder) {
const app = createApp({ const app = createApp({
render() { render() {
return h(WorshipRender, props); return h(WorshipRender, {config: JSON.parse(config) });
}, },
}); });
app.mount(placeholder); app.mount(placeholder);
@@ -71,18 +74,39 @@ export default {
return result; return result;
}; };
const renderDownload = (content) => {
const downloadPattern = /{{ download:(.*?) }}/g;
let result = content;
result = result.replace(downloadPattern, (match, config) => {
const placeholderId = `image-render-placeholder-${Math.random().toString(36).substr(2, 9)}`;
setTimeout(() => {
const placeholder = document.getElementById(placeholderId);
if (placeholder) {
const app = createApp({
render() {
return h(DownloadLink, { hash: config });
},
});
app.mount(placeholder);
}
}, 0);
return `<span id="${placeholderId}"></span>`;
});
return result;
};
const renderEvent = (content) => { const renderEvent = (content) => {
const eventsPattern = /{{ events:(.*?) }}/g; const eventsPattern = /{{ events:(.*?) }}/g;
let result = content; let result = content;
result = result.replace(eventsPattern, (match, config) => { result = result.replace(eventsPattern, (match, config) => {
const props = parseConfig(config);
const placeholderId = `event-render-placeholder-${Math.random().toString(36).substr(2, 9)}`; const placeholderId = `event-render-placeholder-${Math.random().toString(36).substr(2, 9)}`;
setTimeout(() => { setTimeout(() => {
const placeholder = document.getElementById(placeholderId); const placeholder = document.getElementById(placeholderId);
if (placeholder) { if (placeholder) {
const app = createApp({ const app = createApp({
render() { render() {
return h(EventRender, { id: props.id, config: props }); console.log('RC', config)
return h(EventRender, {config: JSON.parse(config) });
}, },
}); });
app.mount(placeholder); app.mount(placeholder);
@@ -97,7 +121,7 @@ export default {
const contactPattern = /{{ contact:(.*?) }}/g; const contactPattern = /{{ contact:(.*?) }}/g;
let result = content; let result = content;
result = result.replace(contactPattern, (match, config) => { result = result.replace(contactPattern, (match, config) => {
const props = JSON.parse(config); const props = parseConfig(config);
const placeholderId = `contact-render-placeholder-${Math.random().toString(36).substr(2, 9)}`; const placeholderId = `contact-render-placeholder-${Math.random().toString(36).substr(2, 9)}`;
setTimeout(() => { setTimeout(() => {
const placeholder = document.getElementById(placeholderId); const placeholder = document.getElementById(placeholderId);
@@ -110,22 +134,42 @@ export default {
app.mount(placeholder); app.mount(placeholder);
} }
}, 0); }, 0);
const tag = props.style === 'box' ? 'div' : 'span' return `<div id="${placeholderId}"></div>`;
return `<${tag} id="${placeholderId}"></${tag}>`; });
return result;
};
const renderInstitution = (content) => {
const institutionPattern = /{{ institution:(.*?) }}/g;
let result = content;
result = result.replace(institutionPattern, (match, config) => {
const props = parseConfig(config);
const placeholderId = `institution-render-placeholder-${Math.random().toString(36).substr(2, 9)}`;
setTimeout(() => {
const placeholder = document.getElementById(placeholderId);
if (placeholder) {
const app = createApp({
render() {
return h(InstitutionRender, { config: props });
},
});
app.mount(placeholder);
}
}, 0);
return `<div id="${placeholderId}"></div>`;
}); });
return result; return result;
}; };
const parseConfig = (configString) => { const parseConfig = (configString) => {
const config = {}; try {
const configArray = configString.split(','); const config = JSON.parse(configString);
configArray.forEach((item) => { return config;
const [key, value] = item.split('='); } catch (error) {
if (key && value !== undefined) { console.error('Error parsing config:', error);
config[key.trim()] = isNaN(value) ? value.trim() : Number(value); console.log(configString);
} return {};
}); }
return config;
}; };
watch( watch(

View File

@@ -66,7 +66,7 @@ export default {
}; };
const confirmWorshipConfiguration = () => { const confirmWorshipConfiguration = () => {
const selectedLocationIds = selectedLocations.value.map(location => location.id).join('|'); const selectedLocationIds = JSON.stringify(selectedLocations.value.map(location => location.id));
emit('confirm', selectedLocationIds); emit('confirm', selectedLocationIds);
closeWorshipDialog(); closeWorshipDialog();
}; };

View File

@@ -32,14 +32,10 @@ import { formatTime, formatDate } from '@/utils/strings';
export default { export default {
name: 'WorshipRender', name: 'WorshipRender',
props: { props: {
location: { config: {
type: Number, type: Object,
required: true required: true
}, },
orderBy: {
type: String,
default: 'date ASC'
}
}, },
data() { data() {
return { return {
@@ -55,10 +51,7 @@ export default {
async fetchWorships() { async fetchWorships() {
try { try {
const response = await axios.get('/worships/filtered', { const response = await axios.get('/worships/filtered', {
params: { params: this.config
location: this.location,
orderBy: this.orderBy
}
}); });
this.worships = response.data; this.worships = response.data;
} catch (error) { } catch (error) {

View File

@@ -5,7 +5,7 @@
</template> </template>
<script> <script>
import { menuData } from '../../config/menuData'; import { mapState } from 'vuex';
export default { export default {
name: 'ImageContent', name: 'ImageContent',
@@ -15,6 +15,9 @@ export default {
currentImage: '/images/homepage1.png' currentImage: '/images/homepage1.png'
}; };
}, },
computed: {
...mapState(['menuData']),
},
watch: { watch: {
$route: { $route: {
immediate: true, immediate: true,
@@ -26,6 +29,7 @@ export default {
methods: { methods: {
updateImage() { updateImage() {
const routePath = this.$route.path; const routePath = this.$route.path;
const menuData = this.menuData;
const menuItem = this.findMenuItemByPath(menuData, routePath); const menuItem = this.findMenuItemByPath(menuData, routePath);
if (menuItem && menuItem.image) { if (menuItem && menuItem.image) {
this.currentImage = `/images/${menuItem.image}`; this.currentImage = `/images/${menuItem.image}`;

View File

@@ -77,7 +77,7 @@
<div class="additional-toolbar"> <div class="additional-toolbar">
<button @click="openAddEventsDialog">Events</button> <button @click="openAddEventsDialog">Events</button>
<button @click="openAddContactDialog">Kontaktpersonen</button> <button @click="openAddContactDialog">Kontaktpersonen</button>
<button>Institutionen</button> <button @click="openAddInstitutionDialog">Institutionen</button>
<button @click="openWorshipDialog">Gottesdienste</button> <button @click="openWorshipDialog">Gottesdienste</button>
</div> </div>
<div :class="['htmleditor']"> <div :class="['htmleditor']">
@@ -90,7 +90,7 @@
<AddEventDialog ref="addEventDialog" @confirm="insertEvent" /> <AddEventDialog ref="addEventDialog" @confirm="insertEvent" />
<AddLinkDialog ref="addLinkDialog" @confirm="insertLink" /> <AddLinkDialog ref="addLinkDialog" @confirm="insertLink" />
<AddDownloadDialog ref="addDownloadDialog" @confirm="insertDownload" /> <AddDownloadDialog ref="addDownloadDialog" @confirm="insertDownload" />
<AddContactDialog ref="addContactDialog" @confirm="insertContact" /> <AddInstitutionDialog ref="addInstitutionDialog" @confirm="insertInstitution" />
<input type="color" ref="colorPicker" @input="setColor" style="display: none;" /> <input type="color" ref="colorPicker" @input="setColor" style="display: none;" />
</div> </div>
</template> </template>
@@ -119,8 +119,7 @@ import AddImageDialog from '@/components/AddImageDialog.vue';
import AddEventDialog from '@/components/AddEventDialog.vue'; import AddEventDialog from '@/components/AddEventDialog.vue';
import AddLinkDialog from '@/components/AddLinkDialog.vue'; import AddLinkDialog from '@/components/AddLinkDialog.vue';
import AddDownloadDialog from '@/components/AddDownloadDialog.vue'; import AddDownloadDialog from '@/components/AddDownloadDialog.vue';
import AddContactDialog from '@/components/AddContactDialog.vue'; import AddInstitutionDialog from '@/components/AddInstitutionDialog.vue';
import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, ListIcon, NumberedListLeftIcon, TableIcon, import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, ListIcon, NumberedListLeftIcon, TableIcon,
Table2ColumnsIcon, ArrowDownIcon, ArrowRightIcon, TableRowsIcon, AlignTopBoxIcon, AlignLeftBoxIcon, StatsReportIcon, Table2ColumnsIcon, ArrowDownIcon, ArrowRightIcon, TableRowsIcon, AlignTopBoxIcon, AlignLeftBoxIcon, StatsReportIcon,
OpenInWindowIcon, DownloadIcon OpenInWindowIcon, DownloadIcon
@@ -149,7 +148,7 @@ export default {
AddEventDialog, AddEventDialog,
AddLinkDialog, AddLinkDialog,
AddDownloadDialog, AddDownloadDialog,
AddContactDialog, AddInstitutionDialog,
OpenInWindowIcon, OpenInWindowIcon,
DownloadIcon, DownloadIcon,
}, },
@@ -163,7 +162,7 @@ export default {
const addEventDialog = ref(null); const addEventDialog = ref(null);
const addLinkDialog = ref(null); const addLinkDialog = ref(null);
const addDownloadDialog = ref(null); const addDownloadDialog = ref(null);
const addContactDialog = ref(null); const addInstitutionDialog = ref(null);
const colorPicker = ref(null); const colorPicker = ref(null);
const editor = useEditor({ const editor = useEditor({
@@ -280,8 +279,11 @@ export default {
const insertWorshipList = (selectedLocations) => { const insertWorshipList = (selectedLocations) => {
if (editor.value) { if (editor.value) {
const configuration = `location=${selectedLocations},order:"date asc"`; const configuration = {
editor.value.chain().focus().insertContent(`{{ worshipslist:${configuration} }}`).run(); location: selectedLocations,
order: "date asc",
}
editor.value.chain().focus().insertContent('{{ worshipslist:' + JSON.stringify(configuration) + ' }}').run();
} }
}; };
@@ -315,18 +317,18 @@ export default {
addDownloadDialog.value.openAddDownloadDialog(); addDownloadDialog.value.openAddDownloadDialog();
}; };
const insertDownload = ({ title, hash, extension }) => { const insertDownload = ({ hash }) => {
if (title && hash && extension && editor.value) { if (hash && editor.value) {
const url = `/files/download/${hash}`; const downloadString = '{{ download:' + hash + ' }}'
editor.value.chain().focus().extendMarkRange('link').setLink({ href: url }).insertContent(title).run(); editor.value.chain().focus().insertContent(downloadString).run();
} }
}; };
const openAddContactDialog = () => { const openAddInstitutionDialog = () => {
addContactDialog.value.openAddContactDialog(); addInstitutionDialog.value.openAddInstitutionDialog();
}; };
const insertContact = (configString) => { const insertInstitution = (configString) => {
if (editor.value) { if (editor.value) {
editor.value.chain().focus().insertContent(configString).run(); editor.value.chain().focus().insertContent(configString).run();
} }
@@ -375,38 +377,6 @@ export default {
editor.value.chain().focus().toggleOrderedList().run(); editor.value.chain().focus().toggleOrderedList().run();
}; };
const addColumnBefore = () => {
editor.value.chain().focus().addColumnBefore().run();
};
const addColumnAfter = () => {
editor.value.chain().focus().addColumnAfter().run();
};
const addRowBefore = () => {
editor.value.chain().focus().addRowBefore().run();
};
const addRowAfter = () => {
editor.value.chain().focus().addRowAfter().run();
};
const deleteColumn = () => {
editor.value.chain().focus().deleteColumn().run();
};
const deleteRow = () => {
editor.value.chain().focus().deleteRow().run();
};
const toggleHeaderColumn = () => {
editor.value.chain().focus().toggleHeaderColumn().run();
};
const toggleHeaderRow = () => {
editor.value.chain().focus().toggleHeaderRow().run();
};
return { return {
pages, pages,
sortedPages, sortedPages,
@@ -430,9 +400,9 @@ export default {
addDownloadDialog, addDownloadDialog,
openAddDownloadDialog, openAddDownloadDialog,
insertDownload, insertDownload,
addContactDialog, addInstitutionDialog,
openAddContactDialog, openAddInstitutionDialog,
insertContact, insertInstitution,
colorPicker, colorPicker,
openColorPicker, openColorPicker,
setColor, setColor,
@@ -444,14 +414,6 @@ export default {
insertTable, insertTable,
toggleBulletList, toggleBulletList,
toggleOrderedList, toggleOrderedList,
addColumnBefore,
addColumnAfter,
addRowBefore,
addRowAfter,
deleteColumn,
deleteRow,
toggleHeaderColumn,
toggleHeaderRow,
}; };
}, },
}; };

View File

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

View File

@@ -0,0 +1,11 @@
<template>
<div>
<h2>Flötenkinder</h2>
</div>
</template>
<script>
export default {
name: 'FlootChildrenContent',
};
</script>

View File

@@ -35,6 +35,7 @@ function buildMenuStructure(menuItems) {
requiresAuth: item.requires_auth, requiresAuth: item.requires_auth,
order_id: item.order_id, order_id: item.order_id,
pageTitle: item.page_title, pageTitle: item.page_title,
image: item.image,
submenu: [] submenu: []
}; };
}); });