Merge pull request #19 from FRE-Informatica/bugfix/fd-645

FIX: Hístorico de Visitas
This commit is contained in:
Lucas Martin Mota 2024-08-15 08:58:02 -03:00 committed by GitHub
commit 7e002981b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 250 additions and 167 deletions

View File

@ -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,

View File

@ -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<dynamic> Function(BuildContext, int, int, String, String)?
changeStatusAction) {
Widget buildDetails(dynamic visitaWrapItem, BuildContext context, Future<dynamic> 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<String, String>.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',

View File

@ -1,5 +1,6 @@
import 'dart:developer';
import 'package:easy_debounce/easy_debounce.dart';
import 'package:flutter/services.dart';
import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/validator_util.dart';
@ -49,13 +50,11 @@ class _RegisiterVistorTemplateComponentWidgetState
visitorAlreadyRegistered = BehaviorSubject<bool>.seeded(false);
_model =
createModel(context, () => RegisiterVistorTemplateComponentModel());
_model = createModel(context, () => RegisiterVistorTemplateComponentModel());
_model.textController1 ??= TextEditingController();
_model.textFieldFocusNode1 ??= FocusNode();
log('doc: ${widget.doc}');
_model.textController2 ??= TextEditingController();
_model.textFieldFocusNode2 ??= FocusNode();
_model.textController2?.addListener(_onTextChanged);
@ -162,7 +161,7 @@ class _RegisiterVistorTemplateComponentWidgetState
controller: _model.textController2,
focusNode: _model.textFieldFocusNode2,
autovalidateMode: AutovalidateMode.onUserInteraction,
autofocus: false,
autofocus: true,
textCapitalization: TextCapitalization.none,
autofillHints: const [AutofillHints.password],
keyboardType: TextInputType.number,
@ -296,7 +295,14 @@ class _RegisiterVistorTemplateComponentWidgetState
controller: _model.textController1,
autovalidateMode: AutovalidateMode.onUserInteraction,
focusNode: _model.textFieldFocusNode1,
autofocus: false,
onChanged: (_) =>
EasyDebounce.debounce(
'_model.textFieldFocusNode1',
const Duration(
milliseconds: 500),
() => setState(() {}),
),
autofocus: true,
textInputAction: TextInputAction.next,
obscureText: false,
decoration: InputDecoration(
@ -722,7 +728,14 @@ class _RegisiterVistorTemplateComponentWidgetState
controller: _model.textController4,
focusNode: _model.textFieldFocusNode4,
autovalidateMode: AutovalidateMode.onUserInteraction,
autofocus: false,
autofocus: true,
onChanged: (_) =>
EasyDebounce.debounce(
'_model.textFieldFocusNode4',
const Duration(
milliseconds: 500),
() => setState(() {}),
),
textInputAction: TextInputAction.done,
obscureText: false,
decoration: InputDecoration(

View File

@ -64,7 +64,7 @@ class _VisitorSearchModalTemplateComponentWidgetState
context.watch<FFAppState>();
return Padding(
padding: const EdgeInsetsDirectional.fromSTEB(0.0, 50.0, 0.0, 0.0),
padding: const EdgeInsetsDirectional.fromSTEB(0.0, 20.0, 0.0, 0.0),
child: Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
@ -78,8 +78,16 @@ class _VisitorSearchModalTemplateComponentWidgetState
),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 40,
height: 5,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(10),
),
),
Padding(
padding:
const EdgeInsetsDirectional.fromSTEB(16.0, 10.0, 16.0, 0.0),

View File

@ -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<VisitHistoryWidget> {
List<dynamic> visitaWrap = [];
var pageNumber = 1;
late Future<void> visitFuture;
class _VisitHistoryWidgetState extends State<VisitHistoryWidget> with TickerProviderStateMixin {
late ScrollController _scrollController;
int _pageNumber = 1;
final int _pageSize = 10;
bool _hasData = false;
bool _loading = false;
late Future<void> _visitFuture;
List<dynamic> _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<ApiCallResponse?> _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<dynamic>?; // Ajuste conforme a estrutura da resposta
if (newVisits != null && newVisits.isNotEmpty) {
safeSetState(() {
visitaWrap.addAll(newVisits);
final List<dynamic> 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<void>(
future: visitFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting &&
visitaWrap.isEmpty) {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
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<Color>(
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<void>(
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<Color>(
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;
});
});
},
);
}

View File

@ -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);
}
}