$24.990 CLP al mes · IVA incluido
- 10 usuarios
- Exportaciones ilimitadas
- Soporte prioritario
Patrón canónico de plan comercial para cis-admin, cis-infra, cis-inbox, usaia y servicios internos.
Primero el componente, después la variación de marca y finalmente su uso dentro de una página.
$24.990 CLP al mes · IVA incluido
$24.990 CLP al mes · IVA incluido · cobro rechazado el 25 sep
$24.990 CLP al mes · IVA incluido
<section class="ui-sample ui-service" data-billing-plan="true"><header><strong>Plan Equipo</strong><span class="badge badge--ok">Vigente</span></header><p><b>$24.990 CLP</b> al mes · IVA incluido</p><ul><li>10 usuarios</li><li>Exportaciones ilimitadas</li><li>Soporte prioritario</li></ul><a class="btn btn--secondary" href="#plan">Administrar plan</a></section>Cada cambio visible declara su autoridad; lo que permanece canónico no se vuelve a inventar en el producto.
$24.990 CLP al mes · IVA incluido
$24.990 CLP al mes · IVA incluido · cobro rechazado el 25 sep
Compara la propuesta con cortes reales del repositorio. La ausencia de una muestra se declara y nunca se reconstruye de memoria.
Preparando comparación histórica…
La comparación convierte una regla abstracta en una diferencia visible y verificable.
$24.990 CLP al mes · IVA incluido
La misma anatomía debe conservar lectura, foco y acciones sin cortar contenido ni crear scroll horizontal en la página.
$24.990 CLP al mes · IVA incluido
$24.990 CLP al mes · IVA incluido · cobro rechazado el 25 sep
| Dimensión | Contrato |
|---|---|
| Propietario canónico | Sistema de diseño CIS e Infraestructura · core/core-style |
| Consumidores | cis-admin, cis-infra, cis-inbox, usaia y servicios internos |
| Dependencias | API del servicio, recibos verificables |
| Estado | candidato |
Patrón propuesto. 0 implementaciones observadas en 0 repositorios.
La observación demuestra uso existente; la aceptación canónica sigue dependiendo de esta ficha y de su propietario.
| Dato | Resultado |
|---|---|
| Clasificación | Patrón propuesto |
| Implementaciones | 0 implementaciones observadas |
| Repositorios | Ningún repositorio observado |
| Snapshot | kit/componentes/componentes-observados.json |
El inventario conserva repositorio, archivo fuente y criterio de asociación. Observar una implementación no la convierte automáticamente en canónica.
| Estado requerido |
|---|
| operativo |
| degradado |
| fallido |
| sin datos |
Copia el bloque completo; después cambia contenido y destinos, no su anatomía.
<section class="ui-sample ui-service" data-billing-plan="true"><header><strong>Plan Equipo</strong><span class="badge badge--ok">Vigente</span></header><p><b>$24.990 CLP</b> al mes · IVA incluido</p><ul><li>10 usuarios</li><li>Exportaciones ilimitadas</li><li>Soporte prioritario</li></ul><a class="btn btn--secondary" href="#plan">Administrar plan</a></section>Copia el bloque completo; después cambia contenido y destinos, no su anatomía.
<section class="ui-sample ui-service border border-slate-300 bg-white p-4 text-slate-950 grid gap-3" data-billing-plan="true"><header class="flex flex-wrap items-center justify-between gap-3"><strong>Plan Equipo</strong><span class="badge badge--ok">Vigente</span></header><p><b>$24.990 CLP</b> al mes · IVA incluido</p><ul class="grid gap-2"><li>10 usuarios</li><li>Exportaciones ilimitadas</li><li>Soporte prioritario</li></ul><a class="btn btn--secondary underline underline-offset-4" href="#plan">Administrar plan</a></section>Copia el bloque completo; después cambia contenido y destinos, no su anatomía.
export interface BillingPlanFeature {
/** Qué incluye el plan, en una frase corta («10 usuarios»). */
label: string;
}
export interface BillingPlanProps {
/** Nombre del plan. */
title?: string;
/** Estado de la suscripción: vigente, próxima renovación, pago pendiente o vencida; se muestra como etiqueta y vacío la oculta. */
status?: string;
/** Tono de la etiqueta de estado; por defecto se deduce del texto (vigente o activo: `ok`; pago pendiente: `warn`; vencida, suspendida o cancelada: `err`; otro: `neutral`). */
statusTone?: "ok" | "warn" | "err" | "neutral";
/** Precio con moneda, en negrita; vacío lo oculta. */
price?: string;
/** Período de cobro e impuestos, después del precio; vacío lo oculta. */
detail?: string;
/** Lo que incluye el plan; sin elementos no se muestra la lista. */
features?: BillingPlanFeature[];
/** URL de la página para administrar la suscripción. */
href?: string;
/** Texto del enlace para administrar la suscripción; vacío lo oculta. */
linkLabel?: string;
className?: string;
}
const FEATURES: BillingPlanFeature[] = [
{ label: "10 usuarios" },
{ label: "Exportaciones ilimitadas" },
{ label: "Soporte prioritario" },
];
const BILLING_PLAN_TONOS: [string, "ok" | "warn" | "err" | "neutral"][] = [
["vigente", "ok"],
["activ", "ok"],
["pago pendiente", "warn"],
["pendiente", "warn"],
["vencid", "err"],
["suspendid", "err"],
["cancelad", "err"],
];
function claseEstado(status: string, tone?: "ok" | "warn" | "err" | "neutral") {
const texto = status.toLowerCase();
const tono = tone ?? BILLING_PLAN_TONOS.find(([clave]) => texto.startsWith(clave))?.[1] ?? "neutral";
return tono === "neutral" ? "badge" : `badge badge--${tono}`;
}
/**
* Plan de suscripción de la cuenta, con nombre, estado, precio, lo que incluye y un enlace para administrarlo; se usa en la sección de facturación.
*
* El estado va en texto dentro de una etiqueta con tono (`badge`), no sólo en color; el enlace para administrar el plan es una acción secundaria (`btn--secondary`).
*
* @example <BillingPlan title="Plan Equipo" status="Renueva el 4 sep" price="$24.990 CLP" detail="al mes · IVA incluido" features={[{ label: "10 usuarios" }, { label: "Soporte prioritario" }]} href="/cuenta/plan" />
* @example <BillingPlan status="Pago pendiente" detail="al mes · IVA incluido · cobro rechazado el 25 sep" href="/cuenta/pago" linkLabel="Actualizar medio de pago" />
*/
export function BillingPlan({
title = "Plan Equipo",
status = "Vigente",
statusTone,
price = "$24.990 CLP",
detail = "al mes · IVA incluido",
features = FEATURES,
href = "#plan",
linkLabel = "Administrar plan",
className,
}: BillingPlanProps) {
return (
<section className={["ui-service", className].filter(Boolean).join(" ")} data-billing-plan>
<header>
<strong>{title}</strong>
{status ? <span className={claseEstado(status, statusTone)}>{status}</span> : null}
</header>
{price || detail ? (
<p>
{price ? <b>{price}</b> : null}
{detail ? (price ? ` ${detail}` : detail) : null}
</p>
) : null}
{features.length ? (
<ul>
{features.map((feature, i) => <li key={`${feature.label}-${i}`}>{feature.label}</li>)}
</ul>
) : null}
{linkLabel ? <a className="btn btn--secondary" href={href}>{linkLabel}</a> : null}
</section>
);
}