diff --git a/FrontendV2/src/App.tsx b/FrontendV2/src/App.tsx
index b1d32d2..3efeed6 100644
--- a/FrontendV2/src/App.tsx
+++ b/FrontendV2/src/App.tsx
@@ -10,6 +10,7 @@ import { setIsLoggedInAtom } from "@/states/Atoms";
import { UserContext, type User } from "./states/Context";
import { triggerLogoutAtom } from "@/states/Atoms";
import { MyLoansPage } from "./pages/MyLoansPage";
+import Landingpage from "./pages/Landingpage";
const API_BASE =
(import.meta as any).env?.VITE_BACKEND_URL ||
@@ -53,6 +54,7 @@ function App() {
}>
} />
} />
+ } />
} />
diff --git a/FrontendV2/src/pages/Landingpage.tsx b/FrontendV2/src/pages/Landingpage.tsx
new file mode 100644
index 0000000..8102816
--- /dev/null
+++ b/FrontendV2/src/pages/Landingpage.tsx
@@ -0,0 +1,245 @@
+import React, { useEffect, useState } from "react";
+import {
+ Spinner,
+ Text,
+ VStack,
+ Table,
+ Heading,
+ HStack,
+ Card,
+ SimpleGrid,
+ Button,
+} from "@chakra-ui/react";
+import { Lock, LockOpen } from "lucide-react";
+import MyAlert from "@/components/myChakra/MyAlert";
+
+export const formatDateTime = (value: string | null | undefined) => {
+ if (!value) return "N/A";
+ const m = value.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})/);
+ if (!m) return "N/A";
+ const [, y, M, d, h, min] = m;
+ return `${d}.${M}.${y} ${h}:${min} Uhr`;
+};
+
+const API_BASE =
+ (import.meta as any).env?.VITE_BACKEND_URL ||
+ import.meta.env.VITE_BACKEND_URL ||
+ "http://localhost:8002";
+
+type Loan = {
+ id: number;
+ username: string;
+ start_date: string;
+ end_date: string;
+ returned_date: string | null;
+ take_date: string | null;
+ loaned_items_name: string[] | string;
+};
+
+type Device = {
+ id: number;
+ item_name: string;
+ can_borrow_role: string;
+ inSafe: number;
+ entry_created_at: string;
+};
+
+const Landingpage: React.FC = () => {
+ const [isLoading, setIsLoading] = useState(false);
+ const [loans, setLoans] = useState([]);
+ const [devices, setDevices] = useState([]);
+ const [isError, setIsError] = useState(false);
+ const [errorStatus, setErrorStatus] = useState<"error" | "success">("error");
+ const [errorMessage, setErrorMessage] = useState("");
+ const [errorDsc, setErrorDsc] = useState("");
+
+ const setError = (
+ status: "error" | "success",
+ message: string,
+ description: string
+ ) => {
+ setIsError(false);
+ setErrorStatus(status);
+ setErrorMessage(message);
+ setErrorDsc(description);
+ setIsError(true);
+ };
+
+ useEffect(() => {
+ const fetchData = async () => {
+ setIsLoading(true);
+ try {
+ const loanRes = await fetch(`${API_BASE}/apiV2/allLoans`);
+ const loanData = await loanRes.json();
+ if (Array.isArray(loanData)) {
+ setLoans(loanData);
+ } else {
+ setError(
+ "error",
+ "Fehler beim Laden",
+ "Unerwartetes Datenformat erhalten. (Ausleihen)"
+ );
+ }
+
+ const deviceRes = await fetch(`${API_BASE}/apiV2/allItems`);
+ const deviceData = await deviceRes.json();
+ if (Array.isArray(deviceData)) {
+ setDevices(deviceData);
+ } else {
+ setError(
+ "error",
+ "Fehler beim Laden",
+ "Unerwartetes Datenformat erhalten. (Geräte)"
+ );
+ }
+ } catch (e) {
+ setError(
+ "error",
+ "Fehler beim Laden",
+ "Die Ausleihen konnten nicht geladen werden."
+ );
+ } finally {
+ setIsLoading(false);
+ }
+ };
+ fetchData();
+ }, []);
+
+ return (
+ <>
+
+ Matthias-Claudius-Schule Technik
+
+
+
+ Alle Ausleihen
+
+
+ {isError && (
+
+ )}
+
+ {isLoading && (
+
+
+ Loading...
+
+ )}
+
+ {!isLoading && (
+
+
+
+
+ #
+
+
+ Benutzername
+
+
+ Startdatum
+
+
+ Enddatum
+
+
+ Ausgeliehene Artikel
+
+
+ Rückgabedatum
+
+
+ Ausleihdatum
+
+
+
+
+ {loans.map((loan) => (
+
+ {loan.id}
+ {loan.username}
+ {formatDateTime(loan.start_date)}
+ {formatDateTime(loan.end_date)}
+
+ {Array.isArray(loan.loaned_items_name)
+ ? loan.loaned_items_name.join(", ")
+ : loan.loaned_items_name}
+
+ {formatDateTime(loan.returned_date)}
+ {formatDateTime(loan.take_date)}
+
+ ))}
+
+
+ )}
+
+ {!isLoading && loans.length === 0 && !isError && (
+
+ Keine Ausleihen vorhanden.
+
+ )}
+
+
+ Alle Geräte
+
+
+ {/* Responsive Grid mit gleich hohen Karten */}
+
+ {devices.map((device) => (
+
+
+ {device.inSafe ? : }
+ {device.item_name}
+
+
+ Ausleihrolle: {device.can_borrow_role}
+
+
+ ))}
+
+
+
+ Legende:
+
+
+
+
+ >
+ );
+};
+
+export default Landingpage;
diff --git a/FrontendV2/src/utils/ProtectedRoutes.tsx b/FrontendV2/src/utils/ProtectedRoutes.tsx
index d152733..923434b 100644
--- a/FrontendV2/src/utils/ProtectedRoutes.tsx
+++ b/FrontendV2/src/utils/ProtectedRoutes.tsx
@@ -1,9 +1,20 @@
-import { Navigate, Outlet } from "react-router-dom";
-import { useAtom } from "jotai";
-import { setIsLoggedInAtom } from "@/states/Atoms";
+import { Navigate, Outlet, useLocation } from "react-router-dom";
+import Cookies from "js-cookie";
+import { useContext } from "react";
+import { UserContext } from "@/states/Context";
export const ProtectedRoutes = () => {
- const [isLoggedIn] = useAtom(setIsLoggedInAtom);
+ const user = useContext(UserContext);
+ const location = useLocation();
+ const hasToken = Boolean(Cookies.get("token"));
- return isLoggedIn ? : ;
+ if (hasToken && !user) {
+ return null;
+ }
+
+ return user ? (
+
+ ) : (
+
+ );
};