feat(9-mejoras): limpieza leads + admin CRUD + calendario + CRM360 FRASA

1. Leads limpiados (207 eliminados, 18 apartados conservados)
2. Round-robin desactivado (config round_robin_habilitado=false)
3. Admin puede borrar/reasignar/mover leads (DELETE/PATCH/POST)
4. Calendario: fechaCita guardada y pasada correctamente
5. Avisos Monday eliminados (BannerModoLocal, ChipPendienteSync, vinculación)
6. Contactos filtrados por usuario asignado
7. Modal bitácora: notas persisten entre fases
8. Fases oportunidades: Agendo→Afluencia→Cotizar→Aparto
9. Toast de nota eliminado en cambios de status
10. Branding: CRM360 FRASA + logo en todas las apps
11. 7 apps construidas
This commit is contained in:
2026-09-10 07:05:40 +00:00
parent 356bf46216
commit 16cacd5f31
43 changed files with 246 additions and 190 deletions

View File

@@ -117,6 +117,8 @@ export interface OportunidadMiDia {
updatedAt: string
/** Último evento del activity log del board; null si el item no tiene eventos */
ultimoCambio: { fechaISO: string; usuario: string | null; detalle: string } | null
/** Fecha y hora de la cita agendada (ej. '2026-09-10T14:30' o '2026-09-10') */
fechaCita?: string | undefined
/** true = captura local aún no sincronizada a Monday (badge ⏳ del front; aditivo) */
pendienteSync?: boolean
}
@@ -319,6 +321,7 @@ export async function resumenMiDia(
unidadCodigo: o.unidadCodigo,
updatedAt: o.updatedAt,
ultimoCambio: null,
fechaCita: o.fechaCita,
}))
.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))
@@ -681,11 +684,13 @@ export function resumenMiDiaLocal(
.filter((c) => !esEtapaTerminal(c.etapa))
.map((c) => {
let unidadCodigo = ''
let fechaCita: string | undefined
if (c.datosJson) {
try {
const datos = JSON.parse(c.datosJson) as Record<string, unknown>
if (typeof datos.unidadCodigo === 'string' && datos.unidadCodigo !== '') unidadCodigo = datos.unidadCodigo
else if (typeof datos.desarrollo === 'string' && datos.desarrollo !== '') unidadCodigo = datos.desarrollo
if (typeof datos.fechaCita === 'string') fechaCita = datos.fechaCita
} catch { /* datosJson corrupto: ignorar */ }
}
return {
@@ -699,6 +704,7 @@ export function resumenMiDiaLocal(
unidadCodigo,
updatedAt: c.updatedAt.toISOString(),
ultimoCambio: ultimoCambioLocal(c, usuario.nombre),
fechaCita,
pendienteSync: c.pendienteSync,
}
})
@@ -962,6 +968,7 @@ export function unirPendientesLocales(
unidadCodigo: '',
updatedAt: p.updatedAt.toISOString(),
ultimoCambio: ultimoCambioLocal(p, nombreUsuario),
fechaCita: (() => { try { const d = JSON.parse(p.datosJson ?? '{}') as Record<string, unknown>; return typeof d.fechaCita === 'string' ? d.fechaCita : undefined } catch { return undefined } })(),
pendienteSync: true,
})
}