Untitled
unknown
plain_text
8 months ago
7.2 kB
6
Indexable
// app/[clientId]/Auswahl/[selectionId]/page.tsx
"use client"
import { useEffect, useState } 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"
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 router = useRouter()
// Get the client config using the parent client ID or the current client ID
const clientConfig = selection?.data?.parentClientId
? getClientConfig(selection.data.parentClientId)
: getClientConfig(params.clientId);
if (!clientConfig) {
notFound();
}
// Filter sections based on the selection favorites
const [filteredSections, setFilteredSections] = useState(clientConfig.sections);
// Fetch the selection data
useEffect(() => {
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();
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) {
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);
setError("Die Auswahl konnte nicht geladen werden.");
} finally {
setIsLoading(false);
}
};
fetchSelection();
}, [params.clientId, params.selectionId, clientConfig.sections]);
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 (!isAuthenticated && selection?.data.requirePassword) {
return (
<main className="relative flex min-h-screen flex-col items-center justify-center p-4 bg-black">
<BackgroundBeams className="opacity-70" />
<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. 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>
);
}
// After authentication, render the filtered layout
const filteredClientConfig = {
...clientConfig,
title: `${clientConfig.title} - Auswahl`,
};
return (
<>
<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}
/>
</div>
<FooterWithContact clientConfig={clientConfig} />
</main>
<Cursor />
</>
);
}Editor is loading...
Leave a Comment