import React, { useState, useEffect, useMemo, useRef, useLayoutEffect } from 'react'; import { Link, usePage } from '@inertiajs/react'; import { useTranslation } from 'react-i18next'; import type { TFunction } from 'i18next'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'; import { Sheet, SheetContent } from '@/components/ui/sheet'; import { Separator } from '@/components/ui/separator'; import { cn } from '@/lib/utils'; import MarketingLayout from '@/layouts/mainWebsite'; import { useAnalytics } from '@/hooks/useAnalytics'; import { useCtaExperiment } from '@/hooks/useCtaExperiment'; import { useLocalizedRoutes } from '@/hooks/useLocalizedRoutes'; import { useLocale } from '@/hooks/useLocale'; import { ArrowRight, Check, Headphones, LayoutGrid, Star } from 'lucide-react'; import toast from 'react-hot-toast'; import { motion, useReducedMotion } from 'framer-motion'; interface Package { id: number; name: string; slug: string; description: string; description_breakdown: DescriptionEntry[]; gallery_duration_label?: string; price: number; events: number | null; features: string[]; included_package_slug?: string | null; max_events_per_year?: number | null; limits?: { max_photos?: number; max_guests?: number; max_tenants?: number; max_events_per_year?: number; gallery_days?: number; }; watermark_allowed?: boolean; branding_allowed?: boolean; } export const resolveWatermarkFeatureKey = (pkg: Package): string => { if (pkg.slug === 'starter') { return 'watermark_base'; } if (pkg.slug === 'standard') { return 'no_watermark'; } if (pkg.slug === 'pro') { return 'watermark_custom'; } const features = Array.isArray(pkg.features) ? pkg.features : []; if (pkg.watermark_allowed === false) { return 'watermark_base'; } if (features.includes('no_watermark')) { return 'no_watermark'; } return pkg.watermark_allowed === true ? 'watermark_custom' : 'watermark'; }; const sortPackagesByPrice = (packages: Package[]): Package[] => [...packages].sort((a, b) => Number(a.price ?? 0) - Number(b.price ?? 0)); interface PackageComparisonProps { packages: Package[]; variant: 'endcustomer' | 'reseller'; serviceTierNames?: Record; } const buildDisplayFeatures = (pkg: Package, variant: 'endcustomer' | 'reseller'): string[] => { const features = [...pkg.features]; const removeFeature = (key: string) => { const index = features.indexOf(key); if (index !== -1) { features.splice(index, 1); } }; const addFeature = (key: string) => { if (!features.includes(key)) { features.push(key); } }; if (variant === 'endcustomer') { const watermarkFeature = resolveWatermarkFeatureKey(pkg); ['watermark', 'no_watermark', 'watermark_base', 'watermark_custom'].forEach(removeFeature); addFeature(watermarkFeature); if (pkg.branding_allowed) { addFeature('custom_branding'); } else { removeFeature('custom_branding'); } } addFeature('photobooth_connect'); return Array.from(new Set(features)); }; function PackageComparison({ packages, variant, serviceTierNames = {} }: PackageComparisonProps) { const { t } = useTranslation('marketing'); const { t: tCommon } = useTranslation('common'); if (packages.length === 0) { return null; } const formatPrice = (pkg: Package) => pkg.price === 0 ? t('packages.free') : `${pkg.price.toLocaleString()} ${t('packages.currency.euro')}`; const limits = variant === 'endcustomer' ? [ { key: 'price', label: t('packages.price'), value: (pkg: Package) => `${formatPrice(pkg)} / ${t('packages.billing_per_event')}`, }, { key: 'max_photos', label: t('packages.max_photos_label'), value: (pkg: Package) => pkg.limits?.max_photos?.toLocaleString() ?? tCommon('unlimited'), }, { key: 'max_guests', label: t('packages.max_guests_label'), value: (pkg: Package) => pkg.limits?.max_guests?.toLocaleString() ?? tCommon('unlimited'), }, { key: 'gallery_days', label: t('packages.gallery_days_label'), value: (pkg: Package) => pkg.gallery_duration_label ?? pkg.limits?.gallery_days?.toLocaleString() ?? tCommon('unlimited'), }, ] : [ { key: 'price', label: t('packages.price'), value: (pkg: Package) => `${formatPrice(pkg)} / ${t('packages.billing_per_kontingent')}`, }, { key: 'included_package_slug', label: t('packages.included_package_label', 'Inklusive Event-Level'), value: (pkg: Package) => { const slug = pkg.included_package_slug ?? null; if (!slug) { return tCommon('unlimited'); } return serviceTierNames[slug] ?? slug; }, }, { key: 'max_events_per_year', label: t('packages.max_events_year'), value: (pkg: Package) => pkg.limits?.max_events_per_year?.toLocaleString() ?? tCommon('unlimited'), }, ]; const features = variant === 'endcustomer' ? [ { key: 'watermark', label: t('packages.watermark_label'), value: (pkg: Package) => t(`packages.feature_${resolveWatermarkFeatureKey(pkg)}`), }, { key: 'branding', label: t('packages.feature_custom_branding'), value: (pkg: Package) => (pkg.branding_allowed ? t('packages.available') : t('packages.not_available')), }, { key: 'support', label: t('packages.feature_support'), value: (pkg: Package) => pkg.features.includes('priority_support') ? t('packages.priority_support') : t('packages.standard_support'), }, { key: 'photobooth_connect', label: t('packages.feature_photobooth_connect'), value: () => t('packages.available'), }, ] : [ { key: 'recommended_usage_window', label: t('packages.recommended_usage_label', 'Empfehlung'), value: () => t('packages.recommended_usage_window'), }, { key: 'support', label: t('packages.feature_support'), value: (pkg: Package) => pkg.features.includes('priority_support') ? t('packages.priority_support') : t('packages.standard_support'), }, { key: 'dashboard', label: t('packages.feature_reseller_dashboard'), value: (pkg: Package) => pkg.features.includes('reseller_dashboard') ? t('packages.available') : t('packages.not_available'), }, { key: 'reporting', label: t('packages.feature_advanced_reporting'), value: (pkg: Package) => pkg.features.includes('advanced_reporting') ? t('packages.available') : t('packages.not_available'), }, { key: 'photobooth_connect', label: t('packages.feature_photobooth_connect'), value: () => t('packages.available'), }, ]; return (

