import React, { useState, useEffect, useMemo } from 'react'; import { Head, 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 { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'; 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 { ArrowRight, ShoppingCart, Check, Users, Image, Shield, Star, Sparkles } from 'lucide-react'; interface Package { id: number; name: string; slug: string; description: string; description_breakdown: DescriptionEntry[]; gallery_duration_label?: string; price: number; events: number | null; features: string[]; 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; } interface PackageComparisonProps { packages: Package[]; variant: 'endcustomer' | 'reseller'; } function PackageComparison({ packages, variant }: 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_year')}`, }, { key: 'max_tenants', label: t('packages.max_tenants'), value: (pkg: Package) => pkg.limits?.max_tenants?.toLocaleString() ?? tCommon('unlimited'), }, { 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 = [ { key: 'watermark', label: t('packages.watermark_label'), value: (pkg: Package) => pkg.watermark_allowed === false ? t('packages.no_watermark') : t('packages.feature_watermark'), }, { 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'), }, ]; 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 [currentStep, setCurrentStep] = useState<'overview' | 'testimonials'>('overview'); const { props } = usePage(); const { auth } = props as any; const { t } = useTranslation('marketing'); const { t: tCommon } = useTranslation('common'); const { variant: packagesHeroVariant, trackClick: trackPackagesHeroClick, } = useCtaExperiment('packages_hero_cta'); 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]); const testimonials = [ { name: tCommon('testimonials.anna.name'), text: t('packages.testimonials.anna'), rating: 5 }, { name: tCommon('testimonials.max.name'), text: t('packages.testimonials.max'), rating: 5 }, { name: tCommon('testimonials.lisa.name'), text: t('packages.testimonials.lisa'), rating: 5 }, ]; const allPackages = [...endcustomerPackages, ...resellerPackages]; const 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; }; const highlightEndcustomerId = useMemo( () => selectHighlightPackageId(endcustomerPackages), [endcustomerPackages], ); const highlightResellerId = useMemo( () => selectHighlightPackageId(resellerPackages), [resellerPackages], ); 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 ? `/purchase-wizard/${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); setCurrentStep('overview'); 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 getFeatureIcon = (feature: string) => { switch (feature) { case 'basic_uploads': return ; case 'unlimited_sharing': return ; case 'no_watermark': return ; case 'custom_tasks': return ; case 'advanced_analytics': return ; case 'priority_support': return ; case 'reseller_dashboard': return ; case 'custom_branding': return ; default: return ; } }; const getAccentTheme = (variant: 'endcustomer' | 'reseller') => variant === 'reseller' ? { badge: 'bg-amber-50 text-amber-700', price: 'text-amber-600', buttonHighlight: 'bg-gray-900 text-white hover:bg-gray-800', buttonDefault: 'border border-amber-200 text-amber-700 hover:bg-amber-50', cardBorder: 'border border-amber-100', highlightShadow: 'shadow-lg shadow-amber-100/60', } : { badge: 'bg-rose-50 text-rose-700', price: 'text-rose-600', buttonHighlight: 'bg-gray-900 text-white hover:bg-gray-800', buttonDefault: 'border border-rose-100 text-rose-700 hover:bg-rose-50', cardBorder: 'border border-rose-100', highlightShadow: 'shadow-lg shadow-rose-100/60', }; type PackageMetric = { key: string; label: string; value: string; }; const resolvePackageMetrics = ( pkg: Package, variant: 'endcustomer' | 'reseller', t: TFunction, tCommon: TFunction, ): PackageMetric[] => { if (variant === 'reseller') { return [ { key: 'max_tenants', label: t('packages.max_tenants'), value: pkg.limits?.max_tenants ? pkg.limits.max_tenants.toLocaleString() : 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: 'branding', label: t('packages.feature_custom_branding'), value: pkg.branding_allowed ? tCommon('included') : t('packages.feature_no_branding'), }, ]; } 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; className?: string; showCTA?: boolean; ctaLabel?: string; compact?: boolean; } function PackageCard({ pkg, variant, highlight = false, onSelect, className, showCTA = true, ctaLabel, compact = false, }: PackageCardProps) { const { t } = useTranslation('marketing'); const { t: tCommon } = useTranslation('common'); const accent = getAccentTheme(variant); 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_year') : 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_most_popular')) : pkg.price === 0 ? t('packages.badge_starter') : null; const keyFeatures = pkg.features.slice(0, 3); const metrics = resolvePackageMetrics(pkg, variant, t, tCommon); return (
{typeLabel} {badgeLabel && ( {badgeLabel} )}
{pkg.name} {pkg.description}
{priceLabel} {pkg.price !== 0 && ( / {cadenceLabel} )}
{variant === 'endcustomer' && (

{pkg.events} × {t('packages.one_time')}

)}
{metrics.map((metric) => (

{metric.value}

{metric.label}

))}
    {keyFeatures.map((feature) => (
  • {t(`packages.feature_${feature}`)}
  • ))} {pkg.watermark_allowed === false && (
  • {t('packages.no_watermark')}
  • )} {pkg.branding_allowed && (
  • {t('packages.custom_branding')}
  • )}
{showCTA && onSelect && ( )}
); } return (

{t('packages.for_endcustomers')}

{t('packages.hero_title')}

{t('packages.hero_description')}

{ trackPackagesHeroClick(); trackEvent({ category: 'marketing_packages', action: 'hero_cta', name: `demo:${packagesHeroVariant}`, }); }} className="inline-flex items-center gap-2 rounded-full bg-gradient-to-r from-rose-500 via-pink-500 to-amber-400 px-10 py-4 text-lg font-semibold text-white shadow-xl shadow-rose-500/40 transition hover:from-rose-500/95 hover:via-pink-500/95 hover:to-amber-400/95" > {t('packages.cta_demo')}

