Email: Review-Link auf /review/:token umgestellt; Token-Erzeugung konsolidiert. Reviews: Client-Validation hinzugefügt. Verfügbarkeiten: Auto-Update nach Regelanlage. Galerie: Cover-Foto-Flag + Setzen im Admin, sofortige Aktualisierung nach Upload/Löschen/Reihenfolge-Änderung. Startseite: Featured-Foto = Reihenfolge 0, Seitenverhältnis beibehalten, Texte aktualisiert.

This commit is contained in:
2025-10-05 20:09:12 +02:00
parent 6d7e8eceba
commit 53aca01131
13 changed files with 1807 additions and 23 deletions

View File

@@ -8,12 +8,16 @@ 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 { AdminGallery } from "@/client/components/admin-gallery";
import { AdminReviews } from "@/client/components/admin-reviews";
import BookingStatusPage from "@/client/components/booking-status-page";
import ReviewSubmissionPage from "@/client/components/review-submission-page";
import LegalPage from "@/client/components/legal-page";
import { ProfileLanding } from "@/client/components/profile-landing";
function App() {
const { user, isLoading, isOwner } = useAuth();
const [activeTab, setActiveTab] = useState<"booking" | "admin-treatments" | "admin-bookings" | "admin-calendar" | "admin-availability" | "profile" | "legal">("booking");
const [activeTab, setActiveTab] = useState<"profile-landing" | "booking" | "admin-treatments" | "admin-bookings" | "admin-calendar" | "admin-availability" | "admin-gallery" | "admin-reviews" | "profile" | "legal">("profile-landing");
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
// Prevent background scroll when menu is open
@@ -31,6 +35,14 @@ function App() {
}
}
// Handle review submission page
if (path.startsWith('/review/')) {
const token = path.split('/review/')[1];
if (token) {
return <ReviewSubmissionPage token={token} />;
}
}
// Show loading spinner while checking authentication
if (isLoading) {
return (
@@ -48,7 +60,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 === "admin-calendar" || activeTab === "admin-availability" || activeTab === "profile");
const needsAuth = !user && (activeTab === "admin-treatments" || activeTab === "admin-bookings" || activeTab === "admin-calendar" || activeTab === "admin-availability" || activeTab === "admin-gallery" || activeTab === "admin-reviews" || activeTab === "profile");
if (needsAuth) {
return <LoginForm />;
}
@@ -59,12 +71,15 @@ function App() {
}
const tabs = [
{ id: "profile-landing", label: "Startseite", icon: "🏠", requiresAuth: false },
{ 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 },
{ id: "admin-gallery", label: "Photo-Wall", icon: "📸", requiresAuth: true },
{ id: "admin-reviews", label: "Bewertungen", icon: "⭐", requiresAuth: true },
...(user ? [{ id: "profile", label: "Profil", icon: "👤", requiresAuth: true }] : []),
] as const;
@@ -78,7 +93,7 @@ function App() {
<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")}
onClick={() => setActiveTab("profile-landing")}
>
<img
src="/assets/stargilnails_logo_transparent_112.png"
@@ -240,6 +255,10 @@ function App() {
{/* Main Content */}
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{activeTab === "profile-landing" && (
<ProfileLanding onNavigateToBooking={() => setActiveTab("booking")} />
)}
{activeTab === "booking" && (
<div>
<div className="text-center mb-8">
@@ -311,6 +330,34 @@ function App() {
</div>
)}
{activeTab === "admin-gallery" && isOwner && (
<div>
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-gray-900 mb-4">
Photo-Wall verwalten
</h2>
<p className="text-lg text-gray-600">
Lade Fotos hoch und verwalte deine Galerie.
</p>
</div>
<AdminGallery />
</div>
)}
{activeTab === "admin-reviews" && isOwner && (
<div>
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-gray-900 mb-4">
Bewertungen verwalten
</h2>
<p className="text-lg text-gray-600">
Prüfe und verwalte Kundenbewertungen.
</p>
</div>
<AdminReviews />
</div>
)}
{activeTab === "profile" && user && (
<div>
<div className="text-center mb-8">