{t('packages.comparison_title')}

{t('packages.comparison_subtitle')}

{t('packages.comparison_limits')} {t('packages.comparison_features')} {t('packages.feature')} {packages.map((pkg) => ( {pkg.name} ))} {limits.map((row) => ( {row.label} {packages.map((pkg) => ( {row.value(pkg)} ))} ))}
{t('packages.feature')} {packages.map((pkg) => ( {pkg.name} ))} {features.map((row) => ( {row.label} {packages.map((pkg) => ( {row.value(pkg)} ))} ))}
); } type DescriptionEntry = { title?: string | null; value: string; }; interface PackagesProps { endcustomerPackages: Package[]; resellerPackages: Package[]; } const Packages: React.FC = ({ endcustomerPackages, resellerPackages }) => { const [open, setOpen] = useState(false); const [selectedPackage, setSelectedPackage] = useState(null); const serviceTierNames = useMemo(() => { const map: Record = {}; endcustomerPackages.forEach((pkg) => { if (pkg?.slug) { map[pkg.slug] = pkg.name; } }); return map; }, [endcustomerPackages]); const [isMobile, setIsMobile] = useState(false); const dialogScrollRef = useRef(null); const dialogHeadingRef = useRef(null); const mobileEndcustomerRef = useRef(null); const mobileResellerRef = useRef(null); const { localizedPath } = useLocalizedRoutes(); const locale = useLocale(); const { t } = useTranslation('marketing'); const { t: tCommon } = useTranslation('common'); const { flash } = usePage<{ flash?: { error?: string } }>().props; const shouldReduceMotion = useReducedMotion(); const { variant: packagesHeroVariant, trackClick: trackPackagesHeroClick, } = useCtaExperiment('packages_hero_cta'); const viewportOnce = { once: true, amount: 0.25 }; const revealUp = { hidden: { opacity: 0, y: shouldReduceMotion ? 0 : 18 }, visible: { opacity: 1, y: 0, transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] }, }, }; const stagger = { hidden: {}, visible: { transition: { staggerChildren: 0.12 } }, }; useEffect(() => { if (flash?.error) { toast.error(flash.error); } }, [flash?.error]); useEffect(() => { const urlParams = new URLSearchParams(window.location.search); const packageId = urlParams.get('package_id'); if (packageId) { const id = parseInt(packageId); const pkg = [...endcustomerPackages, ...resellerPackages].find(p => p.id === id); if (pkg) { setSelectedPackage(pkg); setOpen(true); setCurrentStep('overview'); } } }, [endcustomerPackages, resellerPackages]); useLayoutEffect(() => { if (open && dialogScrollRef.current) { dialogScrollRef.current.scrollTo({ top: 0 }); } }, [open, selectedPackage]); const highlightEndcustomerId = useMemo( () => selectHighlightPackageId(endcustomerPackages), [endcustomerPackages], ); const highlightResellerId = useMemo( () => selectHighlightPackageId(resellerPackages), [resellerPackages], ); const orderedEndcustomerPackages = useMemo( () => sortPackagesByPrice(endcustomerPackages), [endcustomerPackages], ); const orderedResellerPackages = useMemo( () => sortPackagesByPrice(resellerPackages), [resellerPackages], ); const highlightResellerPackage = useMemo( () => orderedResellerPackages.find((pkg) => pkg.id === highlightResellerId) ?? null, [orderedResellerPackages, highlightResellerId], ); const resellerBundles = useMemo( () => orderedResellerPackages.filter((pkg) => pkg.id !== highlightResellerId), [orderedResellerPackages, highlightResellerId], ); const guestSliderMin = 1; const guestSliderMax = useMemo(() => { const limits = orderedEndcustomerPackages .map((pkg) => pkg.limits?.max_guests ?? pkg.max_guests) .filter((value): value is number => typeof value === 'number' && Number.isFinite(value)); if (limits.length === 0) { return 500; } return Math.max(500, ...limits); }, [orderedEndcustomerPackages]); const [guestCount, setGuestCount] = useState(() => Math.min(100, guestSliderMax)); useEffect(() => { setGuestCount((current) => { if (current < guestSliderMin) { return guestSliderMin; } if (current > guestSliderMax) { return guestSliderMax; } return current; }); }, [guestSliderMax, guestSliderMin]); const recommendedPackage = useMemo(() => { if (orderedEndcustomerPackages.length === 0) { return null; } const match = orderedEndcustomerPackages.find((pkg) => { const limit = pkg.limits?.max_guests ?? pkg.max_guests; const limitValue = typeof limit === 'number' ? limit : Number.POSITIVE_INFINITY; return limitValue >= guestCount; }); return match ?? orderedEndcustomerPackages[orderedEndcustomerPackages.length - 1]; }, [orderedEndcustomerPackages, guestCount]); useEffect(() => { if (typeof window === 'undefined') { return; } const media = window.matchMedia('(max-width: 768px)'); const update = () => setIsMobile(media.matches); update(); if (media.addEventListener) { media.addEventListener('change', update); } else { media.addListener(update); } return () => { if (media.removeEventListener) { media.removeEventListener('change', update); } else { media.removeListener(update); } }; }, []); const scrollMobileListToHighlight = ( container: HTMLDivElement | null, packages: Package[], highlightId: number | null, ) => { if (!container || !highlightId) { return; } const index = packages.findIndex((pkg) => pkg.id === highlightId); if (index < 0) { return; } const child = container.children[index] as HTMLElement | undefined; if (!child) { return; } const targetLeft = child.offsetLeft - container.clientWidth / 2 + child.clientWidth / 2; container.scrollTo({ left: Math.max(targetLeft, 0), behavior: 'smooth' }); }; useLayoutEffect(() => { scrollMobileListToHighlight(mobileEndcustomerRef.current, orderedEndcustomerPackages, highlightEndcustomerId); }, [orderedEndcustomerPackages, highlightEndcustomerId]); useLayoutEffect(() => { scrollMobileListToHighlight(mobileResellerRef.current, orderedResellerPackages, highlightResellerId); }, [orderedResellerPackages, highlightResellerId]); const testimonialsByPackage = useMemo(() => { const raw = t('packages.testimonials', { returnObjects: true }); if (!raw || typeof raw !== 'object') { return {}; } return raw as Record; }, [locale, t]); const testimonials = useMemo(() => { if (!selectedPackage) { return []; } const entries = testimonialsByPackage[selectedPackage.slug] ?? testimonialsByPackage.default ?? []; if (!Array.isArray(entries)) { return []; } return entries.map((entry) => ({ name: entry.name ?? '', text: entry.text ?? '', rating: entry.rating ?? 4, })); }, [selectedPackage, testimonialsByPackage]); const renderDetailBody = (wrapperClass: string) => { if (!selectedPackage) { return null; } return (

{selectedVariant === 'reseller' ? t('packages.subscription') : t('packages.one_time')}

{selectedPackage.name}

{selectedPackage.description}

{ handleCtaClick(selectedPackage, selectedVariant); localStorage.setItem('preferred_package', JSON.stringify(selectedPackage)); }} t={t} tCommon={tCommon} testimonials={testimonials} close={() => setOpen(false)} />
); }; function selectHighlightPackageId(packages: Package[]): number | null { const count = packages.length; if (count <= 1) { return null; } const sortedByPrice = [...packages].sort((a, b) => a.price - b.price); if (count === 2) { return sortedByPrice[1]?.id ?? null; } if (count === 3) { return sortedByPrice[1]?.id ?? null; } return sortedByPrice[count - 2]?.id ?? null; } function isHighlightedPackage(pkg: Package, variant: 'endcustomer' | 'reseller') { return variant === 'reseller' ? pkg.id === highlightResellerId : pkg.id === highlightEndcustomerId; } const selectedVariant = useMemo<'endcustomer' | 'reseller'>(() => { if (!selectedPackage) return 'endcustomer'; return resellerPackages.some((pkg) => pkg.id === selectedPackage.id) ? 'reseller' : 'endcustomer'; }, [selectedPackage, resellerPackages]); const selectedHighlight = selectedPackage ? isHighlightedPackage(selectedPackage, selectedVariant) : false; const purchaseUrl = selectedPackage ? localizedPath(`/bestellen/${selectedPackage.id}`) : '#'; const { trackEvent } = useAnalytics(); const handleCardClick = (pkg: Package, variant: 'endcustomer' | 'reseller') => { trackEvent({ category: 'marketing_packages', action: 'open_dialog', name: `${variant}:${pkg.name}`, value: pkg.price, }); setSelectedPackage(pkg); setOpen(true); }; const handleCtaClick = (pkg: Package, variant: 'endcustomer' | 'reseller') => { trackEvent({ category: 'marketing_packages', action: 'cta_dialog', name: `${variant}:${pkg.name}`, value: pkg.price, }); }; // nextStep entfernt, da Tabs nun parallel sind const getAccentTheme = (variant: 'endcustomer' | 'reseller') => variant === 'reseller' ? { badge: 'border border-amber-200/70 bg-amber-100 text-amber-700 dark:border-amber-500/40 dark:bg-amber-500/20 dark:text-amber-100', price: 'text-amber-600 dark:text-amber-200', buttonHighlight: 'bg-gray-900 text-white hover:bg-gray-800 dark:bg-amber-600 dark:hover:bg-amber-500', buttonDefault: 'border border-amber-200 text-amber-700 hover:bg-amber-50 dark:border-amber-500/40 dark:text-amber-100 dark:hover:bg-amber-500/10', cardBorder: 'border-amber-200/70 dark:border-amber-500/40', highlightShadow: 'shadow-xl shadow-amber-200/40 ring-1 ring-amber-200/70 dark:shadow-amber-900/40 dark:ring-amber-500/30', } : { badge: 'border border-rose-200/70 bg-rose-100 text-rose-700 dark:border-pink-500/40 dark:bg-pink-500/20 dark:text-pink-100', price: 'text-rose-600 dark:text-pink-200', buttonHighlight: 'bg-gray-900 text-white hover:bg-gray-800 dark:bg-pink-600 dark:hover:bg-pink-500', buttonDefault: 'border border-rose-200 text-rose-700 hover:bg-rose-50 dark:border-pink-500/40 dark:text-pink-100 dark:hover:bg-pink-500/10', cardBorder: 'border-rose-200/70 dark:border-pink-500/40', highlightShadow: 'shadow-xl shadow-rose-200/40 ring-1 ring-rose-200/70 dark:shadow-pink-900/40 dark:ring-pink-500/30', }; type PackageMetric = { key: string; label: string; value: string; }; const resolveServiceTierLabel = (slug: string | null | undefined): string => { if (!slug) { return ''; } if (slug === 'starter') { return 'Starter'; } if (slug === 'standard') { return 'Standard'; } if (slug === 'pro') { return 'Premium'; } return slug; }; const resolvePackageMetrics = ( pkg: Package, variant: 'endcustomer' | 'reseller', t: TFunction, tCommon: TFunction, ): PackageMetric[] => { if (variant === 'reseller') { return [ { key: 'included_package_slug', label: t('packages.included_package_label', 'Inklusive Event-Level'), value: resolveServiceTierLabel(pkg.included_package_slug) || tCommon('unlimited'), }, { key: 'max_events_per_year', label: t('packages.max_events_year'), value: pkg.limits?.max_events_per_year ? pkg.limits.max_events_per_year.toLocaleString() : tCommon('unlimited'), }, { key: 'recommended_usage_window', label: t('packages.recommended_usage_label', 'Empfehlung'), value: t('packages.recommended_usage_window'), }, ]; } return [ { key: 'max_photos', label: t('packages.max_photos_label'), value: pkg.limits?.max_photos ? pkg.limits.max_photos.toLocaleString() : tCommon('unlimited'), }, { key: 'max_guests', label: t('packages.max_guests_label'), value: pkg.limits?.max_guests ? pkg.limits.max_guests.toLocaleString() : tCommon('unlimited'), }, { key: 'gallery_days', label: t('packages.gallery_days_label'), value: pkg.gallery_duration_label ?? (pkg.limits?.gallery_days ? pkg.limits.gallery_days.toLocaleString() : tCommon('unlimited')), }, ]; }; interface PackageCardProps { pkg: Package; variant: 'endcustomer' | 'reseller'; highlight?: boolean; onSelect?: (pkg: Package) => void; onCtaClick?: (pkg: Package, variant: 'endcustomer' | 'reseller') => void; className?: string; showCTA?: boolean; ctaLabel?: string; compact?: boolean; } function PackageCard({ pkg, variant, highlight = false, onSelect, onCtaClick, className, showCTA = true, ctaLabel, compact = false, }: PackageCardProps) { const { t } = useTranslation('marketing'); const { t: tCommon } = useTranslation('common'); const { localizedPath } = useLocalizedRoutes(); const accent = getAccentTheme(variant); const purchaseUrl = localizedPath(`/bestellen/${pkg.id}`); const numericPrice = Number(pkg.price); const priceLabel = numericPrice === 0 ? t('packages.free') : `${numericPrice.toLocaleString()} ${t('packages.currency.euro')}`; const cadenceLabel = variant === 'reseller' ? t('packages.billing_per_kontingent') : t('packages.billing_per_event'); const typeLabel = variant === 'reseller' ? t('packages.subscription') : t('packages.one_time'); const badgeLabel = highlight ? (variant === 'reseller' ? t('packages.badge_best_value') : t('packages.badge_recommended')) : pkg.price === 0 ? t('packages.badge_starter') : null; const eventBadge = variant === 'reseller' && pkg.events ? t('packages.events_badge', { count: pkg.events, defaultValue: `${pkg.events} Events` }) : null; const displayFeatures = buildDisplayFeatures(pkg, variant); const visibleFeatures = compact ? displayFeatures.slice(0, 3) : displayFeatures.slice(0, 5); const metrics = resolvePackageMetrics(pkg, variant, t, tCommon); const metricList = (
    {metrics.map((metric) => (
  • {metric.value} {metric.label}
  • ))}
); const featureList = (
    {visibleFeatures.map((feature) => (
  • {t(`packages.feature_${feature}`)}
  • ))}
); return (
{typeLabel}
{eventBadge && ( {eventBadge} )} {badgeLabel && ( {badgeLabel} )}
{pkg.name} {pkg.description}
{priceLabel} {pkg.price !== 0 && ( / {cadenceLabel} )}

{typeLabel}

{metricList} {featureList}
{showCTA && onSelect && (
)}
); } interface FeaturedBundleCardProps { pkg: Package; onSelect?: (pkg: Package) => void; onCtaClick?: (pkg: Package, variant: 'reseller') => void; className?: string; } function FeaturedBundleCard({ pkg, onSelect, onCtaClick, className }: FeaturedBundleCardProps) { const { t } = useTranslation('marketing'); const { t: tCommon } = useTranslation('common'); const { localizedPath } = useLocalizedRoutes(); const accent = getAccentTheme('reseller'); const purchaseUrl = localizedPath(`/bestellen/${pkg.id}`); const numericPrice = Number(pkg.price); const priceLabel = numericPrice === 0 ? t('packages.free') : `${numericPrice.toLocaleString()} ${t('packages.currency.euro')}`; const cadenceLabel = t('packages.billing_per_kontingent'); const metrics = resolvePackageMetrics(pkg, 'reseller', t, tCommon); const highlightFeatures = buildDisplayFeatures(pkg, 'reseller').slice(0, 4); return (
{t('packages.subscription')} {t('packages.badge_best_value')}
{pkg.name} {pkg.description}

{t('packages.price')}

{priceLabel} / {cadenceLabel}
{pkg.events && ( {t('packages.events_badge', { count: pkg.events, defaultValue: `${pkg.events} Events` })} )}

{t('packages.limits_label', 'Limits')}

    {metrics.map((metric) => (
  • {metric.value} {metric.label}
  • ))}

{t('packages.features_label', 'Features')}

    {highlightFeatures.map((feature) => (
  • {t(`packages.feature_${feature}`)}
  • ))}
{onSelect && ( )}
); } interface PackageDetailGridProps { packageData: Package; variant: 'endcustomer' | 'reseller'; isHighlight: boolean; purchaseUrl: string; onCtaClick: () => void; t: TFunction; tCommon: TFunction; testimonials: { name: string; text: string; rating: number }[]; close: () => void; } const PackageDetailGrid: React.FC = ({ packageData, variant, isHighlight, purchaseUrl, onCtaClick, t, tCommon, testimonials, close, }) => { const metrics = resolvePackageMetrics(packageData, variant, t, tCommon); const highlightFeatures = useMemo( () => buildDisplayFeatures(packageData, variant).slice(0, 5), [packageData, variant], ); return (

{t('packages.price')}

{Number(packageData.price).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })}{' '} {t('packages.currency.euro')}

