diff --git a/app/checkout/page.tsx b/app/checkout/page.tsx index 87613ef..2db9cc9 100644 --- a/app/checkout/page.tsx +++ b/app/checkout/page.tsx @@ -11,6 +11,7 @@ import { getSubscription } from '@/lib/api/billing' import { PLAN_PRICES, TRAFFIC_TIERS } from '@/lib/plans' import PlanSummary from '@/components/checkout/PlanSummary' import PaymentForm from '@/components/checkout/PaymentForm' +import FeatureSlideshow from '@/components/checkout/FeatureSlideshow' import pulseIcon from '@/public/pulse_icon_no_margins.png' // --------------------------------------------------------------------------- @@ -171,46 +172,52 @@ function CheckoutContent() { const pageviewLimit = Number(limit) return ( -
- {/* Header */} -
- - Pulse - Pulse - +
+ {/* Left — Feature slideshow (hidden on mobile) */} +
+
- {/* Main content */} -
- -
- {/* Left — Plan summary */} + {/* Right — Payment */} +
+ {/* Header */} +
+ + Pulse + Pulse + +
+ + {/* Main content */} +
+ + {/* Plan summary (compact) */} - {/* Right — Payment form */} + {/* Payment form */} -
- + +
) diff --git a/components/checkout/FeatureSlideshow.tsx b/components/checkout/FeatureSlideshow.tsx new file mode 100644 index 0000000..b8d9d63 --- /dev/null +++ b/components/checkout/FeatureSlideshow.tsx @@ -0,0 +1,160 @@ +'use client' + +import { useState, useEffect, useCallback } from 'react' +import Image from 'next/image' +import { AnimatePresence, motion } from 'framer-motion' +import { Check } from '@phosphor-icons/react' +import { PulseMockup } from '@/components/marketing/mockups/pulse-mockup' +import { PulseFeaturesCarousel } from '@/components/marketing/mockups/pulse-features-carousel' +import { FunnelMockup } from '@/components/marketing/mockups/funnel-mockup' +import { EmailReportMockup } from '@/components/marketing/mockups/email-report-mockup' + +interface Slide { + headline: string + description: string + features: string[] + mockup: React.ReactNode +} + +const slides: Slide[] = [ + { + headline: 'Your traffic, at a glance.', + description: + 'A clean, real-time dashboard that shows pageviews, visitors, bounce rate, and session duration — no learning curve required.', + features: [ + 'Real-time visitor count', + 'Pageview trends over time', + 'Bounce rate & session duration', + 'Top pages & referrers', + ], + mockup: , + }, + { + headline: 'Everything you need to know about your visitors.', + description: + 'Break down your audience by device, browser, OS, country, and language — all without cookies or fingerprinting.', + features: [ + 'Device & browser breakdown', + 'Country & region stats', + 'Language preferences', + 'Screen size distribution', + ], + mockup: , + }, + { + headline: 'See where visitors drop off.', + description: + 'Build funnels to track multi-step flows and find exactly where users abandon your conversion paths.', + features: [ + 'Multi-step funnel builder', + 'Drop-off visualization', + 'Conversion rate tracking', + 'Custom event support', + ], + mockup: , + }, + { + headline: 'Reports delivered to your inbox.', + description: + 'Schedule weekly or monthly email reports so your team stays informed without logging in.', + features: [ + 'Weekly & monthly digests', + 'Customizable metrics', + 'Team-wide distribution', + 'PDF & inline previews', + ], + mockup: , + }, +] + +export default function FeatureSlideshow() { + const [activeIndex, setActiveIndex] = useState(0) + + const advance = useCallback(() => { + setActiveIndex((prev) => (prev + 1) % slides.length) + }, []) + + useEffect(() => { + const timer = setInterval(advance, 5000) + return () => clearInterval(timer) + }, [advance]) + + const slide = slides[activeIndex] + + return ( +
+ {/* Background image */} + + + {/* Dark overlay */} +
+ + {/* Content */} +
+ + + {/* Text */} +
+

+ {slide.headline} +

+

+ {slide.description} +

+ +
    + {slide.features.map((f) => ( +
  • + + {f} +
  • + ))} +
+
+ + {/* Mockup */} +
+ {/* Orange glow */} +
+ +
+ {slide.mockup} +
+
+ + + + {/* Dot indicators */} +
+ {slides.map((_, i) => ( +
+
+
+ ) +} diff --git a/components/checkout/PlanSummary.tsx b/components/checkout/PlanSummary.tsx index f9af880..bec4c3e 100644 --- a/components/checkout/PlanSummary.tsx +++ b/components/checkout/PlanSummary.tsx @@ -3,11 +3,8 @@ import { useState } from 'react' import { useRouter, useSearchParams } from 'next/navigation' import { motion } from 'framer-motion' -import { Check } from '@phosphor-icons/react' import { TRAFFIC_TIERS, - getSitesLimitForPlan, - getMaxRetentionMonthsForPlan, PLAN_PRICES, } from '@/lib/plans' @@ -30,12 +27,6 @@ export default function PlanSummary({ plan, interval, limit }: PlanSummaryProps) const tierLabel = TRAFFIC_TIERS.find((t) => t.value === limit)?.label || `${(limit / 1000).toFixed(0)}k` - const sitesLimit = getSitesLimitForPlan(plan) - const retentionMonths = getMaxRetentionMonthsForPlan(plan) - const retentionLabel = - retentionMonths >= 12 - ? `${retentionMonths / 12} year${retentionMonths > 12 ? 's' : ''}` - : `${retentionMonths} months` const handleIntervalToggle = (newInterval: string) => { setCurrentInterval(newInterval) @@ -44,80 +35,59 @@ export default function PlanSummary({ plan, interval, limit }: PlanSummaryProps) router.replace(`/checkout?${params.toString()}`, { scroll: false }) } - const features = [ - `${tierLabel} pageviews/mo`, - `${sitesLimit} site${sitesLimit && sitesLimit > 1 ? 's' : ''}`, - `${retentionLabel} data retention`, - 'Unlimited team members', - 'Custom events & goals', - 'Funnels & user journeys', - ] - return ( -
- {/* Plan header */} -
-

{plan}

- - 30-day trial - +
+
+ {/* Plan name + badge */} +
+

{plan}

+ + 30-day trial + +
+ + {/* Interval toggle */} +
+ {(['month', 'year'] as const).map((iv) => ( + + ))} +
- {/* Price display */} -
-
- - €{isYearly ? monthlyEquivalent.toFixed(2) : displayPrice.toFixed(0)} - - /mo -
+ {/* Price row */} +
+ + €{isYearly ? monthlyEquivalent.toFixed(2) : displayPrice.toFixed(0)} + + /mo + · {tierLabel} pageviews {isYearly && ( -
- - €{displayPrice.toFixed(2)} billed yearly - - - Save 1 month - -
+ + Save 1 month + )}
- - {/* Interval toggle */} -
- {(['month', 'year'] as const).map((iv) => ( - - ))} -
- - {/* Divider */} -
- - {/* Features list */} -
    - {features.map((feature) => ( -
  • - - {feature} -
  • - ))} -
+ {isYearly && ( +

+ €{displayPrice.toFixed(2)} billed yearly +

+ )}
) }