120 lines
4.7 KiB
TypeScript
120 lines
4.7 KiB
TypeScript
"use client"
|
|||
|
|
|
||
|
|
import { motion } from "framer-motion"
|
||
|
|
import { Star } from "lucide-react"
|
||
|
|
|
||
|
|
const TESTIMONIALS = [
|
||
|
|
{
|
||
|
|
name: "James T.",
|
||
|
|
role: "Landlord · 6 properties · Austin, TX",
|
||
|
|
body: "Property Management Network replaced three separate spreadsheets. My rent collection rate went from 80% to 98% in the first month because tenants actually get reminders now.",
|
||
|
|
rating: 5,
|
||
|
|
initials: "JT",
|
||
|
|
color: "from-indigo-500 to-violet-600",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "Maria S.",
|
||
|
|
role: "Property Manager · 22 units · Miami, FL",
|
||
|
|
body: "The maintenance portal alone is worth it. Tenants submit requests, I get notified, everything is tracked. No more texts at midnight. Absolute game changer.",
|
||
|
|
rating: 5,
|
||
|
|
initials: "MS",
|
||
|
|
color: "from-emerald-500 to-teal-600",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "David K.",
|
||
|
|
role: "Real estate investor · 4 properties · Denver, CO",
|
||
|
|
body: "I do my own books. The expense tracker and CSV export save me 3 hours every time I prepare for my accountant. Clean, fast, actually useful — rare.",
|
||
|
|
rating: 5,
|
||
|
|
initials: "DK",
|
||
|
|
color: "from-amber-500 to-orange-600",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "Rachel M.",
|
||
|
|
role: "Landlord · 2 properties · Seattle, WA",
|
||
|
|
body: "The tenant portal is brilliant. My tenants love having their own link. And lease expiry alerts saved me from an accidental month-to-month situation.",
|
||
|
|
rating: 5,
|
||
|
|
initials: "RM",
|
||
|
|
color: "from-rose-500 to-pink-600",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "Tom B.",
|
||
|
|
role: "Portfolio investor · 11 properties · Chicago, IL",
|
||
|
|
body: "Switched from a £150/month enterprise tool. Property Management Network does everything I actually use — at a fraction of the cost. The Lifetime deal was a no-brainer.",
|
||
|
|
rating: 5,
|
||
|
|
initials: "TB",
|
||
|
|
color: "from-blue-500 to-cyan-600",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "Aisha R.",
|
||
|
|
role: "Property manager · 8 units · London, UK",
|
||
|
|
body: "Gorgeous UI, fast, and actually works. I've tried 4 property management tools — this is the first one I've stuck with past 2 weeks.",
|
||
|
|
rating: 5,
|
||
|
|
initials: "AR",
|
||
|
|
color: "from-violet-500 to-purple-600",
|
||
|
|
},
|
||
|
|
]
|
||
|
|
|
||
|
|
function Stars({ count }: { count: number }) {
|
||
|
|
return (
|
||
|
|
<div className="flex gap-0.5">
|
||
|
|
{Array.from({ length: count }).map((_, i) => (
|
||
|
|
<Star key={i} className="h-4 w-4 fill-amber-400 text-amber-400" />
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
export function Testimonials() {
|
||
|
|
return (
|
||
|
|
<section className="mx-auto max-w-7xl px-4 sm:px-6 py-16 sm:py-24">
|
||
|
|
<motion.div
|
||
|
|
initial={{ opacity: 0, y: 20 }}
|
||
|
|
whileInView={{ opacity: 1, y: 0 }}
|
||
|
|
viewport={{ once: true }}
|
||
|
|
className="text-center mb-14"
|
||
|
|
>
|
||
|
|
<p className="text-xs font-semibold uppercase tracking-widest text-indigo-400 mb-3">Social proof</p>
|
||
|
|
<h2 className="text-3xl font-bold text-white sm:text-4xl">Landlords love Property Management Network</h2>
|
||
|
|
<p className="mt-4 text-white/50 max-w-xl mx-auto">
|
||
|
|
Real feedback from property owners who ditched their spreadsheets.
|
||
|
|
</p>
|
||
|
|
{/* Aggregate rating */}
|
||
|
|
<div className="mt-5 inline-flex items-center gap-2 rounded-full border border-amber-500/20 bg-amber-500/10 px-4 py-1.5">
|
||
|
|
<Stars count={5} />
|
||
|
|
<span className="text-sm font-semibold text-white">5.0</span>
|
||
|
|
<span className="text-xs text-white/40">from 200+ reviews</span>
|
||
|
|
</div>
|
||
|
|
</motion.div>
|
||
|
|
|
||
|
|
<div className="grid gap-5 sm:grid-cols-2 lg:grid-cols-3">
|
||
|
|
{TESTIMONIALS.map((t, i) => (
|
||
|
|
<motion.div
|
||
|
|
key={t.name}
|
||
|
|
initial={{ opacity: 0, y: 24 }}
|
||
|
|
whileInView={{ opacity: 1, y: 0 }}
|
||
|
|
viewport={{ once: true }}
|
||
|
|
transition={{ duration: 0.5, delay: i * 0.08 }}
|
||
|
|
whileHover={{ y: -4, scale: 1.01 }}
|
||
|
|
className="relative rounded-2xl border border-white/[0.06] bg-[#16161f] p-6 flex flex-col gap-4 group overflow-hidden cursor-default"
|
||
|
|
>
|
||
|
|
{/* Hover glow */}
|
||
|
|
<div className="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-500 bg-gradient-to-br from-white/[0.02] to-transparent" />
|
||
|
|
|
||
|
|
<Stars count={t.rating} />
|
||
|
|
<p className="text-sm text-white/70 leading-relaxed flex-1 relative">"{t.body}"</p>
|
||
|
|
<div className="flex items-center gap-3 relative">
|
||
|
|
<div className={`flex h-10 w-10 items-center justify-center rounded-full bg-gradient-to-br ${t.color} text-xs font-bold text-white shadow-lg`}>
|
||
|
|
{t.initials}
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<p className="text-sm font-semibold text-white">{t.name}</p>
|
||
|
|
<p className="text-xs text-white/40">{t.role}</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</motion.div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
)
|
||
|
|
}
|