瀏覽代碼

Productos y categoría de productos

OscarGil03 1 年之前
父節點
當前提交
a65237adcf

+ 1 - 0
lib/main.dart

@@ -24,6 +24,7 @@ void main() {
       ChangeNotifierProvider(create: (_) => UsuariosViewModel()),
       ChangeNotifierProvider(create: (_) => ProfileViewModel()),
       ChangeNotifierProvider(create: (_) => CategoriaProductoViewModel()),
+      ChangeNotifierProvider(create: (_) => ProductoViewModel()),
       // Agrega aquí cualquier otro provider que necesites
     ], child: const MyApp()));
   });

+ 1 - 0
lib/models/models.dart

@@ -5,3 +5,4 @@ export '../models/media_model.dart';
 export '../models/profile_model.dart';
 export '../models/categoria_producto_model.dart';
 export '../models/pedido_model.dart';
+export '../models/producto_model.dart';

+ 69 - 0
lib/models/producto_model.dart

@@ -0,0 +1,69 @@
+import 'package:yoshi_papas_app/models/models.dart';
+
+import 'basico_model.dart';
+
+class Producto extends Basico {
+  int? idCategoria;
+  CategoriaProducto? categoria;
+  String? nombre;
+  String? descripcion;
+  String? imagen;
+  int? venta;
+  int? existencia;
+  String? precio;
+  int? verMenu;
+  String? codigo;
+  String? descuento;
+  String? venceDescuento;
+
+  Producto({
+    super.id,
+    this.idCategoria,
+    this.nombre,
+    this.descripcion,
+    this.imagen,
+    this.venta,
+    this.existencia,
+    this.precio,
+    this.verMenu,
+    this.codigo,
+    this.descuento,
+    this.venceDescuento,
+  });
+
+  @override
+  Map<String, dynamic> toJson() {
+    return {
+      'id': id,
+      'idCategoria': idCategoria,
+      'nombre': nombre,
+      'descripcion': descripcion,
+      'imagen': imagen,
+      'venta': venta,
+      'existencia': existencia,
+      'precio': precio,
+      'verMenu': verMenu,
+      'codigo': codigo,
+      'descuento': descuento,
+      'venceDescuento': venceDescuento,
+    }..addAll(super.toJson());
+  }
+
+  Producto.fromJson(Map<String, dynamic> json) {
+    super.parseJson(json);
+    idCategoria = Basico.parseInt(json['idCategoria']);
+    categoria = json["categoria"] != null
+        ? CategoriaProducto.fromJson(json["categoria"])
+        : null;
+    nombre = Basico.parseString(json['nombre']);
+    descripcion = Basico.parseString(json['descripcion']);
+    imagen = Basico.parseString(json['imagen']);
+    venta = Basico.parseInt(json['venta']);
+    existencia = Basico.parseInt(json['existencia']);
+    precio = Basico.parseString(json['precio']);
+    verMenu = Basico.parseInt(json['verMenu']);
+    codigo = Basico.parseString(json['codigo']);
+    descuento = Basico.parseString(json['descuento']);
+    venceDescuento = Basico.parseString(json['venceDescuento']);
+  }
+}

+ 14 - 8
lib/services/categoria_producto_service.dart

@@ -1,3 +1,5 @@
+import 'dart:convert';
+
 import 'package:yoshi_papas_app/data/api_response.dart';
 import 'package:yoshi_papas_app/models/models.dart';
 
@@ -11,20 +13,24 @@ class CategoriaProductoService extends BaseService {
     "ordenar": "id-desc",
     "pagina": "1"
   };
