Initial commit
This commit is contained in:
@@ -0,0 +1,348 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user