feat(mejoras): 14 mejoras al CRM Frasa

Fase 1 - UI: dark mode, skeletons, toasts
Fase 2 - Filtros: avanzados Mi día, búsqueda global Ctrl+K
Fase 3 - Datos: export Excel, notas apartados, auditoría
Fase 4 - Dashboard: gráficas vendedor + métricas uso
Fase 5 - Responsive: tablets optimizadas
Fase 6 - PWA: IndexedDB offline, push notifications

Backend: 3 tablas nuevas, 6 services, 6 endpoints nuevos
721 API tests + fronts verdes.
This commit is contained in:
2026-09-07 06:04:49 +00:00
parent 388e1da338
commit c77b4c0628
170 changed files with 5802 additions and 637 deletions

View File

@@ -0,0 +1,41 @@
import type { Request, Response } from 'express'
import { z } from 'zod'
import {
registrarSuscripcion,
eliminarSuscripcion,
obtenerVapidPublicKey,
} from '../services/push.service.js'
const suscripcionSchema = z.object({
endpoint: z.string().url(),
p256dh: z.string().min(1),
auth: z.string().min(1),
})
/** POST /api/push/suscribir — registrar suscripción push del navegador */
export async function suscribirEndpoint(req: Request, res: Response): Promise<void> {
const usuarioId = req.usuarioToken?.sub
if (!usuarioId) {
res.status(401).json({ error: 'Token requerido' })
return
}
const body = suscripcionSchema.parse(req.body)
await registrarSuscripcion(usuarioId, body)
res.json({ ok: true })
}
/** POST /api/push/desuscribir — eliminar suscripción push */
export async function desuscribirEndpoint(req: Request, res: Response): Promise<void> {
const usuarioId = req.usuarioToken?.sub
if (!usuarioId) {
res.status(401).json({ error: 'Token requerido' })
return
}
await eliminarSuscripcion(usuarioId)
res.json({ ok: true })
}
/** GET /api/push/vapid-key — devuelve la VAPID public key (pública) */
export function vapidKeyEndpoint(_req: Request, res: Response): void {
res.json({ publicKey: obtenerVapidPublicKey() })
}