200 lines
12 KiB
TypeScript
200 lines
12 KiB
TypeScript
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Dialog, DialogContent } from '@/components/ui/dialog';
|
|
import { useLocalizedRoutes } from '@/hooks/useLocalizedRoutes';
|
|
import { useLocale } from '@/hooks/useLocale';
|
|
import MarketingLayout from '@/layouts/mainWebsite';
|
|
import { Head, Link } from '@inertiajs/react';
|
|
import { CheckCircle2, Sparkles } from 'lucide-react';
|
|
import React from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
type DemoFeature = { title: string; description: string };
|
|
|
|
interface DemoPageProps {
|
|
demoToken?: string | null;
|
|
}
|
|
|
|
const DemoPage: React.FC<DemoPageProps> = ({ demoToken }) => {
|
|
const { t } = useTranslation('marketing');
|
|
const { localizedPath } = useLocalizedRoutes();
|
|
const locale = useLocale();
|
|
const embedUrl = demoToken ? `/e/${demoToken}` : '/e/demo?demo=1';
|
|
const [isDemoOpen, setIsDemoOpen] = React.useState(false);
|
|
const demoOpenLabel = t('labels.demoOpenOverlay', locale === 'en' ? 'Open demo overlay' : 'Demo im Overlay öffnen');
|
|
|
|
const demo = t('demo_page', { returnObjects: true }) as {
|
|
title: string;
|
|
subtitle: string;
|
|
primaryCta: string;
|
|
secondaryCta: string;
|
|
iframeNote: string;
|
|
openFull: string;
|
|
features: DemoFeature[];
|
|
};
|
|
const demoFeatures = Array.isArray(demo.features) ? demo.features : [];
|
|
const handleOpenDemo = (): void => {
|
|
setIsDemoOpen(true);
|
|
};
|
|
|
|
return (
|
|
<MarketingLayout title={demo.title}>
|
|
<Head title={demo.title} />
|
|
|
|
<section className="relative overflow-hidden bg-gradient-to-br from-pink-100 via-white to-white px-4 py-16 lg:pb-16 lg:pt-6 dark:from-pink-950/40 dark:via-gray-950 dark:to-gray-950">
|
|
<div className="absolute -top-32 right-20 hidden h-72 w-72 rounded-full bg-pink-200/50 blur-3xl lg:block dark:bg-pink-900/30" />
|
|
<div className="relative z-10 container mx-auto flex max-w-5xl flex-col gap-10 lg:flex-row lg:items-start">
|
|
<div className="flex-1 space-y-6">
|
|
<Badge variant="outline" className="border-pink-400 text-pink-600 dark:border-pink-500 dark:text-pink-300">
|
|
Demo Live
|
|
</Badge>
|
|
<h1 className="text-4xl font-bold tracking-tight text-gray-900 md:text-5xl dark:text-gray-50">{demo.title}</h1>
|
|
<p className="max-w-xl text-lg text-gray-600 dark:text-gray-300">{demo.subtitle}</p>
|
|
<div className="flex flex-wrap items-center gap-3">
|
|
<Button asChild size="lg" className="bg-pink-500 hover:bg-pink-600">
|
|
<Link href={localizedPath('/packages')}>{demo.primaryCta}</Link>
|
|
</Button>
|
|
<Button asChild size="lg" variant="ghost" className="text-pink-600 hover:text-pink-700 dark:text-pink-300">
|
|
<Link href={localizedPath('/so-funktionierts')}>{demo.secondaryCta}</Link>
|
|
</Button>
|
|
<Button
|
|
asChild
|
|
size="lg"
|
|
variant="outline"
|
|
className="border-pink-200 text-pink-600 hover:bg-pink-50 dark:border-pink-800 dark:text-pink-200"
|
|
>
|
|
<Link href={localizedPath(locale === 'en' ? '/gift-card' : '/gutschein')}>
|
|
{t('packages.gift_cta', 'Paket verschenken')}
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<div className="flex-1">
|
|
{embedUrl ? (
|
|
<>
|
|
<div className="relative mx-auto w-[min(92vw,calc(75dvh*10/14))] aspect-[10/14] rounded-[2.5rem] border border-gray-200 bg-gray-900 px-3 pb-3 pt-4 shadow-2xl dark:border-gray-700">
|
|
<div
|
|
className="absolute top-2 left-1/2 h-1.5 w-16 -translate-x-1/2 rounded-full bg-gray-300 dark:bg-gray-600"
|
|
aria-hidden
|
|
/>
|
|
<div className="h-full w-full overflow-hidden rounded-[1.75rem] bg-white shadow-inner dark:bg-gray-950">
|
|
{isDemoOpen ? (
|
|
<div className="flex h-full w-full flex-col items-center justify-center gap-2 bg-gradient-to-br from-pink-200 via-white to-white px-4 text-center dark:from-pink-900/40 dark:via-gray-950 dark:to-gray-950">
|
|
<p className="text-xs uppercase tracking-[0.2em] text-pink-600/70 dark:text-pink-300/70">Live Demo</p>
|
|
<p className="text-sm font-semibold text-gray-900 dark:text-gray-100">Demo läuft im Overlay</p>
|
|
<p className="text-xs text-gray-600 dark:text-gray-300">Schließe das Overlay, um hier weiterzumachen.</p>
|
|
</div>
|
|
) : (
|
|
<iframe
|
|
title="Demo der Fotospiel App"
|
|
src={embedUrl}
|
|
className="h-full w-full border-0 bg-white dark:bg-gray-950"
|
|
loading="lazy"
|
|
sandbox="allow-scripts allow-same-origin allow-forms"
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="mt-4 flex flex-col items-center gap-1 text-center">
|
|
<p className="text-sm text-gray-600 dark:text-gray-300">{demo.iframeNote}</p>
|
|
<Button
|
|
type="button"
|
|
variant="link"
|
|
className="text-pink-600 hover:text-pink-700 dark:text-pink-300"
|
|
onClick={handleOpenDemo}
|
|
>
|
|
{demoOpenLabel}
|
|
</Button>
|
|
</div>
|
|
</>
|
|
) : (
|
|
<Alert className="border-pink-200 bg-white shadow-lg dark:border-pink-900/50 dark:bg-gray-950">
|
|
<AlertTitle className="text-gray-900 dark:text-gray-100">
|
|
{t('labels.demoUnavailable', 'Demo-Link aktuell nicht verfügbar')}
|
|
</AlertTitle>
|
|
<AlertDescription className="mt-2 text-sm text-gray-600 dark:text-gray-300">
|
|
{t(
|
|
'labels.demoUnavailableCopy',
|
|
'Führe die Demo-Seeds aus oder kontaktiere uns, damit wir dir sofort einen neuen Zugangscode hinterlegen können.',
|
|
)}
|
|
</AlertDescription>
|
|
<div className="mt-4 flex flex-wrap gap-3">
|
|
<Button asChild size="sm" className="bg-pink-500 hover:bg-pink-600">
|
|
<Link href={localizedPath('/packages')}>{demo.primaryCta}</Link>
|
|
</Button>
|
|
<Button
|
|
asChild
|
|
size="sm"
|
|
variant="outline"
|
|
className="text-pink-600 hover:text-pink-700 dark:border-pink-900/40 dark:text-pink-300"
|
|
>
|
|
<Link href={localizedPath('/kontakt')}>{t('nav.contact', 'Kontakt')}</Link>
|
|
</Button>
|
|
</div>
|
|
</Alert>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="container mx-auto px-4 pb-16">
|
|
<div className="mx-auto max-w-5xl">
|
|
<div className="grid gap-6 md:grid-cols-3">
|
|
{demoFeatures.map((feature) => (
|
|
<Card key={feature.title} className="border-gray-100 shadow-sm dark:border-gray-800">
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2 text-lg">
|
|
<Sparkles className="h-5 w-5 text-pink-500" aria-hidden />
|
|
{feature.title}
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<CardDescription className="text-sm text-gray-600 dark:text-gray-300">{feature.description}</CardDescription>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
|
|
<Alert className="mt-10 border-pink-200 bg-white shadow-lg dark:border-pink-900/50 dark:bg-gray-950">
|
|
<AlertTitle className="flex items-center gap-2 text-gray-900 dark:text-gray-100">
|
|
<CheckCircle2 className="h-5 w-5 text-pink-500" aria-hidden />
|
|
{t('marketing.labels.readyToLaunch', 'Bereit für dein Event?')}
|
|
</AlertTitle>
|
|
<AlertDescription className="mt-3 flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
|
<span className="text-sm text-gray-600 dark:text-gray-300">
|
|
{t('marketing.labels.readyToLaunchCopy', 'Registriere dich kostenlos und lege noch heute dein erstes Event an.')}
|
|
</span>
|
|
<Button asChild className="bg-pink-500 hover:bg-pink-600">
|
|
<Link href={localizedPath('/packages')}>{demo.primaryCta}</Link>
|
|
</Button>
|
|
</AlertDescription>
|
|
</Alert>
|
|
</div>
|
|
</section>
|
|
<Dialog open={isDemoOpen} onOpenChange={setIsDemoOpen}>
|
|
<DialogContent className="flex items-center justify-center border-0 bg-transparent p-0 shadow-none">
|
|
<div className="relative h-[75dvh] w-auto max-w-[92vw] aspect-[10/14] rounded-[2.5rem] border border-gray-200 bg-gray-900 p-3 shadow-2xl dark:border-gray-700">
|
|
<div
|
|
className="absolute top-2 left-1/2 h-1.5 w-16 -translate-x-1/2 rounded-full bg-gray-300 dark:bg-gray-600"
|
|
aria-hidden
|
|
/>
|
|
<iframe
|
|
title="Demo der Fotospiel App"
|
|
src={embedUrl}
|
|
className="h-full w-full rounded-[1.75rem] border-0 bg-white shadow-inner dark:bg-gray-950"
|
|
loading="lazy"
|
|
sandbox="allow-scripts allow-same-origin allow-forms"
|
|
/>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</MarketingLayout>
|
|
);
|
|
};
|
|
|
|
DemoPage.layout = (page: React.ReactNode) => page;
|
|
|
|
export default DemoPage;
|