349 lines
11 KiB
TypeScript
349 lines
11 KiB
TypeScript
"use client";
|
|
|
|
import { useMemo, useState } from "react";
|
|
|
|
type PricingTableProps = {
|
|
lang: "es" | "en";
|
|
onContact: () => void;
|
|
};
|
|
|
|
type Plan = {
|
|
id: string;
|
|
name: string;
|
|
setup: string;
|
|
monthly: number | null;
|
|
term: string;
|
|
features: string[];
|
|
optional: string[];
|
|
cta: string;
|
|
popular?: boolean;
|
|
subtext?: string;
|
|
};
|
|
|
|
const formatMonthly = (
|
|
value: number,
|
|
yearly: boolean,
|
|
lang: PricingTableProps["lang"]
|
|
) => {
|
|
const discounted = yearly ? Math.round(value * 0.85) : value;
|
|
return `${discounted} €/${lang === "es" ? "mes" : "mo"}`;
|
|
};
|
|
|
|
export default function PricingTable({ lang, onContact }: PricingTableProps) {
|
|
const [yearly, setYearly] = useState(false);
|
|
const [showFairUse, setShowFairUse] = useState(false);
|
|
|
|
const pricingContent = useMemo(
|
|
() => ({
|
|
es: {
|
|
labels: {
|
|
popular: "Más popular",
|
|
setup: "Instalación",
|
|
billedAnnually: "(facturado anualmente)",
|
|
},
|
|
plans: [
|
|
{
|
|
id: "starter",
|
|
name: "Smart Starter",
|
|
setup: "900 €",
|
|
monthly: 299,
|
|
term: "6-12 meses",
|
|
features: [
|
|
"Chat IA en la web (1 idioma)",
|
|
"Reservas y captación de leads",
|
|
"Bandeja ligera de leads",
|
|
"Analíticas básicas",
|
|
],
|
|
optional: ["+WhatsApp (+100€/mes)", "+Idioma extra (+80€/mes)"],
|
|
cta: "Empezar",
|
|
},
|
|
{
|
|
id: "site",
|
|
name: "Smart Site",
|
|
setup: "3.500 €",
|
|
monthly: 749,
|
|
term: "6-12 meses",
|
|
features: [
|
|
"Todo lo incluido en Starter",
|
|
"Nuevo sitio web Next.js",
|
|
"WhatsApp incluido",
|
|
"2 idiomas (ES+EN)",
|
|
"Sugerencias de contenido con IA",
|
|
"Analíticas avanzadas",
|
|
],
|
|
optional: [
|
|
"+Llamadas de voz (+150€/mes)",
|
|
"+Ubicación extra (+120€/mes)",
|
|
],
|
|
cta: "Empezar",
|
|
popular: true,
|
|
},
|
|
{
|
|
id: "growth",
|
|
name: "AI Growth Partner",
|
|
setup: "5.000 €",
|
|
monthly: 1950,
|
|
term: "12 meses",
|
|
features: [
|
|
"Todo lo incluido en Smart Site",
|
|
"Llamadas de voz incluidas",
|
|
"Soporte multiubicación",
|
|
"Integraciones CRM",
|
|
"Automatizaciones personalizadas",
|
|
"Llamada estratégica mensual",
|
|
"Soporte prioritario",
|
|
],
|
|
optional: ["+Pack de contenido IA (+200€/mes)"],
|
|
cta: "Empezar",
|
|
},
|
|
{
|
|
id: "enterprise",
|
|
name: "Enterprise / A medida",
|
|
setup: "Personalizado",
|
|
monthly: null,
|
|
term: "Definimos el alcance contigo",
|
|
features: [
|
|
"Todo a medida",
|
|
"Multimarca y white-label",
|
|
"Account manager dedicado",
|
|
"SLA de rendimiento",
|
|
],
|
|
optional: [],
|
|
cta: "Contactar",
|
|
subtext: "Hablemos",
|
|
},
|
|
] satisfies Plan[],
|
|
},
|
|
en: {
|
|
labels: {
|
|
popular: "Most popular",
|
|
setup: "Setup",
|
|
billedAnnually: "(billed annually)",
|
|
},
|
|
plans: [
|
|
{
|
|
id: "starter",
|
|
name: "Smart Starter",
|
|
setup: "900 €",
|
|
monthly: 299,
|
|
term: "6-12 months",
|
|
features: [
|
|
"AI website chat (1 language)",
|
|
"Booking & lead capture",
|
|
"Light lead inbox",
|
|
"Basic analytics",
|
|
],
|
|
optional: ["+WhatsApp (+100€/mo)", "+Extra language (+80€/mo)"],
|
|
cta: "Get started",
|
|
},
|
|
{
|
|
id: "site",
|
|
name: "Smart Site",
|
|
setup: "3,500 €",
|
|
monthly: 749,
|
|
term: "6-12 months",
|
|
features: [
|
|
"Everything in Starter",
|
|
"New Next.js website",
|
|
"WhatsApp included",
|
|
"2 languages (ES+EN)",
|
|
"AI content suggestions",
|
|
"Advanced analytics",
|
|
],
|
|
optional: ["+Voice calls (+150€/mo)", "+Extra location (+120€/mo)"],
|
|
cta: "Get started",
|
|
popular: true,
|
|
},
|
|
{
|
|
id: "growth",
|
|
name: "AI Growth Partner",
|
|
setup: "5,000 €",
|
|
monthly: 1950,
|
|
term: "12 months",
|
|
features: [
|
|
"Everything in Smart Site",
|
|
"Voice calls included",
|
|
"Multi-location support",
|
|
"CRM integrations",
|
|
"Custom automations",
|
|
"Monthly strategy call",
|
|
"Priority support",
|
|
],
|
|
optional: ["+AI content pack (+200€/mo)"],
|
|
cta: "Get started",
|
|
},
|
|
{
|
|
id: "enterprise",
|
|
name: "Enterprise / Custom",
|
|
setup: "Custom",
|
|
monthly: null,
|
|
term: "Let us scope it",
|
|
features: [
|
|
"Everything tailored",
|
|
"Multi-brand & white-label",
|
|
"Dedicated account manager",
|
|
"Performance SLAs",
|
|
],
|
|
optional: [],
|
|
cta: "Contact us",
|
|
subtext: "Let us talk",
|
|
},
|
|
] satisfies Plan[],
|
|
},
|
|
}),
|
|
[]
|
|
);
|
|
|
|
const pricing = pricingContent[lang];
|
|
const plans = pricing.plans;
|
|
|
|
return (
|
|
<div className="mt-10">
|
|
<div className="flex flex-col items-center justify-between gap-4 rounded-2xl border border-white/15 bg-white/10 p-5 text-center backdrop-blur md:flex-row md:text-left">
|
|
<div>
|
|
<p className="text-sm font-semibold uppercase tracking-[0.2em] text-white/70">
|
|
{lang === "es" ? "Pago anual" : "Pay yearly"}
|
|
</p>
|
|
<p className="mt-2 text-base text-white/90">
|
|
{lang === "es"
|
|
? "Paga anual y ahorra 15%"
|
|
: "Pay yearly - Save 15%"}
|
|
</p>
|
|
</div>
|
|
<label className="flex items-center gap-3 rounded-full border border-white/25 bg-white/10 px-4 py-2 text-sm font-semibold text-white">
|
|
<span>{lang === "es" ? "Descuento 15%" : "Save 15%"}</span>
|
|
<button
|
|
type="button"
|
|
onClick={() => setYearly((prev) => !prev)}
|
|
className={`relative h-6 w-12 rounded-full transition ${
|
|
yearly ? "bg-brand-pink" : "bg-white/20"
|
|
}`}
|
|
>
|
|
<span
|
|
className={`absolute left-1 top-1 h-4 w-4 rounded-full bg-white transition ${
|
|
yearly ? "translate-x-6" : ""
|
|
}`}
|
|
/>
|
|
</button>
|
|
</label>
|
|
</div>
|
|
|
|
<div className="mt-10 grid gap-6 lg:grid-cols-4 items-stretch">
|
|
{plans.map((plan) => (
|
|
<div
|
|
key={plan.id}
|
|
className={`flex h-full flex-col rounded-2xl border p-6 backdrop-blur transition duration-300 hover:-translate-y-2 hover:shadow-[0_25px_50px_-20px_rgba(118,75,162,0.65)] ${
|
|
plan.popular
|
|
? "border-brand-pink bg-white/12"
|
|
: "border-white/15 bg-white/8"
|
|
}`}
|
|
>
|
|
{plan.popular && (
|
|
<span className="inline-flex rounded-full bg-brand-pink/20 px-3 py-1 text-xs font-semibold text-white">
|
|
{pricing.labels.popular}
|
|
</span>
|
|
)}
|
|
<h3 className="mt-4 text-xl font-semibold">{plan.name}</h3>
|
|
<p className="mt-2 text-sm text-white/70">
|
|
{pricing.labels.setup}: {plan.setup}
|
|
</p>
|
|
<p className="mt-6 text-3xl font-bold">
|
|
{plan.monthly === null
|
|
? plan.subtext
|
|
: formatMonthly(plan.monthly, yearly, lang)}
|
|
</p>
|
|
<p className="mt-2 text-sm text-white/70">
|
|
{plan.term}
|
|
{plan.monthly !== null && yearly && (
|
|
<span className="block text-xs text-white/60">
|
|
{pricing.labels.billedAnnually}
|
|
</span>
|
|
)}
|
|
</p>
|
|
<ul className="mt-6 space-y-2 text-sm text-white/90">
|
|
{plan.features.map((feature) => (
|
|
<li key={feature}>• {feature}</li>
|
|
))}
|
|
</ul>
|
|
{plan.optional.length > 0 && (
|
|
<div className="mt-4 text-xs text-white/60">
|
|
{plan.optional.map((option) => (
|
|
<p key={option}>{option}</p>
|
|
))}
|
|
</div>
|
|
)}
|
|
<button
|
|
onClick={onContact}
|
|
className="mt-auto w-full rounded-lg bg-brand-pink px-4 py-2 text-sm font-semibold text-white transition hover:-translate-y-1 hover:bg-[#ff7bc0]"
|
|
>
|
|
{plan.cta}
|
|
</button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<p className="mt-6 text-center text-xs text-white/70">
|
|
Todos los planes incluyen un uso generoso de IA para un negocio típico.
|
|
Se aplica una{" "}
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowFairUse(true)}
|
|
className="font-semibold text-white underline decoration-white/60 underline-offset-4"
|
|
>
|
|
política de uso justo
|
|
</button>
|
|
, sin cargos sorpresa.
|
|
</p>
|
|
|
|
{showFairUse && (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center px-4">
|
|
<div
|
|
className="absolute inset-0 bg-black/60 backdrop-blur-sm"
|
|
onClick={() => setShowFairUse(false)}
|
|
/>
|
|
<div className="relative z-10 w-full max-w-2xl rounded-2xl border border-white/20 bg-white/10 p-8 text-white shadow-purple-soft backdrop-blur">
|
|
<div className="flex items-start justify-between gap-4">
|
|
<div>
|
|
<p className="text-sm uppercase tracking-[0.3em] text-white/70">
|
|
Uso justo
|
|
</p>
|
|
<h3 className="mt-3 text-2xl font-bold">
|
|
Qué significa "uso justo"?
|
|
</h3>
|
|
</div>
|
|
<button
|
|
onClick={() => setShowFairUse(false)}
|
|
className="rounded-full border border-white/40 px-3 py-1 text-xs font-semibold text-white/80 transition hover:bg-white/10 hover:text-white"
|
|
>
|
|
Cerrar
|
|
</button>
|
|
</div>
|
|
<div className="mt-6 space-y-4 text-sm text-white/85">
|
|
<p>
|
|
Cada plan incluye suficientes mensajes de IA, llamadas y
|
|
conversaciones de WhatsApp para un negocio típico de tu tamaño.
|
|
</p>
|
|
<p>
|
|
Si tu uso se mantiene muy por encima de lo normal (por ejemplo,
|
|
porque añades nuevas marcas, locales o campañas), haremos lo
|
|
siguiente:
|
|
</p>
|
|
<ol className="list-decimal space-y-2 pl-5">
|
|
<li>Te avisaremos primero.</li>
|
|
<li>Te enviaremos un informe sencillo de uso.</li>
|
|
<li>
|
|
Te propondremos opciones (seguir igual con algunos límites o
|
|
subir de plan / añadir más capacidad).
|
|
</li>
|
|
</ol>
|
|
<p>
|
|
Nunca aplicamos cargos extra sin hablar contigo antes.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|