Initial commit: Kalender, Buchungen mit Slot-Reservierung, Resend-E-Mails, Admin-UI, Startscript

This commit is contained in:
2025-09-29 19:10:42 +02:00
parent a3d032af9f
commit b33036300f
13 changed files with 571 additions and 58 deletions

View File

@@ -6,10 +6,11 @@ import { BookingForm } from "@/client/components/booking-form";
import { AdminTreatments } from "@/client/components/admin-treatments";
import { AdminBookings } from "@/client/components/admin-bookings";
import { InitialDataLoader } from "@/client/components/initial-data-loader";
import { AdminAvailability } from "@/client/components/admin-availability";
function App() {
const { user, isLoading, isOwner } = useAuth();
const [activeTab, setActiveTab] = useState<"booking" | "admin-treatments" | "admin-bookings" | "profile">("booking");
const [activeTab, setActiveTab] = useState<"booking" | "admin-treatments" | "admin-bookings" | "admin-availability" | "profile">("booking");
// Show loading spinner while checking authentication
if (isLoading) {
@@ -24,7 +25,7 @@ function App() {
}
// Show login form if user is not authenticated and trying to access admin features
const needsAuth = !user && (activeTab === "admin-treatments" || activeTab === "admin-bookings" || activeTab === "profile");
const needsAuth = !user && (activeTab === "admin-treatments" || activeTab === "admin-bookings" || activeTab === "admin-availability" || activeTab === "profile");
if (needsAuth) {
return <LoginForm />;
}
@@ -33,6 +34,7 @@ function App() {
{ id: "booking", label: "Termin buchen", icon: "📅", requiresAuth: false },
{ id: "admin-treatments", label: "Behandlungen verwalten", icon: "💅", requiresAuth: true },
{ id: "admin-bookings", label: "Buchungen verwalten", icon: "📋", requiresAuth: true },
{ id: "admin-availability", label: "Verfügbarkeiten", icon: "⏰", requiresAuth: true },
...(user ? [{ id: "profile", label: "Profil", icon: "👤", requiresAuth: true }] : []),
] as const;
@@ -159,6 +161,20 @@ function App() {
</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">