{packageData.price > 0 && (

/ {variant === 'reseller' ? t('packages.billing_per_kontingent') : t('packages.billing_per_event')}

)}
{isHighlight && ( {variant === 'reseller' ? t('packages.badge_best_value') : t('packages.badge_recommended')} )}
{metrics.map((metric) => (

{metric.value}

{metric.label}

))}

{t('packages.order_hint')}

{t('packages.feature_highlights')}

    {highlightFeatures.map((feature) => (
  • {t(`packages.feature_${feature}`)}
  • ))}

{t('packages.more_details_tab')}

{t('packages.breakdown_label')} {t('packages.testimonials_title')} {packageData.description_breakdown?.length ? ( {packageData.description_breakdown.map((entry, index) => ( {entry.title ?? t('packages.limits_label')} {entry.value} ))} ) : (

{t('packages.breakdown_label_hint')}

)}
{testimonials.map((testimonial, index) => (

{testimonial.name}

{packageData.name}

{[...Array(testimonial.rating)].map((_, i) => ( ))}

“{testimonial.text}”

))}
); }; return (

{t('packages.for_endcustomers')} · {t('packages.for_resellers')}

{t('packages.hero_title')}

{t('packages.hero_description')}

{t('packages.hero_secondary')}
{t('packages.tab_endcustomer')} {t('packages.tab_reseller')}

{t('packages.comparison_hint')}

{orderedEndcustomerPackages.map((pkg) => (
handleCardClick(selected, 'endcustomer')} onCtaClick={handleCtaClick} className="h-full" compact />
))}
{orderedEndcustomerPackages.map((pkg) => ( handleCardClick(selected, 'endcustomer')} onCtaClick={handleCtaClick} className="h-full" compact /> ))}
{t('packages.bundles_title')} {t('packages.bundles_description')}

