website-monitor/frontend/components/landing/PricingComparison.tsx

256 lines
11 KiB
TypeScript

'use client'
import { motion } from 'framer-motion'
import { useState } from 'react'
import { TrendingDown, DollarSign } from 'lucide-react'
export function PricingComparison() {
const [monitorCount, setMonitorCount] = useState(50)
// Pricing calculation logic
const calculatePricing = (monitors: number) => {
// Competitors: tiered pricing
let competitorMin, competitorMax
if (monitors <= 10) {
competitorMin = 29
competitorMax = 49
} else if (monitors <= 50) {
competitorMin = 79
competitorMax = 129
} else if (monitors <= 100) {
competitorMin = 129
competitorMax = 199
} else {
competitorMin = 199
competitorMax = 299
}
// Our pricing: simpler, fairer
let ourPrice
if (monitors <= 10) {
ourPrice = 19
} else if (monitors <= 50) {
ourPrice = 49
} else if (monitors <= 100) {
ourPrice = 89
} else {
ourPrice = 149
}
const competitorAvg = (competitorMin + competitorMax) / 2
const savings = competitorAvg - ourPrice
const savingsPercent = Math.round((savings / competitorAvg) * 100)
return {
competitorMin,
competitorMax,
competitorAvg,
ourPrice,
savings,
savingsPercent
}
}
const pricing = calculatePricing(monitorCount)
return (
<section className="py-32 bg-gradient-to-b from-[hsl(var(--section-bg-6))] to-[hsl(var(--section-bg-3))] relative overflow-hidden">
{/* Background Pattern - Enhanced Dot Grid */}
<div className="absolute inset-0 opacity-8">
<div className="absolute inset-0" style={{
backgroundImage: `radial-gradient(circle, hsl(var(--teal)) 1.5px, transparent 1.5px)`,
backgroundSize: '30px 30px'
}} />
</div>
<div className="mx-auto max-w-5xl px-6 relative z-10">
{/* Section Header */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
className="text-center mb-16"
>
<div className="inline-flex items-center gap-2 rounded-full bg-[hsl(var(--teal))]/10 border border-[hsl(var(--teal))]/20 px-4 py-1.5 text-sm font-medium text-[hsl(var(--teal))] mb-6">
<DollarSign className="h-4 w-4" />
Fair Pricing
</div>
<h2 className="text-4xl lg:text-5xl font-display font-bold text-foreground mb-6">
See how much you{' '}
<span className="text-[hsl(var(--teal))]">save</span>
</h2>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
Compare our transparent pricing with typical competitors. No hidden fees, no surprises.
</p>
</motion.div>
{/* Interactive Comparison Card */}
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
className="rounded-3xl border-2 border-border bg-card p-8 lg:p-12 shadow-2xl"
>
{/* Monitor Count Slider */}
<div className="mb-12">
<div className="flex items-center justify-between mb-4">
<label className="text-sm font-bold text-muted-foreground uppercase tracking-wider">
Number of Monitors
</label>
<motion.div
key={monitorCount}
initial={{ scale: 1.2 }}
animate={{ scale: 1 }}
className="text-4xl font-bold text-foreground font-mono"
>
{monitorCount}
</motion.div>
</div>
{/* Slider */}
<div className="relative">
<input
type="range"
min="5"
max="200"
step="5"
value={monitorCount}
onChange={(e) => setMonitorCount(Number(e.target.value))}
className="w-full h-3 bg-secondary rounded-full appearance-none cursor-pointer
[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-6 [&::-webkit-slider-thumb]:h-6
[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-[hsl(var(--teal))]
[&::-webkit-slider-thumb]:shadow-lg [&::-webkit-slider-thumb]:cursor-grab
[&::-webkit-slider-thumb]:active:cursor-grabbing [&::-webkit-slider-thumb]:hover:scale-110
[&::-webkit-slider-thumb]:transition-transform
[&::-moz-range-thumb]:w-6 [&::-moz-range-thumb]:h-6
[&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-[hsl(var(--teal))]
[&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:shadow-lg
[&::-moz-range-thumb]:cursor-grab [&::-moz-range-thumb]:active:cursor-grabbing"
/>
{/* Tick marks - positioned by percentage based on slider range (5-200) */}
<div className="relative mt-2 h-4">
<span className="absolute text-xs text-muted-foreground" style={{ left: '0%', transform: 'translateX(0)' }}>5</span>
<span className="absolute text-xs text-muted-foreground" style={{ left: `${((50 - 5) / (200 - 5)) * 100}%`, transform: 'translateX(-50%)' }}>50</span>
<span className="absolute text-xs text-muted-foreground" style={{ left: `${((100 - 5) / (200 - 5)) * 100}%`, transform: 'translateX(-50%)' }}>100</span>
<span className="absolute text-xs text-muted-foreground" style={{ left: '100%', transform: 'translateX(-100%)' }}>200</span>
</div>
</div>
</div>
{/* Price Comparison Bars */}
<div className="grid lg:grid-cols-2 gap-8 mb-8">
{/* Competitors */}
<motion.div
layout
className="space-y-4"
>
<div className="flex items-center justify-between">
<span className="text-sm font-bold text-muted-foreground uppercase tracking-wider">
Typical Competitors
</span>
</div>
{/* Bar */}
<motion.div
className="relative h-24 rounded-2xl bg-gradient-to-r from-red-500/10 to-red-500/20 border-2 border-red-500/30 overflow-hidden"
whileHover={{ scale: 1.02 }}
transition={{ duration: 0.2 }}
>
<motion.div
className="absolute inset-0 bg-gradient-to-r from-red-500/20 to-red-500/40"
initial={{ scaleX: 0 }}
animate={{ scaleX: 1 }}
transition={{ duration: 0.8, ease: [0.22, 1, 0.36, 1] }}
style={{ transformOrigin: 'left' }}
/>
<div className="relative h-full flex items-center justify-center">
<div className="text-center">
<motion.div
key={`comp-${pricing.competitorMin}-${pricing.competitorMax}`}
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
className="text-4xl font-bold text-red-700 font-mono"
>
${pricing.competitorMin}-{pricing.competitorMax}
</motion.div>
<div className="text-xs font-medium text-red-600">per month</div>
</div>
</div>
</motion.div>
</motion.div>
{/* Us */}
<motion.div
layout
className="space-y-4"
>
<div className="flex items-center justify-between">
<span className="text-sm font-bold text-[hsl(var(--teal))] uppercase tracking-wider">
Our Pricing
</span>
</div>
{/* Bar */}
<motion.div
className="relative h-24 rounded-2xl bg-gradient-to-r from-[hsl(var(--teal))]/10 to-[hsl(var(--teal))]/20 border-2 border-[hsl(var(--teal))]/30 overflow-hidden"
whileHover={{ scale: 1.02 }}
transition={{ duration: 0.2 }}
>
<motion.div
className="absolute inset-0 bg-gradient-to-r from-[hsl(var(--teal))]/20 to-[hsl(var(--teal))]/40"
initial={{ scaleX: 0 }}
animate={{ scaleX: pricing.ourPrice / pricing.competitorMax }}
transition={{ duration: 0.8, ease: [0.22, 1, 0.36, 1] }}
style={{ transformOrigin: 'left' }}
/>
<div className="relative h-full flex items-center justify-center">
<div className="text-center">
<motion.div
key={`our-${pricing.ourPrice}`}
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
className="text-5xl font-bold text-[hsl(var(--teal))] font-mono"
>
${pricing.ourPrice}
</motion.div>
<div className="text-xs font-medium text-[hsl(var(--teal))]">per month</div>
</div>
</div>
</motion.div>
</motion.div>
</div>
{/* Savings Badge */}
<motion.div
key={`savings-${pricing.savings}`}
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ type: 'spring', stiffness: 300, damping: 20 }}
className="flex items-center justify-center gap-4 p-6 rounded-2xl bg-gradient-to-r from-[hsl(var(--primary))]/10 via-[hsl(var(--teal))]/10 to-[hsl(var(--burgundy))]/10 border-2 border-[hsl(var(--teal))]/30"
>
<TrendingDown className="h-8 w-8 text-[hsl(var(--teal))]" />
<div className="text-center">
<div className="text-sm font-medium text-muted-foreground">You save</div>
<div className="flex items-baseline gap-2">
<span className="text-4xl font-bold text-foreground">
${Math.round(pricing.savings)}
</span>
<span className="text-xl text-muted-foreground">/month</span>
<span className="ml-2 px-3 py-1 rounded-full bg-[hsl(var(--teal))]/20 text-sm font-bold text-[hsl(var(--teal))]">
{pricing.savingsPercent}% off
</span>
</div>
</div>
</motion.div>
{/* Fine Print */}
<p className="mt-6 text-center text-xs text-muted-foreground">
* Based on average pricing from Visualping, Distill.io, and similar competitors as of Jan 2026
</p>
</motion.div>
</div>
</section>
)
}