From 57dd2f59552e44781017d27da0933803301836a4 Mon Sep 17 00:00:00 2001 From: eddy Date: Mon, 13 Apr 2026 14:43:06 +0200 Subject: [PATCH] update --- src/App.jsx | 9 + src/components/Layout.jsx | 2 + src/pages/CalenderPostPage.jsx | 322 +++++++++++++++++++++++++++++++++ 3 files changed, 333 insertions(+) create mode 100644 src/pages/CalenderPostPage.jsx diff --git a/src/App.jsx b/src/App.jsx index ff82c56..d9405be 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -16,6 +16,7 @@ import HomePage from './pages/HomePage'; import EditOrganizationPage from "./pages/EditOrganizationPage.jsx"; import CompanyPage from "./pages/CompanyPage.jsx"; import EditCompanyPage from "./pages/EditCompanyPage.jsx"; +import CalenderPostPage from "./pages/CalenderPostPage.jsx"; const theme = createTheme({ palette: { @@ -75,6 +76,14 @@ export default function App() { } /> + + + + } + /> , roles: ['ADMIN', 'REPORTER'] }, + { label: 'Kalendereinträge', path: '/calenderPosts', icon: , roles: ['ADMIN', 'REPORTER'] }, { label: 'Sehenswürdigkeiten', path: '/attractions', icon: , roles: ['ADMIN', 'REPORTER'] }, ], }, diff --git a/src/pages/CalenderPostPage.jsx b/src/pages/CalenderPostPage.jsx new file mode 100644 index 0000000..f4a2a45 --- /dev/null +++ b/src/pages/CalenderPostPage.jsx @@ -0,0 +1,322 @@ +import { useEffect, useState } from 'react'; +import { + Box, Typography, Alert, IconButton, Tooltip, + Dialog, DialogTitle, DialogContent, DialogActions, + Button, Stack, TextField, FormControlLabel, Checkbox, Chip, +} from '@mui/material'; +import { DataGrid } from '@mui/x-data-grid'; +import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline'; +import EditIcon from '@mui/icons-material/Edit'; +import AddIcon from '@mui/icons-material/Add'; +import axiosInstance from '../api/axiosInstance'; + +const emptyForm = { + title: '', + description: '', + location: '', + organizer: '', + fullDay: false, + startTime: '', + endTime: '', +}; + +export default function CalenderPostPage() { + const [rows, setRows] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(''); + const [detailEntry, setDetailEntry] = useState(null); + const [editEntry, setEditEntry] = useState(null); + const [formData, setFormData] = useState(emptyForm); + const [saving, setSaving] = useState(false); + + useEffect(() => { + axiosInstance.get('/calenderPost') + .then(({ data }) => setRows(data)) + .catch(() => setError('Fehler beim Laden der Kalendereinträge')) + .finally(() => setLoading(false)); + }, []); + + const handleDelete = async (id) => { + if (!window.confirm('Kalendereintrag wirklich löschen?')) return; + try { + await axiosInstance.delete(`/calenderPost/${id}`); + setRows((prev) => prev.filter((r) => r.id !== id)); + } catch { + alert('Löschen fehlgeschlagen'); + } + }; + + const openCreate = () => { + setFormData(emptyForm); + setEditEntry({}); + }; + + const openEdit = (row) => { + setFormData({ + title: row.title || '', + description: row.description || '', + location: row.location || '', + organizer: row.organizer || '', + fullDay: row.fullDay || false, + startTime: row.fullDay + ? (row.startTime ? row.startTime.substring(0, 10) : '') + : (row.startTime ? row.startTime.substring(0, 16) : ''), + endTime: row.endTime ? row.endTime.substring(0, 16) : '', + }); + setDetailEntry(null); + setEditEntry(row); + }; + + const handleSave = async () => { + setSaving(true); + try { + const payload = { + ...formData, + startTime: formData.fullDay + ? (formData.startTime ? `${formData.startTime}T00:00:00` : null) + : (formData.startTime || null), + endTime: formData.fullDay ? null : (formData.endTime || null), + }; + if (editEntry?.id) { + const { data } = await axiosInstance.put(`/calenderPost/${editEntry.id}`, payload); + setRows((prev) => prev.map((r) => r.id === data.id ? data : r)); + } else { + await axiosInstance.post('/calenderPost', payload); + const { data: updated } = await axiosInstance.get('/calenderPost'); + setRows(updated); + } + setEditEntry(null); + } catch { + alert('Speichern fehlgeschlagen'); + } finally { + setSaving(false); + } + }; + + const formatDateTime = (value) => { + if (!value) return '—'; + return new Date(value).toLocaleString('de-DE', { dateStyle: 'short', timeStyle: 'short' }); + }; + + const columns = [ + { field: 'id', headerName: 'ID', width: 70 }, + { + field: 'title', headerName: 'Titel', flex: 1.5, + renderCell: ({ row, value }) => ( + + setDetailEntry(row)} + sx={{ cursor: 'pointer', color: 'primary.main', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} + > + {value} + + + ), + }, + { field: 'location', headerName: 'Ort', width: 130 }, + { field: 'organizer', headerName: 'Organisator', width: 140 }, + { + field: 'fullDay', headerName: 'Ganztag', width: 95, + renderCell: ({ value }) => value + ? + : , + }, + { + field: 'startTime', headerName: 'Beginn', width: 150, + valueFormatter: (value) => formatDateTime(value), + }, + { + field: 'endTime', headerName: 'Ende', width: 150, + valueFormatter: (value) => formatDateTime(value), + }, + { + field: 'author', headerName: 'Autor', width: 130, + valueGetter: (value) => value || '—', // war: value?.username || value?.name || '—' + }, + { + field: 'actions', headerName: '', width: 100, sortable: false, + renderCell: ({ row }) => ( + + + openEdit(row)}> + + + + + handleDelete(row.id)}> + + + + + ), + }, + ]; + + const isEditing = editEntry !== null; + const isNew = isEditing && !editEntry?.id; + + return ( + + + Kalendereinträge + + + + {error && {error}} + + + + + + {/* Detail Dialog */} + setDetailEntry(null)} maxWidth="sm" fullWidth> + {detailEntry?.title} + + + + Beschreibung + {detailEntry?.description} + + + + Ort + {detailEntry?.location || '—'} + + + Organisator + {detailEntry?.organizer || '—'} + + + Ganztag + {detailEntry?.fullDay ? 'Ja' : 'Nein'} + + + + + Beginn + {formatDateTime(detailEntry?.startTime)} + + + Ende + {formatDateTime(detailEntry?.endTime)} + + + + Autor + {detailEntry?.author || '—'} + + + + + + + + + + + {/* Erstellen / Bearbeiten Dialog */} + setEditEntry(null)} maxWidth="sm" fullWidth> + + {isNew ? 'Neuer Kalendereintrag' : 'Kalendereintrag bearbeiten'} + + + + setFormData((p) => ({ ...p, title: e.target.value }))} + fullWidth + required + /> + setFormData((p) => ({ ...p, description: e.target.value }))} + fullWidth + multiline + rows={3} + required + /> + setFormData((p) => ({ ...p, location: e.target.value }))} + fullWidth + /> + setFormData((p) => ({ ...p, organizer: e.target.value }))} + fullWidth + /> + setFormData((p) => ({ + ...p, + fullDay: e.target.checked, + startTime: '', + endTime: '', + }))} + /> + } + label="Ganztägig" + /> + {formData.fullDay ? ( + setFormData((p) => ({ ...p, startTime: e.target.value }))} + fullWidth + required + InputLabelProps={{ shrink: true }} + /> + ) : ( + <> + setFormData((p) => ({ ...p, startTime: e.target.value }))} + fullWidth + InputLabelProps={{ shrink: true }} + /> + setFormData((p) => ({ ...p, endTime: e.target.value }))} + fullWidth + InputLabelProps={{ shrink: true }} + /> + + )} + + + + + + + + + ); +} \ No newline at end of file