{t('packages.feature_reseller_dashboard')}

{t('packages.feature_priority_support')}

{orderedResellerPackages.map((pkg) => (
handleCardClick(selected, 'reseller')} onCtaClick={handleCtaClick} className="h-full" compact />
))}
{resellerBundles.map((pkg) => ( handleCardClick(selected, 'reseller')} onCtaClick={handleCtaClick} className="h-full" compact /> ))} {highlightResellerPackage && ( handleCardClick(selected, 'reseller')} onCtaClick={handleCtaClick} className="h-full" /> )}

{t('packages.calculator_title')}

{t('packages.calculator_description')}

{t('packages.calculator_question')} {t('packages.calculator_hint')}
{t('packages.calculator_min_label')} {t('packages.calculator_max_label', { count: guestSliderMax.toLocaleString() })}
setGuestCount(Number(event.target.value))} className="h-2 w-full cursor-pointer appearance-none rounded-full bg-gray-200 accent-pink-500 dark:bg-gray-800" />
{t('packages.max_guests_label')} {guestCount.toLocaleString()} {t('packages.max_guests')}
{recommendedPackage && (() => { const limit = recommendedPackage.limits?.max_guests ?? recommendedPackage.max_guests ?? null; const hasLimit = typeof limit === 'number' && Number.isFinite(limit); const limitLabel = hasLimit ? limit.toLocaleString() : tCommon('unlimited'); const priceLabel = Number(recommendedPackage.price) === 0 ? t('packages.free') : `${Number(recommendedPackage.price).toLocaleString()} ${t('packages.currency.euro')}`; return (

{t('packages.calculator_recommendation')}

{recommendedPackage.name}

{priceLabel} · {hasLimit ? t('packages.calculator_recommendation_hint', { count: limitLabel }) : t('packages.calculator_recommendation_hint_unlimited')}

); })()}

