feat: ecosistema FRASA — apps Cotizador, Alta Clientes, Cobranza y Landing

- Cotizador (/quote): 4 propuestas con formulas validadas del Excel, comparador,
  combobox de unidades, vigencia, PDF ANEXO A
- Alta Clientes (/client): wizard 8 pasos, validacion CURP RENAPO, OCR de INE,
  checklist de expediente, firma digital, 5 PDFs legales
- Cobranza (/pay): planes de enganche, mora, vista cobranza del dia, recibos PDF,
  bitacora, dashboard con filtros
- Landing (/): entrada al ecosistema
- Design system StudioBlank (monocromo, acento #1B4332) en las 4 apps
- 123 tests vitest
This commit is contained in:
2026-08-21 22:27:36 +00:00
commit ecd4edac02
147 changed files with 27345 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
const formatoMXN = new Intl.NumberFormat('es-MX', {
style: 'currency',
currency: 'MXN',
})
/** Formato monetario MXN, p. ej. $4,579,000.00 */
export function formatoMoneda(valor: number): string {
return formatoMXN.format(valor)
}
/** Fracción (0.02) a texto porcentaje (2%) */
export function formatoPorcentaje(fraccion: number): string {
return `${(fraccion * 100).toLocaleString('es-MX', { maximumFractionDigits: 2 })}%`
}
/** Fecha en formato largo es-MX: "20 de agosto de 2026" */
export function formatoFechaLarga(fecha: Date): string {
return fecha.toLocaleDateString('es-MX', { day: 'numeric', month: 'long', year: 'numeric' })
}
/** ISO 'YYYY-MM-DD' a fecha legible corta: "08/10/2027" */
export function formatoFechaCorta(iso: string): string {
return new Date(`${iso}T00:00:00`).toLocaleDateString('es-MX', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
}
/** Fecha ISO del día (para nombre de archivo): 'YYYY-MM-DD' */
export function fechaISOHoy(fecha: Date = new Date()): string {
const y = fecha.getFullYear()
const m = String(fecha.getMonth() + 1).padStart(2, '0')
const d = String(fecha.getDate()).padStart(2, '0')
return `${y}-${m}-${d}`
}