pedido_form.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. import 'package:flutter/material.dart';
  2. import '../../themes/themes.dart'; // Asegúrate de tener este archivo con los temas correctos
  3. import '../../models/models.dart'; // Tus modelos de datos
  4. import '../../viewmodels/viewmodels.dart'; // Tus ViewModels
  5. class PedidoForm extends StatefulWidget {
  6. @override
  7. _PedidoFormState createState() => _PedidoFormState();
  8. }
  9. class ItemCarrito {
  10. Producto producto;
  11. int cantidad;
  12. ItemCarrito({required this.producto, this.cantidad = 1});
  13. }
  14. class _PedidoFormState extends State<PedidoForm> {
  15. CategoriaProductoViewModel cvm = CategoriaProductoViewModel();
  16. ProductoViewModel pvm = ProductoViewModel();
  17. bool _isLoading = false;
  18. ScrollController horizontalScrollController = ScrollController();
  19. CategoriaProducto? categoriaSeleccionada;
  20. List<CategoriaProducto> categorias = [];
  21. List<Producto> productos = [];
  22. List<ItemCarrito> carrito = [];
  23. double calcularTotalPedido() {
  24. double total = 0;
  25. for (var item in carrito) {
  26. total += double.parse(item.producto.precio!) * item.cantidad;
  27. }
  28. return total;
  29. }
  30. @override
  31. void initState() {
  32. super.initState();
  33. cargarCategoriasIniciales();
  34. }
  35. @override
  36. void dispose() {
  37. horizontalScrollController.dispose();
  38. super.dispose();
  39. }
  40. Future<void> cargarCategoriasIniciales() async {
  41. setState(() => _isLoading = true);
  42. var categoriasObtenidas = await cvm.getCategoriaProducto();
  43. setState(() {
  44. categorias = categoriasObtenidas;
  45. _isLoading = false;
  46. // Selecciona la primera categoría por defecto si hay categorías disponibles
  47. if (categorias.isNotEmpty) {
  48. categoriaSeleccionada = categorias.first;
  49. seleccionarCategoria(categoriaSeleccionada!);
  50. }
  51. });
  52. }
  53. Future<void> seleccionarCategoria(CategoriaProducto categoria) async {
  54. if (!mounted) return;
  55. setState(() {
  56. _isLoading = true;
  57. categoriaSeleccionada = categoria;
  58. });
  59. productos = await pvm.fetchRegistros(categoriaProducto: categoria);
  60. if (!mounted) return;
  61. setState(() => _isLoading = false);
  62. }
  63. void agregarAlCarrito(Producto producto) {
  64. setState(() {
  65. var indice =
  66. carrito.indexWhere((item) => item.producto.id == producto.id);
  67. if (indice != -1) {
  68. carrito[indice].cantidad++;
  69. } else {
  70. // Se agrega el nuevo producto al carrito con cantidad inicial de 1
  71. carrito.add(ItemCarrito(producto: producto));
  72. }
  73. });
  74. }
  75. void quitarDelCarrito(Producto producto) {
  76. setState(() {
  77. // Comienza con setState por la misma razón
  78. var indice =
  79. carrito.indexWhere((item) => item.producto.id == producto.id);
  80. if (indice != -1) {
  81. if (carrito[indice].cantidad > 1) {
  82. carrito[indice].cantidad--;
  83. } else {
  84. carrito.removeAt(indice);
  85. }
  86. }
  87. });
  88. }
  89. @override
  90. Widget build(BuildContext context) {
  91. return Scaffold(
  92. appBar: AppBar(
  93. title: Text("Crear Pedido"),
  94. ),
  95. body: Row(
  96. children: [
  97. Flexible(
  98. flex: 3,
  99. child: _buildCartSection(),
  100. ),
  101. SizedBox(width: 35),
  102. Flexible(
  103. flex: 7,
  104. child: _buildProductsSection(),
  105. ),
  106. ],
  107. ),
  108. );
  109. }
  110. Widget _buildTotalSection() {
  111. double total =
  112. calcularTotalPedido(); // Aquí llamarías a la función calcularTotalPedido
  113. return Padding(
  114. padding: const EdgeInsets.symmetric(horizontal: 8.0),
  115. child: Row(
  116. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  117. children: [
  118. const Text('Total',
  119. style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
  120. Text("\$${total.toStringAsFixed(2)}",
  121. style:
  122. const TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
  123. ],
  124. ),
  125. );
  126. }
  127. Widget _buildCartSection() {
  128. return Card(
  129. margin: const EdgeInsets.all(8.0),
  130. child: Column(
  131. children: [
  132. const Padding(
  133. padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 16.0),
  134. child: Row(
  135. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  136. children: [
  137. Text('Producto',
  138. style:
  139. TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
  140. Text('Cantidad',
  141. style:
  142. TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
  143. ],
  144. ),
  145. ),
  146. Expanded(
  147. child: ListView.builder(
  148. itemCount: carrito.length,
  149. itemBuilder: (context, index) {
  150. final item = carrito[index];
  151. return ListTile(
  152. title: Text(item.producto.nombre!),
  153. subtitle: Text('\$${item.producto.precio}'),
  154. trailing: Row(
  155. mainAxisSize: MainAxisSize.min,
  156. children: [
  157. IconButton(
  158. icon: const Icon(Icons.delete, color: Colors.red),
  159. onPressed: () => eliminarProductoDelCarrito(index),
  160. ),
  161. IconButton(
  162. icon: const Icon(Icons.remove),
  163. onPressed: () => quitarDelCarrito(item.producto),
  164. ),
  165. const SizedBox(width: 5),
  166. Text(
  167. '${item.cantidad}',
  168. style: const TextStyle(
  169. fontWeight: FontWeight.bold, fontSize: 14),
  170. ),
  171. const SizedBox(width: 5),
  172. IconButton(
  173. icon: const Icon(Icons.add),
  174. onPressed: () => agregarAlCarrito(item.producto),
  175. ),
  176. // Botón para eliminar el producto del carrito
  177. ],
  178. ),
  179. );
  180. },
  181. ),
  182. ),
  183. const Divider(
  184. thickness: 5,
  185. ),
  186. _buildTotalSection(),
  187. const SizedBox(height: 25),
  188. Padding(
  189. padding: const EdgeInsets.all(8.0),
  190. child: ElevatedButton(
  191. onPressed: () {
  192. // Aquí implementarías la lógica para finalizar el pedido
  193. },
  194. style: ElevatedButton.styleFrom(
  195. primary: AppTheme.primary,
  196. onPrimary: AppTheme.secondary,
  197. textStyle: const TextStyle(fontSize: 22),
  198. fixedSize: const Size(250, 50)),
  199. child: const Text('Finalizar Pedido'),
  200. ),
  201. ),
  202. ],
  203. ),
  204. );
  205. }
  206. void eliminarProductoDelCarrito(int index) {
  207. setState(() {
  208. carrito.removeAt(index);
  209. });
  210. }
  211. Widget _buildProductsSection() {
  212. // Asumiendo que tienes un método para obtener los productos según la categoría seleccionada
  213. return Column(
  214. children: [
  215. _buildCategoryButtons(),
  216. const SizedBox(height: 10),
  217. Expanded(
  218. child: GridView.builder(
  219. gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
  220. crossAxisCount: 3, // Número de columnas
  221. childAspectRatio: 3 / 2, // Proporción de cada tarjeta
  222. ),
  223. itemCount: productos.length,
  224. itemBuilder: (context, index) {
  225. final producto = productos[index];
  226. return Card(
  227. child: InkWell(
  228. onTap: () {
  229. setState(() {
  230. // Aquí manejas la adición de productos al carrito
  231. agregarAlCarrito(producto);
  232. });
  233. },
  234. child: Column(
  235. mainAxisAlignment: MainAxisAlignment.center,
  236. children: [
  237. const Icon(Icons.fastfood, size: 80),
  238. const SizedBox(height: 8),
  239. Padding(
  240. padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
  241. child: Text(
  242. producto.nombre ?? '',
  243. style: const TextStyle(
  244. fontSize: 16, fontWeight: FontWeight.bold),
  245. )),
  246. const SizedBox(height: 8),
  247. Text(
  248. '\$${producto.precio}',
  249. style: const TextStyle(
  250. fontSize: 16,
  251. fontWeight: FontWeight.bold,
  252. color: Color(0xFF008000)),
  253. ),
  254. ],
  255. ),
  256. ),
  257. );
  258. },
  259. ),
  260. ),
  261. ],
  262. );
  263. }
  264. Widget _buildCategoryButtons() {
  265. return Column(
  266. mainAxisSize: MainAxisSize.min,
  267. children: [
  268. SizedBox(
  269. height: 50, // Altura para los botones
  270. child: Scrollbar(
  271. controller: horizontalScrollController,
  272. thumbVisibility: true,
  273. thickness: 5.0,
  274. child: ListView.builder(
  275. scrollDirection: Axis.horizontal,
  276. itemCount: categorias.length,
  277. controller: horizontalScrollController,
  278. itemBuilder: (context, index) {
  279. final categoria = categorias[index];
  280. bool esSeleccionada = categoriaSeleccionada?.id == categoria.id;
  281. return Padding(
  282. padding: const EdgeInsets.symmetric(horizontal: 4.0),
  283. child: ElevatedButton(
  284. onPressed: () => seleccionarCategoria(categoria),
  285. style: ElevatedButton.styleFrom(
  286. primary: esSeleccionada
  287. ? const Color(0xFFFF848F)
  288. : Colors.white,
  289. onPrimary: Colors.black,
  290. textStyle: const TextStyle(
  291. fontWeight: FontWeight.bold,
  292. ),
  293. shape: RoundedRectangleBorder(
  294. borderRadius: BorderRadius.circular(18.0),
  295. side: BorderSide(
  296. color: esSeleccionada ? Colors.black : Colors.grey),
  297. ),
  298. ),
  299. child: Text(categoria.nombre ?? 'Sin nombre'),
  300. ),
  301. );
  302. },
  303. ),
  304. ),
  305. ),
  306. ],
  307. );
  308. }
  309. }