Untitled

 avatar
unknown
plain_text
23 days ago
8.8 kB
3
Indexable
// app/[clientId]/auswahl/[selectionId]/page.tsx

"use client"

import { useEffect, useState, useMemo, useRef } from "react"
import { useRouter } from "next/navigation"
import { notFound } from "next/navigation"
import { LoginForm } from "@/components/login-form"
import { Gallery } from "@/components/gallery"
import { WelcomeHero } from "@/components/welcome-hero"
import { getClientConfig } from "@/lib/client-config"
import { BackgroundBeams } from "@/components/ui/background-beams"
import Cursor from '@/components/cursor/cursor';
import { FooterWithContact } from "@/components/footer-with-contact"
import { Share2 } from "lucide-react"
import { useInView } from "framer-motion"
import { ClientThemeProvider } from "@/components/client-theme-provider" // Import our new component

interface Selection {
  id: string;
  clientId: string;
  selectionId: string;
  data: {
    favorites: Record<string, number[]>;
    requirePassword: boolean;
    password: string;
    createdAt: string;
    parentClientId: string;
  };
  createdAt: string;
}

export default function SelectionPage({ params }: { params: { clientId: string; selectionId: string } }) {
  const [isAuthenticated, setIsAuthenticated] = useState(false)
  const [isLoading, setIsLoading] = useState(true)
  const [selection, setSelection] = useState<Selection | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [filteredSections, setFilteredSections] = useState([])
  const footerRef = useRef(null)
  const inView = useInView(footerRef, { amount: 0.1 })
  const router = useRouter()
  
  // Use useMemo to cache the client config and prevent recalculation on every render
  const clientConfig = useMemo(() => {
    const config = selection?.data?.parentClientId 
      ? getClientConfig(selection.data.parentClientId) 
      : getClientConfig(params.clientId);
    
    if (!config && !isLoading) {
      return null;
    }
    
    return config || getClientConfig(params.clientId);
  }, [params.clientId, selection?.data?.parentClientId, isLoading]);
  
  // Catch null clientConfig after loading is complete
  useEffect(() => {
    if (!isLoading && !clientConfig) {
      notFound();
    }
  }, [clientConfig, isLoading]);
  
  // Fetch the selection data
  useEffect(() => {
    let isMounted = true; // For preventing state updates after component unmount
    
    const fetchSelection = async () => {
      try {
        const response = await fetch(`/api/selections/${params.clientId}/${params.selectionId}`);
        
        if (!response.ok) {
          if (response.status === 404) {
            notFound();
          }
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        const data = await response.json();
        
        if (isMounted) {
          setSelection(data);
          
          // If no password is required, auto-authenticate
          if (data.data && !data.data.requirePassword) {
            setIsAuthenticated(true);
          }
          
          // Filter the sections based on the favorites
          if (data.data && data.data.favorites && clientConfig) {
            const favorites = data.data.favorites;
            const filtered = clientConfig.sections
              .map(section => {
                // If no favorites for this section, skip it
                if (!favorites[section.title] || favorites[section.title].length === 0) {
                  return null;
                }
                
                // Include only favorited images
                return {
                  ...section,
                  images: section.images.filter((_, index) => 
                    favorites[section.title].includes(index)
                  )
                };
              })
              .filter(Boolean); // Remove null sections
            
            setFilteredSections(filtered);
          }
        }
        
      } catch (error) {
        console.error("Error fetching selection:", error);
        if (isMounted) {
          setError("Die Auswahl konnte nicht geladen werden.");
        }
      } finally {
        if (isMounted) {
          setIsLoading(false);
        }
      }
    };
    
    fetchSelection();
    
    return () => {
      isMounted = false; // Cleanup to prevent setting state after unmount
    };
  }, [params.clientId, params.selectionId, clientConfig]); // clientConfig dependency is safe now with useMemo
  
  // Handle authentication via cookies or URL hash
  useEffect(() => {
    if (!selection) return;
    
    // Check for hash-based password
    const hash = window.location.hash;
    if (hash.startsWith("#password=")) {
      const password = hash.slice(10);
      if (password === selection.data.password) {
        document.cookie = `auth-selection-${params.clientId}-${params.selectionId}=true; path=/`;
        setIsAuthenticated(true);
        // Optionally remove the hash from URL
        window.history.replaceState(null, '', window.location.pathname);
      }
    }
    
    // Check for existing authentication
    const authCookie = document.cookie
      .split("; ")
      .find((row) => row.startsWith(`auth-selection-${params.clientId}-${params.selectionId}=`));
    
    setIsAuthenticated(authCookie?.split("=")[1] === "true" || !selection.data.requirePassword);
    
  }, [selection, params.clientId, params.selectionId]);
  
  if (isLoading) {
    return null;
  }
  
  if (error) {
    return (
      <main className="flex min-h-screen flex-col items-center justify-center p-4 bg-black">
        <div className="text-center">
          <h1 className="text-2xl font-bold mb-4">Fehler</h1>
          <p className="text-muted-foreground">{error}</p>
        </div>
      </main>
    );
  }
  
  if (!clientConfig) {
    return null;
  }
  
  // After authentication, render the filtered layout
  const filteredClientConfig = {
    ...clientConfig,
  };
  
  // Wrap everything in the ClientThemeProvider
  return (
    <ClientThemeProvider clientConfig={clientConfig}>
      {!isAuthenticated && selection?.data.requirePassword ? (
        <main className="relative flex min-h-screen flex-col items-center justify-center p-4 bg-black">
          <BackgroundBeams className="opacity-100" />
          
          <div className="relative z-10">
            <div className="mb-8 flex flex-col items-center">
              <div className="h-12 w-12 rounded-full bg-indigo-600/20 flex items-center justify-center mb-4">
                <Share2 className="h-6 w-6 text-indigo-500" />
              </div>
              <h1 className="text-2xl font-bold text-center mb-1">Geteilte Auswahl</h1>
              <p className="text-muted-foreground text-center">
                Diese Auswahl wurde mit Ihnen geteilt.<br />Bitte geben Sie das Passwort ein, um fortzufahren.
              </p>
            </div>
            
            <LoginForm 
              clientId={`${params.clientId}/auswahl/${params.selectionId}`}
              customPassword={selection?.data.password}
              onSuccess={() => setIsAuthenticated(true)} 
            />
          </div>
          <Cursor />
        </main>
      ) : (
        <>
          <WelcomeHero config={filteredClientConfig} />
          <main className="container mx-auto min-h-screen flex flex-col">
            <div className="space-y-8 px-4 py-8 md:space-y-12 md:py-12 flex-grow">
              <div className="bg-muted/20 p-4 rounded-lg flex items-center gap-4">
                <div className="h-10 w-10 rounded-full bg-indigo-600/20 flex items-center justify-center">
                  <Share2 className="h-5 w-5 text-indigo-500" />
                </div>
                <div>
                  <h2 className="text-lg font-semibold">Geteilte Auswahl</h2>
                  <p className="text-sm text-muted-foreground">
                    Diese Auswahl wurde speziell für Sie zusammengestellt.
                  </p>
                </div>
              </div>
              
              <Gallery 
                sections={filteredSections} 
                clientConfig={filteredClientConfig}
                isSelectionView={true} // IMPORTANT: Changed to false to enable toolbar and all features
              />
              
              {/* Invisible ref element to detect when we're at the bottom */}
              <div ref={footerRef} className="h-1" />
            </div>
            <FooterWithContact clientConfig={clientConfig} />
          </main>
          <Cursor />
        </>
      )}
    </ClientThemeProvider>
  );
}
Editor is loading...
Leave a Comment