feat(mejoras): 22 mejoras UX en todos los módulos

Mi día: cancelación con motivo, conteo escrituración real, cita sin retroceder, calendario completo
Cobranza: MoraDashboard respeta alcance, hoy dinámico, cancelar con motivo
Landing: contactos paginados, error vs vacío diferenciado
Dashboards: KPI renombrado, drill-down planes activos
Chat: historial recarga, preguntas rotativas, error solo toast
Transversal: shadow-sm corrupto corregido en 9 archivos

553 API tests + 7 apps construidas
This commit is contained in:
2026-09-11 12:48:47 +00:00
parent 89d95eb53b
commit 1ba7aa49da
28 changed files with 518 additions and 160 deletions

View File

@@ -0,0 +1,24 @@
import { describe, expect, it } from 'vitest'
import { DESARROLLOS, preguntasSugeridas } from './vocabulario'
describe('preguntasSugeridas', () => {
it('devuelve 4 preguntas, cada una de un desarrollo distinto', () => {
const preguntas = preguntasSugeridas(new Date('2026-09-11T12:00:00'))
expect(preguntas).toHaveLength(4)
const usados = DESARROLLOS.filter((d) => preguntas.some((p) => p.includes(d)))
expect(usados).toHaveLength(4)
})
it('rota día con día: dos fechas consecutivas no comparten desarrollo en la primera pregunta', () => {
const lunes = preguntasSugeridas(new Date('2026-09-07T00:00:00'))
const martes = preguntasSugeridas(new Date('2026-09-08T00:00:00'))
expect(lunes[0]).not.toBe(martes[0])
})
it('tras DESARROLLOS.length días vuelve a la combinación inicial', () => {
const base = new Date('2026-01-01T00:00:00')
const inicial = preguntasSugeridas(base)
const vuelta = preguntasSugeridas(new Date(base.getTime() + DESARROLLOS.length * 86_400_000))
expect(vuelta).toEqual(inicial)
})
})

View File

@@ -0,0 +1,33 @@
/**
* Espejo del vocabulario del API (api-gateway/src/config/vocabulario.ts):
* DESARROLLOS es la lista canónica de desarrollos FRASA. Mantener sincronizado.
*/
export const DESARROLLOS = ['ATELIER', 'DIAGONAL', 'ESTANZA', 'SENDA', 'SOLANA'] as const
/** Plantillas de preguntas sugeridas, parametrizadas por desarrollo */
const PLANTILLAS: ((desarrollo: string) => string)[] = [
(d) => `¿Qué modelos hay en el catálogo ${d}?`,
(d) => `¿Qué incluye la propuesta del cotizador ${d}?`,
(d) => `¿Cuál es la disponibilidad de unidades en ${d}?`,
(d) => `¿Qué amenidades y ubicación tiene ${d}?`,
]
/** Día del año (1..366) para la rotación diaria */
function diaDelAnio(fecha: Date): number {
const inicio = Date.UTC(fecha.getFullYear(), 0, 1)
const actual = Date.UTC(fecha.getFullYear(), fecha.getMonth(), fecha.getDate())
return Math.round((actual - inicio) / 86_400_000) + 1
}
/**
* Preguntas sugeridas rotativas: cada una toma un desarrollo distinto
* (VOCABULARIO.DESARROLLOS) y la combinación avanza día con día, de modo que
* las sugerencias del chat rotan por desarrollo sin repetirse el mismo día.
*/
export function preguntasSugeridas(fecha: Date = new Date()): string[] {
const dia = diaDelAnio(fecha)
return PLANTILLAS.map((plantilla, i) => {
const desarrollo = DESARROLLOS[(dia + i) % DESARROLLOS.length]!
return plantilla(desarrollo)
})
}