diff --git a/src/App.jsx b/src/App.jsx
index 700c6df..8ef80fc 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,4 +1,4 @@
-import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
+import {BrowserRouter, Routes, Route} from 'react-router-dom';
import { createTheme, ThemeProvider, CssBaseline } from '@mui/material';
import { AuthProvider } from './context/AuthContext';
import PrivateRoute from './components/PrivateRoute';
@@ -19,139 +19,139 @@ import EditCompanyPage from "./pages/Company/EditCompanyPage.jsx";
import CalenderPostPage from "./pages/Calender/CalenderPostPage.jsx";
const theme = createTheme({
- palette: {
- mode: 'light',
- primary: { main: '#1976d2' },
- background: { default: '#f5f5f5' },
- },
- shape: { borderRadius: 8 },
- typography: {
- fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif',
- },
- components: {
- MuiButton: {
- styleOverrides: {
- root: { textTransform: 'none', fontWeight: 500 },
- },
+ palette: {
+ mode: 'light',
+ primary: { main: '#1976d2' },
+ background: { default: '#f5f5f5' },
},
- MuiCard: {
- styleOverrides: {
- root: { boxShadow: '0 1px 3px rgba(0,0,0,0.08)', border: '1px solid #e0e0e0' },
- },
+ shape: { borderRadius: 8 },
+ typography: {
+ fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif',
+ },
+ components: {
+ MuiButton: {
+ styleOverrides: {
+ root: { textTransform: 'none', fontWeight: 500 },
+ },
+ },
+ MuiCard: {
+ styleOverrides: {
+ root: { boxShadow: '0 1px 3px rgba(0,0,0,0.08)', border: '1px solid #e0e0e0' },
+ },
+ },
},
- },
});
export default function App() {
- return (
-
-
-
-
-
- } />
- } />
-
-
-
- }
- >
- } />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+ } />
+ } />
+
+
+
+ }
+ >
+ } />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+
+
+ );
}
\ No newline at end of file
diff --git a/src/components/ErrorBoundary.jsx b/src/components/ErrorBoundary.jsx
new file mode 100644
index 0000000..6c198a9
--- /dev/null
+++ b/src/components/ErrorBoundary.jsx
@@ -0,0 +1,29 @@
+import { Component } from 'react';
+
+class ErrorBoundary extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { hasError: false, error: null };
+ }
+
+ static getDerivedStateFromError(error) {
+ return { hasError: true, error };
+ }
+
+ render() {
+ if (this.state.hasError) {
+ return (
+
+
Etwas ist schiefgelaufen.
+
{this.state.error?.message || 'Unbekannter Fehler'}
+
+
+ );
+ }
+ return this.props.children;
+ }
+}
+
+export default ErrorBoundary;
\ No newline at end of file
diff --git a/src/components/Layout.jsx b/src/components/Layout.jsx
index 47be6ea..b394833 100644
--- a/src/components/Layout.jsx
+++ b/src/components/Layout.jsx
@@ -14,6 +14,7 @@ import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
import HomeIcon from '@mui/icons-material/Home';
import StoreIcon from '@mui/icons-material/Store';
import { useAuth } from '../context/AuthContext';
+import ErrorBoundary from './ErrorBoundary';
const DRAWER_WIDTH = 240;
@@ -34,9 +35,9 @@ const navCategories = [
{
label: 'Reporter',
items: [
- { label: 'Neuigkeiten', path: '/posts', icon: , roles: ['ADMIN', 'REPORTER'] },
- { label: 'Kalendereinträge', path: '/calenderPosts', icon: , roles: ['ADMIN', 'REPORTER'] },
- { label: 'Sehenswürdigkeiten', path: '/attractions', icon: , roles: ['ADMIN', 'REPORTER'] },
+ { label: 'Neuigkeiten', path: '/posts', icon: , roles: ['ADMIN', 'REPORTER'] },
+ { label: 'Kalendereinträge', path: '/calenderPosts', icon: , roles: ['ADMIN', 'REPORTER'] },
+ { label: 'Sehenswürdigkeiten', path: '/attractions', icon: , roles: ['ADMIN', 'REPORTER'] },
],
},
{
@@ -173,8 +174,11 @@ export default function Layout() {
+
-
+
+
+
diff --git a/src/pages/Attraction/AttractionPage.jsx b/src/pages/Attraction/AttractionPage.jsx
index 6cb099c..838cd91 100644
--- a/src/pages/Attraction/AttractionPage.jsx
+++ b/src/pages/Attraction/AttractionPage.jsx
@@ -31,7 +31,7 @@ export default function AttractionPage() {
const { data } = await axiosInstance.get('/attraction');
setRows(data);
} catch (err) {
- setError(err.response?.data?.message ?? 'Fehler beim laden der Attractions');
+ setError(err.response?.data?.error ?? 'Fehler beim laden der Attractions');
} finally {
setLoading(false);
@@ -61,7 +61,7 @@ export default function AttractionPage() {
handleCreateClose();
} catch (err) {
- setCreatingError(err.response?.data?.message ?? 'Erstellen fehlgeschlagen');
+ setCreatingError(err.response?.data?.error ?? 'Erstellen fehlgeschlagen');
} finally {
setCreating(false);
}
@@ -80,7 +80,7 @@ export default function AttractionPage() {
await axiosInstance.delete(`/attraction/${id}`);
setRows((prev) => prev.filter((r) => r.id !== id));
} catch(err){
- alert(err.response?.data?.message ?? 'Löschen fehlgeschlagen');
+ alert(err.response?.data?.error ?? 'Löschen fehlgeschlagen');
}
};
diff --git a/src/pages/Attraction/EditAttractionPage.jsx b/src/pages/Attraction/EditAttractionPage.jsx
index 97b8dc0..07355fd 100644
--- a/src/pages/Attraction/EditAttractionPage.jsx
+++ b/src/pages/Attraction/EditAttractionPage.jsx
@@ -60,7 +60,8 @@ export default function EditAttractionPage() {
setTitleImageUrl(imgs[0] || null);
setOtherImageUrls(imgs.slice(1));
} catch (err) {
- setError(err.response?.data?.message ?? 'Fehler beim Laden der Sehenswürdigkeit');
+ const msg = err.response?.data?.error;
+ setError(typeof msg === 'string' ? msg : 'Fehler beim Laden der Sehenswürdigkeit');
}
};
fetchData();
@@ -135,7 +136,8 @@ export default function EditAttractionPage() {
});
navigate('/attractions');
} catch (err) {
- setError(err.response?.data?.message ?? 'Fehler beim Speichern');
+ const msg = err.response?.data?.error;
+ setError(typeof msg === 'string' ? msg : 'Fehler beim Speichern');
setSaving(false);
}
};
@@ -155,8 +157,11 @@ export default function EditAttractionPage() {
- {error && {error}}
-
+ {error && (
+
+ {typeof error === 'string' ? error : JSON.stringify(error)}
+
+ )}
prev.filter((r) => r.id !== id));
} catch (err){
- alert(err.response?.data?.message ?? 'Löschen fehlgeschlagen');
+ alert(err.response?.data?.error ?? 'Löschen fehlgeschlagen');
}
};
diff --git a/src/pages/Company/EditCompanyPage.jsx b/src/pages/Company/EditCompanyPage.jsx
index 2e55117..cbf6b7b 100644
--- a/src/pages/Company/EditCompanyPage.jsx
+++ b/src/pages/Company/EditCompanyPage.jsx
@@ -70,7 +70,9 @@ export default function EditCompanyPage() {
setTitleImageUrl(imgs[0] || null);
setOtherImageUrls(imgs.slice(1));
} catch (err) {
- setError(err.response?.data || 'Fehler beim Laden');
+ // ✅ err.response.data kann ein Objekt sein → .error extrahieren
+ const serverMessage = err.response?.data?.error || err.response?.data;
+ setError(typeof serverMessage === 'string' ? serverMessage : 'Fehler beim Laden');
}
};
fetchData();
@@ -143,9 +145,15 @@ export default function EditCompanyPage() {
await axiosInstance.put(`/company/${id}`, formData, {
headers: { 'Content-Type': undefined }
});
+
navigate('/companies');
} catch (err) {
- setError(err.response?.data || 'Fehler beim Speichern');
+ // ✅ Fehlermeldung korrekt aus Axios-Response extrahieren
+ const serverMessage = err.response?.data?.error || err.response?.data;
+ const message = typeof serverMessage === 'string'
+ ? serverMessage
+ : err.message || 'Fehler beim Speichern';
+ setError(message);
setSaving(false);
}
};
@@ -165,8 +173,11 @@ export default function EditCompanyPage() {
- {error && {error}}
-
+ {error && (
+
+ {typeof error === 'string' ? error : JSON.stringify(error)}
+
+ )}
@@ -224,7 +235,6 @@ export default function EditCompanyPage() {
{titleImageFile ? titleImageFile.name : titleImageUrl}
- {/* Titelbild tauschen ohne zu löschen */}