diff --git a/.gitignore b/.gitignore
index 829a367..4e4545b 100755
--- a/.gitignore
+++ b/.gitignore
@@ -13,12 +13,6 @@ node_modules/
.DS_Store
Thumbs.db
-# IDE spezifische Ignorierungen
-.idea/
-.vscode/
-*.swp
-*~
-
# Weitere Build-Verzeichnisse
**/dist/
**/build/
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 768ae7d..74609b3 100755
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,4 +1,9 @@
{
"editor.formatOnSave": true,
- "cSpell.language": "en,de-DE"
+ "cSpell.language": "en,de-DE",
+ "files.autoSave": "afterDelay",
+ "editor.formatOnPaste": false,
+ "deno.disablePaths": [
+ "frontend-react"
+ ]
}
diff --git a/backend-dart/run.sh b/backend-dart/run.sh
new file mode 100644
index 0000000..d740187
--- /dev/null
+++ b/backend-dart/run.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+dart run bin/backend_dart.dart # Backend on port 8080
diff --git a/frontend-react/deno.json b/frontend-react/deno.json
new file mode 100644
index 0000000..dc438fe
--- /dev/null
+++ b/frontend-react/deno.json
@@ -0,0 +1,3 @@
+{
+ "unstable": ["unsafe-proto"]
+}
\ No newline at end of file
diff --git a/frontend-react/import_map.json b/frontend-react/import_map.json
new file mode 100644
index 0000000..33b1426
--- /dev/null
+++ b/frontend-react/import_map.json
@@ -0,0 +1,5 @@
+{
+ "imports": {
+ "@/components/": "./components/"
+ }
+}
\ No newline at end of file
diff --git a/frontend-react/messages/de.json b/frontend-react/messages/de.json
index 75f8b73..4b95c9f 100755
--- a/frontend-react/messages/de.json
+++ b/frontend-react/messages/de.json
@@ -19,5 +19,12 @@
"NotFoundPage": {
"description": "Bitte überprüfe die Addressleiste deines Browsers oder verwende die Navigation um zu einer bekannten Seite zu wechseln.",
"title": "Seite nicht gefunden"
+ },
+ "Auth": {
+ "login": "Anmelden",
+ "logout": "Abmelden",
+ "profile": "Profil",
+ "register": "Registrieren",
+ "resetPassword": "Passwort zurücksetzen"
}
}
\ No newline at end of file
diff --git a/frontend-react/src/app/[locale]/(auth)/login/page.tsx b/frontend-react/src/app/[locale]/(auth)/login/page.tsx
index 2d9d247..8f5d993 100755
--- a/frontend-react/src/app/[locale]/(auth)/login/page.tsx
+++ b/frontend-react/src/app/[locale]/(auth)/login/page.tsx
@@ -1,4 +1,6 @@
"use client";
+import BackButton from "@/components/Buttons/BackButton";
+import StartpageButton from "@/components/Buttons/StartpageButton";
import Link from "next/link";
import React from "react";
import { useState } from "react";
@@ -20,7 +22,8 @@ const LoginPage = () => {
);
diff --git a/frontend-react/src/app/[locale]/(auth)/register/layout.tsx b/frontend-react/src/app/[locale]/(auth)/register/layout.tsx
new file mode 100755
index 0000000..ec30286
--- /dev/null
+++ b/frontend-react/src/app/[locale]/(auth)/register/layout.tsx
@@ -0,0 +1,9 @@
+const LoginLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default LoginLayout;
\ No newline at end of file
diff --git a/frontend-react/src/app/[locale]/(auth)/register/page.tsx b/frontend-react/src/app/[locale]/(auth)/register/page.tsx
new file mode 100755
index 0000000..65f12b0
--- /dev/null
+++ b/frontend-react/src/app/[locale]/(auth)/register/page.tsx
@@ -0,0 +1,108 @@
+"use client";
+import Link from "next/link";
+import React, { FormEvent, useState } from "react";
+import BackButton from "@/components/Buttons/BackButton";
+import StartpageButton from "@/components/Buttons/StartpageButton";
+
+const RegisterPage = () => {
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+ const [confirmPassword, setConfirmPassword] = useState("");
+
+ interface RegisterFormState {
+ email: string;
+ password: string;
+ confirmPassword: string;
+ }
+
+ const handleSubmit = (e: FormEvent) => {
+ e.preventDefault();
+ if (password !== confirmPassword) {
+ alert("Passwords do not match");
+ return;
+ }
+ const formData: RegisterFormState = {
+ email,
+ password,
+ confirmPassword,
+ };
+ // Registrierungshandhabung hier hinzufügen
+ console.log("Registering user with data", formData);
+ };
+
+ return (
+
+ );
+};
+
+export default RegisterPage;
diff --git a/frontend-react/src/app/[locale]/(info)/about/layout.tsx b/frontend-react/src/app/[locale]/(info)/about/layout.tsx
new file mode 100755
index 0000000..02539f3
--- /dev/null
+++ b/frontend-react/src/app/[locale]/(info)/about/layout.tsx
@@ -0,0 +1,16 @@
+import { ReactNode } from "react";
+import BaseLayout from "@/components/Layout/BaseLayout";
+import { routing } from "@/i18n/routing";
+import UnauthenticatedLayout from "@/components/Layout/UnauthenticatedLayout";
+
+type Props = {
+ children: ReactNode;
+};
+
+export default function RootLayout({ children }: Props) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/frontend-react/src/app/[locale]/(info)/about/page.tsx b/frontend-react/src/app/[locale]/(info)/about/page.tsx
new file mode 100755
index 0000000..9b2bd93
--- /dev/null
+++ b/frontend-react/src/app/[locale]/(info)/about/page.tsx
@@ -0,0 +1,48 @@
+"use client";
+
+import React from "react";
+
+export default function About() {
+ return (
+
+
+
+
+ Über das Projekt
+
+
+ Entwickler: Jean Jacques Avril
+
+
+ Webseite:{" "}
+
+ jeanavril.com
+
+
+
+ Technologien: Next.js, Go, Docker, Deno, Dart
+
+
+ Mit ActaTempus können Sie Ihre Arbeitszeiten mühelos erfassen und
+ Einblicke in Ihre Arbeitsgewohnheiten gewinnen. Beginnen Sie noch
+ heute und steigern Sie Ihre Produktivität.
+
+
+
+
+
+ );
+}
diff --git a/frontend-react/src/app/[locale]/(landing)/page.tsx b/frontend-react/src/app/[locale]/(landing)/page.tsx
index b1425dd..8257b2c 100755
--- a/frontend-react/src/app/[locale]/(landing)/page.tsx
+++ b/frontend-react/src/app/[locale]/(landing)/page.tsx
@@ -1,4 +1,7 @@
"use client";
+
+import Link from "next/link";
+
export default function Home() {
return (
@@ -14,13 +17,17 @@ export default function Home() {
diff --git a/frontend-react/src/app/[locale]/dashboard/layout.tsx b/frontend-react/src/app/[locale]/dashboard/layout.tsx
new file mode 100755
index 0000000..188a85c
--- /dev/null
+++ b/frontend-react/src/app/[locale]/dashboard/layout.tsx
@@ -0,0 +1,19 @@
+import { ReactNode } from "react";
+import BaseLayout from "@/components/Layout/BaseLayout";
+import { routing } from "@/i18n/routing";
+import UnauthenticatedLayout from "@/components/Layout/UnauthenticatedLayout";
+import AuthGuard from "@/components/guards/AuthGuard";
+
+type Props = {
+ children: ReactNode;
+};
+
+export default function RootLayout({ children }: Props) {
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/frontend-react/src/app/[locale]/dashboard/page.tsx b/frontend-react/src/app/[locale]/dashboard/page.tsx
new file mode 100755
index 0000000..04406d0
--- /dev/null
+++ b/frontend-react/src/app/[locale]/dashboard/page.tsx
@@ -0,0 +1,97 @@
+"use client";
+import React, { FormEvent, useState } from "react";
+
+const Dashboard = () => {
+ const [newEntry, setNewEntry] = useState({ task: "", duration: "" });
+ const [entries, setEntries] = useState([
+ { id: 1, task: "Meeting", duration: "1h 30m", date: "2024-12-30" },
+ { id: 2, task: "Development", duration: "3h 45m", date: "2024-12-29" },
+ { id: 3, task: "Code Review", duration: "2h", date: "2024-12-28" },
+ ]);
+
+ const handleInputChange = (e: FormEvent) => {
+ const { name, value } = e.target as HTMLInputElement;
+ setNewEntry({ ...newEntry, [name]: value });
+ };
+
+ const handleAddEntry = () => {
+ if (!newEntry.task || !newEntry.duration) return;
+ const newId = entries.length ? entries[entries.length - 1].id + 1 : 1;
+ setEntries([
+ ...entries,
+ { id: newId, ...newEntry, date: new Date().toISOString().split("T")[0] },
+ ]);
+ setNewEntry({ task: "", duration: "" });
+ };
+
+ return (
+
+
+ {/* Timer Section */}
+
+
+ {/* Past Entries Section */}
+
+
+ Past Entries
+
+
+ {entries.length
+ ? (
+
+ {entries.map((entry) => (
+
+
+
+ {entry.task}
+
+
+ {entry.date} - {entry.duration}
+
+
+
+ ))}
+
+ )
+ : (
+
+ No entries yet. Start adding some!
+
+ )}
+
+
+
+
+ );
+};
+
+export default Dashboard;
diff --git a/frontend-react/src/app/layout.tsx b/frontend-react/src/app/layout.tsx
index 0a7f803..c1eb2c8 100755
--- a/frontend-react/src/app/layout.tsx
+++ b/frontend-react/src/app/layout.tsx
@@ -1,4 +1,5 @@
-import {ReactNode} from 'react';
+import { UserProvider } from "@/context/UserContext";
+import { ReactNode } from "react";
type Props = {
children: ReactNode;
@@ -6,6 +7,10 @@ type Props = {
// Since we have a `not-found.tsx` page on the root, a layout file
// is required, even if it's just passing children through.
-export default function RootLayout({children}: Props) {
- return children;
-}
\ No newline at end of file
+export default function RootLayout({ children }: Props) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/frontend-react/src/components/Buttons/BackButton.tsx b/frontend-react/src/components/Buttons/BackButton.tsx
new file mode 100644
index 0000000..37382da
--- /dev/null
+++ b/frontend-react/src/components/Buttons/BackButton.tsx
@@ -0,0 +1,26 @@
+import { ChevronLeft } from "lucide-react";
+import { useRouter } from "next/navigation";
+
+const BackButton = () => {
+ const router = useRouter();
+
+ const handleBack = () => {
+ if (window.history.length > 1) {
+ router.back();
+ } else {
+ router.push("/");
+ }
+ };
+
+ return (
+
+
+ Zurück
+
+ );
+};
+
+export default BackButton;
diff --git a/frontend-react/src/components/Buttons/StartpageButton.tsx b/frontend-react/src/components/Buttons/StartpageButton.tsx
new file mode 100644
index 0000000..0184067
--- /dev/null
+++ b/frontend-react/src/components/Buttons/StartpageButton.tsx
@@ -0,0 +1,16 @@
+import { HomeIcon } from "lucide-react";
+import Link from "next/link";
+
+const StartpageButton = () => {
+ return (
+
+
+ Startseite
+
+ );
+};
+
+export default StartpageButton;
diff --git a/frontend-react/src/components/guards/AuthGuard.tsx b/frontend-react/src/components/guards/AuthGuard.tsx
new file mode 100644
index 0000000..0ff5352
--- /dev/null
+++ b/frontend-react/src/components/guards/AuthGuard.tsx
@@ -0,0 +1,23 @@
+"use client";
+import { useRouter } from "next/navigation";
+import { useUser } from "@/context/UserContext";
+import React, { useEffect } from "react";
+
+const AuthGuard = ({ children }: { children: React.ReactNode }) => {
+ const router = useRouter();
+ const { user } = useUser(); // Benutzer aus dem globalen Zustand abrufen
+
+ useEffect(() => {
+ if (!user) {
+ router.push("/login"); // Weiterleitung zur Login-Seite
+ }
+ }, [user, router]);
+
+ if (!user) {
+ return Lade...
; // Anzeige während des Ladens oder Weiterleitens
+ }
+
+ return <>{children}>;
+};
+
+export default AuthGuard;
diff --git a/frontend-react/src/context/UserContext.tsx b/frontend-react/src/context/UserContext.tsx
new file mode 100644
index 0000000..59bdbb8
--- /dev/null
+++ b/frontend-react/src/context/UserContext.tsx
@@ -0,0 +1,33 @@
+"use client";
+import React, { createContext, ReactNode, useContext, useState } from "react";
+
+type User = {
+ id: string;
+ name: string;
+ email: string;
+};
+
+type UserContextType = {
+ user: User | null;
+ setUser: (user: User | null) => void;
+};
+
+const UserContext = createContext(undefined);
+
+export const UserProvider = ({ children }: { children: ReactNode }) => {
+ const [user, setUser] = useState(null);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useUser = (): UserContextType => {
+ const context = useContext(UserContext);
+ if (!context) {
+ throw new Error("useUser must be used within a UserProvider");
+ }
+ return context;
+};