- 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
263 lines
9.7 KiB
TypeScript
263 lines
9.7 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import { useAuth } from "@/client/components/auth-provider";
|
|
import { LoginForm } from "@/client/components/login-form";
|
|
import { UserProfile } from "@/client/components/user-profile";
|
|
import { BookingForm } from "@/client/components/booking-form";
|
|
import { AdminTreatments } from "@/client/components/admin-treatments";
|
|
import { AdminBookings } from "@/client/components/admin-bookings";
|
|
import { AdminCalendar } from "@/client/components/admin-calendar";
|
|
import { InitialDataLoader } from "@/client/components/initial-data-loader";
|
|
import { AdminAvailability } from "@/client/components/admin-availability";
|
|
import CancellationPage from "@/client/components/cancellation-page";
|
|
import LegalPage from "@/client/components/legal-page";
|
|
|
|
function App() {
|
|
const { user, isLoading, isOwner } = useAuth();
|
|
const [activeTab, setActiveTab] = useState<"booking" | "admin-treatments" | "admin-bookings" | "admin-calendar" | "admin-availability" | "profile" | "legal">("booking");
|
|
|
|
// Check for cancellation token in URL
|
|
useEffect(() => {
|
|
const path = window.location.pathname;
|
|
if (path.startsWith('/cancel/')) {
|
|
const token = path.split('/cancel/')[1];
|
|
if (token) {
|
|
// Set a special state to show cancellation page
|
|
setActiveTab("cancellation" as any);
|
|
return;
|
|
}
|
|
}
|
|
}, []);
|
|
|
|
// Handle cancellation page
|
|
const path = window.location.pathname;
|
|
if (path.startsWith('/cancel/')) {
|
|
const token = path.split('/cancel/')[1];
|
|
if (token) {
|
|
return <CancellationPage token={token} />;
|
|
}
|
|
}
|
|
|
|
// Show loading spinner while checking authentication
|
|
if (isLoading) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-pink-50 to-purple-50">
|
|
<div className="text-center">
|
|
<img
|
|
src="/assets/stargilnails_logo_transparent_112.png"
|
|
alt="Stargil Nails Logo"
|
|
className="w-16 h-16 mx-auto mb-4 object-contain animate-pulse"
|
|
/>
|
|
<div className="text-lg text-gray-600">Lade...</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Show login form if user is not authenticated and trying to access admin features
|
|
const needsAuth = !user && (activeTab === "admin-treatments" || activeTab === "admin-bookings" || activeTab === "admin-calendar" || activeTab === "admin-availability" || activeTab === "profile");
|
|
if (needsAuth) {
|
|
return <LoginForm />;
|
|
}
|
|
|
|
// Show legal page if legal tab is active
|
|
if (activeTab === "legal") {
|
|
return <LegalPage />;
|
|
}
|
|
|
|
const tabs = [
|
|
{ id: "booking", label: "Termin buchen", icon: "📅", requiresAuth: false },
|
|
{ id: "legal", label: "Impressum/Datenschutz", icon: "📋", requiresAuth: false },
|
|
{ id: "admin-treatments", label: "Behandlungen verwalten", icon: "💅", requiresAuth: true },
|
|
{ id: "admin-bookings", label: "Buchungen verwalten", icon: "📋", requiresAuth: true },
|
|
{ id: "admin-calendar", label: "Kalender", icon: "📆", requiresAuth: true },
|
|
{ id: "admin-availability", label: "Verfügbarkeiten", icon: "⏰", requiresAuth: true },
|
|
...(user ? [{ id: "profile", label: "Profil", icon: "👤", requiresAuth: true }] : []),
|
|
] as const;
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gradient-to-br from-pink-50 to-purple-50">
|
|
<InitialDataLoader />
|
|
|
|
{/* Header */}
|
|
<header className="bg-white shadow-sm border-b border-pink-100">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="flex justify-between items-center py-6">
|
|
<div
|
|
className="flex items-center space-x-3 cursor-pointer hover:opacity-80 transition-opacity"
|
|
onClick={() => setActiveTab("booking")}
|
|
>
|
|
<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">Stargirlnails Kiel</h1>
|
|
<p className="text-sm text-gray-600">Professional Nail Design & Care</p>
|
|
</div>
|
|
</div>
|
|
|
|
{user && (
|
|
<div className="flex items-center space-x-4">
|
|
<span className="text-sm text-gray-600">
|
|
Willkommen, {user.username}
|
|
</span>
|
|
{isOwner && (
|
|
<span className="bg-pink-100 text-pink-800 px-2 py-1 rounded-full text-xs font-medium">
|
|
Inhaber
|
|
</span>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
{/* Navigation */}
|
|
<nav className="bg-white shadow-sm">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="flex space-x-8">
|
|
{tabs.map((tab) => {
|
|
// Hide admin tabs for non-owners
|
|
if (tab.requiresAuth && !isOwner && tab.id !== "profile") {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<button
|
|
key={tab.id}
|
|
onClick={() => {
|
|
if (tab.requiresAuth && !user) {
|
|
// This will trigger the login form
|
|
setActiveTab(tab.id as any);
|
|
} else {
|
|
setActiveTab(tab.id as any);
|
|
}
|
|
}}
|
|
className={`py-4 px-1 border-b-2 font-medium text-sm flex items-center space-x-2 ${
|
|
activeTab === tab.id
|
|
? "border-pink-500 text-pink-600"
|
|
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300"
|
|
}`}
|
|
>
|
|
<span>{tab.icon}</span>
|
|
<span>{tab.label}</span>
|
|
</button>
|
|
);
|
|
})}
|
|
|
|
{!user && (
|
|
<button
|
|
onClick={() => setActiveTab("profile")} // This will trigger login
|
|
className="py-4 px-1 border-b-2 border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 font-medium text-sm flex items-center space-x-2"
|
|
>
|
|
<span>🔑</span>
|
|
<span>Inhaber Login</span>
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
{/* Main Content */}
|
|
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
{activeTab === "booking" && (
|
|
<div>
|
|
<div className="text-center mb-8">
|
|
<h2 className="text-3xl font-bold text-gray-900 mb-4">
|
|
Buche deine perfekte Nagelbehandlung
|
|
</h2>
|
|
<p className="text-lg text-gray-600 max-w-2xl mx-auto">
|
|
Erlebe professionelle Nagelpflege mit unseren Experten.
|
|
Wähle aus unserem breiten Angebot an Behandlungen und buche noch heute deinen Termin.
|
|
</p>
|
|
</div>
|
|
<BookingForm />
|
|
</div>
|
|
)}
|
|
|
|
{activeTab === "admin-treatments" && isOwner && (
|
|
<div>
|
|
<div className="text-center mb-8">
|
|
<h2 className="text-3xl font-bold text-gray-900 mb-4">
|
|
Behandlungen verwalten
|
|
</h2>
|
|
<p className="text-lg text-gray-600">
|
|
Füge Behandlungen hinzu, bearbeite und verwalte deine Nagelbehandlungen.
|
|
</p>
|
|
</div>
|
|
<AdminTreatments />
|
|
</div>
|
|
)}
|
|
|
|
{activeTab === "admin-bookings" && isOwner && (
|
|
<div>
|
|
<div className="text-center mb-8">
|
|
<h2 className="text-3xl font-bold text-gray-900 mb-4">
|
|
Buchungen verwalten
|
|
</h2>
|
|
<p className="text-lg text-gray-600">
|
|
Sieh dir Kundentermine an und verwalte Buchungen.
|
|
</p>
|
|
</div>
|
|
<AdminBookings />
|
|
</div>
|
|
)}
|
|
|
|
{activeTab === "admin-calendar" && isOwner && (
|
|
<div>
|
|
<div className="text-center mb-8">
|
|
<h2 className="text-3xl font-bold text-gray-900 mb-4">
|
|
Kalender - Bevorstehende Buchungen
|
|
</h2>
|
|
<p className="text-lg text-gray-600">
|
|
Übersichtliche Darstellung aller bevorstehenden Termine im Kalenderformat.
|
|
</p>
|
|
</div>
|
|
<AdminCalendar />
|
|
</div>
|
|
)}
|
|
|
|
{activeTab === "admin-availability" && isOwner && (
|
|
<div>
|
|
<div className="text-center mb-8">
|
|
<h2 className="text-3xl font-bold text-gray-900 mb-4">
|
|
Verfügbarkeiten verwalten
|
|
</h2>
|
|
<p className="text-lg text-gray-600">
|
|
Lege freie Slots an und entferne sie bei Bedarf.
|
|
</p>
|
|
</div>
|
|
<AdminAvailability />
|
|
</div>
|
|
)}
|
|
|
|
{activeTab === "profile" && user && (
|
|
<div>
|
|
<div className="text-center mb-8">
|
|
<h2 className="text-3xl font-bold text-gray-900 mb-4">
|
|
Benutzerprofil
|
|
</h2>
|
|
<p className="text-lg text-gray-600">
|
|
Verwalte deine Kontoinformationen und Einstellungen.
|
|
</p>
|
|
</div>
|
|
<UserProfile />
|
|
</div>
|
|
)}
|
|
</main>
|
|
|
|
{/* Footer */}
|
|
<footer className="bg-white border-t border-pink-100 mt-16">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
<div className="text-center text-gray-600">
|
|
<p>© 2024 Stargirlnails Kiel. Professional nail care services.</p>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default App;
|