Fix: Eliminar re-renderizados usando mutaciones directas en lugar de clonaciones
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m4s

- Modificar useIndexedDB para no reemplazar sesionActiva en actualizar()
- Modificar useCatacion para mutar directamente las propiedades
- Eliminar todas las clonaciones con JSON.parse/stringify
- Mantener referencias de objetos estables para Vue reactivity
This commit is contained in:
2025-10-18 03:36:13 -06:00
parent 9daafc2a3e
commit f17ff66613
3 changed files with 25 additions and 45 deletions

View File

@@ -8,14 +8,17 @@
<script setup lang="ts"> <script setup lang="ts">
const { isAuthenticated } = useAuthentik() const { isAuthenticated } = useAuthentik()
const { inicializar } = useColorCustomization() const { inicializar, getCurrentColors } = useColorCustomization()
// Inicializar personalización de colores // Inicializar personalización de colores
onMounted(() => { onMounted(() => {
inicializar() inicializar()
}) })
// Configurar meta tags para PWA // Color de tema reactivo basado en el background del tema actual
const themeColor = computed(() => getCurrentColors.value.background)
// Configurar meta tags para PWA con theme-color reactivo
useHead({ useHead({
link: [ link: [
{ rel: 'manifest', href: '/manifest.webmanifest' }, { rel: 'manifest', href: '/manifest.webmanifest' },
@@ -23,7 +26,7 @@ useHead({
{ rel: 'apple-touch-icon', href: '/apple-touch-icon.png' } { rel: 'apple-touch-icon', href: '/apple-touch-icon.png' }
], ],
meta: [ meta: [
{ name: 'theme-color', content: '#00DC82' }, { name: 'theme-color', content: themeColor },
{ name: 'mobile-web-app-capable', content: 'yes' }, { name: 'mobile-web-app-capable', content: 'yes' },
{ name: 'apple-mobile-web-app-capable', content: 'yes' }, { name: 'apple-mobile-web-app-capable', content: 'yes' },
{ name: 'apple-mobile-web-app-status-bar-style', content: 'default' } { name: 'apple-mobile-web-app-status-bar-style', content: 'default' }

View File

@@ -40,33 +40,22 @@ export const useCatacion = () => {
} }
try { try {
const sesionClonada = JSON.parse(JSON.stringify(sesionActiva.value)) as SesionCatacion const muestra = sesionActiva.value.muestras.find(m => m.muestraId === muestraId)
const indexMuestra = sesionClonada.muestras.findIndex(m => m.muestraId === muestraId)
if (indexMuestra === -1) { if (!muestra) {
throw new Error(`Muestra con ID ${muestraId} no encontrada`) throw new Error(`Muestra con ID ${muestraId} no encontrada`)
} }
// Actualizar muestra // Actualizar muestra directamente (mutación)
const muestraActual = sesionClonada.muestras[indexMuestra] Object.assign(muestra, muestraActualizada)
if (!muestraActual) {
throw new Error(`Muestra con ID ${muestraId} no encontrada`)
}
sesionClonada.muestras[indexMuestra] = {
...muestraActual,
...muestraActualizada,
} as Muestra
// Recalcular puntaje final si hay cambios en intensidades // Recalcular puntaje final si hay cambios en intensidades
if (muestraActualizada.intensidades) { if (muestraActualizada.intensidades) {
const muestraFinal = sesionClonada.muestras[indexMuestra] muestra.puntajeFinal = calcularPuntajeFinal(muestra)
if (muestraFinal) {
sesionClonada.muestras[indexMuestra]!.puntajeFinal = calcularPuntajeFinal(muestraFinal)
}
} }
await actualizar(sesionClonada) // Guardar en IndexedDB
await actualizar(sesionActiva.value)
} catch (err) { } catch (err) {
console.error('Error al actualizar muestra:', err) console.error('Error al actualizar muestra:', err)
throw err throw err
@@ -87,32 +76,20 @@ export const useCatacion = () => {
} }
try { try {
const sesionClonada = JSON.parse(JSON.stringify(sesionActiva.value)) as SesionCatacion const muestra = sesionActiva.value.muestras.find(m => m.muestraId === muestraId)
const indexMuestra = sesionClonada.muestras.findIndex(m => m.muestraId === muestraId)
if (indexMuestra === -1) { if (!muestra) {
throw new Error(`Muestra con ID ${muestraId} no encontrada`) throw new Error(`Muestra con ID ${muestraId} no encontrada`)
} }
// Actualizar valor de intensidad // Actualizar valor de intensidad directamente (mutación)
const muestraActual = sesionClonada.muestras[indexMuestra] muestra.intensidades[parametro][tipo] = valor
if (!muestraActual) {
throw new Error(`Muestra con ID ${muestraId} no encontrada`)
}
const intensidadActual = muestraActual.intensidades[parametro]
sesionClonada.muestras[indexMuestra]!.intensidades[parametro] = {
...intensidadActual,
[tipo]: valor,
}
// Recalcular puntaje final // Recalcular puntaje final
const muestraFinal = sesionClonada.muestras[indexMuestra] muestra.puntajeFinal = calcularPuntajeFinal(muestra)
if (muestraFinal) {
sesionClonada.muestras[indexMuestra]!.puntajeFinal = calcularPuntajeFinal(muestraFinal)
}
await actualizar(sesionClonada) // Guardar en IndexedDB (pasa la sesión actual, no un clon)
await actualizar(sesionActiva.value)
} catch (err) { } catch (err) {
console.error('Error al actualizar intensidad:', err) console.error('Error al actualizar intensidad:', err)
throw err throw err
@@ -208,8 +185,7 @@ export const useCatacion = () => {
const obtenerMuestra = (muestraId: number): Muestra | null => { const obtenerMuestra = (muestraId: number): Muestra | null => {
if (!sesionActiva.value) return null if (!sesionActiva.value) return null
const muestra = sesionActiva.value.muestras.find(m => m.muestraId === muestraId) const muestra = sesionActiva.value.muestras.find(m => m.muestraId === muestraId)
if (!muestra) return null return muestra || null
return JSON.parse(JSON.stringify(muestra)) as Muestra
} }
/** /**
@@ -295,7 +271,7 @@ export const useCatacion = () => {
const estadisticasSesion = computed(() => { const estadisticasSesion = computed(() => {
if (!sesionActiva.value) return null if (!sesionActiva.value) return null
const muestras = JSON.parse(JSON.stringify(sesionActiva.value.muestras)) as Muestra[] const muestras = sesionActiva.value.muestras
const totalMuestras = muestras.length const totalMuestras = muestras.length
const muestrasCompletas = muestras.filter(esMuestraCompleta).length const muestrasCompletas = muestras.filter(esMuestraCompleta).length
const promedioCompletitud = muestras.reduce((acc, m) => acc + porcentajeCompletitud(m), 0) / totalMuestras const promedioCompletitud = muestras.reduce((acc, m) => acc + porcentajeCompletitud(m), 0) / totalMuestras

View File

@@ -299,7 +299,8 @@ export const useIndexedDB = () => {
cargando.value = true cargando.value = true
error.value = null error.value = null
await updateSession(sesion) await updateSession(sesion)
sesionActiva.value = sesion // NO reemplazar el objeto completo para mantener las referencias de Vue
// sesionActiva.value = sesion
} catch (err) { } catch (err) {
error.value = err as Error error.value = err as Error
console.error('Error al actualizar sesión:', err) console.error('Error al actualizar sesión:', err)
@@ -339,7 +340,7 @@ export const useIndexedDB = () => {
return { return {
// Estado // Estado
sesionActiva: readonly(sesionActiva), sesionActiva, // No readonly para permitir mutaciones directas
cargando: readonly(cargando), cargando: readonly(cargando),
error: readonly(error), error: readonly(error),
tieneSecion, tieneSecion,