Frontend migration

This commit is contained in:
2025-04-27 17:33:20 +00:00
parent 01bb308740
commit c3f43016c6
94 changed files with 10729 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,37 @@
import type {Metadata} from "next";
import "../globals.css";
import Nav from "@/components/Navbar/Nav";
import Footer from "@/components/Footer/Footer";
import {ThemeProvider} from "@/components/provider/ThemeProvider";
import React from "react";
import {cookies} from "next/headers";
import {themeColors} from "@/components/Helper/ThemeColors";
export const metadata: Metadata = {
title: "Rhein Software",
description: "Rhein Software Development",
};
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const cookieStore = await cookies();
const theme = cookieStore.get("theme")?.value === "dark" ? "dark" : "light";
const bgColor = themeColors[theme].primaryBg;
return (
<html lang="de" data-theme={theme}>
<head/>
<body className="antialiased" style={{backgroundColor: bgColor}}>
<ThemeProvider>
<Nav/>
{children}
<Footer/>
</ThemeProvider>
</body>
</html>
);
}

View File

@@ -0,0 +1,12 @@
import React from 'react';
import Home from "@/components/Home/Home";
const HomePage = () => {
return (
<div>
<Home />
</div>
);
};
export default HomePage;

View File

@@ -0,0 +1,37 @@
import type {Metadata} from "next";
import "../globals.css";
import Nav from "@/components/Navbar/Nav";
import Footer from "@/components/Footer/Footer";
import {ThemeProvider} from "@/components/provider/ThemeProvider";
import React from "react";
import {cookies} from "next/headers";
import {themeColors} from "@/components/Helper/ThemeColors";
export const metadata: Metadata = {
title: "Über Uns | Rhein Software",
description: "Rhein Software Development",
};
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const cookieStore = await cookies();
const theme = cookieStore.get("theme")?.value === "dark" ? "dark" : "light";
const bgColor = themeColors[theme].primaryBg;
return (
<html lang="de" data-theme={theme}>
<head/>
<body className="antialiased" style={{backgroundColor: bgColor}}>
<ThemeProvider>
<Nav/>
{children}
<Footer/>
</ThemeProvider>
</body>
</html>
);
}

View File

@@ -0,0 +1,12 @@
import React from 'react';
import AboutContent from "@/components/About/AboutContent";
const AboutPage = () => {
return (
<div>
<AboutContent/>
</div>
);
};
export default AboutPage;

View File

@@ -0,0 +1,54 @@
import {NextRequest, NextResponse} from 'next/server';
const HCAPTCHA_SECRET = process.env.HCAPTCHA_SECRET ?? '';
const SHARED_API_KEY = process.env.SHARED_API_KEY ?? '';
export async function POST(req: NextRequest) {
try {
const body = await req.json();
const origin = req.headers.get("origin") || "http://localhost:3000";
const captchaToken = body.captcha;
if (!captchaToken) {
return NextResponse.json({success: false, error: 'Captcha is required'}, {status: 400});
}
// Step 1: Verify hCaptcha token with their API
const verifyResponse = await fetch('https://api.hcaptcha.com/siteverify', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
secret: HCAPTCHA_SECRET,
response: captchaToken,
}),
});
const captchaResult = await verifyResponse.json();
if (!captchaResult.success) {
return NextResponse.json({success: false, error: 'Captcha verification failed'}, {status: 403});
}
// Step 2: Forward valid contact request to Spring Boot backend
const backendRes = await fetch('http://localhost:8080/api/contact', {
method: 'POST',
headers: {
"Origin": origin,
'Content-Type': 'application/json',
'X-Frontend-Key': SHARED_API_KEY,
},
body: JSON.stringify(body),
});
const backendText = await backendRes.text();
if (!backendRes.ok) {
return NextResponse.json({success: false, error: backendText}, {status: backendRes.status});
}
return NextResponse.json({success: true, message: backendText});
} catch (err: any) {
console.error('[ContactAPI] error:', err);
return NextResponse.json({success: false, error: err.message}, {status: 500});
}
}

View File

@@ -0,0 +1,37 @@
import type {Metadata} from "next";
import "../globals.css";
import Nav from "@/components/Navbar/Nav";
import Footer from "@/components/Footer/Footer";
import {ThemeProvider} from "@/components/provider/ThemeProvider";
import React from "react";
import {cookies} from "next/headers";
import {themeColors} from "@/components/Helper/ThemeColors";
export const metadata: Metadata = {
title: "Kontakt | Rhein Software",
description: "Rhein Software Development",
};
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const cookieStore = await cookies();
const theme = cookieStore.get("theme")?.value === "dark" ? "dark" : "light";
const bgColor = themeColors[theme].primaryBg;
return (
<html lang="de" data-theme={theme}>
<head/>
<body className="antialiased" style={{backgroundColor: bgColor}}>
<ThemeProvider>
<Nav/>
{children}
<Footer/>
</ThemeProvider>
</body>
</html>
);
}

