Events renderable
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
const { Event, Institution, EventPlace, ContactPerson } = require('../models');
|
const { Event, Institution, EventPlace, ContactPerson, EventType } = require('../models');
|
||||||
|
const { Op } = require('sequelize');
|
||||||
|
const moment = require('moment'); // Import von Moment.js
|
||||||
|
|
||||||
const getAllEvents = async (req, res) => {
|
const getAllEvents = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
@@ -6,6 +8,7 @@ const getAllEvents = async (req, res) => {
|
|||||||
include: [
|
include: [
|
||||||
{ model: Institution, as: 'institution' },
|
{ model: Institution, as: 'institution' },
|
||||||
{ model: EventPlace, as: 'eventPlace' },
|
{ model: EventPlace, as: 'eventPlace' },
|
||||||
|
{ model: EventType, as: 'eventType' },
|
||||||
{ model: ContactPerson, as: 'contactPersons', through: { attributes: [] } }
|
{ model: ContactPerson, as: 'contactPersons', through: { attributes: [] } }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@@ -16,6 +19,107 @@ const getAllEvents = async (req, res) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const filterEvents = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { id, 'event-places': eventPlaces, 'event-types': eventTypes, display } = req.query;
|
||||||
|
const where = {
|
||||||
|
[Op.or]: [
|
||||||
|
{
|
||||||
|
date: {
|
||||||
|
[Op.or]: [
|
||||||
|
{ [Op.gte]: moment().startOf('day').toDate() },
|
||||||
|
{ [Op.eq]: null }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ dayOfWeek: { [Op.ne]: null } }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (id === 'all') {
|
||||||
|
const events = await Event.findAll({
|
||||||
|
where,
|
||||||
|
include: [
|
||||||
|
{ model: Institution, as: 'institution' },
|
||||||
|
{ model: EventPlace, as: 'eventPlace' },
|
||||||
|
{ model: EventType, as: 'eventType' },
|
||||||
|
{ model: ContactPerson, as: 'contactPersons', through: { attributes: [] } }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
return res.json({ events });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id === 'home') {
|
||||||
|
const events = await Event.findAll({
|
||||||
|
where: {
|
||||||
|
alsoOnHomepage: 1,
|
||||||
|
date: { [Op.gte]: moment().startOf('day').toDate() }
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{ model: Institution, as: 'institution' },
|
||||||
|
{ model: EventPlace, as: 'eventPlace' },
|
||||||
|
{ model: EventType, as: 'eventType' },
|
||||||
|
{ model: ContactPerson, as: 'contactPersons', through: { attributes: [] } }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
return res.json({ events });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!id && !eventPlaces && !eventTypes) {
|
||||||
|
return res.json({ events: [], eventPlaces: [], eventTypes: [], contactPersons: [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
where.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventPlaces) {
|
||||||
|
where.event_place_id = {
|
||||||
|
[Op.in]: eventPlaces.split('|').map(id => parseInt(id))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventTypes) {
|
||||||
|
where.eventTypeId = {
|
||||||
|
[Op.in]: eventTypes.split('|').map(id => parseInt(id))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const events = await Event.findAll({
|
||||||
|
where,
|
||||||
|
include: [
|
||||||
|
{ model: Institution, as: 'institution' },
|
||||||
|
{ model: EventPlace, as: 'eventPlace' },
|
||||||
|
{ model: EventType, as: 'eventType' },
|
||||||
|
{ model: ContactPerson, as: 'contactPersons', through: { attributes: [] } }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const displayFields = display ? display.split('|') : [];
|
||||||
|
|
||||||
|
const filteredEvents = events.map(event => {
|
||||||
|
const filteredEvent = { ...event.toJSON() };
|
||||||
|
|
||||||
|
if (!displayFields.includes('name')) delete filteredEvent.name;
|
||||||
|
if (!displayFields.includes('type')) delete filteredEvent.eventType;
|
||||||
|
if (!displayFields.includes('place')) delete filteredEvent.eventPlace;
|
||||||
|
if (!displayFields.includes('description')) delete filteredEvent.description;
|
||||||
|
if (!displayFields.includes('time')) delete filteredEvent.time;
|
||||||
|
if (!displayFields.includes('time')) delete filteredEvent.endTime;
|
||||||
|
if (!displayFields.includes('contactPerson')) delete filteredEvent.contactPersons;
|
||||||
|
if (!displayFields.includes('day')) delete filteredEvent.dayOfWeek;
|
||||||
|
if (!displayFields.includes('institution')) delete filteredEvent.institution;
|
||||||
|
|
||||||
|
return filteredEvent;
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json({ events: filteredEvents });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: 'Failed to filter events' });
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const createEvent = async (req, res) => {
|
const createEvent = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { contactPersonIds, ...eventData } = req.body;
|
const { contactPersonIds, ...eventData } = req.body;
|
||||||
@@ -70,5 +174,6 @@ module.exports = {
|
|||||||
getAllEvents,
|
getAllEvents,
|
||||||
createEvent,
|
createEvent,
|
||||||
updateEvent,
|
updateEvent,
|
||||||
deleteEvent
|
deleteEvent,
|
||||||
|
filterEvents
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ module.exports = (sequelize) => {
|
|||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
allowNull: true
|
allowNull: true
|
||||||
},
|
},
|
||||||
eventPlaceId: {
|
event_place_id: {
|
||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
allowNull: true
|
allowNull: true
|
||||||
},
|
},
|
||||||
@@ -37,6 +37,10 @@ module.exports = (sequelize) => {
|
|||||||
description: {
|
description: {
|
||||||
type: DataTypes.TEXT,
|
type: DataTypes.TEXT,
|
||||||
allowNull: true
|
allowNull: true
|
||||||
|
},
|
||||||
|
alsoOnHomepage: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
tableName: 'events',
|
tableName: 'events',
|
||||||
@@ -52,6 +56,10 @@ module.exports = (sequelize) => {
|
|||||||
foreignKey: 'event_place_id',
|
foreignKey: 'event_place_id',
|
||||||
as: 'eventPlace'
|
as: 'eventPlace'
|
||||||
});
|
});
|
||||||
|
Event.belongsTo(models.EventType, {
|
||||||
|
foreignKey: 'eventTypeId',
|
||||||
|
as: 'eventType'
|
||||||
|
});
|
||||||
Event.belongsToMany(models.ContactPerson, {
|
Event.belongsToMany(models.ContactPerson, {
|
||||||
through: 'EventContactPerson',
|
through: 'EventContactPerson',
|
||||||
foreignKey: 'event_id',
|
foreignKey: 'event_id',
|
||||||
|
|||||||
1
package-lock.json
generated
1
package-lock.json
generated
@@ -32,6 +32,7 @@
|
|||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"moment": "^2.30.1",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"mysql2": "^3.10.1",
|
"mysql2": "^3.10.1",
|
||||||
"nodemon": "^3.1.3",
|
"nodemon": "^3.1.3",
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"moment": "^2.30.1",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"mysql2": "^3.10.1",
|
"mysql2": "^3.10.1",
|
||||||
"nodemon": "^3.1.3",
|
"nodemon": "^3.1.3",
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { getAllEvents, createEvent, updateEvent, deleteEvent } = require('../controllers/eventController.js');
|
const { getAllEvents, createEvent, updateEvent, deleteEvent, filterEvents } = require('../controllers/eventController.js');
|
||||||
const authMiddleware = require('../middleware/authMiddleware')
|
const authMiddleware = require('../middleware/authMiddleware')
|
||||||
|
|
||||||
router.get('/', authMiddleware, getAllEvents);
|
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);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ html, body {
|
|||||||
|
|
||||||
.left-column {
|
.left-column {
|
||||||
margin: 0.5em 0 0.5em 0.5em;
|
margin: 0.5em 0 0.5em 0.5em;
|
||||||
|
padding-right: 0.5em;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
208
src/components/AddEventDialog.vue
Normal file
208
src/components/AddEventDialog.vue
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div v-if="isOpen" class="dialog-overlay">
|
||||||
|
<div class="dialog-content">
|
||||||
|
<h3>Ereignisse hinzufügen</h3>
|
||||||
|
<div>
|
||||||
|
<label for="selection-type">Wählen Sie den Typ:</label>
|
||||||
|
<multiselect id="selection-type" v-model="selectedTypes" :options="typeOptions" :multiple="true"
|
||||||
|
:close-on-select="false" :clear-on-select="false" :preserve-search="true" @select="onTypeSelect" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label><input type="checkbox" v-model="isHomepage" /> Auch Ereignisse für die Homepage zeigen</label>
|
||||||
|
</div>
|
||||||
|
<div v-if="selectedTypes.includes('Für bestimmte Orte')">
|
||||||
|
<label for="places-select">Wählen Sie Orte:</label>
|
||||||
|
<multiselect id="places-select" v-model="selectedPlaces" :options="places" :multiple="true"
|
||||||
|
:close-on-select="false" :clear-on-select="false" :preserve-search="true" label="name" track-by="id" />
|
||||||
|
</div>
|
||||||
|
<div v-if="selectedTypes.includes('Für bestimmte Typen')">
|
||||||
|
<label for="types-select">Wählen Sie Typen:</label>
|
||||||
|
<multiselect id="types-select" v-model="selectedEventTypes" :options="eventTypes" :multiple="true"
|
||||||
|
:close-on-select="false" :clear-on-select="false" :preserve-search="true" label="caption" track-by="id" />
|
||||||
|
</div>
|
||||||
|
<div v-if="selectedTypes.includes('Ein bestimmtes')">
|
||||||
|
<label for="event-select">Wählen Sie ein Event:</label>
|
||||||
|
<multiselect id="event-select" v-model="selectedEvent" :options="events" :multiple="false" label="name"
|
||||||
|
track-by="id" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Wählen Sie welche Elemente angezeigt werden sollen:</label>
|
||||||
|
<div class="display-options">
|
||||||
|
<label><input type="checkbox" v-model="displayOptions.name" /> Name</label>
|
||||||
|
<label><input type="checkbox" v-model="displayOptions.type" /> Typ</label>
|
||||||
|
<label><input type="checkbox" v-model="displayOptions.place" /> Ort</label>
|
||||||
|
<label><input type="checkbox" v-model="displayOptions.description" /> Beschreibung</label>
|
||||||
|
<label><input type="checkbox" v-model="displayOptions.time" /> Uhrzeit</label>
|
||||||
|
<label><input type="checkbox" v-model="displayOptions.contactPerson" /> Kontaktperson</label>
|
||||||
|
<label><input type="checkbox" v-model="displayOptions.day" /> Veranstaltungstag</label>
|
||||||
|
<label><input type="checkbox" v-model="displayOptions.institution" /> Institution</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button @click="confirmAddEventConfiguration">Bestätigen</button>
|
||||||
|
<button @click="closeAddEventDialog">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: 'AddEventDialog',
|
||||||
|
components: {
|
||||||
|
Multiselect,
|
||||||
|
},
|
||||||
|
emits: ['confirm'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const isOpen = ref(false);
|
||||||
|
const typeOptions = ref(['Alle', 'Für bestimmte Orte', 'Für bestimmte Typen', 'Ein bestimmtes', 'Ereignisse für Homepage']);
|
||||||
|
const selectedTypes = ref([]);
|
||||||
|
const places = ref([]);
|
||||||
|
const eventTypes = ref([]);
|
||||||
|
const events = ref([]);
|
||||||
|
const selectedPlaces = ref([]);
|
||||||
|
const selectedEventTypes = ref([]);
|
||||||
|
const selectedEvent = ref(null);
|
||||||
|
const isHomepage = ref(false);
|
||||||
|
|
||||||
|
const displayOptions = ref({
|
||||||
|
name: false,
|
||||||
|
type: false,
|
||||||
|
place: false,
|
||||||
|
description: false,
|
||||||
|
time: false,
|
||||||
|
contactPerson: false,
|
||||||
|
day: false,
|
||||||
|
institution: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const openAddEventDialog = () => {
|
||||||
|
isOpen.value = true;
|
||||||
|
fetchPlaces();
|
||||||
|
fetchEventTypes();
|
||||||
|
fetchEvents();
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeAddEventDialog = () => {
|
||||||
|
isOpen.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTypeSelect = (selectedOption) => {
|
||||||
|
if (selectedOption === 'Alle' || selectedOption === 'Ein bestimmtes') {
|
||||||
|
selectedTypes.value = [selectedOption];
|
||||||
|
} else {
|
||||||
|
selectedTypes.value = selectedTypes.value.filter(option => option !== 'Alle' && option !== 'Ein bestimmtes');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmAddEventConfiguration = () => {
|
||||||
|
let configString = '';
|
||||||
|
const displayString = Object.keys(displayOptions.value)
|
||||||
|
.filter(key => displayOptions.value[key])
|
||||||
|
.join('|');
|
||||||
|
|
||||||
|
if (isHomepage.value) {
|
||||||
|
configString = `{{ events:id=home,display=${displayString} }}`
|
||||||
|
} else if (selectedTypes.value.includes('Alle')) {
|
||||||
|
configString = `{{ events:id=all,display=${displayString} }}`;
|
||||||
|
} else if (selectedTypes.value.includes('Ein bestimmtes')) {
|
||||||
|
configString = `{{ events:id=${selectedEvent.value.id},display=${displayString} }}`;
|
||||||
|
} else {
|
||||||
|
const placesString = selectedPlaces.value.map(place => place.id).join('|');
|
||||||
|
const eventTypesString = selectedEventTypes.value.map(eventType => eventType.id).join('|');
|
||||||
|
configString = `{{ events:${placesString ? `event-places=${placesString},` : ''}${eventTypesString ? `event-types=${eventTypesString},` : ''}display=${displayString} }}`;
|
||||||
|
}
|
||||||
|
emit('confirm', configString);
|
||||||
|
closeAddEventDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchPlaces = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get('/event-places');
|
||||||
|
places.value = response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fehler beim Laden der Orte:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchEventTypes = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get('/event-types');
|
||||||
|
eventTypes.value = response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fehler beim Laden der Typen:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchEvents = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get('/events');
|
||||||
|
events.value = response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fehler beim Laden der Events:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isOpen,
|
||||||
|
typeOptions,
|
||||||
|
selectedTypes,
|
||||||
|
places,
|
||||||
|
eventTypes,
|
||||||
|
events,
|
||||||
|
selectedPlaces,
|
||||||
|
selectedEventTypes,
|
||||||
|
selectedEvent,
|
||||||
|
displayOptions,
|
||||||
|
openAddEventDialog,
|
||||||
|
closeAddEventDialog,
|
||||||
|
confirmAddEventConfiguration,
|
||||||
|
onTypeSelect,
|
||||||
|
isHomepage,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</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%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-block {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 2.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-options label {
|
||||||
|
display:block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
97
src/components/EventRender.vue
Normal file
97
src/components/EventRender.vue
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<table v-if="events.length > 1" class="event-table">
|
||||||
|
<tr v-for="event in events" :key="event.id">
|
||||||
|
<td>
|
||||||
|
<div v-if="shouldDisplay('name')" class="event-name">{{ event.name }}</div>
|
||||||
|
<div>{{ formatDateOrDay(event.date, event.dayOfWeek) }}</div>
|
||||||
|
<div v-if="shouldDisplay('time')">{{ event.time }} <span v-if="event.endTime"> - {{ event.endTime }}</span> Uhr</div>
|
||||||
|
<div v-if="shouldDisplay('place')">{{ event.eventPlace?.name }}</div>
|
||||||
|
<div v-if="shouldDisplay('description')" class="description">{{ event.description }}</div>
|
||||||
|
<div v-if="shouldDisplay('contactPerson')">{{ event.contactPersons.map(cp => cp.name).join(', ') }}</div>
|
||||||
|
<div v-if="shouldDisplay('institution')">{{ event.institution?.name }}</div>
|
||||||
|
<div v-if="shouldDisplay('type')">{{ event.eventType?.caption }}</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div v-else-if="events.length === 1" :class="events[0].alsoOnHomepage && config.id === 'home' ? 'homepage' : ''">
|
||||||
|
<div v-if="shouldDisplay('name')" class="event-name">{{ events[0].name }}</div>
|
||||||
|
<div>{{ formatDateOrDay(events[0].date, events[0].dayOfWeek) }}</div>
|
||||||
|
<div v-if="shouldDisplay('time')">{{ events[0].time }} <span v-if="events[0].endTime"> - {{ events[0].endTime }}</span> Uhr</div>
|
||||||
|
<div v-if="shouldDisplay('place')">{{ events[0].eventPlace?.name }}</div>
|
||||||
|
<div v-if="shouldDisplay('description')" class="description">{{ events[0].description }}</div>
|
||||||
|
<div v-if="shouldDisplay('contactPerson')">{{ events[0].contactPersons.map(cp => cp.name).join(', ') }}</div>
|
||||||
|
<div v-if="shouldDisplay('institution')">{{ events[0].institution?.name }}</div>
|
||||||
|
<div v-if="shouldDisplay('type')">{{ events[0].eventType?.caption }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from '@/axios';
|
||||||
|
import { format } from 'date-fns'; // Importiere date-fns für die Datumsformatierung
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'EventRender',
|
||||||
|
props: {
|
||||||
|
config: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
events: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
await this.fetchEvents();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchEvents() {
|
||||||
|
try {
|
||||||
|
const response = await axios.get('/events/filter', {
|
||||||
|
params: this.config
|
||||||
|
});
|
||||||
|
console.log('Fetched events:', response.data.events);
|
||||||
|
this.events = response.data.events;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fehler beim Abrufen der Events', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shouldDisplay(field) {
|
||||||
|
const displayFields = this.config.display.split('|');
|
||||||
|
return displayFields.includes(field);
|
||||||
|
},
|
||||||
|
formatDateOrDay(date, dayOfWeek) {
|
||||||
|
if (date) {
|
||||||
|
return format(new Date(date), 'dd.MM.yyyy');
|
||||||
|
} else if (dayOfWeek !== null && dayOfWeek !== undefined) {
|
||||||
|
const daysOfWeek = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
|
||||||
|
return daysOfWeek[dayOfWeek];
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.event-name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.event-table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.event-table td {
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
.homepage {
|
||||||
|
border: 1px solid #9400ff;
|
||||||
|
padding: 0.5em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.description {
|
||||||
|
padding: 0.5em 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
import { createApp, h, ref, watch } from 'vue';
|
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';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RenderContentComponent',
|
name: 'RenderContentComponent',
|
||||||
@@ -20,7 +21,8 @@ export default {
|
|||||||
|
|
||||||
const renderContent = (content) => {
|
const renderContent = (content) => {
|
||||||
let result = renderWorship(content);
|
let result = renderWorship(content);
|
||||||
result = renderImage(content);
|
result = renderImage(result); // Use result here
|
||||||
|
result = renderEvent(result); // Use result here
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -44,7 +46,7 @@ export default {
|
|||||||
return `<div id="${placeholderId}"></div>`;
|
return `<div id="${placeholderId}"></div>`;
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
};
|
||||||
|
|
||||||
const renderImage = (content) => {
|
const renderImage = (content) => {
|
||||||
const imagePattern = /{{ image:(.*?) }}/g;
|
const imagePattern = /{{ image:(.*?) }}/g;
|
||||||
@@ -57,7 +59,7 @@ export default {
|
|||||||
const app = createApp({
|
const app = createApp({
|
||||||
render() {
|
render() {
|
||||||
console.log(config);
|
console.log(config);
|
||||||
return h(ImageRender, { 'id': config });
|
return h(ImageRender, { id: config });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
app.mount(placeholder);
|
app.mount(placeholder);
|
||||||
@@ -66,7 +68,31 @@ export default {
|
|||||||
return `<span id="${placeholderId}"></span>`;
|
return `<span id="${placeholderId}"></span>`;
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderEvent = (content) => {
|
||||||
|
const eventsPattern = /{{ events:(.*?) }}/g;
|
||||||
|
let result = content;
|
||||||
|
result = result.replace(eventsPattern, (match, config) => {
|
||||||
|
console.log(config);
|
||||||
|
const props = parseConfig(config);
|
||||||
|
console.log(props);
|
||||||
|
const placeholderId = `event-render-placeholder-${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
setTimeout(() => {
|
||||||
|
const placeholder = document.getElementById(placeholderId);
|
||||||
|
if (placeholder) {
|
||||||
|
const app = createApp({
|
||||||
|
render() {
|
||||||
|
return h(EventRender, { id: props.id, config: props });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
app.mount(placeholder);
|
||||||
}
|
}
|
||||||
|
}, 0);
|
||||||
|
return `<div id="${placeholderId}"></div>`;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
const parseConfig = (configString) => {
|
const parseConfig = (configString) => {
|
||||||
const config = {};
|
const config = {};
|
||||||
@@ -88,9 +114,9 @@ export default {
|
|||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
parsedContent,
|
parsedContent,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="additional-toolbar">
|
<div class="additional-toolbar">
|
||||||
<button>Events</button>
|
<button @click="openAddEventsDialog">Events</button>
|
||||||
<button>Kontaktpersonen</button>
|
<button>Kontaktpersonen</button>
|
||||||
<button>Institutionen</button>
|
<button>Institutionen</button>
|
||||||
<button @click="openWorshipDialog">Gottesdienste</button>
|
<button @click="openWorshipDialog">Gottesdienste</button>
|
||||||
@@ -79,6 +79,7 @@
|
|||||||
|
|
||||||
<WorshipDialog ref="worshipDialog" @confirm="insertWorshipList" />
|
<WorshipDialog ref="worshipDialog" @confirm="insertWorshipList" />
|
||||||
<AddImageDialog ref="addImageDialog" @confirm="insertImage" />
|
<AddImageDialog ref="addImageDialog" @confirm="insertImage" />
|
||||||
|
<AddEventDialog ref="addEventDialog" @confirm="insertEvent" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -100,6 +101,7 @@ import Heading from '@tiptap/extension-heading';
|
|||||||
import { CustomTableCell, CustomTableHeader } from '../../extensions/CustomTableCell';
|
import { CustomTableCell, CustomTableHeader } from '../../extensions/CustomTableCell';
|
||||||
import WorshipDialog from '@/components/WorshipDialog.vue';
|
import WorshipDialog from '@/components/WorshipDialog.vue';
|
||||||
import AddImageDialog from '@/components/AddImageDialog.vue';
|
import AddImageDialog from '@/components/AddImageDialog.vue';
|
||||||
|
import AddEventDialog from '@/components/AddEventDialog.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
|
||||||
@@ -125,6 +127,7 @@ export default {
|
|||||||
AlignTopBoxIcon,
|
AlignTopBoxIcon,
|
||||||
AlignLeftBoxIcon,
|
AlignLeftBoxIcon,
|
||||||
StatsReportIcon,
|
StatsReportIcon,
|
||||||
|
AddEventDialog,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@@ -133,6 +136,7 @@ export default {
|
|||||||
const pageHtmlContent = computed(() => store.state.pageContent);
|
const pageHtmlContent = computed(() => store.state.pageContent);
|
||||||
const worshipDialog = ref(null);
|
const worshipDialog = ref(null);
|
||||||
const addImageDialog = ref(null);
|
const addImageDialog = ref(null);
|
||||||
|
const addEventDialog = ref(null);
|
||||||
|
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
extensions: [
|
extensions: [
|
||||||
@@ -254,6 +258,16 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openAddEventDialog = () => {
|
||||||
|
addEventDialog.value.openAddEventDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
const insertEvent = (configString) => {
|
||||||
|
if (editor.value) {
|
||||||
|
editor.value.chain().focus().insertContent(configString).run();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pages,
|
pages,
|
||||||
sortedPages,
|
sortedPages,
|
||||||
@@ -268,6 +282,9 @@ export default {
|
|||||||
addImageDialog,
|
addImageDialog,
|
||||||
openAddImageDialog,
|
openAddImageDialog,
|
||||||
insertImage,
|
insertImage,
|
||||||
|
addEventDialog,
|
||||||
|
openAddEventsDialog: openAddEventDialog,
|
||||||
|
insertEvent,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user