diff --git a/lib/config/rutas.dart b/lib/config/rutas.dart index aaa4c02..95330d7 100644 --- a/lib/config/rutas.dart +++ b/lib/config/rutas.dart @@ -7,6 +7,6 @@ Map getApplicationRoutes() { return { 'login': (context) => const LoginPage(), 'home': (context) => const HomePage(), - 'articles': (context) => const ArticlesPage(), + 'articles': (context) => const ArticlePage(categoryId: 1), }; } diff --git a/lib/src/controllers/ArticuloController.dart b/lib/src/controllers/ArticuloController.dart new file mode 100644 index 0000000..040d040 --- /dev/null +++ b/lib/src/controllers/ArticuloController.dart @@ -0,0 +1,49 @@ +import 'dart:convert'; +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:miapp_flutter/src/models/ArticuloModel.dart'; +import '../http_api/ArticleApi.dart'; + +class ArticuloController { + final Connectivity _connectivity = Connectivity(); + final ArticleApi _articleApi = ArticleApi(); + + Future> getArticles(int categoryId) async { + Map mapResp = { + 'ok': false, + 'message': 'No hay artículos', + 'data': null + }; + + // Verificar la conectividad de la red + List connectivityResult = await _connectivity.checkConnectivity(); + if (!connectivityResult.contains(ConnectivityResult.none)) { + if (connectivityResult.contains(ConnectivityResult.wifi) || connectivityResult.contains(ConnectivityResult.mobile)) { + try { + // Realizar la solicitud a la API + Map respGet = await _articleApi.getArticles(categoryId); + if (respGet['statusCode'] == 200) { + try { + var decodeResp = json.decode(respGet['body']); + List listArticles = ArticleModel.fromJsonArray(decodeResp['data']); + mapResp['ok'] = true; + mapResp['message'] = "${listArticles.length} artículos encontrados"; + mapResp['data'] = listArticles; + } catch (e) { + mapResp['message'] = "Error en procesamiento de datos: $e"; + } + } else { + mapResp['message'] = "Error en la respuesta de la API: ${respGet['body']}"; + } + } catch (e) { + mapResp['message'] = "Error en la solicitud a la API: $e"; + } + } else { + mapResp['message'] = 'No hay conexión a internet'; + } + } else { + mapResp['message'] = 'No hay conexión a internet'; + } + + return mapResp; + } +} \ No newline at end of file diff --git a/lib/src/http_api/ArticleApi.dart b/lib/src/http_api/ArticleApi.dart new file mode 100644 index 0000000..b9c53d3 --- /dev/null +++ b/lib/src/http_api/ArticleApi.dart @@ -0,0 +1,37 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:flutter/foundation.dart'; +import 'package:miapp_flutter/environments/archivo.dart'; + +class ArticleApi { + final String apiUrl = 'articulo'; + + // Método para obtener los artículos + Future> getArticles(int categoryId) async { + String url = '${apiApp}/$apiUrl?categoria=$categoryId&offset=0&max=100'; + if (kDebugMode) { + print('Url -> $url'); + } + try { + final response = await http.get(Uri.parse(url)); + + // Verifica el estado de la respuesta + if (response.statusCode == 200) { + return { + 'statusCode': response.statusCode, + 'body': response.body, + }; + } else { + return { + 'statusCode': response.statusCode, + 'body': 'Error: ${response.reasonPhrase}', + }; + } + } catch (e) { + return { + 'statusCode': 501, + 'body': 'Error: $e', + }; + } + } +} diff --git a/lib/src/pages/articles_page.dart b/lib/src/pages/articles_page.dart index dad77c0..709c9c2 100644 --- a/lib/src/pages/articles_page.dart +++ b/lib/src/pages/articles_page.dart @@ -1,22 +1,70 @@ import 'package:flutter/material.dart'; -class ArticlesPage extends StatelessWidget { - const ArticlesPage({Key? key}) : super(key: key); +import '../controllers/ArticuloController.dart'; +import '../models/ArticuloModel.dart'; + + +class ArticlePage extends StatefulWidget { + final int categoryId; + + const ArticlePage({Key? key, required this.categoryId}) : super(key: key); + + @override + _ArticlePageState createState() => _ArticlePageState(); +} + +class _ArticlePageState extends State { + final ArticuloController _articleController = ArticuloController(); + late Future> _articlesFuture; + + @override + void initState() { + super.initState(); + _articlesFuture = _articleController.getArticles(widget.categoryId); + } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Articles Page'), + title: const Text('Artículos'), + backgroundColor: Colors.indigoAccent, + foregroundColor: Colors.white, ), - body: Center( - child: ElevatedButton( - onPressed: () { - Navigator.pushNamed(context, 'login'); - }, - child: const Text('Hola articles_page'), - ), + + body: FutureBuilder>( + future: _articlesFuture, + builder: (context, snapshot) { + if (snapshot.hasData) { + if (snapshot.data!['ok']) { + if (snapshot.data!['data'] != null && (snapshot.data!['data'] as List).isNotEmpty) { + List articles = snapshot.data!['data'] as List; + return ListView.builder( + itemCount: articles.length, + itemBuilder: (context, index) { + final article = articles[index]; + return Card( + child: ListTile( + title: Text(article.nombre), + subtitle: Text('Clave: ${article.clave}'), + trailing: Text('\$${article.precios.isNotEmpty ? article.precios.first.precio.toStringAsFixed(2) : 'N/A'}'), + ), + ); + }, + ); + } else { + return Center(child: Text('No se encontraron artículos.')); + } + } else { + return Center(child: Text('Error: ${snapshot.data!['message']}')); + } + } else if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); + } else { + return const Center(child: CircularProgressIndicator()); + } + }, ), ); } -} +} \ No newline at end of file diff --git a/lib/src/pages/category/CategoryListWidget.dart b/lib/src/pages/category/CategoryListWidget.dart index d7a4182..aa453e2 100644 --- a/lib/src/pages/category/CategoryListWidget.dart +++ b/lib/src/pages/category/CategoryListWidget.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; - +import 'package:miapp_flutter/src/pages/articles_page.dart'; import '../../controllers/CategoriaController.dart'; import '../../models/CategoriaModel.dart'; @@ -9,15 +9,14 @@ class CategoryListWidget extends StatefulWidget { } class _CategoryWidgetState extends State { - final CategoryController _categoryCtrl = CategoryController(); //El categoryCtrl se usa para obtener las categorías + final CategoryController _categoryCtrl = CategoryController(); @override Widget build(BuildContext context) { return SafeArea( child: Padding( padding: const EdgeInsets.all(16.0), - child: FutureBuilder>( //El futureBuilder se utiliza para - // manejar operaciones asíncronas y donde map tiene las categorias + child: FutureBuilder>( future: _categoryCtrl.getCategories(), builder: (context, snapshot) { if (snapshot.hasData) { @@ -32,7 +31,12 @@ class _CategoryWidgetState extends State { title: Text(category.name ?? 'No Name'), leading: const Icon(Icons.touch_app), onTap: () { - // Navegar al listado de servicios + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ArticlePage(categoryId: category.id), + ), + ); }, ), ); @@ -57,4 +61,4 @@ class _CategoryWidgetState extends State { ), ); } -} \ No newline at end of file +}