import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:omni_datetime_picker/omni_datetime_picker.dart'; import 'package:provider/provider.dart'; import '../pedido/pedido_csv.dart'; import '../pedido/pedido_detalle_screen.dart'; import '../../widgets/widgets.dart'; import '../../themes/themes.dart'; import '../../models/models.dart'; import '../../viewmodels/viewmodels.dart'; import '../../widgets/widgets_components.dart' as clase; import 'pedido_form.dart'; import 'pedido_sync.dart'; class PedidoScreen extends StatefulWidget { const PedidoScreen({Key? key}) : super(key: key); @override State createState() => _PedidoScreenState(); } class _PedidoScreenState extends State { int _syncAgainTapCount = 0; final _busqueda = TextEditingController(text: ''); DateTime? fechaInicio; DateTime? fechaFin; ScrollController horizontalScrollController = ScrollController(); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of(context, listen: false) .fetchLocalPedidosForScreen(); }); } void exportCSV() async { final pedidosViewModel = Provider.of(context, listen: false); List pedidosConProductos = []; for (Pedido pedido in pedidosViewModel.pedidos) { Pedido? pedidoConProductos = await pedidosViewModel.fetchPedidoConProductos(pedido.id); if (pedidoConProductos != null) { pedidosConProductos.add(pedidoConProductos); } } if (pedidosConProductos.isNotEmpty) { String fileName = 'Pedidos_JoshiPapas_POS'; if (fechaInicio != null && fechaFin != null) { String startDateStr = DateFormat('dd-MM-yyyy').format(fechaInicio!); String endDateStr = DateFormat('dd-MM-yyyy').format(fechaFin!); fileName += '_${startDateStr}_al_${endDateStr}'; } fileName += '.csv'; await exportarPedidosACSV(pedidosConProductos, fileName); ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text('Archivo CSV descargado! Archivo: $fileName'))); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('No hay pedidos para exportar.'))); } } void clearSearchAndReset() { setState(() { _busqueda.clear(); fechaInicio = null; fechaFin = null; Provider.of(context, listen: false) .fetchLocalPedidosForScreen(); }); } void go(Pedido item) async { Pedido? pedidoCompleto = await Provider.of(context, listen: false) .fetchPedidoConProductos(item.id); if (pedidoCompleto != null) { Navigator.push( context, MaterialPageRoute( builder: (context) => PedidoDetalleScreen(pedido: pedidoCompleto), ), ); } else { print("Error al cargar el pedido con productos"); } } @override Widget build(BuildContext context) { final pvm = Provider.of(context); double screenWidth = MediaQuery.of(context).size.width; final isMobile = screenWidth < 1250; final double? columnSpacing = isMobile ? null : 0; TextStyle estilo = const TextStyle(fontWeight: FontWeight.bold); List registros = []; for (Pedido item in pvm.pedidos) { final sincronizadoStatus = item.sincronizado == null || item.sincronizado!.isEmpty ? "No Sincronizado" : _formatDateTime(item.sincronizado); registros.add(DataRow(cells: [ DataCell( Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ PopupMenuButton( itemBuilder: (context) => [ PopupMenuItem( child: const Text('Detalle'), onTap: () => go(item), ), PopupMenuItem( child: const Text('Cancelar Pedido'), onTap: () async { bool confirmado = await showDialog( context: context, builder: (context) { return AlertDialog( title: const Text("Cancelar Pedido", style: TextStyle( fontWeight: FontWeight.w500, fontSize: 22)), content: const Text( '¿Estás seguro de que deseas cancelar este pedido?', style: TextStyle(fontSize: 18)), actions: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextButton( onPressed: () => Navigator.of(context).pop(false), child: const Text('No', style: TextStyle(fontSize: 18)), style: ButtonStyle( padding: MaterialStatePropertyAll( EdgeInsets.fromLTRB( 20, 10, 20, 10)), backgroundColor: MaterialStatePropertyAll( Colors.red), foregroundColor: MaterialStatePropertyAll( AppTheme.secondary)), ), TextButton( onPressed: () => Navigator.of(context).pop(true), child: const Text('Sí', style: TextStyle(fontSize: 18)), style: ButtonStyle( padding: MaterialStatePropertyAll( EdgeInsets.fromLTRB( 20, 10, 20, 10)), backgroundColor: MaterialStatePropertyAll( AppTheme.tertiary), foregroundColor: MaterialStatePropertyAll( AppTheme.quaternary)), ), ], ) ], ); }, ) ?? false; if (confirmado) { await Provider.of(context, listen: false) .cancelarPedido(item.id); ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text("Pedido cancelado correctamente"))); } }, ) ], icon: const Icon(Icons.more_vert), ) ])), DataCell( Text(item.folio.toString()), onTap: () => go(item), ), DataCell( Text(item.nombreCliente ?? "Sin nombre"), onTap: () => go(item), ), DataCell( Text(item.comentarios ?? "Sin comentarios"), onTap: () => go(item), ), DataCell( Text(item.estatus ?? "Sin Estatus"), onTap: () => go(item), ), DataCell( Text(_formatDateTime(item.peticion)), onTap: () => go(item), ), DataCell( Text(sincronizadoStatus), onTap: () => go(item), ), ])); } return Scaffold( appBar: AppBar( title: GestureDetector( onTap: () { _syncAgainTapCount++; if (_syncAgainTapCount == 5) { alertaSync(context); _syncAgainTapCount = 0; } }, child: Text( 'Pedidos', style: TextStyle( color: AppTheme.secondary, fontWeight: FontWeight.w500), ), ), actions: [ IconButton( icon: const Icon(Icons.save_alt), onPressed: exportCSV, tooltip: 'Exportar a CSV', ), ], iconTheme: IconThemeData(color: AppTheme.secondary)), body: Stack( children: [ Column( children: [ Expanded( child: ListView( padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), children: [ const SizedBox(height: 8), clase.tarjeta( Padding( padding: const EdgeInsets.all(8.0), child: LayoutBuilder( builder: (context, constraints) { if (screenWidth > 1000) { return Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ Expanded( flex: 7, child: _buildDateRangePicker(), ), const SizedBox(width: 5), botonBuscar() ], ); } else { return Column( children: [ Row( children: [_buildDateRangePicker()], ), Row( children: [botonBuscar()], ), ], ); } }, ), ), ), const SizedBox(height: 8), pvm.isLoading ? const Center(child: CircularProgressIndicator()) : Container(), clase.tarjeta( Column( children: [ LayoutBuilder(builder: (context, constraints) { return SingleChildScrollView( scrollDirection: Axis.vertical, child: Scrollbar( controller: horizontalScrollController, interactive: true, thumbVisibility: true, thickness: 10.0, child: SingleChildScrollView( controller: horizontalScrollController, scrollDirection: Axis.horizontal, child: ConstrainedBox( constraints: BoxConstraints( minWidth: isMobile ? constraints.maxWidth : screenWidth), child: DataTable( columnSpacing: columnSpacing, sortAscending: true, sortColumnIndex: 1, columns: [ DataColumn( label: Text(" ", style: estilo)), DataColumn( label: Text("FOLIO", style: estilo)), DataColumn( label: Text("NOMBRE", style: estilo)), DataColumn( label: Text("COMENTARIOS", style: estilo)), DataColumn( label: Text("ESTATUS", style: estilo)), DataColumn( label: Text("FECHA", style: estilo)), DataColumn( label: Text("SINCRONIZADO", style: estilo)), ], rows: registros, ), ), ), ), ); }), ], ), ), const SizedBox(height: 15), if (!pvm.isLoading) Row( mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton( onPressed: pvm.currentPage > 1 ? pvm.previousPage : null, child: Text('Anterior'), style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith( (Set states) { if (states.contains(MaterialState.disabled)) { return Colors.grey; } return AppTheme.tertiary; }, ), foregroundColor: MaterialStateProperty.resolveWith( (Set states) { if (states.contains(MaterialState.disabled)) { return Colors.black; } return Colors.white; }, ), ), ), SizedBox(width: 15), Text( 'Página ${pvm.currentPage} de ${pvm.totalPages}'), SizedBox(width: 15), TextButton( onPressed: pvm.currentPage < pvm.totalPages ? pvm.nextPage : null, child: Text('Siguiente'), style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith( (Set states) { if (states.contains(MaterialState.disabled)) { return Colors.grey; } return AppTheme.tertiary; }, ), foregroundColor: MaterialStateProperty.resolveWith( (Set states) { if (states.contains(MaterialState.disabled)) { return Colors.black; } return Colors.white; }, ), ), ), ], ), const SizedBox(height: 15), ], ), ), ], ), Positioned( bottom: 16, right: 16, child: FloatingActionButton.extended( heroTag: 'addPedido', onPressed: () async { await Navigator.push( context, MaterialPageRoute( builder: (context) => PedidoForm(), ), ).then((_) => Provider.of(context, listen: false) .fetchLocalPedidosForScreen()); }, icon: Icon(Icons.add, size: 30, color: AppTheme.quaternary), label: Text( "Agregar Pedido", style: TextStyle(fontSize: 20, color: AppTheme.quaternary), ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, backgroundColor: AppTheme.tertiary, ), ), // Positioned( // bottom: 16, // left: 16, // child: FloatingActionButton.extended( // heroTag: 'sincronizacion', // onPressed: () { // alerta(context, etiqueta: "Sincronización Empezada"); // PedidoSync().startSync( // Provider.of(context, listen: false)); // }, // icon: Icon(Icons.sync, size: 30, color: AppTheme.quaternary), // label: Text( // "Sincronización", // style: TextStyle(fontSize: 20, color: AppTheme.quaternary), // ), // shape: RoundedRectangleBorder( // borderRadius: BorderRadius.circular(8), // ), // materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, // backgroundColor: AppTheme.tertiary, // ), // ), ], ), ); } Widget _buildDateRangePicker() { return Row( children: [ Expanded( flex: 3, child: AppTextField( prefixIcon: const Icon(Icons.search), etiqueta: 'Búsqueda por folio...', controller: _busqueda, hintText: 'Búsqueda por folio...', ), ), const SizedBox(width: 5), Expanded( flex: 3, child: clase.FechaSelectWidget( fecha: fechaInicio, onFechaChanged: (d) { setState(() { fechaInicio = d; }); }, etiqueta: "Fecha Inicial", context: context, ), ), const SizedBox(width: 5), Expanded( flex: 3, child: clase.FechaSelectWidget( fecha: fechaFin, onFechaChanged: (d) { setState(() { fechaFin = d; }); }, etiqueta: "Fecha Final", context: context, ), ), ], ); } Widget botonBuscar() { return Expanded( flex: 2, child: Row( children: [ Expanded( flex: 2, child: Padding( padding: const EdgeInsets.only(bottom: 5), child: ElevatedButton( onPressed: clearSearchAndReset, style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20.0), ), primary: AppTheme.tertiary, padding: const EdgeInsets.symmetric(vertical: 25), ), child: Text('Limpiar', style: TextStyle(color: AppTheme.quaternary)), ), ), ), const SizedBox(width: 8), Expanded( flex: 2, child: Padding( padding: const EdgeInsets.only(bottom: 5), child: ElevatedButton( onPressed: () async { if (_busqueda.text.isNotEmpty) { await Provider.of(context, listen: false) .buscarPedidosPorFolio(_busqueda.text.trim()); } else if (fechaInicio != null && fechaFin != null) { DateTime fechaInicioUTC = DateTime(fechaInicio!.year, fechaInicio!.month, fechaInicio!.day) .toUtc(); DateTime fechaFinUTC = DateTime(fechaFin!.year, fechaFin!.month, fechaFin!.day, 23, 59, 59) .toUtc(); await Provider.of(context, listen: false) .buscarPedidosPorFecha(fechaInicioUTC, fechaFinUTC); } else { ScaffoldMessenger.of(context).showSnackBar(const SnackBar( content: Text( 'Introduce un folio o selecciona un rango de fechas para buscar.'))); } }, style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20.0), ), primary: AppTheme.tertiary, padding: const EdgeInsets.symmetric(vertical: 25), ), child: Text('Buscar', style: TextStyle(color: AppTheme.quaternary)), ), ), ), ], ), ); } void alertaSync(BuildContext context) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Confirmación', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 22)), content: const Text('¿Deseas sincronizar todos los pedidos de nuevo?', style: TextStyle(fontSize: 18)), actions: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextButton( child: const Text('No', style: TextStyle(fontSize: 18)), style: ButtonStyle( padding: MaterialStatePropertyAll( EdgeInsets.fromLTRB(20, 10, 20, 10)), backgroundColor: MaterialStatePropertyAll(Colors.red), foregroundColor: MaterialStatePropertyAll(AppTheme.secondary)), onPressed: () { Navigator.of(context).pop(); }, ), TextButton( child: const Text('Sí', style: TextStyle(fontSize: 18)), style: ButtonStyle( padding: MaterialStatePropertyAll( EdgeInsets.fromLTRB(20, 10, 20, 10)), backgroundColor: MaterialStatePropertyAll(AppTheme.tertiary), foregroundColor: MaterialStatePropertyAll(AppTheme.quaternary)), onPressed: () { // No hace nada por el momento Navigator.of(context).pop(); }, ), ], ) ], ); }, ); } String _formatDateTime(String? dateTimeString) { if (dateTimeString == null) return "Sin fecha"; DateTime parsedDate = DateTime.parse(dateTimeString); var formatter = DateFormat('dd-MM-yyyy HH:mm:ss'); return formatter.format(parsedDate.toLocal()); } }