{t('packages.hero_secondary')}

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

{t('packages.comparison_hint')}

{endcustomerPackages.map((pkg) => ( handleCardClick(selected, 'endcustomer')} className="min-w-[280px]" compact /> ))}
{resellerPackages.map((pkg) => ( handleCardClick(selected, 'reseller')} className="min-w-[280px]" compact /> ))}

{t('packages.faq_title')}

{t('packages.faq_lead')}

{[ { title: t('packages.faq_free'), body: t('packages.faq_free_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') }, ].map((item) => ( {item.title}

{item.body}

))}
{/* Modal */} {selectedPackage && (

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

{selectedPackage.name}

{selectedPackage.description}

{t('packages.price')}

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

{selectedPackage.price > 0 && (

/ {selectedVariant === 'reseller' ? t('packages.billing_per_year') : t('packages.billing_per_event')}

)}
{selectedHighlight && ( {selectedVariant === 'reseller' ? t('packages.badge_best_value') : t('packages.badge_most_popular')} )}
{resolvePackageMetrics(selectedPackage, selectedVariant, t, tCommon).map((metric) => (

{metric.value}

{metric.label}

))}

{t('packages.order_hint')}

{t('packages.feature_highlights')}

    {selectedPackage.features.slice(0, 5).map((feature) => (
  • {t(`packages.feature_${feature}`)}
  • ))} {selectedPackage.watermark_allowed === false && (
  • {t('packages.no_watermark')}
  • )} {selectedPackage.branding_allowed && (
  • {t('packages.custom_branding')}
  • )}
{t('packages.details')} {t('packages.customer_opinions')}

{t('packages.quick_facts')}

{t('packages.quick_facts_hint')}

{resolvePackageMetrics(selectedPackage, selectedVariant, t, tCommon).map((metric) => (

{metric.value}

{metric.label}

))}

{t('packages.feature_highlights')}

    {selectedPackage.features.slice(0, 4).map((feature) => (
  • {t(`packages.feature_${feature}`)}
  • ))} {selectedPackage.watermark_allowed === false && (
  • {t('packages.no_watermark')}
  • )} {selectedPackage.branding_allowed && (
  • {t('packages.custom_branding')}
  • )}
{selectedPackage.description_breakdown?.length ? ( {selectedPackage.description_breakdown.map((entry, index) => ( {entry.title ?? t('packages.limits_label')} {entry.value} ))} ) : (

{t('packages.breakdown_label_hint')}

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

{testimonial.name}

{selectedPackage.name}

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

“{testimonial.text}”

))}
)} {/* Testimonials Section entfernt, da nun im Dialog */}
); }; Packages.layout = (page: React.ReactNode) => page; export default Packages;