Solucionado el error de eliminacion del componente
This commit is contained in:
@@ -619,20 +619,89 @@ class NegociosCardsView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
|
// Cerrar el diálogo antes de la operación asíncrona
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
final success = await provider.eliminarNegocio(negocio.id);
|
|
||||||
|
// Mostrar indicador de carga
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
showDialog(
|
||||||
SnackBar(
|
context: context,
|
||||||
content: Text(
|
barrierDismissible: false,
|
||||||
success
|
builder: (context) => Center(
|
||||||
? 'Sucursal eliminada correctamente'
|
child: CircularProgressIndicator(
|
||||||
: 'Error al eliminar la sucursal',
|
color: AppTheme.of(context).primaryColor,
|
||||||
),
|
),
|
||||||
backgroundColor: success ? Colors.green : Colors.red,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final success = await provider.eliminarNegocio(negocio.id);
|
||||||
|
|
||||||
|
// Cerrar indicador de carga
|
||||||
|
if (context.mounted) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mostrar resultado solo si el contexto sigue válido
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
success ? Icons.check_circle : Icons.error,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text(
|
||||||
|
success
|
||||||
|
? 'Sucursal eliminada correctamente'
|
||||||
|
: 'Error al eliminar la sucursal',
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
backgroundColor: success ? Colors.green : Colors.red,
|
||||||
|
behavior: SnackBarBehavior.floating,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Cerrar indicador de carga en caso de error
|
||||||
|
if (context.mounted) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mostrar error solo si el contexto sigue válido
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.warning, color: Colors.white),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'Error: $e',
|
||||||
|
style:
|
||||||
|
const TextStyle(fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
behavior: SnackBarBehavior.floating,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'Eliminar',
|
'Eliminar',
|
||||||
|
|||||||
@@ -514,20 +514,90 @@ class NegociosTable extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
|
// Cerrar el diálogo antes de la operación asíncrona
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
final success = await provider.eliminarNegocio(negocioId);
|
|
||||||
|
// Mostrar indicador de carga
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
showDialog(
|
||||||
SnackBar(
|
context: context,
|
||||||
content: Text(
|
barrierDismissible: false,
|
||||||
success
|
builder: (context) => Center(
|
||||||
? 'Sucursal eliminada correctamente'
|
child: CircularProgressIndicator(
|
||||||
: 'Error al eliminar la sucursal',
|
color: AppTheme.of(context).primaryColor,
|
||||||
),
|
),
|
||||||
backgroundColor: success ? Colors.green : Colors.red,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final success = await provider.eliminarNegocio(negocioId);
|
||||||
|
|
||||||
|
// Cerrar indicador de carga
|
||||||
|
if (context.mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mostrar resultado solo si el contexto sigue válido
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
success ? Icons.check_circle : Icons.error,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text(
|
||||||
|
success
|
||||||
|
? 'Sucursal eliminada correctamente'
|
||||||
|
: 'Error al eliminar la sucursal',
|
||||||
|
style:
|
||||||
|
const TextStyle(fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
backgroundColor: success ? Colors.green : Colors.red,
|
||||||
|
behavior: SnackBarBehavior.floating,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Cerrar indicador de carga en caso de error
|
||||||
|
if (context.mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mostrar error solo si el contexto sigue válido
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.warning, color: Colors.white),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'Error: $e',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
behavior: SnackBarBehavior.floating,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'Eliminar',
|
'Eliminar',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1255
lib/pages/infrastructure/widgets/add_componente_dialog.dart
Normal file
1255
lib/pages/infrastructure/widgets/add_componente_dialog.dart
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -62,10 +61,26 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
DetalleRouterFirewall? detalleRouterFirewall;
|
DetalleRouterFirewall? detalleRouterFirewall;
|
||||||
DetalleEquipoActivo? detalleEquipoActivo;
|
DetalleEquipoActivo? detalleEquipoActivo;
|
||||||
|
|
||||||
|
// Variable para controlar si el provider está activo
|
||||||
|
bool _isDisposed = false;
|
||||||
|
|
||||||
ComponentesProvider() {
|
ComponentesProvider() {
|
||||||
getCategorias();
|
getCategorias();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_isDisposed = true;
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Método seguro para notificar listeners
|
||||||
|
void _safeNotifyListeners() {
|
||||||
|
if (!_isDisposed) {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Métodos para categorías
|
// Métodos para categorías
|
||||||
Future<void> getCategorias([String? busqueda]) async {
|
Future<void> getCategorias([String? busqueda]) async {
|
||||||
try {
|
try {
|
||||||
@@ -82,7 +97,7 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
_buildCategoriasRows();
|
_buildCategoriasRows();
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error en getCategorias: ${e.toString()}');
|
print('Error en getCategorias: ${e.toString()}');
|
||||||
}
|
}
|
||||||
@@ -122,7 +137,7 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
_buildComponentesRows();
|
_buildComponentesRows();
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error en getComponentesPorNegocio: ${e.toString()}');
|
print('Error en getComponentesPorNegocio: ${e.toString()}');
|
||||||
}
|
}
|
||||||
@@ -177,7 +192,7 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
imagenToUpload = picker.files.single.bytes;
|
imagenToUpload = picker.files.single.bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> uploadImagen() async {
|
Future<String?> uploadImagen() async {
|
||||||
@@ -328,15 +343,44 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
Future<bool> eliminarComponente(String componenteId) async {
|
Future<bool> eliminarComponente(String componenteId) async {
|
||||||
try {
|
try {
|
||||||
|
// Primero obtener la información del componente para obtener la URL de la imagen
|
||||||
|
final componenteData = await supabaseLU
|
||||||
|
.from('componente')
|
||||||
|
.select('imagen_url')
|
||||||
|
.eq('id', componenteId)
|
||||||
|
.maybeSingle();
|
||||||
|
|
||||||
|
// Guardar la URL de la imagen para eliminarla después
|
||||||
|
String? imagenUrl;
|
||||||
|
if (componenteData != null && componenteData['imagen_url'] != null) {
|
||||||
|
imagenUrl = componenteData['imagen_url'] as String;
|
||||||
|
}
|
||||||
|
|
||||||
// Eliminar todos los detalles específicos primero
|
// Eliminar todos los detalles específicos primero
|
||||||
await _eliminarDetallesComponente(componenteId);
|
await _eliminarDetallesComponente(componenteId);
|
||||||
|
|
||||||
// Luego eliminar el componente
|
// Eliminar el componente de la base de datos
|
||||||
await supabaseLU.from('componente').delete().eq('id', componenteId);
|
await supabaseLU.from('componente').delete().eq('id', componenteId);
|
||||||
|
|
||||||
if (negocioSeleccionadoId != null) {
|
// Actualizar la lista ANTES de eliminar la imagen
|
||||||
|
if (!_isDisposed && negocioSeleccionadoId != null) {
|
||||||
await getComponentesPorNegocio(negocioSeleccionadoId!);
|
await getComponentesPorNegocio(negocioSeleccionadoId!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AHORA eliminar la imagen del storage (después de que la UI se haya actualizado)
|
||||||
|
if (imagenUrl != null) {
|
||||||
|
try {
|
||||||
|
await supabaseLU.storage
|
||||||
|
.from('nethive')
|
||||||
|
.remove(["componentes/$imagenUrl"]);
|
||||||
|
print('Imagen eliminada del storage: $imagenUrl');
|
||||||
|
} catch (storageError) {
|
||||||
|
print(
|
||||||
|
'Error al eliminar imagen del storage: ${storageError.toString()}');
|
||||||
|
// No retornamos false aquí porque el componente ya fue eliminado exitosamente
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error en eliminarComponente: ${e.toString()}');
|
print('Error en eliminarComponente: ${e.toString()}');
|
||||||
@@ -344,42 +388,6 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _eliminarDetallesComponente(String componenteId) async {
|
|
||||||
// Eliminar de todas las tablas de detalles
|
|
||||||
await supabaseLU
|
|
||||||
.from('detalle_cable')
|
|
||||||
.delete()
|
|
||||||
.eq('componente_id', componenteId);
|
|
||||||
await supabaseLU
|
|
||||||
.from('detalle_switch')
|
|
||||||
.delete()
|
|
||||||
.eq('componente_id', componenteId);
|
|
||||||
await supabaseLU
|
|
||||||
.from('detalle_patch_panel')
|
|
||||||
.delete()
|
|
||||||
.eq('componente_id', componenteId);
|
|
||||||
await supabaseLU
|
|
||||||
.from('detalle_rack')
|
|
||||||
.delete()
|
|
||||||
.eq('componente_id', componenteId);
|
|
||||||
await supabaseLU
|
|
||||||
.from('detalle_organizador')
|
|
||||||
.delete()
|
|
||||||
.eq('componente_id', componenteId);
|
|
||||||
await supabaseLU
|
|
||||||
.from('detalle_ups')
|
|
||||||
.delete()
|
|
||||||
.eq('componente_id', componenteId);
|
|
||||||
await supabaseLU
|
|
||||||
.from('detalle_router_firewall')
|
|
||||||
.delete()
|
|
||||||
.eq('componente_id', componenteId);
|
|
||||||
await supabaseLU
|
|
||||||
.from('detalle_equipo_activo')
|
|
||||||
.delete()
|
|
||||||
.eq('componente_id', componenteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Métodos para obtener detalles específicos
|
// Métodos para obtener detalles específicos
|
||||||
Future<void> getDetallesComponente(
|
Future<void> getDetallesComponente(
|
||||||
String componenteId, int categoriaId) async {
|
String componenteId, int categoriaId) async {
|
||||||
@@ -408,7 +416,7 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showDetallesEspecificos = true;
|
showDetallesEspecificos = true;
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error en getDetallesComponente: ${e.toString()}');
|
print('Error en getDetallesComponente: ${e.toString()}');
|
||||||
}
|
}
|
||||||
@@ -535,7 +543,7 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
detalleRouterFirewall = null;
|
detalleRouterFirewall = null;
|
||||||
detalleEquipoActivo = null;
|
detalleEquipoActivo = null;
|
||||||
|
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void buscarComponentes(String busqueda) {
|
void buscarComponentes(String busqueda) {
|
||||||
@@ -687,7 +695,7 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
// Cargar toda la información de topología para este negocio
|
// Cargar toda la información de topología para este negocio
|
||||||
await cargarTopologiaCompleta(negocioId);
|
await cargarTopologiaCompleta(negocioId);
|
||||||
|
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error en setNegocioSeleccionado: ${e.toString()}');
|
print('Error en setNegocioSeleccionado: ${e.toString()}');
|
||||||
}
|
}
|
||||||
@@ -714,7 +722,7 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
// Cargar toda la información de topología de forma optimizada
|
// Cargar toda la información de topología de forma optimizada
|
||||||
Future<void> cargarTopologiaCompleta(String negocioId) async {
|
Future<void> cargarTopologiaCompleta(String negocioId) async {
|
||||||
isLoadingTopologia = true;
|
isLoadingTopologia = true;
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Cargar datos en paralelo para mejor performance
|
// Cargar datos en paralelo para mejor performance
|
||||||
@@ -733,7 +741,7 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
];
|
];
|
||||||
} finally {
|
} finally {
|
||||||
isLoadingTopologia = false;
|
isLoadingTopologia = false;
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -952,73 +960,6 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtener switches principales (core/distribución)
|
|
||||||
List<Componente> getSwitchesPrincipales() {
|
|
||||||
return componentes.where((c) {
|
|
||||||
final categoria = getCategoriaById(c.categoriaId);
|
|
||||||
final isSwitch =
|
|
||||||
categoria?.nombre?.toLowerCase().contains('switch') ?? false;
|
|
||||||
final isCore = c.ubicacion?.toLowerCase().contains('mdf') ?? false;
|
|
||||||
return isSwitch && isCore;
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener routers/firewalls
|
|
||||||
List<Componente> getRoutersFirewalls() {
|
|
||||||
return componentes.where((c) {
|
|
||||||
final categoria = getCategoriaById(c.categoriaId);
|
|
||||||
final nombre = categoria?.nombre?.toLowerCase() ?? '';
|
|
||||||
return nombre.contains('router') || nombre.contains('firewall');
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener servidores
|
|
||||||
List<Componente> getServidores() {
|
|
||||||
return componentes.where((c) {
|
|
||||||
final categoria = getCategoriaById(c.categoriaId);
|
|
||||||
final nombre = categoria?.nombre?.toLowerCase() ?? '';
|
|
||||||
return nombre.contains('servidor') || nombre.contains('server');
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener cables por tipo
|
|
||||||
List<Componente> getCablesPorTipo(String tipoCable) {
|
|
||||||
return componentes.where((c) {
|
|
||||||
final categoria = getCategoriaById(c.categoriaId);
|
|
||||||
final nombre = categoria?.nombre?.toLowerCase() ?? '';
|
|
||||||
return nombre.contains('cable') &&
|
|
||||||
(c.descripcion?.toLowerCase().contains(tipoCable.toLowerCase()) ??
|
|
||||||
false);
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener estadísticas de conectividad
|
|
||||||
Map<String, int> getEstadisticasConectividad() {
|
|
||||||
int componentesActivos = componentes.where((c) => c.activo).length;
|
|
||||||
int componentesEnUso = componentes.where((c) => c.enUso).length;
|
|
||||||
int conexionesActivas = conexiones.where((c) => c.activo).length;
|
|
||||||
int totalConexiones = conexiones.length;
|
|
||||||
|
|
||||||
return {
|
|
||||||
'componentesActivos': componentesActivos,
|
|
||||||
'componentesEnUso': componentesEnUso,
|
|
||||||
'conexionesActivas': conexionesActivas,
|
|
||||||
'totalConexiones': totalConexiones,
|
|
||||||
'porcentajeUso': componentesActivos > 0
|
|
||||||
? ((componentesEnUso / componentesActivos) * 100).round()
|
|
||||||
: 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cargar toda la información de topología
|
|
||||||
Future<void> cargarTopologia(String negocioId) async {
|
|
||||||
await Future.wait([
|
|
||||||
getComponentesPorNegocio(negocioId),
|
|
||||||
getDistribucionesPorNegocio(negocioId),
|
|
||||||
getConexionesPorNegocio(negocioId),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validar integridad de topología mejorado
|
// Validar integridad de topología mejorado
|
||||||
List<String> validarTopologia() {
|
List<String> validarTopologia() {
|
||||||
List<String> problemas = [];
|
List<String> problemas = [];
|
||||||
@@ -1158,4 +1099,63 @@ class ComponentesProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
return sugerencias;
|
return sugerencias;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Obtener estadísticas de conectividad
|
||||||
|
Map<String, double> getEstadisticasConectividad() {
|
||||||
|
final totalComponentes = componentes.length;
|
||||||
|
final componentesActivos = componentes.where((c) => c.activo).length;
|
||||||
|
final componentesEnUso = componentes.where((c) => c.enUso).length;
|
||||||
|
final conexionesActivas = conexiones.where((c) => c.activo).length;
|
||||||
|
|
||||||
|
return {
|
||||||
|
'totalComponentes': totalComponentes.toDouble(),
|
||||||
|
'componentesActivos': componentesActivos.toDouble(),
|
||||||
|
'componentesEnUso': componentesEnUso.toDouble(),
|
||||||
|
'conexionesActivas': conexionesActivas.toDouble(),
|
||||||
|
'porcentajeActivos': totalComponentes > 0
|
||||||
|
? (componentesActivos / totalComponentes) * 100
|
||||||
|
: 0,
|
||||||
|
'porcentajeUso': componentesActivos > 0
|
||||||
|
? (componentesEnUso / componentesActivos) * 100
|
||||||
|
: 0,
|
||||||
|
'densidadConexiones':
|
||||||
|
componentesActivos > 0 ? (conexionesActivas / componentesActivos) : 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _eliminarDetallesComponente(String componenteId) async {
|
||||||
|
// Eliminar de todas las tablas de detalles
|
||||||
|
await supabaseLU
|
||||||
|
.from('detalle_cable')
|
||||||
|
.delete()
|
||||||
|
.eq('componente_id', componenteId);
|
||||||
|
await supabaseLU
|
||||||
|
.from('detalle_switch')
|
||||||
|
.delete()
|
||||||
|
.eq('componente_id', componenteId);
|
||||||
|
await supabaseLU
|
||||||
|
.from('detalle_patch_panel')
|
||||||
|
.delete()
|
||||||
|
.eq('componente_id', componenteId);
|
||||||
|
await supabaseLU
|
||||||
|
.from('detalle_rack')
|
||||||
|
.delete()
|
||||||
|
.eq('componente_id', componenteId);
|
||||||
|
await supabaseLU
|
||||||
|
.from('detalle_organizador')
|
||||||
|
.delete()
|
||||||
|
.eq('componente_id', componenteId);
|
||||||
|
await supabaseLU
|
||||||
|
.from('detalle_ups')
|
||||||
|
.delete()
|
||||||
|
.eq('componente_id', componenteId);
|
||||||
|
await supabaseLU
|
||||||
|
.from('detalle_router_firewall')
|
||||||
|
.delete()
|
||||||
|
.eq('componente_id', componenteId);
|
||||||
|
await supabaseLU
|
||||||
|
.from('detalle_equipo_activo')
|
||||||
|
.delete()
|
||||||
|
.eq('componente_id', componenteId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,28 @@ class EmpresasNegociosProvider extends ChangeNotifier {
|
|||||||
String? empresaSeleccionadaId;
|
String? empresaSeleccionadaId;
|
||||||
Empresa? empresaSeleccionada;
|
Empresa? empresaSeleccionada;
|
||||||
|
|
||||||
|
// Variable para controlar si el provider está activo
|
||||||
|
bool _isDisposed = false;
|
||||||
|
|
||||||
EmpresasNegociosProvider() {
|
EmpresasNegociosProvider() {
|
||||||
getEmpresas();
|
getEmpresas();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_isDisposed = true;
|
||||||
|
busquedaEmpresaController.dispose();
|
||||||
|
busquedaNegocioController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Método seguro para notificar listeners
|
||||||
|
void _safeNotifyListeners() {
|
||||||
|
if (!_isDisposed) {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Métodos para empresas
|
// Métodos para empresas
|
||||||
Future<void> getEmpresas([String? busqueda]) async {
|
Future<void> getEmpresas([String? busqueda]) async {
|
||||||
try {
|
try {
|
||||||
@@ -56,7 +74,7 @@ class EmpresasNegociosProvider extends ChangeNotifier {
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
_buildEmpresasRows();
|
_buildEmpresasRows();
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error en getEmpresas: ${e.toString()}');
|
print('Error en getEmpresas: ${e.toString()}');
|
||||||
}
|
}
|
||||||
@@ -105,7 +123,7 @@ class EmpresasNegociosProvider extends ChangeNotifier {
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
_buildNegociosRows();
|
_buildNegociosRows();
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error en getNegociosPorEmpresa: ${e.toString()}');
|
print('Error en getNegociosPorEmpresa: ${e.toString()}');
|
||||||
}
|
}
|
||||||
@@ -164,7 +182,7 @@ class EmpresasNegociosProvider extends ChangeNotifier {
|
|||||||
logoToUpload = picker.files.single.bytes;
|
logoToUpload = picker.files.single.bytes;
|
||||||
|
|
||||||
// Notificar inmediatamente después de seleccionar
|
// Notificar inmediatamente después de seleccionar
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +204,7 @@ class EmpresasNegociosProvider extends ChangeNotifier {
|
|||||||
imagenToUpload = picker.files.single.bytes;
|
imagenToUpload = picker.files.single.bytes;
|
||||||
|
|
||||||
// Notificar inmediatamente después de seleccionar
|
// Notificar inmediatamente después de seleccionar
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,7 +315,10 @@ class EmpresasNegociosProvider extends ChangeNotifier {
|
|||||||
// Luego eliminar la empresa
|
// Luego eliminar la empresa
|
||||||
await supabaseLU.from('empresa').delete().eq('id', empresaId);
|
await supabaseLU.from('empresa').delete().eq('id', empresaId);
|
||||||
|
|
||||||
await getEmpresas();
|
// Solo actualizar si el provider sigue activo
|
||||||
|
if (!_isDisposed) {
|
||||||
|
await getEmpresas();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error en eliminarEmpresa: ${e.toString()}');
|
print('Error en eliminarEmpresa: ${e.toString()}');
|
||||||
@@ -309,7 +330,8 @@ class EmpresasNegociosProvider extends ChangeNotifier {
|
|||||||
try {
|
try {
|
||||||
await supabaseLU.from('negocio').delete().eq('id', negocioId);
|
await supabaseLU.from('negocio').delete().eq('id', negocioId);
|
||||||
|
|
||||||
if (empresaSeleccionadaId != null) {
|
// Solo actualizar si el provider sigue activo y hay una empresa seleccionada
|
||||||
|
if (!_isDisposed && empresaSeleccionadaId != null) {
|
||||||
await getNegociosPorEmpresa(empresaSeleccionadaId!);
|
await getNegociosPorEmpresa(empresaSeleccionadaId!);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -324,7 +346,7 @@ class EmpresasNegociosProvider extends ChangeNotifier {
|
|||||||
empresaSeleccionadaId = empresaId;
|
empresaSeleccionadaId = empresaId;
|
||||||
empresaSeleccionada = empresas.firstWhere((e) => e.id == empresaId);
|
empresaSeleccionada = empresas.firstWhere((e) => e.id == empresaId);
|
||||||
getNegociosPorEmpresa(empresaId);
|
getNegociosPorEmpresa(empresaId);
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetFormData() {
|
void resetFormData() {
|
||||||
@@ -332,7 +354,7 @@ class EmpresasNegociosProvider extends ChangeNotifier {
|
|||||||
imagenFileName = null;
|
imagenFileName = null;
|
||||||
logoToUpload = null;
|
logoToUpload = null;
|
||||||
imagenToUpload = null;
|
imagenToUpload = null;
|
||||||
notifyListeners();
|
_safeNotifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void buscarEmpresas(String busqueda) {
|
void buscarEmpresas(String busqueda) {
|
||||||
|
|||||||
Reference in New Issue
Block a user