Files
FRASA-CAS/apps/cobranza/src/components/Semaforo.tsx
Consult AS Technology 599dce2629 style: reskin NovaSpark en las 7 apps
Del look editorial (verde #1B4332, esquinas a 0, botones en mayusculas)
al sistema NovaSpark: primario azul #2563EB, detalle naranja #F97316,
fondo #F8FAFC con tarjetas blancas rounded-xl + shadow-sm, chips
rounded-full semanticos, focus ring azul, transiciones 100-200ms.
Incluye headers de tabla en los PDFs (cotizador y estado de cuenta).
2026-09-03 02:35:34 +00:00

46 lines
1.4 KiB
TypeScript

import type { PlanPago } from '../types'
import { diasParaProximoVencimiento, statusPago, statusPlan } from '../lib/cobranza'
export type Semaforo = 'VERDE' | 'AMBAR' | 'ROJO' | 'GRIS'
const ETIQUETA: Record<Semaforo, string> = {
VERDE: 'Al corriente',
AMBAR: 'Por vencer / parcial',
ROJO: 'Vencido',
GRIS: 'Cerrado',
}
const CLASE_DOT: Record<Semaforo, string> = {
VERDE: 'bg-green-50 text-green-700',
AMBAR: 'bg-amber-50 text-amber-700',
ROJO: 'bg-red-50 text-red-700',
GRIS: 'bg-gray-100 text-gray-600',
}
/**
* Semáforo del plan:
* - gris: LIQUIDADO o CANCELADO
* - rojo: tiene pagos VENCIDOS
* - ámbar: tiene un pago PARCIAL o el próximo vencimiento es en 7 días o menos
* - verde: al corriente
*/
export function semaforoPlan(plan: PlanPago, hoy: Date = new Date()): Semaforo {
if (statusPlan(plan) !== 'ACTIVO') return 'GRIS'
const estados = plan.pagos.map((p) => statusPago(p, hoy))
if (estados.includes('VENCIDO')) return 'ROJO'
if (estados.includes('PARCIAL')) return 'AMBAR'
const dias = diasParaProximoVencimiento(plan, hoy)
if (dias !== null && dias <= 7) return 'AMBAR'
return 'VERDE'
}
export default function SemaforoDot({ valor }: { valor: Semaforo }) {
return (
<span
className={`inline-block rounded-full px-2.5 py-0.5 text-xs font-medium ${CLASE_DOT[valor]}`}
>
{ETIQUETA[valor]}
</span>
)
}