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:
@@ -1,6 +1,7 @@
|
||||
import type { Unidad, TipoPropuesta } from '../types'
|
||||
import { INVENTARIO_SEED } from '../data/unidades'
|
||||
import { conAuth, manejar401 } from './auth'
|
||||
import { guardarUnidades, cargarUnidadesLocal } from './offline-db'
|
||||
|
||||
// TODO produccion: '/api' same-origin detras de NGINX
|
||||
const API_URL = import.meta.env.VITE_API_URL ?? '/api'
|
||||
@@ -24,9 +25,15 @@ export async function getUnidades(): Promise<GetUnidadesResult> {
|
||||
manejar401(resp)
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
||||
const unidades = (await resp.json()) as Unidad[]
|
||||
// Cache en IDB para uso offline
|
||||
void guardarUnidades(unidades)
|
||||
return { unidades, usandoSeed: false }
|
||||
} catch (err) {
|
||||
console.warn('[api] No se pudo obtener el inventario del API; usando seed local.', err)
|
||||
console.warn('[api] No se pudo obtener el inventario del API; intentando cache offline.', err)
|
||||
const cached = await cargarUnidadesLocal()
|
||||
if (cached && Array.isArray(cached) && cached.length > 0) {
|
||||
return { unidades: cached as Unidad[], usandoSeed: true }
|
||||
}
|
||||
return { unidades: INVENTARIO_SEED, usandoSeed: true }
|
||||
}
|
||||
}
|
||||
|
||||
33
apps/cotizador/src/services/offline-db.ts
Normal file
33
apps/cotizador/src/services/offline-db.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { openDB, type IDBPDatabase } from 'idb'
|
||||
|
||||
const DB_NAME = 'frasa-cotizador'
|
||||
const DB_VERSION = 1
|
||||
|
||||
async function getDB(): Promise<IDBPDatabase> {
|
||||
return openDB(DB_NAME, DB_VERSION, {
|
||||
upgrade(db) {
|
||||
if (!db.objectStoreNames.contains('unidades')) db.createObjectStore('unidades')
|
||||
if (!db.objectStoreNames.contains('cotizaciones')) db.createObjectStore('cotizaciones')
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export async function guardarUnidades(unidades: unknown[]) {
|
||||
const db = await getDB()
|
||||
await db.put('unidades', unidades, 'actual')
|
||||
}
|
||||
|
||||
export async function cargarUnidadesLocal() {
|
||||
const db = await getDB()
|
||||
return db.get('unidades', 'actual')
|
||||
}
|
||||
|
||||
export async function guardarCotizaciones(cotizaciones: unknown[]) {
|
||||
const db = await getDB()
|
||||
await db.put('cotizaciones', cotizaciones, 'historial')
|
||||
}
|
||||
|
||||
export async function cargarCotizacionesLocal() {
|
||||
const db = await getDB()
|
||||
return db.get('cotizaciones', 'historial')
|
||||
}
|
||||
Reference in New Issue
Block a user