Implementiere Impressum/Datenschutz-System und bereinige URL-Konfiguration
- Neues Impressum/Datenschutz-Tab mit konfigurierbaren rechtlichen Daten - Konfigurationsdatei legal-config.ts für alle rechtlichen Informationen - RPC-Endpoint legal.getConfig() für rechtliche Daten - Schöne Tab-Navigation zwischen Impressum und Datenschutz - Responsive Design mit Loading-States und Fehlerbehandlung - Alle rechtlichen Daten über Umgebungsvariablen konfigurierbar - FRONTEND_URL entfernt - nur noch DOMAIN wird verwendet - Hilfsfunktion generateUrl() für konsistente URL-Generierung - Code-Duplikation in bookings.ts eliminiert - .env.example aktualisiert mit allen neuen Variablen - README.md dokumentiert neue rechtliche Konfiguration - DSGVO- und TMG-konforme Inhalte implementiert
This commit is contained in:
241
src/client/components/legal-page.tsx
Normal file
241
src/client/components/legal-page.tsx
Normal file
@@ -0,0 +1,241 @@
|
||||
import React, { useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { queryClient } from "@/client/rpc-client";
|
||||
|
||||
export default function LegalPage() {
|
||||
const [activeSection, setActiveSection] = useState<"impressum" | "datenschutz">("impressum");
|
||||
|
||||
const { data: legalConfig, isLoading, error } = useQuery({
|
||||
queryKey: ["legal", "config"],
|
||||
queryFn: () => queryClient.legal.getConfig(),
|
||||
});
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-pink-50 to-purple-50 flex items-center justify-center">
|
||||
<div className="bg-white p-8 rounded-lg shadow-lg max-w-md w-full">
|
||||
<div className="flex items-center justify-center">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-pink-500"></div>
|
||||
<span className="ml-3 text-gray-600">Lade rechtliche Informationen...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error || !legalConfig) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-pink-50 to-purple-50 flex items-center justify-center">
|
||||
<div className="bg-white p-8 rounded-lg shadow-lg max-w-md w-full">
|
||||
<div className="text-center">
|
||||
<div className="w-16 h-16 mx-auto mb-4 bg-red-100 rounded-full flex items-center justify-center">
|
||||
<svg className="w-8 h-8 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h2 className="text-xl font-bold text-gray-900 mb-2">Fehler</h2>
|
||||
<p className="text-gray-600 mb-4">
|
||||
Die rechtlichen Informationen konnten nicht geladen werden.
|
||||
</p>
|
||||
<a
|
||||
href="/"
|
||||
className="inline-flex items-center px-4 py-2 bg-pink-600 text-white rounded-lg hover:bg-pink-700 transition-colors"
|
||||
>
|
||||
Zur Startseite
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-pink-50 to-purple-50">
|
||||
<div className="max-w-4xl mx-auto px-4 py-8">
|
||||
{/* Header */}
|
||||
<div className="bg-white rounded-lg shadow-lg mb-6">
|
||||
<div className="px-6 py-4 border-b border-gray-200">
|
||||
<div className="flex items-center space-x-3">
|
||||
<img
|
||||
src="/assets/stargilnails_logo_transparent_112.png"
|
||||
alt="Stargil Nails Logo"
|
||||
className="w-12 h-12 object-contain"
|
||||
/>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-gray-900">Rechtliche Informationen</h1>
|
||||
<p className="text-sm text-gray-600">Impressum und Datenschutz</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tab Navigation */}
|
||||
<div className="px-6 py-4">
|
||||
<div className="flex space-x-1 bg-gray-100 p-1 rounded-lg">
|
||||
<button
|
||||
onClick={() => setActiveSection("impressum")}
|
||||
className={`flex-1 py-2 px-4 rounded-md text-sm font-medium transition-colors ${
|
||||
activeSection === "impressum"
|
||||
? "bg-white text-pink-600 shadow-sm"
|
||||
: "text-gray-600 hover:text-gray-900"
|
||||
}`}
|
||||
>
|
||||
📋 Impressum
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveSection("datenschutz")}
|
||||
className={`flex-1 py-2 px-4 rounded-md text-sm font-medium transition-colors ${
|
||||
activeSection === "datenschutz"
|
||||
? "bg-white text-pink-600 shadow-sm"
|
||||
: "text-gray-600 hover:text-gray-900"
|
||||
}`}
|
||||
>
|
||||
🔒 Datenschutz
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="bg-white rounded-lg shadow-lg p-6">
|
||||
{activeSection === "impressum" ? (
|
||||
<div className="prose max-w-none">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-6">Impressum</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Anbieter</h3>
|
||||
<p className="text-gray-700">
|
||||
<strong>{legalConfig.companyName}</strong><br />
|
||||
Inhaber: {legalConfig.ownerName}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 mt-2">
|
||||
ℹ️ Diese Informationen können über Umgebungsvariablen in der .env-Datei angepasst werden.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Anschrift</h3>
|
||||
<p className="text-gray-700">
|
||||
{legalConfig.address.street}<br />
|
||||
{legalConfig.address.postalCode} {legalConfig.address.city}<br />
|
||||
{legalConfig.address.country}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Kontakt</h3>
|
||||
<p className="text-gray-700">
|
||||
<strong>Telefon:</strong> {legalConfig.contact.phone}<br />
|
||||
<strong>E-Mail:</strong> {legalConfig.contact.email}<br />
|
||||
<strong>Website:</strong> {legalConfig.contact.website}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{legalConfig.businessDetails.taxId && (
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Geschäftliche Angaben</h3>
|
||||
<p className="text-gray-700">
|
||||
{legalConfig.businessDetails.taxId && (
|
||||
<>Steuernummer: {legalConfig.businessDetails.taxId}<br /></>
|
||||
)}
|
||||
{legalConfig.businessDetails.vatId && (
|
||||
<>USt-IdNr.: {legalConfig.businessDetails.vatId}<br /></>
|
||||
)}
|
||||
{legalConfig.businessDetails.commercialRegister && (
|
||||
<>Handelsregister: {legalConfig.businessDetails.commercialRegister}<br /></>
|
||||
)}
|
||||
Verantwortlich für den Inhalt: {legalConfig.businessDetails.responsibleForContent}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="bg-gray-50 p-4 rounded-lg">
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Haftungsausschluss</h3>
|
||||
<p className="text-sm text-gray-600">
|
||||
Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit,
|
||||
Vollständigkeit und Aktualität der Inhalte können wir jedoch keine Gewähr übernehmen.
|
||||
Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten
|
||||
nach den allgemeinen Gesetzen verantwortlich.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="prose max-w-none">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-6">Datenschutzerklärung</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Verantwortlicher</h3>
|
||||
<p className="text-gray-700">
|
||||
{legalConfig.dataProtection.responsiblePerson}<br />
|
||||
E-Mail: {legalConfig.dataProtection.email}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Zweck der Datenverarbeitung</h3>
|
||||
<p className="text-gray-700">{legalConfig.dataProtection.purpose}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Rechtsgrundlage</h3>
|
||||
<p className="text-gray-700">{legalConfig.dataProtection.legalBasis}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Datenspeicherung</h3>
|
||||
<p className="text-gray-700">{legalConfig.dataProtection.dataRetention}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Ihre Rechte</h3>
|
||||
<p className="text-gray-700">{legalConfig.dataProtection.rights}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Cookies</h3>
|
||||
<p className="text-gray-700">{legalConfig.dataProtection.cookies}</p>
|
||||
</div>
|
||||
|
||||
{legalConfig.dataProtection.thirdPartyServices.length > 0 && (
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Drittanbieter-Services</h3>
|
||||
<ul className="list-disc list-inside text-gray-700 space-y-1">
|
||||
{legalConfig.dataProtection.thirdPartyServices.map((service, index) => (
|
||||
<li key={index}>{service}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Datensicherheit</h3>
|
||||
<p className="text-gray-700">{legalConfig.dataProtection.dataSecurity}</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-blue-50 p-4 rounded-lg">
|
||||
<h3 className="text-lg font-semibold text-blue-900 mb-2">Kontakt zum Datenschutz</h3>
|
||||
<p className="text-blue-800">{legalConfig.dataProtection.contactDataProtection}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Back to Home */}
|
||||
<div className="text-center mt-6">
|
||||
<a
|
||||
href="/"
|
||||
className="inline-flex items-center px-4 py-2 bg-pink-600 text-white rounded-lg hover:bg-pink-700 transition-colors"
|
||||
>
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||
</svg>
|
||||
Zurück zur Startseite
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user