View File

@@ -0,0 +1,12 @@
import React from 'react';
import Contact from "@/components/Contact/Contact";
const ContactPage = () => {
return (
<div>
<Contact/>
</div>
);
};
export default ContactPage;

27
frontend/app/globals.css Normal file
View File

@@ -0,0 +1,27 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer utilities {
.nav__link {
@apply relative text-base font-medium w-fit block after:block after:content-[''] after:absolute after:h-[3px] after:bg-pink-600 after:w-full after:scale-x-0 after:hover:scale-x-100 after:transition after:duration-300 after:origin-right;
}
}
/* Global theme transition */
.transition-theme {
transition: background-color 0.7s ease, color 0.7s ease;
}
@keyframes float {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-6px);
}
}
.animate-float {
animation: float 3.5s ease-in-out infinite;
}

View File

@@ -0,0 +1,12 @@
import React from 'react';
import ImprintComp from "@/components/Legal/Imprint/ImprintComp";
const ImprintPage = () => {
return (
<div>
<ImprintComp />
</div>
);
};
export default ImprintPage;

View File

@@ -0,0 +1,38 @@
import type {Metadata} from "next";
import "../globals.css";
import Nav from "@/components/Navbar/Nav";
import Footer from "@/components/Footer/Footer";
import {ThemeProvider} from "@/components/provider/ThemeProvider";
import React from "react";
import {cookies} from "next/headers";
import {themeColors} from "@/components/Helper/ThemeColors";
export const metadata: Metadata = {
title: "Rechtliches | Rhein Software",
description: "Rhein Software Development",
};
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const cookieStore = await cookies();
const theme = cookieStore.get("theme")?.value === "dark" ? "dark" : "light";
const bgColor = themeColors[theme].primaryBg;
return (
<html lang="de" data-theme={theme}>
<head/>
<body className="antialiased" style={{backgroundColor: bgColor}}>
<ThemeProvider>
<Nav/>
{children}
<Footer/>
</ThemeProvider>
</body>
</html>
);
}

View File

@@ -0,0 +1,10 @@
import React from 'react';
const LegalPage = () => {
return (
<div>
</div>
);
};
export default LegalPage;

View File

@@ -0,0 +1,12 @@
import React from 'react';
import PrivacyComp from "@/components/Legal/Privacy/PrivacyComp";
const PrivacyPage = () => {
return (
<div>
<PrivacyComp />
</div>
);
};
export default PrivacyPage;

View File

@@ -0,0 +1,12 @@
import React from 'react';
import RevocationComp from "@/components/Legal/RevocationComp";
const RevocationPage = () => {
return (
<div>
<RevocationComp />
</div>
);
};
export default RevocationPage;

View File

@@ -0,0 +1,12 @@
import React from 'react';
import TermsOfUseComp from "@/components/Legal/TermsOfUseComp";
const TermsOfUsePage = () => {
return (
<div>
<TermsOfUseComp/>
</div>
);
};
export default TermsOfUsePage;

View File

@@ -0,0 +1,37 @@
import type {Metadata} from "next";
import "../globals.css";
import Nav from "@/components/Navbar/Nav";
import Footer from "@/components/Footer/Footer";
import {ThemeProvider} from "@/components/provider/ThemeProvider";
import React from "react";
import {cookies} from "next/headers";
import {themeColors} from "@/components/Helper/ThemeColors";
export const metadata: Metadata = {
title: "Leistungen | Rhein Software",
description: "Rhein Software Development",
};
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const cookieStore = await cookies();
const theme = cookieStore.get("theme")?.value === "dark" ? "dark" : "light";
const bgColor = themeColors[theme].primaryBg;
return (
<html lang="de" data-theme={theme}>
<head/>
<body className="antialiased" style={{backgroundColor: bgColor}}>
<ThemeProvider>
<Nav/>
{children}
<Footer/>
</ThemeProvider>
</body>
</html>
);
}

View File

@@ -0,0 +1,12 @@
import React from 'react';
import Services from "@/components/Services/Services";
const ContactPage = () => {
return (
<div>
<Services/>
</div>
);
};
export default ContactPage;