diff --git a/src/admin/AdminDashboard.tsx b/src/admin/AdminDashboard.tsx
index 2659bb46d..bd9d05237 100644
--- a/src/admin/AdminDashboard.tsx
+++ b/src/admin/AdminDashboard.tsx
@@ -1,32 +1,25 @@
-import { Link, useNavigate } from "react-router-dom";
+import { Link } from "react-router-dom";
import { Card, CardContent, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { useAuth } from "@/context/AuthContext";
-import { LogOut } from "lucide-react";
const AdminDashboard = () => {
- const { logout, username } = useAuth();
- const navigate = useNavigate();
-
- const handleLogout = () => {
- logout();
- navigate("/");
- };
+ const { isAuthenticated, username, isAdmin, logout } = useAuth();
return (
Willkommen, {username}!
-
+ {/* Jeder eingeloggt Benutzer darf News verwalten */}
@@ -36,15 +29,17 @@ const AdminDashboard = () => {
- {/* Hier später weitere Admin-Bereiche */}
-
-
-
- Benutzer verwalten
- Admins erstellen, bearbeiten und löschen
-
-
-
+ {/* Nur Admins sehen diese Card */}
+ {isAdmin && (
+
+
+
+ Benutzer verwalten
+ Admins und Benutzer verwalten
+
+
+
+ )}
);
diff --git a/src/admin/UserCreatePage.tsx b/src/admin/UserCreatePage.tsx
new file mode 100644
index 000000000..16ab12a37
--- /dev/null
+++ b/src/admin/UserCreatePage.tsx
@@ -0,0 +1,89 @@
+import { useEffect, useState } from "react";
+import { Input } from "@/components/ui/input";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { useNavigate } from "react-router-dom";
+import { useAuth } from "@/context/AuthContext";
+
+
+
+const UserCreatePage = () => {
+ const [username, setUsername] = useState("");
+ const [password, setPassword] = useState("");
+ const [role, setRole] = useState("user");
+ const { token } = useAuth();
+
+const {isAuthenticated, isAdmin} = useAuth();
+const navigate = useNavigate();
+
+useEffect(() => {
+ if(!isAuthenticated || !isAdmin) {
+ navigate("/admin");
+ }
+}, [isAuthenticated, isAdmin, navigate]);
+
+
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ try {
+ const res = await fetch("http://192.168.50.65:3000/api/users", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify({ username, password, role }),
+ });
+
+ if (!res.ok) {
+ throw new Error("Fehler beim Anlegen des Benutzers");
+ }
+
+ navigate("/admin/users");
+ } catch (err) {
+ console.error(err);
+ alert("Benutzer konnte nicht angelegt werden");
+ }
+ };
+
+ return (
+
+
+
+ Benutzer erstellen
+
+
+
+
+
+
+ );
+};
+
+export default UserCreatePage;
diff --git a/src/admin/UserEditPage.tsx b/src/admin/UserEditPage.tsx
new file mode 100644
index 000000000..8ef8962fa
--- /dev/null
+++ b/src/admin/UserEditPage.tsx
@@ -0,0 +1,105 @@
+import { useEffect, useState } from "react";
+import { useParams, useNavigate } from "react-router-dom";
+import { Input } from "@/components/ui/input";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { useAuth } from "@/context/AuthContext";
+
+const UserEditPage = () => {
+ const { id } = useParams<{ id: string }>();
+ const { token, isAuthenticated, isAdmin } = useAuth();
+ const navigate = useNavigate();
+
+ const [username, setUsername] = useState("");
+ const [password, setPassword] = useState(""); // optional neu setzen
+ const [role, setRole] = useState("user");
+
+ useEffect(() => {
+ if (!isAuthenticated || !isAdmin) {
+ navigate("/admin");
+ }
+ }, [isAuthenticated, isAdmin, navigate]);
+
+ useEffect(() => {
+ const fetchUser = async () => {
+ try {
+ const res = await fetch(`http://192.168.50.65:3000/api/users/${id}`, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ });
+ const data = await res.json();
+ setUsername(data.username);
+ setRole(data.role);
+ } catch (err) {
+ console.error(err);
+ }
+ };
+
+ if (id) {
+ fetchUser();
+ }
+ }, [id, token]);
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ try {
+ await fetch(`http://192.168.50.65:3000/api/users/${id}`, {
+ method: "PUT",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify({
+ username,
+ password: password || undefined, // Passwort nur mitschicken wenn eingegeben
+ role,
+ }),
+ });
+
+ navigate("/admin/users");
+ } catch (err) {
+ console.error(err);
+ alert("Fehler beim Aktualisieren des Benutzers");
+ }
+ };
+
+ return (
+
+
+
+ Benutzer bearbeiten
+
+
+
+
+
+
+ );
+};
+
+export default UserEditPage;
diff --git a/src/admin/UserManagementPage.tsx b/src/admin/UserManagementPage.tsx
new file mode 100644
index 000000000..58c4ffbfb
--- /dev/null
+++ b/src/admin/UserManagementPage.tsx
@@ -0,0 +1,135 @@
+import { useEffect, useState } from "react";
+import { Card, CardContent, CardTitle } from "@/components/ui/card";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
+import { useAuth } from "@/context/AuthContext";
+import { useNavigate } from "react-router-dom";
+
+
+
+interface User {
+ id: number;
+ username: string;
+ email: string;
+ role: string;
+}
+
+const UserManagementPage = () => {
+ const [users, setUsers] = useState([]);
+ const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
+ const [userToDelete, setUserToDelete] = useState(null);
+ const { token } = useAuth();
+
+ const {isAuthenticated, isAdmin} = useAuth();
+const navigate = useNavigate();
+
+useEffect(() => {
+ if(!isAuthenticated || !isAdmin) {
+ navigate("/admin");
+ }
+}, [isAuthenticated, isAdmin, navigate]);
+
+ useEffect(() => {
+ const fetchUsers = async () => {
+ try {
+ const res = await fetch("http://192.168.50.65:3000/api/users", {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ });
+ const data = await res.json();
+ setUsers(data);
+ } catch (err) {
+ console.error(err);
+ }
+ };
+
+ fetchUsers();
+ }, [token]);
+
+ const handleDelete = async () => {
+ if (!userToDelete) return;
+
+ try {
+ await fetch(`http://192.168.50.65:3000/api/users/${userToDelete.id}`, {
+ method: "DELETE",
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ });
+
+ // Nach dem Löschen die Liste neu laden
+ setUsers((prev) => prev.filter((u) => u.id !== userToDelete.id));
+ setIsDeleteModalOpen(false);
+ } catch (err) {
+ console.error(err);
+ }
+ };
+
+ return (
+
+
+
Benutzerverwaltung
+
+
+
+
+ {users.map((user) => (
+
+
+ {user.username}
+ {user.email}
+
+ Rolle: {user.role}
+
+
+
+
+
+
+
+
+ ))}
+
+
+ {/* Delete Confirm Modal */}
+
+
+ );
+};
+
+export default UserManagementPage;
diff --git a/src/context/AuthContext.tsx b/src/context/AuthContext.tsx
index 449d4c4de..9f2b6f95c 100644
--- a/src/context/AuthContext.tsx
+++ b/src/context/AuthContext.tsx
@@ -1,11 +1,11 @@
import { createContext, useContext, useState, useEffect, ReactNode } from "react";
-import {jwtDecode} from "jwt-decode";
-
-
+import { jwtDecode } from "jwt-decode";
interface AuthContextType {
token: string | null;
username: string | null;
+ role: string | null;
+ isAdmin: boolean;
login: (token: string) => void;
logout: () => void;
isAuthenticated: boolean;
@@ -13,15 +13,22 @@ interface AuthContextType {
const AuthContext = createContext({
token: null,
+ username: null,
+ role: null,
+ isAdmin: false,
login: () => {},
logout: () => {},
isAuthenticated: false,
- username: null
});
export const AuthProvider = ({ children }: { children: ReactNode }) => {
const [token, setToken] = useState(null);
const [username, setUsername] = useState(null);
+ const [role, setRole] = useState(null);
+
+ const isAdmin = role === "admin";
+
+ const isAuthenticated = !!token;
useEffect(() => {
const storedToken = localStorage.getItem("token");
@@ -29,7 +36,8 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
setToken(storedToken);
try {
const decoded: any = jwtDecode(storedToken);
- setUsername(decoded.username); // <-- Username speichern
+ setUsername(decoded.username);
+ setRole(decoded.role);
} catch (error) {
console.error("Token konnte nicht gelesen werden");
}
@@ -44,12 +52,12 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
const logout = () => {
localStorage.removeItem("token");
setToken(null);
+ setUsername(null);
+ setRole(null);
};
- const isAuthenticated = !!token;
-
return (
-
+
{children}
);
diff --git a/src/main.tsx b/src/main.tsx
index 930cff42c..3efebac59 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -16,6 +16,9 @@ import AdminDashboard from "./admin/AdminDashboard";
import NewsManager from "./admin/NewsManager";
import { AuthProvider } from "./context/AuthContext";
import PrivateRoute from "./components/PrivateRoute";
+import UserManagementPage from "./admin/UserManagementPage";
+import UserCreatePage from "./admin/UserCreatePage";
+import UserEditPage from "./admin/UserEditPage";
@@ -53,6 +56,9 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
} />
} />
} />
+ } />
+ } />
+ } />