{t('packages.faq_title')}

{t('packages.faq_lead')}

{[ { title: t('packages.faq_branding'), body: t('packages.faq_branding_desc') }, { title: t('packages.faq_upgrade'), body: t('packages.faq_upgrade_desc') }, { title: t('packages.faq_reseller'), body: t('packages.faq_reseller_desc') }, { title: t('packages.faq_payment'), body: t('packages.faq_payment_desc') }, { title: t('packages.faq_photobooth'), body: t('packages.faq_photobooth_desc') }, ].map((item) => ( {item.title}

{item.body}

))}
{/* Details overlay */} {selectedPackage && ( isMobile ? ( {renderDetailBody('h-full overflow-y-auto space-y-8 p-6')} ) : ( {renderDetailBody('max-h-[88vh] overflow-y-auto space-y-8 p-6 md:p-10')} ) )} {/* Testimonials Section entfernt, da nun im Dialog */}
); }; const handleDetailAutoFocus = (event: Event) => { event.preventDefault(); // Guard in case refs are not in scope when autofocusing if (typeof dialogScrollRef !== 'undefined') { dialogScrollRef.current?.scrollTo({ top: 0 }); } if (typeof dialogHeadingRef !== 'undefined') { dialogHeadingRef.current?.focus(); } }; Packages.layout = (page: React.ReactNode) => page; export default Packages;