298 lines
11 KiB
TypeScript
298 lines
11 KiB
TypeScript
import { motion } from "framer-motion";
|
|
import { Check, Users, Clock, Sparkles } from "lucide-react";
|
|
import { GridPattern } from "./GridPattern";
|
|
import { Badge } from "./ui/badge";
|
|
|
|
interface PricingTier {
|
|
name: string;
|
|
price: string;
|
|
pricePerMonth: string;
|
|
description: string;
|
|
isPopular?: boolean;
|
|
teamSize: string;
|
|
projectManager: string;
|
|
uiuxDesigners: string;
|
|
frontendDevs: string;
|
|
backendDevs: string;
|
|
qaTesters: string;
|
|
leadTime: string;
|
|
minEngagement: string;
|
|
}
|
|
|
|
const pricingTiers: PricingTier[] = [
|
|
{
|
|
name: "Small",
|
|
price: "$7,500",
|
|
pricePerMonth: "/mo",
|
|
description: "Maintenance & updates",
|
|
teamSize: "3-5 Members",
|
|
projectManager: "Part-time (≤ 32 hrs/month)",
|
|
uiuxDesigners: "Part-time",
|
|
frontendDevs: "Shared",
|
|
backendDevs: "Shared",
|
|
qaTesters: "Part-time",
|
|
leadTime: "< 3 Days",
|
|
minEngagement: "1 Month",
|
|
},
|
|
{
|
|
name: "Medium",
|
|
price: "$12,000",
|
|
pricePerMonth: "/mo",
|
|
description: "Ongoing MVP development",
|
|
isPopular: true,
|
|
teamSize: "4-8 Members",
|
|
projectManager: "Shared (≤ 80 hrs/month)",
|
|
uiuxDesigners: "Shared",
|
|
frontendDevs: "Shared",
|
|
backendDevs: "Shared",
|
|
qaTesters: "Shared",
|
|
leadTime: "< 2 Weeks",
|
|
minEngagement: "2 Months",
|
|
},
|
|
{
|
|
name: "Large",
|
|
price: "$22,680",
|
|
pricePerMonth: "/mo",
|
|
description: "Long-term growth & GTM",
|
|
teamSize: "6-10 Members",
|
|
projectManager: "Dedicated full-time",
|
|
uiuxDesigners: "Full-time",
|
|
frontendDevs: "Full-time",
|
|
backendDevs: "Full-time",
|
|
qaTesters: "Full-time",
|
|
leadTime: "< 4 Weeks",
|
|
minEngagement: "3 Months",
|
|
},
|
|
];
|
|
|
|
const includedFeatures = [
|
|
{
|
|
left: "Access to WDI Code Library",
|
|
right: "Direct Communication",
|
|
},
|
|
{
|
|
left: "Time Zone Overlap: 3 Hours",
|
|
right: "Resource Replacement (within 1 week)",
|
|
},
|
|
{
|
|
left: "No Obligation Trial (conditional)",
|
|
right: "IPR & Code Ownership",
|
|
},
|
|
{
|
|
left: "Termination Notice: 1 Month",
|
|
right: "Performance Guarantee",
|
|
},
|
|
];
|
|
|
|
const comparisonRows = [
|
|
{ label: "Team Size", key: "teamSize" as keyof PricingTier },
|
|
{ label: "Project Manager", key: "projectManager" as keyof PricingTier },
|
|
{ label: "UI/UX Designers", key: "uiuxDesigners" as keyof PricingTier },
|
|
{ label: "Frontend Developers", key: "frontendDevs" as keyof PricingTier },
|
|
{ label: "Backend Developers", key: "backendDevs" as keyof PricingTier },
|
|
{ label: "QA Testers", key: "qaTesters" as keyof PricingTier },
|
|
{ label: "Lead Time to Start", key: "leadTime" as keyof PricingTier },
|
|
{
|
|
label: "Minimum Engagement Period",
|
|
key: "minEngagement" as keyof PricingTier,
|
|
},
|
|
];
|
|
|
|
export const DedicatedTeamPricing = () => {
|
|
return (
|
|
<section className="relative py-20 bg-background overflow-hidden">
|
|
<GridPattern strokeDasharray="4 2" />
|
|
|
|
<div className="relative z-10 container mx-auto px-6 lg:px-8">
|
|
{/* Header */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 30 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.8 }}
|
|
viewport={{ once: true }}
|
|
className="text-center mb-16"
|
|
>
|
|
<div className="inline-flex items-center gap-2 mb-4">
|
|
<Users className="w-6 h-6 text-accent" />
|
|
<h2 className="text-4xl lg:text-5xl font-semibold text-foreground font-manrope">
|
|
Dedicated Team Pricing
|
|
</h2>
|
|
</div>
|
|
<p className="text-muted-foreground text-lg max-w-2xl mx-auto font-manrope">
|
|
Scale your AI mobile and web development with flexible team
|
|
structures tailored to your project needs.
|
|
</p>
|
|
</motion.div>
|
|
|
|
{/* Pricing Cards Row */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 40 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.8, delay: 0.2 }}
|
|
viewport={{ once: true }}
|
|
className="grid md:grid-cols-3 gap-6 mb-12 max-w-6xl mx-auto"
|
|
>
|
|
{pricingTiers.map((tier, index) => (
|
|
<motion.div
|
|
key={tier.name}
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
|
viewport={{ once: true }}
|
|
className={`relative bg-card/50 backdrop-blur-sm border rounded-[20px] p-6 transition-all duration-300 ${
|
|
tier.isPopular
|
|
? "border-blue-500/50 shadow-xl shadow-blue-500/10 scale-105"
|
|
: "border-border/50 hover:border-accent/30"
|
|
}`}
|
|
>
|
|
{tier.isPopular && (
|
|
<div className="absolute -top-4 left-1/2 -translate-x-1/2">
|
|
<Badge className="bg-blue-600 text-white px-4 py-1 rounded-full font-manrope">
|
|
Most Popular
|
|
</Badge>
|
|
</div>
|
|
)}
|
|
|
|
<div className="text-center mb-6">
|
|
<h3 className="text-2xl font-semibold text-foreground mb-2 font-manrope">
|
|
{tier.name}
|
|
</h3>
|
|
<div className="flex items-baseline justify-center mb-2">
|
|
<span className="text-4xl font-semibold text-foreground font-manrope">
|
|
{tier.price}
|
|
</span>
|
|
<span className="text-xl text-muted-foreground font-manrope">
|
|
{tier.pricePerMonth}
|
|
</span>
|
|
</div>
|
|
<p className="text-sm text-muted-foreground font-manrope">
|
|
{tier.description}
|
|
</p>
|
|
</div>
|
|
</motion.div>
|
|
))}
|
|
</motion.div>
|
|
|
|
{/* Comparison Table */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 40 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.8, delay: 0.4 }}
|
|
viewport={{ once: true }}
|
|
className="max-w-6xl mx-auto mb-16"
|
|
>
|
|
<div className="bg-card/30 backdrop-blur-md border border-border/50 rounded-[20px] overflow-hidden">
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full border-collapse font-manrope">
|
|
{/* Table Header - Hidden on mobile, shown on desktop */}
|
|
<thead className="hidden md:table-header-group">
|
|
<tr className="border-b border-border/50 bg-card/50">
|
|
<th className="p-6 text-left font-semibold text-foreground font-manrope"></th>
|
|
{pricingTiers.map((tier) => (
|
|
<th
|
|
key={tier.name}
|
|
className="p-6 text-center font-semibold text-foreground font-manrope"
|
|
>
|
|
{tier.name}
|
|
</th>
|
|
))}
|
|
</tr>
|
|
</thead>
|
|
|
|
{/* Table Body */}
|
|
<tbody>
|
|
{comparisonRows.map((row, rowIndex) => (
|
|
<motion.tr
|
|
key={row.label}
|
|
initial={{ opacity: 0, x: -20 }}
|
|
whileInView={{ opacity: 1, x: 0 }}
|
|
transition={{ duration: 0.5, delay: rowIndex * 0.05 }}
|
|
viewport={{ once: true }}
|
|
className="border-b border-border/30 last:border-b-0 hover:bg-card/50 transition-colors duration-200"
|
|
>
|
|
<td className="p-6 font-medium text-muted-foreground font-manrope align-top">
|
|
<div className="md:hidden mb-3">{row.label}</div>
|
|
<div className="hidden md:block">{row.label}</div>
|
|
|
|
{/* Mobile: Stack values vertically with tier name */}
|
|
<div className="grid grid-cols-1 md:hidden gap-3 mt-3">
|
|
{pricingTiers.map((tier) => (
|
|
<div
|
|
key={tier.name}
|
|
className="flex justify-between items-center bg-card/30 rounded-lg p-3"
|
|
>
|
|
<span className="text-sm text-muted-foreground font-manrope">
|
|
{tier.name}:
|
|
</span>
|
|
<span className="text-foreground font-manrope text-right">
|
|
{tier[row.key]}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</td>
|
|
|
|
{/* Desktop: Show values in columns */}
|
|
{pricingTiers.map((tier) => (
|
|
<td
|
|
key={tier.name}
|
|
className="hidden md:table-cell p-6 text-center text-foreground font-manrope align-top"
|
|
>
|
|
{tier[row.key]}
|
|
</td>
|
|
))}
|
|
</motion.tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
|
|
{/* Included in All Plans */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 40 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.8, delay: 0.6 }}
|
|
viewport={{ once: true }}
|
|
className="max-w-4xl mx-auto"
|
|
>
|
|
<div className="bg-gradient-to-br from-accent/5 to-blue-500/5 backdrop-blur-sm border border-accent/20 rounded-[20px] p-8">
|
|
<div className="flex items-center gap-3 mb-6">
|
|
<div className="w-12 h-12 bg-accent/20 rounded-full flex items-center justify-center">
|
|
<Sparkles className="w-6 h-6 text-accent" />
|
|
</div>
|
|
<h3 className="text-2xl font-semibold text-foreground font-manrope">
|
|
Included in All Plans
|
|
</h3>
|
|
</div>
|
|
|
|
<div className="grid md:grid-cols-2 gap-6">
|
|
{includedFeatures.map((feature, index) => (
|
|
<div key={index} className="space-y-3">
|
|
<div className="flex items-start gap-3">
|
|
<div className="flex-shrink-0 w-5 h-5 bg-accent/20 rounded-full flex items-center justify-center mt-0.5">
|
|
<Check className="w-3 h-3 text-accent" />
|
|
</div>
|
|
<span className="text-foreground font-manrope leading-relaxed">
|
|
{feature.left}
|
|
</span>
|
|
</div>
|
|
<div className="flex items-start gap-3">
|
|
<div className="flex-shrink-0 w-5 h-5 bg-accent/20 rounded-full flex items-center justify-center mt-0.5">
|
|
<Check className="w-3 h-3 text-accent" />
|
|
</div>
|
|
<span className="text-foreground font-manrope leading-relaxed">
|
|
{feature.right}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|