diff --git a/lib/components/templates_components/card_item_template_component/card_item_template_component_widget.dart b/lib/components/templates_components/card_item_template_component/card_item_template_component_widget.dart index 5a55d31c..b03e6941 100644 --- a/lib/components/templates_components/card_item_template_component/card_item_template_component_widget.dart +++ b/lib/components/templates_components/card_item_template_component/card_item_template_component_widget.dart @@ -102,8 +102,8 @@ class _CardItemTemplateComponentWidgetState borderRadius: BorderRadius.circular(8.0), ), child: Container( - width: 350.0, - height: 115.0, + width: 350, + height: 125, decoration: BoxDecoration( color: FlutterFlowTheme.of(context).primaryBackground, ), @@ -147,7 +147,6 @@ class _CardItemTemplateComponentWidgetState fontFamily: FlutterFlowTheme.of(context) .bodyMediumFamily, - fontSize: screenWidth * 0.025, letterSpacing: 0.0, fontWeight: FontWeight.bold, useGoogleFonts: GoogleFonts @@ -158,12 +157,10 @@ class _CardItemTemplateComponentWidgetState .bodyMediumFamily), color: FlutterFlowTheme.of(context) - .customColor6, + .primaryText, ), ), - const SizedBox( - width: - 5.0), // Espaçamento entre o label e o valor + const SizedBox(width: 3.0), // Espaçamento entre o label e o valor Flexible( child: Text( value, diff --git a/lib/components/templates_components/details_component/details_component_action.dart b/lib/components/templates_components/details_component/details_component_action.dart index 1cd30554..50616ec9 100644 --- a/lib/components/templates_components/details_component/details_component_action.dart +++ b/lib/components/templates_components/details_component/details_component_action.dart @@ -11,18 +11,14 @@ import 'package:hub/flutter_flow/flutter_flow_widgets.dart'; import 'package:hub/flutter_flow/internationalization.dart'; import 'package:hub/flutter_flow/nav/nav.dart'; import 'package:hub/pages/schedule_complete_visit_page/schedule_complete_visit_page_widget.dart'; +import 'package:hub/shared/utils/validator_util.dart'; import 'package:rxdart/rxdart.dart'; import 'package:share_plus/share_plus.dart'; -Widget buildDetails( - dynamic visitaWrapItem, - BuildContext context, - Future Function(BuildContext, int, int, String, String)? - changeStatusAction) { +Widget buildDetails(dynamic visitaWrapItem, BuildContext context, Future Function(BuildContext, int, int, String, String)? changeStatusAction) { return DetailsComponentWidget( buttons: [ - if (getStatus(visitaWrapItem['VAW_STATUS']) == - status.active) // REJECT ACTION + if (getStatus(visitaWrapItem['VAW_STATUS']) == status.active) // REJECT ACTION FFButtonWidget( text: FFLocalizations.of(context).getVariableText( ptText: 'Cancelar', @@ -172,9 +168,9 @@ URL do Convite: https://visita.freaccess.com.br/${visitaWrapItem['VAW_ID']}/${vi ), ], labelsHashMap: Map.from({ - 'Nome': visitaWrapItem['VTE_NOME'] ?? '', - 'Inicio': visitaWrapItem['VAW_DTINICIO'] ?? '', - 'Fim': visitaWrapItem['VAW_DTFIM'] ?? '', + '${FFLocalizations.of(context).getVariableText(ptText: "Nome", enText: "Name")}:': visitaWrapItem['VTE_NOME'] ?? '', + '${FFLocalizations.of(context).getVariableText(ptText: "Inicio", enText: "Start")}:': visitaWrapItem['VAW_DTINICIO'] != '' && visitaWrapItem['VAW_DTINICIO'] != null ? ValidatorUtil.toLocalDateTime('yyyy-MM-dd HH:mm:ss', visitaWrapItem['VAW_DTINICIO']) : '', + '${FFLocalizations.of(context).getVariableText(ptText: "Fim", enText: "End")}:': visitaWrapItem['VAW_DTFIM'] != '' && visitaWrapItem['VAW_DTFIM'] != null ? ValidatorUtil.toLocalDateTime('yyyy-MM-dd HH:mm:ss', visitaWrapItem['VAW_DTFIM']) : '', }), imagePath: 'https://freaccess.com.br/freaccess/getImage.php?cliID=${FFAppState().cliUUID}&atividade=getFoto&Documento=${visitaWrapItem['VTE_DOCUMENTO'] ?? ''}&tipo=E', diff --git a/lib/pages/visit_history_page/visit_history_page_widget.dart b/lib/pages/visit_history_page/visit_history_page_widget.dart index c502759a..52b38c45 100644 --- a/lib/pages/visit_history_page/visit_history_page_widget.dart +++ b/lib/pages/visit_history_page/visit_history_page_widget.dart @@ -11,188 +11,248 @@ import 'package:hub/flutter_flow/flutter_flow_theme.dart'; import 'package:hub/flutter_flow/flutter_flow_util.dart'; import 'package:hub/flutter_flow/internationalization.dart'; import 'package:hub/pages/schedule_complete_visit_page/schedule_complete_visit_page_model.dart'; +import 'package:hub/shared/utils/dialog_util.dart'; +import 'package:hub/shared/utils/log_util.dart'; +import 'package:hub/shared/utils/validator_util.dart'; class VisitHistoryWidget extends StatefulWidget { - VisitHistoryWidget({ - Key? key, - }) : super(key: key); + VisitHistoryWidget({Key? key}) : super(key: key); @override _VisitHistoryWidgetState createState() => _VisitHistoryWidgetState(); } -class _VisitHistoryWidgetState extends State { - List visitaWrap = []; - var pageNumber = 1; - late Future visitFuture; +class _VisitHistoryWidgetState extends State with TickerProviderStateMixin { + late ScrollController _scrollController; + int _pageNumber = 1; + final int _pageSize = 10; + bool _hasData = false; + bool _loading = false; + + late Future _visitFuture; + List _visitWrap = []; @override void initState() { super.initState(); - visitFuture = _fetchVisits(); + _visitFuture = _fetchVisits(); + + _scrollController = ScrollController()..addListener(() { + if (_scrollController.position.atEdge && _scrollController.position.pixels != 0) { + _loadMore(); + } + }); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); } Future _fetchVisits() async { try { + setState(() => _loading = true); + var response = await ScheduleCompleteVisitPageModel().visitHistory( requestFn: () => PhpGroup.getVisitsCall.call( devUUID: FFAppState().devUUID, userUUID: FFAppState().userUUID, cliID: FFAppState().cliUUID, atividade: 'getVisitas', - pageSize: 10, - pageNumber: pageNumber, + pageSize: _pageSize, + pageNumber: _pageNumber, ), ); - var newVisits = response.jsonBody['visitas'] - as List?; // Ajuste conforme a estrutura da resposta - if (newVisits != null && newVisits.isNotEmpty) { - safeSetState(() { - visitaWrap.addAll(newVisits); + final List visits = response.jsonBody['visitas'] ?? []; + + if (visits != null && visits.isNotEmpty) { + setState(() { + _visitWrap.addAll(visits); + _hasData = true; + _loading = false; }); + return response; - } else { - log('No new visits found'); - return null; } - } catch (err) { - log('Erro ao carregar mais visitas: $err'); + + _showNoMoreDataSnackBar(context); + + setState(() { + _hasData = false; + _loading = false; + }); + + return null; + } catch (e, s) { + DialogUtil.errorDefault(context); + LogUtil.requestAPIFailed("proccessRequest.php", "", "Consulta de Visitas", e, s); + setState(() { + _hasData = false; + _loading = false; + }); } } - void _loadMoreVisits() { - pageNumber++; - visitFuture = _fetchVisits(); + void _loadMore() { + if (_hasData == true) { + _pageNumber++; + _visitFuture = _fetchVisits(); + } + } + + void _showNoMoreDataSnackBar(BuildContext context) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + FFLocalizations.of(context).getVariableText( + ptText: "Não há mais dados.", enText: "No more data."), + ), + duration: const Duration(seconds: 3), + backgroundColor: FlutterFlowTheme.of(context).primary, + ), + ); } @override Widget build(BuildContext context) { - return FutureBuilder( - future: visitFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting && - visitaWrap.isEmpty) { - return Center( - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - FlutterFlowTheme.of(context).primary, - ), - ), - ); - } else if (snapshot.hasError) { - return Center(child: Text('Error: ${snapshot.error}')); - } else if (visitaWrap.isEmpty) { - return Center( - child: Text( - FFLocalizations.of(context).getVariableText( - ptText: 'Nenhum visitante foi encontrado', - enText: 'No visitors found', - ), - ), - ); - } - return ListView.builder( - itemCount: visitaWrap.length + 1, - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - itemBuilder: (context, index) { - if (index == visitaWrap.length) { - _loadMoreVisits(); - return Center( - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - FlutterFlowTheme.of(context).primary, - ), - ), - ); - } - - final visitaWrapItem = visitaWrap[index]; - - return CardItemTemplateComponentWidget( - imagePath: - 'https://freaccess.com.br/freaccess/getImage.php?devUUID=${FFAppState().devUUID}&userUUID=${FFAppState().userUUID}&cliID=${FFAppState().cliUUID}&atividade=getFoto&Documento=${visitaWrapItem['VTE_DOCUMENTO'] ?? ''}&tipo=E', - labelsHashMap: { - 'Nome:': visitaWrapItem['VTE_NOME'] ?? '', - 'Inicio:': visitaWrapItem['VAW_DTINICIO'] ?? '', - 'Fim:': visitaWrapItem['VAW_DTFIM'] ?? '', - }, - statusHashMap: [ - if (getStatus(visitaWrapItem['VAW_STATUS']) == status.active) - { - FFLocalizations.of(context).getVariableText( - ptText: 'Ativo', - enText: 'Active', - ): FlutterFlowTheme.of(context).warning, - }, - if (getStatus(visitaWrapItem['VAW_STATUS']) == status.finished) - { - FFLocalizations.of(context).getVariableText( - ptText: 'Finalizado', - enText: 'Finished', - ): FlutterFlowTheme.of(context).success, - }, - if (getStatus(visitaWrapItem['VAW_STATUS']) == status.unknown) - { - FFLocalizations.of(context).getVariableText( - ptText: 'Desconhecido', - enText: 'Unknown', - ): FlutterFlowTheme.of(context).alternate, - }, - if (getStatus(visitaWrapItem['VAW_STATUS']) == status.canceled) - { - FFLocalizations.of(context).getVariableText( - ptText: 'Cancelado', - enText: 'Canceled', - ): FlutterFlowTheme.of(context).error, - }, - if (getStatus(visitaWrapItem['VAW_STATUS']) == status.blocked) - { - FFLocalizations.of(context).getVariableText( - ptText: 'Bloqueado', - enText: 'Blocked', - ): FlutterFlowTheme.of(context).error, - }, - if (getStatus(visitaWrapItem['VAW_STATUS']) == status.inactive) - { - FFLocalizations.of(context).getVariableText( - ptText: 'Inativo', - enText: 'Inactive', - ): FlutterFlowTheme.of(context).error, - }, + return Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + if (_hasData == false && _pageNumber <= 1 && _loading == false) + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + Center( + child: Text(FFLocalizations.of(context).getVariableText( + ptText: "Nenhuma visita encontrada!", + enText: "No visit found")), + ) ], - onTapCardItemAction: () async { - await showDialog( - useSafeArea: true, - context: context, - builder: (context) { - return Dialog( - alignment: Alignment.center, - child: buildDetails( - visitaWrapItem, - context, - changeStatusAction, - ), - ); - }, - ).whenComplete(() { - // updateVisitFuture(); - _fetchVisits().then((response) { - safeSetState(() { - visitaWrap = PhpGroup.getVisitsCall - .visitasList(response!.jsonBody) - ?.toList() ?? - []; - visitFuture = Future.value(response); + ), + ) + else if (_hasData == true || _pageNumber >= 1) + Expanded( + child: FutureBuilder( + future: _visitFuture, + builder: (context, snapshot) { + return ListView.builder( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + controller: _scrollController, + itemCount: _visitWrap.length, + itemBuilder: (context, index) { + final item = _visitWrap[index]; + return _item(context, item); }); - }); - }).catchError((err, stack) {}); }, + ) + ), + if (_hasData == true && _loading == true) + Container( + padding: const EdgeInsets.only(top: 15, bottom: 15), + child: Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation( + FlutterFlowTheme.of(context).primary, + ), + ), + ), + ) + ].addToStart(const SizedBox(height: 0)), + ); + + + } + + Widget _item(BuildContext context, dynamic visitaWrapItem) { + return CardItemTemplateComponentWidget( + imagePath: + 'https://freaccess.com.br/freaccess/getImage.php?devUUID=${FFAppState().devUUID}&userUUID=${FFAppState().userUUID}&cliID=${FFAppState().cliUUID}&atividade=getFoto&Documento=${visitaWrapItem['VTE_DOCUMENTO'] ?? ''}&tipo=E', + labelsHashMap: { + '${FFLocalizations.of(context).getVariableText(ptText: "Nome", enText: "Name")}:': visitaWrapItem['VTE_NOME'] ?? '', + '${FFLocalizations.of(context).getVariableText(ptText: "Inicio", enText: "Start")}:': visitaWrapItem['VAW_DTINICIO'] != '' && visitaWrapItem['VAW_DTINICIO'] != null ? ValidatorUtil.toLocalDateTime('yyyy-MM-dd HH:mm:ss', visitaWrapItem['VAW_DTINICIO']) : '', + '${FFLocalizations.of(context).getVariableText(ptText: "Fim", enText: "End")}:': visitaWrapItem['VAW_DTFIM'] != '' && visitaWrapItem['VAW_DTFIM'] != null ? ValidatorUtil.toLocalDateTime('yyyy-MM-dd HH:mm:ss', visitaWrapItem['VAW_DTFIM']) : '', + }, + statusHashMap: [ + if (getStatus(visitaWrapItem['VAW_STATUS']) == status.active) + { + FFLocalizations.of(context).getVariableText( + ptText: 'Ativo', + enText: 'Active', + ): FlutterFlowTheme.of(context).warning, + }, + if (getStatus(visitaWrapItem['VAW_STATUS']) == status.finished) + { + FFLocalizations.of(context).getVariableText( + ptText: 'Finalizado', + enText: 'Finished', + ): FlutterFlowTheme.of(context).success, + }, + if (getStatus(visitaWrapItem['VAW_STATUS']) == status.unknown) + { + FFLocalizations.of(context).getVariableText( + ptText: 'Desconhecido', + enText: 'Unknown', + ): FlutterFlowTheme.of(context).alternate, + }, + if (getStatus(visitaWrapItem['VAW_STATUS']) == status.canceled) + { + FFLocalizations.of(context).getVariableText( + ptText: 'Cancelado', + enText: 'Canceled', + ): FlutterFlowTheme.of(context).error, + }, + if (getStatus(visitaWrapItem['VAW_STATUS']) == status.blocked) + { + FFLocalizations.of(context).getVariableText( + ptText: 'Bloqueado', + enText: 'Blocked', + ): FlutterFlowTheme.of(context).error, + }, + if (getStatus(visitaWrapItem['VAW_STATUS']) == status.inactive) + { + FFLocalizations.of(context).getVariableText( + ptText: 'Inativo', + enText: 'Inactive', + ): FlutterFlowTheme.of(context).error, + }, + ], + onTapCardItemAction: () async { + await showDialog( + useSafeArea: true, + context: context, + builder: (context) { + return Dialog( + alignment: Alignment.center, + child: buildDetails( + visitaWrapItem, + context, + changeStatusAction, + ), ); }, - ); + ).whenComplete(() { + + safeSetState(() { + _pageNumber = 1; + _visitWrap = []; + _visitFuture = _fetchVisits(); + }); + + }).catchError((e, s) { + DialogUtil.errorDefault(context); + LogUtil.requestAPIFailed("proccessRequest.php", "", "Consulta de Visitas", e, s); + safeSetState(() { + _hasData = false; + _loading = false; + }); + }); }, ); } diff --git a/lib/shared/utils/validator_util.dart b/lib/shared/utils/validator_util.dart index d0888545..926930ea 100644 --- a/lib/shared/utils/validator_util.dart +++ b/lib/shared/utils/validator_util.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:intl/intl.dart'; class ValidatorUtil { @@ -23,4 +25,11 @@ class ValidatorUtil { return dateTime.toIso8601String(); } + + static String toLocalDateTime(String format, String value) { + DateFormat dateFormat = DateFormat(format); + DateTime dateTime = dateFormat.parse(value); + + return DateFormat('dd/MM/yyyy HH:mm:ss').format(dateTime); + } }