-  Future<List<CategoriaProducto>> fetchList() async {
+  Future<List<CategoriaProducto>> fetchList(
+      {String? q, bool segmentar = false}) async {
+    if (q != null) {
+      defaultQueryParameters['q'] = q.toString();
+    }
+    if (segmentar) {
+      defaultQueryParameters['segmentar'] = "1";
+    }
     final response =
         await get(endPoint, queryParameters: defaultQueryParameters);
 
-    final respuesta = ApiResponse(response);
+    final categoriaProductoJson = jsonDecode(response.body);
 
     List<CategoriaProducto> categoriaProductos = [];
 
-    if (respuesta.isOk && respuesta.resultados!.isNotEmpty) {
-      for (var x in respuesta.resultados!) {
-        final categoriaProducto = CategoriaProducto.fromJson(x);
-
-        categoriaProductos.add(categoriaProducto);
-      }
+    for (var x in categoriaProductoJson['resultado']) {
+      CategoriaProducto categoriaProducto = CategoriaProducto.fromJson(x);
+      categoriaProductos.add(categoriaProducto);
     }
 
     return categoriaProductos;

+ 95 - 0
lib/services/producto_service.dart

@@ -0,0 +1,95 @@
+import 'package:yoshi_papas_app/data/api_response.dart';
+import 'package:yoshi_papas_app/models/models.dart';
+
+import '../services/base_service.dart';
+
+class ProductoService extends BaseService {
+  String endPoint = '/admin/categoria';
+  //Consulta de la lista de Sala
+  Map<String, String> defaultQueryParameters = {
+    "limite": "10",
+    "ordenar": "id-desc",
+    "pagina": "1"
+  };
+  Future<List<Producto>> fetchList() async {
+    final response =
+        await get(endPoint, queryParameters: defaultQueryParameters);
+
+    final respuesta = ApiResponse(response);
+
+    List<Producto> productos = [];
+
+    if (respuesta.isOk && respuesta.resultados!.isNotEmpty) {
+      for (var x in respuesta.resultados!) {
+        final producto = Producto.fromJson(x);
+
+        productos.add(producto);
+      }
+    }
+
+    return productos;
+  }
+
+  Future<ApiResponse> postProducto({
+    required String nombre,
+    required String descripcion,
+    String? descuento,
+    required int existencia,
+    required int idCategoria,
+    required String precio,
+    String? venceDescuento,
+  }) async {
+    var response = await post(
+      '$endPoint/guardar',
+      body: {
+        'descripcion': descripcion,
+        'nombre': nombre,
+        'descuento': descuento,
+        'existencia': existencia,
+        'idCategoria': idCategoria,
+        'precio': precio,
+        'venceDescuento': venceDescuento,
+      },
+      withAuth: true,
+    );
+    return ApiResponse(response);
+  }
+
+  Future<ApiResponse> editProducto({
+    required int id,
+    required String nombre,
+    required String descripcion,
+    String? descuento,
+    required int existencia,
+    required int idCategoria,
+    required String precio,
+    String? venceDescuento,
+  }) async {
+    var response = await post(
+      endPoint,
+      body: {
+        'id': id,
+        'descripcion': descripcion,
+        'nombre': nombre,
+        'descuento': descuento,
+        'existencia': existencia,
+        'idCategoria': idCategoria,
+        'precio': precio,
+        'venceDescuento': venceDescuento,
+      },
+      withAuth: true,
+    );
+    return ApiResponse(response);
+  }
+
+  Future<ApiResponse> deleteProducto({required int id}) async {
+    var response = await delete(
+      '$endPoint/eliminar',
+      body: {
+        'id': id,
+      },
+      withAuth: true,
+    );
+    return ApiResponse(response);
+  }
+}

+ 15 - 6
lib/viewmodels/categoria_producto_view_model.dart

@@ -5,20 +5,29 @@ import '../models/models.dart';
 
 class CategoriaProductoViewModel extends ChangeNotifier {
   List<CategoriaProducto> _categoriaProductos = [];
+  CategoriaProducto? _selectedCategoriaProducto;
   bool _isLoading = true;
 
   String _busqueda = "";
   String get busqueda => _busqueda;
 
-  CategoriaProducto? selectedCategoriaProducto;
-
   List<CategoriaProducto> get categoriaProductos => _categoriaProductos;
+  CategoriaProducto? get selectedCategoriaProducto =>
+      _selectedCategoriaProducto;
+
   bool get isLoading => _isLoading;
 
-  //Metodo para obtener lista de CategoriaProducto
-  Future<void> fetchCategoriaProductos() async {
-    _categoriaProductos = await CategoriaProductoService().fetchList();
+  Future<List<CategoriaProducto>> getCategoriaProducto(
+      {String? q, bool segmentar = false}) async {
+    _categoriaProductos =
+        await CategoriaProductoService().fetchList(q: q, segmentar: segmentar);
+    return _categoriaProductos;
+  }
 
+  //Metodo para obtener lista de CategoriaProducto
+  Future<void> fetchCategoriaProductos({bool segmentar = false}) async {
+    _categoriaProductos =
+        await CategoriaProductoService().fetchList(segmentar: segmentar);
     notifyListeners();
   }
 
@@ -38,7 +47,7 @@ class CategoriaProductoViewModel extends ChangeNotifier {
 
   CategoriaProducto selectCategoriaProducto(
       CategoriaProducto categoriaProducto) {
-    selectedCategoriaProducto = categoriaProducto;
+    _selectedCategoriaProducto = categoriaProducto;
     return categoriaProducto;
   }
 

+ 102 - 0
lib/viewmodels/producto_view_model.dart

@@ -0,0 +1,102 @@
+import 'package:flutter/material.dart';
+
+import '../data/api_response.dart';
+import '../services/base_service.dart';
+import '../models/models.dart';
+
+class ProductoViewModel<T> extends ChangeNotifier {
+  String _busqueda = "";
+  String get busqueda => _busqueda;
+
+  List<Producto> _registros = [];
+  Producto? _selectedModelo;
+  bool _isLoading = false;
+
+  List<Producto> get registros => _registros;
+  Producto? get selectedProducto => _selectedModelo;
+  bool get isLoading => _isLoading;
+
+  int pagina = 1;
+  int totalPaginas = 1;
+  int limite = 10;
+
+  setBusqueda(String value) {
+    _busqueda = value;
+    notifyListeners();
+  }
+
+  Future<List<Producto>> fetchRegistros(
+      {CategoriaProducto? categoriaProducto,
+      String? q,
+      bool segmentar = false}) async {
+    Map<String, String> parametros = {
+      "ordenar": "nombre-asc",
+      "pagina": "$pagina",
+      "limite": "$limite",
+      "expand": "categoria"
+    };
+    if (_busqueda.isNotEmpty) {
+      parametros["q"] = _busqueda;
+    }
+    if (categoriaProducto != null) {
+      parametros['idCategoria'] = categoriaProducto.id.toString();
+    }
+    if (segmentar) {
+      parametros['segmentar'] = "1";
+    }
+    var r = ApiResponse(
+        await BaseService().get("admin/producto", queryParameters: parametros));
+    pagina = r.paginacion!.pagina;
+    var total = r.paginacion!.total / r.paginacion!.limite;
+    totalPaginas = total > 0 ? total.ceil() : 1;
+    List<Producto> aux = [];
+    if (r.isOk) {
+      for (var x in r.resultados!) {
+        Producto modelo = Producto.fromJson(x);
+        aux.add(modelo);
+      }
+    }
+    _registros = aux;
+    notifyListeners();
+    return _registros;
+  }
+
+  selectModelo(Producto Producto) {
+    _selectedModelo = Producto;
+    notifyListeners();
+  }
+
+  setIsLoading(bool loading) {
+    _isLoading = loading;
+    notifyListeners();
+  }
+
+  cambiarPagina(int nuevaPagina,
+      {CategoriaProducto? categoriaProducto, bool segmentar = false}) {
+    pagina = nuevaPagina;
+    fetchRegistros(categoriaProducto: categoriaProducto, segmentar: segmentar);
+  }
+
+  Future<void> guardarModelo({
+    required Producto modelo,
+    required String nombre,
+    required String descripcion,
+    String? descuento,
+    required int existencia,
+    required int idCategoria,
+    required String precio,
+    String? venceDescuento,
+  }) async {
+    modelo.nombre = nombre;
+    modelo.descripcion = descripcion;
+    modelo.idCategoria = idCategoria;
+    modelo.descuento = descuento;
+    modelo.existencia = existencia;
+    modelo.precio = precio;
+    modelo.venceDescuento = venceDescuento;
+    var r = await BaseService()
+        .post("admin/producto/guardar", body: modelo.toJson());
+    if (r.statusCode == 200) {}
+    notifyListeners();
+  }
+}

+ 1 - 0
lib/viewmodels/viewmodels.dart

@@ -2,3 +2,4 @@ export '../viewmodels/login_view_model.dart';
 export '../viewmodels/usuarios_view_model.dart';
 export '../viewmodels/profile_view_model.dart';
 export '../viewmodels/categoria_producto_view_model.dart';
+export '../viewmodels/producto_view_model.dart';

+ 0 - 152
lib/views/categoria_producto/categoria_producto_screen copy.dart

@@ -1,152 +0,0 @@
-import 'package:yoshi_papas_app/views/categoria_producto/categoria_producto_form.dart';
-import 'package:flutter/material.dart';
-import '../../themes/themes.dart';
-import '../../viewmodels/viewmodels.dart';
-import 'package:provider/provider.dart';
-
-class CategoriaProductoScreen extends StatefulWidget {
-  const CategoriaProductoScreen({Key? key}) : super(key: key);
-
-  @override
-  State<CategoriaProductoScreen> createState() => _CategoriaProductoState();
-}
-
-class _CategoriaProductoState extends State<CategoriaProductoScreen> {
-  @override
-  void initState() {
-    super.initState();
-    final viewModel =
-        Provider.of<CategoriaProductoViewModel>(context, listen: false);
-    Future(() async {
-      viewModel.setLoading(true);
-      await viewModel.fetchCategoriaProductos();
-      viewModel.setLoading(false);
-    });
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    final viewModel = Provider.of<CategoriaProductoViewModel>(context);
-    final categoriaProductos = viewModel.categoriaProductos;
-    final isLoading = viewModel.isLoading;
-
-    return Scaffold(
-      floatingActionButton: Padding(
-        padding: const EdgeInsets.only(right: 50.0),
-        child: FloatingActionButton(
-            onPressed: () async {
-              Navigator.push(
-                context,
-                MaterialPageRoute(
-                  builder: (context) => const CategoriaProductoForm(),
-                ),
-              ).then((result) async {
-                if (result != null) {
-                  viewModel.setLoading(true);
-                  await viewModel.addCategoriaProducto(
-                    nombre: result.nombre,
-                  );
-                  viewModel.setLoading(false);
-                }
-              });
-            },
-            child: const Icon(
-              Icons.add,
-              size: 30,
-            )),
-      ),
-      appBar: AppBar(
-        title: const Text('Categoria Producto'),
-      ),
-      body: Center(
-        child: isLoading
-            ? const Center(
-                child: CircularProgressIndicator(),
-              )
-            : ListView.separated(
-                itemCount: categoriaProductos.length,
-                itemBuilder: (context, index) {
-                  var categoriaProducto = categoriaProductos[index];
-                  return ListTile(
-                    onTap: () {
-                      viewModel.selectCategoriaProducto(categoriaProducto);
-                    },
-                    title: Text(categoriaProducto.nombre!),
-                    trailing: PopupMenuButton(
-                      surfaceTintColor: AppTheme.quaternary,
-                      itemBuilder: (context) => [
-                        PopupMenuItem(
-                          child: const Text('Editar'),
-                          onTap: () {
-                            Navigator.push(
-                              context,
-                              MaterialPageRoute(
-                                builder: (context) =>
-                                    const CategoriaProductoForm(),
-                              ),
-                            ).then((result) async {
-                              if (result != null) {
-                                viewModel.setLoading(true);
-                                await viewModel.editCategoriaProducto(
-                                  id: categoriaProducto.id,
-                                  nombre: result.nombre,
-                                );
-                                viewModel.setLoading(false);
-                              }
-                            });
-                          },
-                        ),
-                        PopupMenuItem(
-                          child: const Text(
-                            'Eliminar',
-                            style: TextStyle(color: Colors.red),
-                          ),
-                          onTap: () {
-                            showDialog(
-                              context: context,
-                              builder: (context) {
-                                return AlertDialog(
-                                  title:
-                                      const Text('Eliminar CategoriaProducto'),
-                                  content: const Text(
-                                      '¿Estás seguro de que quieres eliminar esta categoriaProducto?'),
-                                  actions: [
-                                    TextButton(
-                                      onPressed: () {
-                                        Navigator.pop(context);
-                                      },
-                                      child: const Text('Cancelar'),
-                                    ),
-                                    TextButton(
-                                      onPressed: () async {
-                                        Navigator.pop(context);
-                                        viewModel.setLoading(true);
-                                        await viewModel.deleteCategoriaProducto(
-                                            categoriaProducto.id);
-                                        viewModel.setLoading(false);
-                                      },
-                                      child: const Text('Eliminar'),
-                                    ),
-                                  ],
-                                );
-                              },
-                            );
-                          },
-                        )
-                      ],
-                      icon: const Icon(Icons.more_vert),
-                      shape: RoundedRectangleBorder(
-                          borderRadius: BorderRadius.circular(15)),
-                    ),
-                  );
-                },
-                separatorBuilder: (context, index) => const Divider(
-                  height: 0,
-                  thickness: 0,
-                  color: Colors.grey,
-                ),
-              ),
-      ),
-    );
-  }
-}

+ 0 - 8
lib/views/categoria_producto/categoria_producto_screen.dart

@@ -114,14 +114,6 @@ class Formulario extends State<CategoriaProductoScreen> {
     return Scaffold(
       appBar: AppBar(
         title: const Text('Categoría Productos'),
-        actions: [
-          IconButton(
-              onPressed: () async {
-                Provider.of<CategoriaProductoViewModel>(context, listen: false)
-                    .fetchCategoriaProductos();
-              },
-              icon: const Icon(Icons.download))
-        ],
       ),
       floatingActionButton: FloatingActionButton(
         onPressed: () {

+ 198 - 0
lib/views/producto/producto_form.dart

@@ -0,0 +1,198 @@
+// ignore_for_file: use_build_context_synchronously
+
+import 'package:flutter/material.dart';
+import 'package:yoshi_papas_app/widgets/widgets.dart';
+import 'package:provider/provider.dart';
+
+import '../../models/models.dart';
+import '../../viewmodels/viewmodels.dart';
+
+class ProductoForm extends StatefulWidget {
+  const ProductoForm({Key? key}) : super(key: key);
+
+  @override
+  State<ProductoForm> createState() => Formulario();
+}
+
+class Formulario extends State<ProductoForm> {
+  final _nombre = TextEditingController();
+  final _descripcion = TextEditingController();
+  final _precio = TextEditingController();
+  final _existencia = TextEditingController();
+  final _descuento = TextEditingController();
+  final _busquedaCategoria = TextEditingController();
+  final _venceDescuento = TextEditingController();
+  CategoriaProducto? categoriaProducto;
+
+  @override
+  void initState() {
+    super.initState();
+    Future(() async {
+      Provider.of<ProductoViewModel>(context, listen: false).setIsLoading(true);
+      final mvm = Provider.of<ProductoViewModel>(context, listen: false);
+      await Provider.of<CategoriaProductoViewModel>(context, listen: false)
+          .fetchCategoriaProductos();
+      List<CategoriaProducto> catProductos =
+          Provider.of<CategoriaProductoViewModel>(context, listen: false)
+              .categoriaProductos;
+      Producto? modelo = mvm.selectedProducto;
+      if (modelo != null && modelo.id > 0) {
+        setState(() {
+          _nombre.text = modelo.nombre.toString();
+          _descripcion.text = modelo.descripcion.toString();
+          _precio.text = modelo.precio.toString();
+          _existencia.text = modelo.existencia.toString();
+          _descuento.text = modelo.descuento.toString();
+          if (modelo.idCategoria != null &&
+              modelo.idCategoria! != "" &&
+              modelo.categoria != null) {
+            categoriaProducto = modelo.categoria;
+          }
+          if (categoriaProducto == null && catProductos.isNotEmpty) {
+            categoriaProducto = catProductos.first;
+          }
+        });
+      }
+      Provider.of<ProductoViewModel>(context, listen: false)
+          .setIsLoading(false);
+    });
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+    _descripcion.dispose();
+    _nombre.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final mvm = Provider.of<ProductoViewModel>(context);
+    final evm = Provider.of<CategoriaProductoViewModel>(context);
+    if (mvm.isLoading) return const Cargando();
+    final producto = mvm.selectedProducto;
+    List<CategoriaProducto> categoriaProductos = [];
+    if (evm.categoriaProductos.isNotEmpty) {
+      categoriaProductos = evm.categoriaProductos;
+    }
+
+    return Scaffold(
+      appBar: encabezado(titulo: "Producto"),
+      body: SingleChildScrollView(
+        padding: const EdgeInsets.all(8),
+        child: Column(
+          children: [
+            tarjeta(
+              Padding(
+                padding: const EdgeInsets.all(8),
+                child: Column(
+                  children: [
+                    categoriaProductos.isNotEmpty
+                        ? AppDropdownSearch(
+                            etiqueta: 'Categoría',
+                            controller: _busquedaCategoria,
+                            selectedItem: categoriaProducto,
+                            onPressedClear: () {
+                              categoriaProducto = null;
+                            },
+                            itemAsString: (item) => '${item.nombre}',
+                            asyncItems: (text) async {
+                              final xregistros = await evm.getCategoriaProducto(
+                                  q: text, segmentar: true);
+                              return xregistros;
+                            },
+                            onChanged: (value) {
+                              categoriaProducto = value;
+                            },
+                            validator: (value) {
+                              if (value == null) {
+                                return 'Seleccione';
+                              }
+                              return null;
+                            },
+                          )
+                        : Container(),
+                    Row(
+                      children: [
+                        Expanded(
+                          child: AppTextField(
+                            maxLength: 100,
+                            etiqueta: 'Nombre',
+                            controller: _nombre,
+                            hintText: 'Nombre producto',
+                          ),
+                        ),
+                      ],
+                    ),
+                    Row(
+                      children: [
+                        Expanded(
+                          child: AppTextField(
+                            maxLength: 100,
+                            etiqueta: 'Precio',
+                            controller: _precio,
+                            hintText: 'Precio del producto',
+                          ),
+                        ),
+                      ],
+                    ),
+                    Row(
+                      children: [
+                        Expanded(
+                          child: AppTextField(
+                            maxLength: 100,
+                            etiqueta: 'Existencia',
+                            controller: _existencia,
+                            hintText: 'Existencia del producto',
+                          ),
+                        ),
+                      ],
+                    ),
+                    Row(
+                      children: [
+                        Expanded(
+                          child: AppTextField(
+                            maxLength: 1000,
+                            maxLines: 3,
+                            etiqueta: 'Descripción',
+                            controller: _descripcion,
+                            hintText: 'descripción del producto',
+                          ),
+                        ),
+                      ],
+                    ),
+                  ],
+                ),
+              ),
+            ),
+            const SizedBox(height: 15),
+            boton("Guardar", () async {
+              if (categoriaProducto == null ||
+                  categoriaProducto!.id == null ||
+                  categoriaProducto!.id == "") {
+                await alerta(context, etiqueta: "Seleccionar categoría");
+                return;
+              }
+              Provider.of<ProductoViewModel>(context, listen: false)
+                  .setIsLoading(true);
+              await mvm.guardarModelo(
+                  modelo: producto!,
+                  nombre: _nombre.text,
+                  descripcion: _descripcion.text,
+                  precio: _precio.text,
+                  descuento: _descuento.text,
+                  existencia: int.tryParse(_existencia.text) ?? 0,
+                  venceDescuento: _venceDescuento.text,
+                  idCategoria: categoriaProducto?.id ?? 0);
+              Provider.of<ProductoViewModel>(context, listen: false)
+                  .setIsLoading(false);
+              if (context.mounted) {
+                Navigator.pop(context);
+              }
+            }),
+          ],
+        ),
+      ),
+    );
+  }
+}

+ 239 - 0
lib/views/producto/producto_screen.dart

@@ -0,0 +1,239 @@
+// ignore_for_file: use_build_context_synchronously
+
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import '../../models/models.dart';
+import '../../themes/themes.dart';
+import '../../viewmodels/viewmodels.dart';
+import '../../widgets/app_textfield.dart';
+import '../../widgets/pagination_buttons.dart';
+import '../../widgets/widgets_components.dart';
+import 'producto_form.dart';
+
+class ProductoScreen extends StatefulWidget {
+  const ProductoScreen({Key? key}) : super(key: key);
+
+  @override
+  State<ProductoScreen> createState() => Formulario();
+}
+
+class Formulario extends State<ProductoScreen> {
+  final _busqueda = TextEditingController(text: '');
+
+  @override
+  void initState() {
+    super.initState();
+    Future(() async {
+      await Provider.of<ProductoViewModel>(context, listen: false)
+          .fetchRegistros();
+      await Provider.of<CategoriaProductoViewModel>(context, listen: false)
+          .fetchCategoriaProductos(segmentar: true);
+    });
+  }
+
+  go(Producto item) async {
+    Provider.of<ProductoViewModel>(context, listen: false).selectModelo(item);
+    Navigator.push(
+      context,
+      MaterialPageRoute(
+        builder: (context) => const ProductoForm(),
+      ),
+    ).then((value) async {
+      await Provider.of<ProductoViewModel>(context, listen: false)
+          .fetchRegistros();
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final evm = Provider.of<CategoriaProductoViewModel>(context);
+    List<CategoriaProducto> categoriaProductos = [];
+    if (evm.categoriaProductos.isNotEmpty) {
+      categoriaProductos = evm.categoriaProductos;
+    }
+
+    final mvm = Provider.of<ProductoViewModel>(context);
+    TextStyle estilo = const TextStyle(fontWeight: FontWeight.bold);
+    int vuelta = 0;
+    List<DataRow> registros = [];
+    if (mvm.registros.isNotEmpty) {
+      for (Producto item in mvm.registros) {
+        String? categoriaProducto = "";
+        if (item.idCategoria != null) {
+          categoriaProducto = item.categoria!.nombre;
+        }
+
+        var _tipo = vuelta % 2;
+        vuelta++;
+        registros.add(DataRow(selected: _tipo > 0, cells: [
+          DataCell(
+            Text(item.nombre.toString()),
+            onTap: () => go(item),
+          ),
+          DataCell(
+            Text(item.descripcion.toString()),
+            onTap: () => go(item),
+          ),
+          DataCell(
+            Text(categoriaProducto.toString()),
+            onTap: () => go(item),
+          ),
+          DataCell(
+            Text(item.precio.toString()),
+            onTap: () => go(item),
+          ),
+          DataCell(
+            Text(item.venta.toString()),
+            onTap: () => go(item),
+          ),
+          DataCell(
+            Text(item.existencia.toString()),
+            onTap: () => go(item),
+          ),
+          DataCell(
+              Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
+            PopupMenuButton(
+              surfaceTintColor: AppTheme.primary,
+              itemBuilder: (context) => [
+                PopupMenuItem(
+                  child: const Text('Editar'),
+                  onTap: () => go(item),
+                ),
+                PopupMenuItem(
+                  child: const Text(
+                    'Eliminar',
+                  ),
+                  onTap: () async {
+                    return showDialog(
+                      context: context,
+                      builder: (context) {
+                        return AlertDialog(
+                          title: const Text("Eliminar registro"),
+                          content: const Text('¿Desea eliminar el registro?'),
+                          actions: [
+                            Row(children: [
+                              Expanded(
+                                  child: TextButton(
+                                onPressed: () {
+                                  Navigator.pop(context);
+                                },
+                                child: const Text('Cancelar'),
+                              )),
+                              Expanded(
+                                  child: TextButton(
+                                onPressed: () async {
+                                  Navigator.pop(context);
+                                },
+                                child: const Text('Continuar'),
+                              ))
+                            ])
+                          ],
+                        );
+                      },
+                    );
+                  },
+                )
+              ],
+              icon: const Icon(Icons.more_vert),
+              shape: RoundedRectangleBorder(
+                  borderRadius: BorderRadius.circular(15)),
+            )
+          ]))
+        ]));
+      }
+    }
+
+    return Scaffold(
+      appBar: AppBar(
+        title: const Text('Productos'),
+      ),
+      floatingActionButton: FloatingActionButton(
+        onPressed: () {
+          mvm.selectModelo(Producto());
+          Navigator.push(
+            context,
+            MaterialPageRoute(
+              builder: (context) => const ProductoForm(),
+            ),
+          ).then((value) async {
+            await Provider.of<ProductoViewModel>(context, listen: false)
+                .fetchRegistros();
+          });
+        },
+        child: const Icon(Icons.add),
+      ),
+      body: Column(
+        children: [
+          Expanded(
+            child: ListView(
+              padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
+              children: [
+                const SizedBox(height: 8),
+                tarjeta(Padding(
+                    padding: const EdgeInsets.all(10),
+                    child: Row(
+                      children: [
+                        Expanded(
+                          flex: 8,
+                          child: AppTextField(
+                            prefixIcon: const Icon(Icons.search),
+                            maxLength: 100,
+                            etiqueta: 'Búsqueda por nombre...',
+                            controller: _busqueda,
+                            hintText: 'Búsqueda por nombre...',
+                          ),
+                        ),
+                        const SizedBox(width: 5),
+                        Expanded(
+                          flex: 2,
+                          child: botonElevated(
+                            accion: () async {
+                              _busqueda.text = _busqueda.text.trim();
+                              await Provider.of<ProductoViewModel>(context,
+                                      listen: false)
+                                  .setIsLoading(true);
+                              await Provider.of<ProductoViewModel>(context,
+                                      listen: false)
+                                  .setBusqueda(_busqueda.text);
+                              await Provider.of<ProductoViewModel>(context,
+                                      listen: false)
+                                  .fetchRegistros();
+                              await Provider.of<ProductoViewModel>(context,
+                                      listen: false)
+                                  .setBusqueda("");
+                              await Provider.of<ProductoViewModel>(context,
+                                      listen: false)
+                                  .setIsLoading(false);
+                            },
+                          ),
+                        ),
+                      ],
+                    ))),
+                const SizedBox(height: 8),
+                tarjeta(DataTable(
+                    sortAscending: true,
+                    sortColumnIndex: 1,
+                    columns: [
+                      DataColumn(label: Text("NOMBRE", style: estilo)),
+                      DataColumn(label: Text("DESCRIPCIÓN", style: estilo)),
+                      DataColumn(
+                          label: Text("CATEGORÍA PRODUCTOS", style: estilo)),
+                      DataColumn(label: Text("PRECIO", style: estilo)),
+                      DataColumn(label: Text("VENTAS", style: estilo)),
+                      DataColumn(label: Text("EN EXISTENCIA", style: estilo)),
+                      DataColumn(label: Text("", style: estilo)),
+                    ],
+                    rows: registros)),
+                PaginationButtons(
+                  currentPage: mvm.pagina,
+                  totalPages: mvm.totalPaginas,
+                  onPageChanged: (i) => mvm.cambiarPagina(i),
+                )
+              ],
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 3 - 1
lib/widgets/app_drawer.dart

@@ -1,10 +1,12 @@
 // ignore_for_file: must_be_immutable
 
 import 'package:flutter/material.dart';
+import 'package:yoshi_papas_app/models/models.dart';
 import 'package:yoshi_papas_app/views/categoria_producto/categoria_producto_screen.dart';
 import 'package:yoshi_papas_app/views/home/home_screen.dart';
 import 'package:yoshi_papas_app/views/perfil/perfil_screen.dart';
 import 'package:yoshi_papas_app/views/pedido/pedido_screen.dart';
+import 'package:yoshi_papas_app/views/producto/producto_screen.dart';
 import '../models/usuario_model.dart';
 import 'package:provider/provider.dart';
 import '../themes/themes.dart';
@@ -143,7 +145,7 @@ class AppDrawer extends StatelessWidget {
                 Navigator.pop(context),
                 Navigator.of(context).push(
                   MaterialPageRoute(
-                    builder: (context) => const HomeScreen(),
+                    builder: (context) => const ProductoScreen(),
                   ),
                 ),
               },

+ 0 - 1
lib/widgets/widgets.dart

@@ -6,4 +6,3 @@ export '../widgets/app_text_span.dart';
 export '../widgets/app_drawer.dart';
 export '../widgets/widgets_components.dart';
 export '../widgets/pagination_buttons.dart';
-export '../widgets/app_form_button.dart';