Merge branch 'main' into fix/fd-685
This commit is contained in:
commit
4c3f0dd014
|
@ -416,8 +416,9 @@ Future<bool> checkLocals({
|
|||
}
|
||||
}
|
||||
|
||||
Future answersRequest(BuildContext context, String? ref, String? task,
|
||||
Future<String> answersRequest(BuildContext context, String? ref, String? task,
|
||||
String? response, String? id) async {
|
||||
try {
|
||||
ApiCallResponse? respondeSolicitacaoCall;
|
||||
|
||||
respondeSolicitacaoCall = await PhpGroup.respondeSolicitacaoCall.call(
|
||||
|
@ -430,11 +431,32 @@ Future answersRequest(BuildContext context, String? ref, String? task,
|
|||
resposta: response,
|
||||
idVisitante: id,
|
||||
);
|
||||
respondeSolicitacaoCall = await PhpGroup.respondeSolicitacaoCall.call(
|
||||
userUUID: FFAppState().userUUID,
|
||||
devUUID: FFAppState().devUUID,
|
||||
cliUUID: FFAppState().cliUUID,
|
||||
atividade: 'respondeSolicitacao',
|
||||
referencia: ref,
|
||||
tarefa: task,
|
||||
resposta: response,
|
||||
idVisitante: id,
|
||||
);
|
||||
|
||||
if (respondeSolicitacaoCall.statusCode == 200) {
|
||||
return !respondeSolicitacaoCall.jsonBody['error'];
|
||||
if (!respondeSolicitacaoCall.jsonBody['error']) {
|
||||
return '';
|
||||
} else {
|
||||
return false;
|
||||
return respondeSolicitacaoCall.jsonBody['error_msg'].toString();
|
||||
}
|
||||
} else {
|
||||
return FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Falha ao Responder Solicitação',
|
||||
enText: 'Failed to Response Request');
|
||||
}
|
||||
} catch (e, s) {
|
||||
return FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Falha ao Responder Solicitação',
|
||||
enText: 'Failed to Response Request');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
|
||||
class ToastUtil {
|
||||
static void showToast({
|
||||
required String message,
|
||||
ToastGravity gravity = ToastGravity.BOTTOM,
|
||||
Toast toastLength = Toast.LENGTH_SHORT,
|
||||
Color backgroundColor = Colors.black,
|
||||
Color textColor = Colors.white,
|
||||
double fontSize = 16.0,
|
||||
}) {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: toastLength,
|
||||
gravity: gravity,
|
||||
backgroundColor: backgroundColor,
|
||||
textColor: textColor,
|
||||
fontSize: fontSize,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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',
|
||||
|
@ -171,9 +167,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=${AppState().cliUUID}&atividade=getFoto&Documento=${visitaWrapItem['VTE_DOCUMENTO'] ?? ''}&tipo=E',
|
||||
|
|
|
@ -265,8 +265,11 @@ class _DetailsComponentWidgetState extends State<DetailsComponentWidget> {
|
|||
SizedBox(height: MediaQuery.of(context).size.height * 0.02),
|
||||
if (widget.buttons
|
||||
.isNotEmpty) // Adicione este SizedBox com a altura desejada
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
OverflowBar(
|
||||
overflowAlignment: OverflowBarAlignment.center,
|
||||
overflowSpacing: 2,
|
||||
spacing: 2,
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: widget.buttons,
|
||||
),
|
||||
SizedBox(height: MediaQuery.of(context).size.height * 0.02),
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:developer';
|
|||
import 'package:hub/components/molecular_components/throw_exception/throw_exception_widget.dart';
|
||||
import 'package:hub/custom_code/actions/convert_image_file_to_base64.dart';
|
||||
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
||||
import 'package:hub/shared/utils/validator_util.dart';
|
||||
|
||||
import '/backend/api_requests/api_calls.dart';
|
||||
import '/flutter_flow/flutter_flow_util.dart';
|
||||
|
@ -12,15 +13,13 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'regisiter_vistor_template_component_widget.dart';
|
||||
|
||||
class RegisiterVistorTemplateComponentModel
|
||||
extends FlutterFlowModel<RegisiterVistorTemplateComponentWidget> {
|
||||
class RegisiterVistorTemplateComponentModel extends FlutterFlowModel<RegisiterVistorTemplateComponentWidget> {
|
||||
/// State fields for stateful widgets in this page.
|
||||
Timer? _debounceTimer;
|
||||
|
||||
final unfocusNode = FocusNode();
|
||||
bool isDataUploading = false;
|
||||
FFUploadedFile uploadedLocalFile =
|
||||
FFUploadedFile(bytes: Uint8List.fromList([]));
|
||||
FFUploadedFile uploadedLocalFile = FFUploadedFile(bytes: Uint8List.fromList([]));
|
||||
|
||||
void debounce(Function() fn, Duration time) {
|
||||
if (_debounceTimer != null) {
|
||||
|
@ -98,13 +97,7 @@ class RegisiterVistorTemplateComponentModel
|
|||
TextEditingController? textController4;
|
||||
String? Function(BuildContext, String?)? textController4Validator;
|
||||
String? _textController4Validator(BuildContext context, String? val) {
|
||||
if (val == null || val.isEmpty) {
|
||||
return FFLocalizations.of(context).getVariableText(
|
||||
enText: 'This field is required',
|
||||
ptText: 'Este campo é obrigatório',
|
||||
);
|
||||
}
|
||||
if (!val.contains('@') || !val.contains('.')) {
|
||||
if (val != null && val.isNotEmpty && ValidatorUtil.isValidEmail(val) == false) {
|
||||
return FFLocalizations.of(context).getVariableText(
|
||||
enText: 'Invalid email',
|
||||
ptText: 'Email inválido',
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
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';
|
||||
import 'package:json_path/fun_sdk.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
|
@ -48,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);
|
||||
|
@ -87,19 +87,15 @@ class _RegisiterVistorTemplateComponentWidgetState
|
|||
return false;
|
||||
}
|
||||
|
||||
if (_model.textController1.text.isEmpty ||
|
||||
_model.textController1.text == '') {
|
||||
if (_model.textController1.text.isEmpty || _model.textController1.text == '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_model.dropDownValue == null ||
|
||||
_model.dropDownValue!.isEmpty ||
|
||||
_model.dropDownValue == '') {
|
||||
if (_model.dropDownValue == null || _model.dropDownValue!.isEmpty || _model.dropDownValue == '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_model.textController2.text.isEmpty ||
|
||||
_model.textController2.text == '') {
|
||||
if (_model.textController2.text.isEmpty || _model.textController2.text == '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -107,6 +103,10 @@ class _RegisiterVistorTemplateComponentWidgetState
|
|||
return false;
|
||||
}
|
||||
|
||||
if (_model.textController4.text.isNotEmpty && _model.textController4.text != '' && ValidatorUtil.isValidEmail(_model.textController4.text) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,6 @@ class _RegisiterVistorTemplateComponentWidgetState
|
|||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Form(
|
||||
// key: UniqueKey(),
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
@ -138,8 +137,7 @@ class _RegisiterVistorTemplateComponentWidgetState
|
|||
Align(
|
||||
alignment: const AlignmentDirectional(-1.0, 0.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(
|
||||
20.0, 30.0, 0.0, 15.0),
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(20.0, 0.0, 0.0, 15.0),
|
||||
child: Text(
|
||||
FFLocalizations.of(context).getText(
|
||||
'zazj5d8b' /* Preencha o formulário com os d... */,
|
||||
|
@ -163,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,
|
||||
|
@ -297,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(
|
||||
|
@ -368,8 +373,7 @@ class _RegisiterVistorTemplateComponentWidgetState
|
|||
),
|
||||
maxLines: null,
|
||||
keyboardType: TextInputType.name,
|
||||
validator:
|
||||
_model.textController1Validator.asValidator(context),
|
||||
validator: _model.textController1Validator.asValidator(context),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
|
@ -455,7 +459,9 @@ class _RegisiterVistorTemplateComponentWidgetState
|
|||
],
|
||||
),
|
||||
),
|
||||
Builder(
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(24.0, 0.0, 24.0, 0.0),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
if ((_model.uploadedLocalFile.bytes?.isNotEmpty ?? false)) {
|
||||
return InkWell(
|
||||
|
@ -485,7 +491,7 @@ class _RegisiterVistorTemplateComponentWidgetState
|
|||
return Stack(
|
||||
children: [
|
||||
Align(
|
||||
alignment: const AlignmentDirectional(0.01, 0.0),
|
||||
alignment: const AlignmentDirectional(0.0, 0.0),
|
||||
child: FFButtonWidget(
|
||||
onPressed: () async {
|
||||
final selectedMedia =
|
||||
|
@ -549,10 +555,9 @@ class _RegisiterVistorTemplateComponentWidgetState
|
|||
size: 30.0,
|
||||
),
|
||||
options: FFButtonOptions(
|
||||
width: 300.0,
|
||||
height: 80.0,
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(
|
||||
0.0, 0.0, 0.0, 0.0),
|
||||
width: double.infinity,
|
||||
height: 120.0,
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(0.0, 0.0, 0.0, 20.0),
|
||||
iconPadding:
|
||||
const EdgeInsetsDirectional.fromSTEB(
|
||||
14.0, 0.0, 0.0, 20.0),
|
||||
|
@ -584,7 +589,7 @@ class _RegisiterVistorTemplateComponentWidgetState
|
|||
alignment: const AlignmentDirectional(0.0, 0.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(
|
||||
0.0, 50.0, 0.0, 0.0),
|
||||
10.0, 65.0, 10.0, 0.0),
|
||||
child: Text(
|
||||
FFLocalizations.of(context).getText(
|
||||
'p4ftwxcy' /* Clique para adicionar a foto p... */,
|
||||
|
@ -610,6 +615,7 @@ class _RegisiterVistorTemplateComponentWidgetState
|
|||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: const AlignmentDirectional(-1.0, 0.0),
|
||||
child: Padding(
|
||||
|
@ -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(
|
||||
|
@ -792,13 +805,11 @@ class _RegisiterVistorTemplateComponentWidgetState
|
|||
FlutterFlowTheme.of(context).bodyMediumFamily),
|
||||
),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
// validator:
|
||||
// _model.textController4Validator.asValidator(context),
|
||||
validator: _model.textController4Validator.asValidator(context),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsetsDirectional.fromSTEB(0.0, 65.0, 0.0, 0.0),
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(0.0, 65.0, 0.0, 0.0),
|
||||
child: FFButtonWidget(
|
||||
onPressed: _isFormValid(context)
|
||||
? () async {
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:developer';
|
|||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hub/backend/api_requests/api_calls.dart';
|
||||
import 'package:hub/components/atomic_components/shared_components_atoms/toast.dart';
|
||||
import 'package:hub/components/molecular_components/visitor_not_found_component/visitor_not_found_component_widget.dart';
|
||||
import 'package:hub/components/templates_components/visitor_details_modal_template_component/visitor_details_modal_template_component_widget.dart';
|
||||
import 'package:hub/components/templates_components/visitor_search_modal_template_component/visitor_search_modal_template_component_model.dart';
|
||||
|
@ -64,12 +65,12 @@ class _VisitorSearchModalTemplateComponentWidgetState
|
|||
context.watch<AppState>();
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(0.0, 50.0, 0.0, 0.0),
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(0.0, 10.0, 0.0, 0.0),
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: BoxDecoration(
|
||||
color: FlutterFlowTheme.of(context).primaryBackground,
|
||||
borderRadius: const BorderRadius.only(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(0.0),
|
||||
bottomRight: Radius.circular(0.0),
|
||||
topLeft: Radius.circular(15.0),
|
||||
|
@ -78,11 +79,19 @@ 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),
|
||||
const EdgeInsetsDirectional.fromSTEB(16.0, 25.0, 16.0, 0.0),
|
||||
child: TextFormField(
|
||||
controller: _model.textController,
|
||||
focusNode: _model.textFieldFocusNode,
|
||||
|
@ -223,12 +232,14 @@ class _VisitorSearchModalTemplateComponentWidgetState
|
|||
builder: (context) {
|
||||
final visitor =
|
||||
_model.visitors.map((e) => e).toList();
|
||||
final doc = _model.docs.map((e) => e).toList();
|
||||
return ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
scrollDirection: Axis.vertical,
|
||||
itemCount: visitor.length,
|
||||
itemBuilder: (context, visitorIndex) {
|
||||
final visitorItem = visitor[visitorIndex];
|
||||
final docItem = doc[visitorIndex];
|
||||
return Padding(
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(
|
||||
0.0, 0.0, 0.0, 1.0),
|
||||
|
@ -237,38 +248,6 @@ class _VisitorSearchModalTemplateComponentWidgetState
|
|||
focusColor: Colors.transparent,
|
||||
hoverColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
onTap: () async {
|
||||
// await showModalBottomSheet(
|
||||
// isScrollControlled: true,
|
||||
// enableDrag: true,
|
||||
// isDismissible: true,
|
||||
// context: context,
|
||||
// builder: (context) {
|
||||
// return Padding(
|
||||
// padding:
|
||||
// MediaQuery.viewInsetsOf(context),
|
||||
// child: SizedBox(
|
||||
// height: 610.0,
|
||||
// child:
|
||||
// VisitorDetailsModalTemplateComponentWidget(
|
||||
// visitorImageURL:
|
||||
// "https://freaccess.com.br/freaccess/getImage.php?devUUID=${FFAppState().devUUID}&userUUID=${FFAppState().userUUID}&cliID=${FFAppState().cliUUID}&atividade=getFoto&Documento=${getJsonField(
|
||||
// visitorItem,
|
||||
// r'''$.VTE_DOCUMENTO''',
|
||||
// ).toString()}&tipo=E",
|
||||
// visitorEmail: '',
|
||||
// visitorName: getJsonField(
|
||||
// visitorItem,
|
||||
// r'''$.VTE_NOME''',
|
||||
// )?.toString(),
|
||||
// visitorPhone: '',
|
||||
// visitorType: '',
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// ).then((value) => safeSetState(() {}));
|
||||
},
|
||||
child: Container(
|
||||
width: 100.0,
|
||||
decoration: BoxDecoration(
|
||||
|
@ -356,6 +335,7 @@ class _VisitorSearchModalTemplateComponentWidgetState
|
|||
onPressed: () async {
|
||||
_model.removeFromVisitors(
|
||||
visitorItem);
|
||||
_model.removeFromDocs(docItem);
|
||||
safeSetState(() {});
|
||||
},
|
||||
),
|
||||
|
@ -479,12 +459,21 @@ class _VisitorSearchModalTemplateComponentWidgetState
|
|||
PhpGroup.getVisitorByDocCall
|
||||
.vistanteId((_model.getVisitorByDoc?.jsonBody ?? '')) !=
|
||||
null) {
|
||||
String newDoc = _model.textController.text;
|
||||
bool existDoc = _model.docs.contains(newDoc);
|
||||
if (existDoc == false) {
|
||||
_model.addToVisitors(PhpGroup.getVisitorByDocCall.visitante(
|
||||
(_model.getVisitorByDoc?.jsonBody ?? ''),
|
||||
));
|
||||
safeSetState(() {});
|
||||
_model.addToDocs(_model.textController.text);
|
||||
safeSetState(() {});
|
||||
} else if (existDoc == true) {
|
||||
ToastUtil.showToast(
|
||||
message: FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Visitante já adicionado!',
|
||||
enText: 'Visitor already added!'));
|
||||
}
|
||||
} else {
|
||||
await showAdaptiveDialog(
|
||||
useSafeArea: true,
|
||||
|
|
|
@ -184,6 +184,7 @@ Theme wrapInMaterialTimePickerTheme(
|
|||
required Color headerForegroundColor,
|
||||
required TextStyle headerTextStyle,
|
||||
required Color pickerBackgroundColor,
|
||||
required Color pickerDialForegroundColor,
|
||||
required Color pickerForegroundColor,
|
||||
required Color selectedDateTimeBackgroundColor,
|
||||
required Color selectedDateTimeForegroundColor,
|
||||
|
@ -265,7 +266,7 @@ Theme wrapInMaterialTimePickerTheme(
|
|||
dialTextColor: WidgetStateColor.resolveWith((states) =>
|
||||
states.contains(WidgetState.selected)
|
||||
? selectedDateTimeForegroundColor
|
||||
: pickerForegroundColor),
|
||||
: pickerDialForegroundColor),
|
||||
dayPeriodBorderSide: BorderSide(
|
||||
color: pickerForegroundColor,
|
||||
),
|
||||
|
|
|
@ -1,24 +1,21 @@
|
|||
// import 'dart:js_interop';
|
||||
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:hub/actions/actions.dart';
|
||||
import 'package:hub/backend/api_requests/api_calls.dart';
|
||||
|
||||
import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.dart';
|
||||
import 'package:hub/components/templates_components/details_component/details_component_widget.dart';
|
||||
import 'package:hub/flutter_flow/custom_functions.dart';
|
||||
import 'package:hub/flutter_flow/flutter_flow_icon_button.dart';
|
||||
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
||||
import 'package:hub/flutter_flow/flutter_flow_util.dart';
|
||||
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
|
||||
import 'package:hub/flutter_flow/nav/nav.dart';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:hub/pages/liberation_history/liberation_history_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';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class LiberationHistoryWidget extends StatefulWidget {
|
||||
|
@ -30,49 +27,79 @@ class LiberationHistoryWidget extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _LiberationHistoryWidgetState extends State<LiberationHistoryWidget> {
|
||||
late LiberationHistoryModel _model;
|
||||
|
||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
bool _hasData = false;
|
||||
bool _loading = false;
|
||||
|
||||
late Future<void> _requestFuture;
|
||||
List<dynamic> _requestWrap = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_model = createModel(context, () => LiberationHistoryModel());
|
||||
_requestFuture = _fetchRequests();
|
||||
|
||||
_model.textController ??= TextEditingController();
|
||||
_model.textFieldFocusNode ??= FocusNode();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_model.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void onUpdate(BuildContext context) {
|
||||
_model.clearGetLiberationsCache();
|
||||
safeSetState(() {});
|
||||
}
|
||||
|
||||
String _imagePath(dynamic request) {
|
||||
return 'https://freaccess.com.br/freaccess/getImage.php?cliID=${FFAppState().cliUUID}&atividade=getFoto&Documento=${request['VTE_ID'] ?? ''}&tipo=E';
|
||||
}
|
||||
|
||||
Map<String, String> _labelsHashMap(dynamic request, bool details) {
|
||||
return Map<String, String>.from({
|
||||
'${FFLocalizations.of(context).getVariableText(ptText: 'Nome', enText: 'Name')}:':
|
||||
request['VTE_NOME'],
|
||||
'${FFLocalizations.of(context).getVariableText(ptText: 'Dt. Envio', enText: 'Date Send')}:':
|
||||
request['NOT_DTENVIO'] != null
|
||||
? ValidatorUtil.toLocalDateTime(
|
||||
'yyyy-MM-dd HH:mm:ss', request['NOT_DTENVIO'])
|
||||
: '',
|
||||
'${FFLocalizations.of(context).getVariableText(ptText: 'Motivo', enText: 'Reason')}:':
|
||||
request['NOT_MOTIVO'],
|
||||
if (details == true)
|
||||
'${FFLocalizations.of(context).getVariableText(ptText: 'Mensagem', enText: 'Message')}:':
|
||||
request['NOT_MSGENVIO'],
|
||||
});
|
||||
}
|
||||
|
||||
Map<String, Color> _statusHashMap(dynamic request) {
|
||||
return Map<String, Color>.from({
|
||||
if (request['NOT_STATUS'] == 'L')
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Finalizado',
|
||||
enText: 'Finished'): FlutterFlowTheme.of(context).success
|
||||
else if (request['NOT_STATUS'] == 'B')
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Bloqueado',
|
||||
enText: 'Blocked'): FlutterFlowTheme.of(context).error
|
||||
else
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Ativo',
|
||||
enText: 'Active'): FlutterFlowTheme.of(context).warning
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
context.watch<AppState>();
|
||||
return GestureDetector(
|
||||
onTap: () => _model.unfocusNode.canRequestFocus
|
||||
? FocusScope.of(context).requestFocus(_model.unfocusNode)
|
||||
: FocusScope.of(context).unfocus(),
|
||||
child: Scaffold(
|
||||
context.watch<FFAppState>();
|
||||
return Scaffold(
|
||||
key: scaffoldKey,
|
||||
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
|
||||
appBar: appBarLiberationHistoryPage(context),
|
||||
body: bodyLiberationHistoryPage(context, _model),
|
||||
),
|
||||
appBar: _appBar(context),
|
||||
body: _body(context),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PreferredSizeWidget appBarLiberationHistoryPage(BuildContext context) {
|
||||
PreferredSizeWidget _appBar(BuildContext context) {
|
||||
return AppBar(
|
||||
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
|
||||
automaticallyImplyLeading: false,
|
||||
|
@ -109,184 +136,62 @@ PreferredSizeWidget appBarLiberationHistoryPage(BuildContext context) {
|
|||
);
|
||||
}
|
||||
|
||||
Widget bodyLiberationHistoryPage(
|
||||
BuildContext context, LiberationHistoryModel _model) {
|
||||
Widget _body(BuildContext context) {
|
||||
return SafeArea(
|
||||
top: true,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
searchBarContainer(context, _model),
|
||||
Expanded(child: liberationDynamicListView(context, _model)),
|
||||
].addToStart(const SizedBox(height: 0)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget searchBarContainer(BuildContext context, LiberationHistoryModel _model) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
if (_hasData == false && _loading == false && _requestWrap.isEmpty)
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0),
|
||||
child: SizedBox(
|
||||
width: 300.0,
|
||||
height: 40.0,
|
||||
child: TextFormField(
|
||||
controller: _model.textController,
|
||||
focusNode: _model.textFieldFocusNode,
|
||||
autofocus: false,
|
||||
obscureText: false,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
labelText: FFLocalizations.of(context).getText(
|
||||
'dy0mx15f' /* Pesquise aqui */,
|
||||
),
|
||||
labelStyle: FlutterFlowTheme.of(context).labelMedium.override(
|
||||
fontFamily:
|
||||
FlutterFlowTheme.of(context).labelMediumFamily,
|
||||
color: FlutterFlowTheme.of(context).primaryText,
|
||||
letterSpacing: 0.0,
|
||||
useGoogleFonts: GoogleFonts.asMap().containsKey(
|
||||
FlutterFlowTheme.of(context).labelMediumFamily),
|
||||
),
|
||||
hintStyle: FlutterFlowTheme.of(context).labelMedium.override(
|
||||
fontFamily:
|
||||
FlutterFlowTheme.of(context).labelMediumFamily,
|
||||
color: FlutterFlowTheme.of(context).primaryText,
|
||||
letterSpacing: 0.0,
|
||||
useGoogleFonts: GoogleFonts.asMap().containsKey(
|
||||
FlutterFlowTheme.of(context).labelMediumFamily),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: FlutterFlowTheme.of(context).alternate,
|
||||
width: 2.0,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: FlutterFlowTheme.of(context).primary,
|
||||
width: 2.0,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: FlutterFlowTheme.of(context).error,
|
||||
width: 2.0,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
focusedErrorBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: FlutterFlowTheme.of(context).error,
|
||||
width: 2.0,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
filled: true,
|
||||
fillColor: FlutterFlowTheme.of(context).alternate,
|
||||
prefixIcon: Icon(
|
||||
Icons.search_sharp,
|
||||
color: FlutterFlowTheme.of(context).primaryText,
|
||||
),
|
||||
),
|
||||
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||
fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily,
|
||||
letterSpacing: 0.0,
|
||||
useGoogleFonts: GoogleFonts.asMap().containsKey(
|
||||
FlutterFlowTheme.of(context).bodyMediumFamily),
|
||||
),
|
||||
validator: _model.textControllerValidator.asValidator(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: Text(FFLocalizations.of(context).getVariableText(
|
||||
ptText: "Nenhuma solicitação encontrada!",
|
||||
enText: "No visit found")),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
else if (_hasData == true &&
|
||||
_loading == false &&
|
||||
_requestWrap.isNotEmpty)
|
||||
Expanded(child: _listItems(context)),
|
||||
if (_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 liberationDynamicListView(
|
||||
BuildContext context,
|
||||
LiberationHistoryModel _model,
|
||||
) {
|
||||
Widget _listItems(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
decoration: const BoxDecoration(),
|
||||
child: StreamBuilder<ApiCallResponse>(
|
||||
stream: _model.getLiberations(
|
||||
requestFn: () => PhpGroup.getLiberationsCall.call(
|
||||
devUUID: AppState().devUUID,
|
||||
userUUID: AppState().userUUID,
|
||||
cliID: AppState().cliUUID,
|
||||
atividade: 'getSolicitacoes',
|
||||
),
|
||||
),
|
||||
child: FutureBuilder<void>(
|
||||
future: _requestFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return Center(
|
||||
child: SizedBox(
|
||||
width: 50.0,
|
||||
height: 50.0,
|
||||
child: SpinKitCircle(
|
||||
color: FlutterFlowTheme.of(context).primary,
|
||||
size: 50.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
final columnGetLiberationsResponse = snapshot.data!;
|
||||
final liberationHistory = PhpGroup.getLiberationsCall
|
||||
.rqList(
|
||||
columnGetLiberationsResponse.jsonBody,
|
||||
)
|
||||
?.toList() ??
|
||||
[];
|
||||
final filteredLiberationHistory = _model.textController.text.isNotEmpty
|
||||
? liberationHistory
|
||||
.where((item) => jsonToStr(getJsonField(
|
||||
item,
|
||||
r'''$.VTE_NOME''',
|
||||
)).toLowerCase().contains(
|
||||
_model.textController.text.toLowerCase(),
|
||||
))
|
||||
.toList()
|
||||
: liberationHistory;
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: filteredLiberationHistory.length,
|
||||
addAutomaticKeepAlives: false,
|
||||
addRepaintBoundaries: true,
|
||||
cacheExtent: 1000.0,
|
||||
shrinkWrap: true,
|
||||
physics: const BouncingScrollPhysics(),
|
||||
itemCount: _requestWrap.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final liberationHistoryItem = filteredLiberationHistory[index];
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: index == 0
|
||||
? MediaQuery.of(context).size.height * 0.075
|
||||
: 8.0,
|
||||
left: 8.0,
|
||||
right: 8.0,
|
||||
bottom: 8.0,
|
||||
),
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional(0.0, 0.0),
|
||||
child: liberationHistoryItemCard(
|
||||
context,
|
||||
liberationHistoryItem,
|
||||
),
|
||||
),
|
||||
);
|
||||
final item = _requestWrap[index];
|
||||
return _item(context, item);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
@ -294,157 +199,213 @@ Widget liberationDynamicListView(
|
|||
);
|
||||
}
|
||||
|
||||
Widget liberationHistoryItemCard(
|
||||
BuildContext context, dynamic liberationHistoryItem) {
|
||||
Widget _item(BuildContext context, dynamic liberationHistoryItem) {
|
||||
return CardItemTemplateComponentWidget(
|
||||
imagePath:
|
||||
'https://freaccess.com.br/freaccess/getImage.php?cliID=${AppState().cliUUID}&atividade=getFoto&Documento=${liberationHistoryItem['VTE_ID'] ?? ''}&tipo=E',
|
||||
labelsHashMap: Map<String, String>.from({
|
||||
'Nome:': liberationHistoryItem['VTE_NOME'],
|
||||
'Data:': liberationHistoryItem['NOT_DTENVIO'],
|
||||
'Motivo:': liberationHistoryItem['NOT_MOTIVO'],
|
||||
}),
|
||||
statusHashMap: [
|
||||
liberationHistoryItem['NOT_STATUS'] == 'L'
|
||||
? Map<String, Color>.from({
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Finalizado',
|
||||
enText: 'Finished',
|
||||
): FlutterFlowTheme.of(context).success,
|
||||
})
|
||||
: liberationHistoryItem['NOT_STATUS'] == 'B'
|
||||
? Map<String, Color>.from({
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Bloqueado',
|
||||
enText: 'Blocked',
|
||||
): FlutterFlowTheme.of(context).error,
|
||||
})
|
||||
: Map<String, Color>.from({
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Ativo',
|
||||
enText: 'Active',
|
||||
): FlutterFlowTheme.of(context).warning,
|
||||
})
|
||||
],
|
||||
imagePath: _imagePath(liberationHistoryItem),
|
||||
labelsHashMap: _labelsHashMap(liberationHistoryItem, false),
|
||||
statusHashMap: [_statusHashMap(liberationHistoryItem)],
|
||||
onTapCardItemAction: () async {
|
||||
showDialog(
|
||||
// isScrollControlled: true,
|
||||
// isDismissible: true,
|
||||
// backgroundColor: Colors.transparent,
|
||||
useSafeArea: true,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Dialog(
|
||||
alignment: Alignment.center,
|
||||
child: DetailsComponentWidget(
|
||||
// vteName: liberationHistoryItem['VTE_NOME'],
|
||||
// vteReason: liberationHistoryItem['NOT_MOTIVO'],
|
||||
// vawDate: liberationHistoryItem['NOT_STATUS'] == 'S'
|
||||
// ? liberationHistoryItem['NOT_DTENVIO']
|
||||
// : liberationHistoryItem['NOT_DTRESPOSTA'],
|
||||
// vawStatus: liberationHistoryItem['NOT_STATUS'],
|
||||
// vteMsg: liberationHistoryItem['NOT_MSGENVIO'],
|
||||
// vteUUID: liberationHistoryItem['VTE_ID'],
|
||||
// cliUUID: FFAppState().cliUUID,
|
||||
// msgUUID: liberationHistoryItem['NOT_ID'],
|
||||
// vawDestino: liberationHistoryItem['NOT_DESTINO'],
|
||||
// vawUUID: liberationHistoryItem['NOT_ID'],
|
||||
// vawName: liberationHistoryItem['NOT_NOME'],
|
||||
// vawRef: liberationHistoryItem['NOT_ID'],
|
||||
labelsHashMap: Map<String, String>.from({
|
||||
'Nome:': liberationHistoryItem['VTE_NOME'],
|
||||
'Data:': liberationHistoryItem['NOT_DTENVIO'],
|
||||
'Motivo:': liberationHistoryItem['NOT_MOTIVO'],
|
||||
'Mensagem:': liberationHistoryItem['NOT_MSGENVIO'],
|
||||
// 'Resposta:': liberationHistoryItem['NOT_MSGRESPOSTA'],
|
||||
}),
|
||||
labelsHashMap: _labelsHashMap(liberationHistoryItem, true),
|
||||
buttons: [
|
||||
if (liberationHistoryItem['NOT_STATUS'] == 'S')
|
||||
FlutterFlowIconButton(
|
||||
FFButtonWidget(
|
||||
text: FFLocalizations.of(context)
|
||||
.getVariableText(ptText: "Aceitar", enText: "Accept"),
|
||||
options: FFButtonOptions(
|
||||
width: 130,
|
||||
height: 40,
|
||||
color: FlutterFlowTheme.of(context).primary,
|
||||
elevation: 0,
|
||||
textStyle: const TextStyle(color: Colors.white),
|
||||
borderSide: BorderSide(
|
||||
color: FlutterFlowTheme.of(context).primaryBackground,
|
||||
width: 1,
|
||||
),
|
||||
// borderRadius: 12,
|
||||
),
|
||||
icon: const Icon(Icons.done),
|
||||
onPressed: () async {
|
||||
Navigator.pop(context);
|
||||
await answersRequest
|
||||
.call(
|
||||
|
||||
safeSetState(() {
|
||||
_requestWrap = [];
|
||||
_requestFuture = _fetchRequests();
|
||||
});
|
||||
|
||||
var message = await answersRequest.call(
|
||||
context,
|
||||
liberationHistoryItem['NOT_ID'].toString(),
|
||||
'L',
|
||||
'Mensagem',
|
||||
'',
|
||||
liberationHistoryItem['VTE_ID'].toString(),
|
||||
)
|
||||
.then((value) {
|
||||
if (value) {
|
||||
return showSnackbar(
|
||||
);
|
||||
|
||||
if (message.isEmpty) {
|
||||
showSnackbar(
|
||||
context,
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
enText: 'Successfully resolved visit',
|
||||
ptText: 'Visita resolvida com sucesso'),
|
||||
false);
|
||||
} else {
|
||||
return showSnackbar(
|
||||
context,
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
enText: 'Error resolving visit',
|
||||
ptText: 'Erro ao resolver visita'),
|
||||
true);
|
||||
showSnackbar(context, message, true);
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
if (liberationHistoryItem['NOT_STATUS'] == 'S')
|
||||
FFButtonWidget(
|
||||
text: FFLocalizations.of(context)
|
||||
.getVariableText(ptText: "Bloquear", enText: "Block"),
|
||||
options: FFButtonOptions(
|
||||
width: 130,
|
||||
height: 40,
|
||||
color: FlutterFlowTheme.of(context).error,
|
||||
elevation: 0,
|
||||
textStyle: const TextStyle(color: Colors.white),
|
||||
borderSide: BorderSide(
|
||||
color: FlutterFlowTheme.of(context).primaryBackground,
|
||||
width: 1,
|
||||
),
|
||||
// borderRadius: 12,
|
||||
),
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () async {
|
||||
Navigator.pop(context);
|
||||
|
||||
safeSetState(() {
|
||||
_requestWrap = [];
|
||||
_requestFuture = _fetchRequests();
|
||||
});
|
||||
|
||||
var message = await answersRequest.call(
|
||||
context,
|
||||
liberationHistoryItem['NOT_ID'].toString(),
|
||||
'B',
|
||||
'',
|
||||
liberationHistoryItem['VTE_ID'].toString(),
|
||||
);
|
||||
|
||||
if (message.isEmpty) {
|
||||
showSnackbar(
|
||||
context,
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
enText: 'Successfully resolved visit',
|
||||
ptText: 'Visita resolvida com sucesso'),
|
||||
false);
|
||||
} else {
|
||||
showSnackbar(context, message, true);
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
statusHashMap: [
|
||||
liberationHistoryItem['NOT_STATUS'] == 'L'
|
||||
? Map<String, Color>.from({
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Finalizado',
|
||||
enText: 'Finished',
|
||||
): FlutterFlowTheme.of(context).success,
|
||||
})
|
||||
: liberationHistoryItem['NOT_STATUS'] == 'B'
|
||||
? Map<String, Color>.from({
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Bloqueado',
|
||||
enText: 'Blocked',
|
||||
): FlutterFlowTheme.of(context).error,
|
||||
})
|
||||
: Map<String, Color>.from({
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Ativo',
|
||||
enText: 'Active',
|
||||
): FlutterFlowTheme.of(context).warning,
|
||||
})
|
||||
],
|
||||
imagePath:
|
||||
'https://freaccess.com.br/freaccess/getImage.php?cliID=${AppState().cliUUID}&atividade=getFoto&Documento=${liberationHistoryItem['VTE_ID'] ?? ''}&tipo=E',
|
||||
statusHashMap: [_statusHashMap(liberationHistoryItem)],
|
||||
imagePath: _imagePath(liberationHistoryItem),
|
||||
),
|
||||
);
|
||||
},
|
||||
).then((_) {
|
||||
// PushNotificationManager _pushNotificationService =
|
||||
// PushNotificationManager();
|
||||
//
|
||||
// _pushNotificationService.onMessageReceived.listen((received) {
|
||||
// if (received.data['click_action'] == 'cancel_request') {
|
||||
// _pushNotificationService.dispose();
|
||||
// showSnackbar(
|
||||
// context,
|
||||
// FFLocalizations.of(context).getVariableText(
|
||||
// enText: 'Successfully resolved visit',
|
||||
// ptText: 'Visita resolvida com sucesso'),
|
||||
// false);
|
||||
// context.pushReplacementNamed(
|
||||
// 'liberationHistory',
|
||||
// extra: <String, dynamic>{
|
||||
// kTransitionInfoKey: const TransitionInfo(
|
||||
// hasTransition: true,
|
||||
// transitionType: PageTransitionType.scale,
|
||||
// alignment: Alignment.bottomCenter,
|
||||
// ),
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
PushNotificationManager _pushNotificationService =
|
||||
PushNotificationManager();
|
||||
|
||||
_pushNotificationService.onMessageReceived.listen((received) {
|
||||
if (received.data['click_action'] == 'cancel_request') {
|
||||
_pushNotificationService.dispose();
|
||||
showSnackbar(
|
||||
context,
|
||||
FFLocalizations.of(context).getVariableText(
|
||||
enText: 'Successfully resolved visit',
|
||||
ptText: 'Visita resolvida com sucesso'),
|
||||
false);
|
||||
context.pushReplacementNamed(
|
||||
'liberationHistory',
|
||||
extra: <String, dynamic>{
|
||||
kTransitionInfoKey: const TransitionInfo(
|
||||
hasTransition: true,
|
||||
transitionType: PageTransitionType.scale,
|
||||
alignment: Alignment.bottomCenter,
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}).whenComplete(() {
|
||||
safeSetState(() {
|
||||
_requestWrap = [];
|
||||
_requestFuture = _fetchRequests();
|
||||
});
|
||||
}).catchError((e, s) {
|
||||
DialogUtil.errorDefault(context);
|
||||
LogUtil.requestAPIFailed(
|
||||
"proccessRequest.php", "", "Consulta de Solitiações", e, s);
|
||||
safeSetState(() {
|
||||
_hasData = false;
|
||||
_loading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<ApiCallResponse?> _fetchRequests() async {
|
||||
try {
|
||||
setState(() => _loading = true);
|
||||
var response = await PhpGroup.getLiberationsCall
|
||||
.call(
|
||||
devUUID: FFAppState().devUUID,
|
||||
userUUID: FFAppState().userUUID,
|
||||
cliID: FFAppState().cliUUID,
|
||||
atividade: 'getSolicitacoes',
|
||||
)
|
||||
.first;
|
||||
|
||||
final List<dynamic> requests = response.jsonBody['solicitacoes'] ?? [];
|
||||
|
||||
if (requests != null && requests.isNotEmpty) {
|
||||
setState(() {
|
||||
_requestWrap.addAll(requests);
|
||||
_hasData = true;
|
||||
_loading = false;
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
_showNoMoreDataSnackBar(context);
|
||||
|
||||
setState(() {
|
||||
_hasData = false;
|
||||
_loading = false;
|
||||
});
|
||||
|
||||
return null;
|
||||
} catch (e, s) {
|
||||
DialogUtil.errorDefault(context);
|
||||
LogUtil.requestAPIFailed(
|
||||
"proccessRequest.php", "", "Consulta de Solicitações", e, s);
|
||||
setState(() {
|
||||
_hasData = false;
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,11 +98,11 @@ class ScheduleCompleteVisitPageModel
|
|||
ptText: 'Este campo é obrigatório.',
|
||||
);
|
||||
}
|
||||
if (val != null) {
|
||||
if (val != '0') {
|
||||
try {
|
||||
DateTime startDate = DateFormat('d/M/y H:mm:ss').parse(val);
|
||||
DateTime startDate = DateFormat('dd/MM/yyyy HH:mm:ss').parse(val);
|
||||
DateTime endDate =
|
||||
DateFormat('d/M/y H:mm:ss').parse(textController2!.text);
|
||||
DateFormat('dd/MM/yyyy HH:mm:ss').parse(textController2!.text);
|
||||
if (startDate.isAfter(endDate)) {
|
||||
return FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'A data de início deve ser anterior à data de término.',
|
||||
|
@ -116,7 +116,9 @@ class ScheduleCompleteVisitPageModel
|
|||
);
|
||||
}
|
||||
} catch (e) {
|
||||
return '$e';
|
||||
return FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Preencha corretamente o campo de término da visita!',
|
||||
enText: 'Fill in the end of visit field correctly!');
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -134,11 +136,12 @@ class ScheduleCompleteVisitPageModel
|
|||
ptText: 'Este campo é obrigatório.',
|
||||
);
|
||||
}
|
||||
if (val != null) {
|
||||
if (val != '0') {
|
||||
try {
|
||||
DateTime endDate = DateFormat('d/M/y H:mm:ss').parse(val);
|
||||
DateTime endDate = DateFormat('dd/MM/yyyy HH:mm:ss').parse(val);
|
||||
DateTime startDate =
|
||||
DateFormat('d/M/y H:mm:ss').parse(textController1!.text);
|
||||
DateFormat('dd/MM/yyyy HH:mm:ss').parse(textController1!.text);
|
||||
|
||||
if (endDate.isBefore(startDate)) {
|
||||
return FFLocalizations.of(context).getVariableText(
|
||||
enText: 'End date must be after start date.',
|
||||
|
@ -152,7 +155,9 @@ class ScheduleCompleteVisitPageModel
|
|||
);
|
||||
}
|
||||
} catch (e) {
|
||||
return '$e';
|
||||
return FFLocalizations.of(context).getVariableText(
|
||||
ptText: 'Preencha corretamente o campo de início da visita!',
|
||||
enText: 'Fill in the visit start field correctly!');
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -1,22 +1,15 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:hub/actions/actions.dart';
|
||||
import 'package:hub/backend/api_requests/api_calls.dart';
|
||||
import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.dart';
|
||||
import 'package:hub/components/templates_components/details_component/details_component_action.dart';
|
||||
import 'package:hub/components/templates_components/details_component/details_component_widget.dart';
|
||||
import 'package:hub/components/templates_components/visit_details_modal_template_component/visit_details_modal_template_component_widget.dart';
|
||||
import 'package:hub/components/templates_components/visitor_search_modal_template_component/visitor_search_modal_template_component_widget.dart';
|
||||
import 'package:hub/flutter_flow/custom_functions.dart';
|
||||
import 'package:hub/flutter_flow/flutter_flow_drop_down.dart';
|
||||
import 'package:hub/flutter_flow/flutter_flow_icon_button.dart';
|
||||
import 'package:hub/flutter_flow/flutter_flow_model.dart';
|
||||
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
||||
import 'package:hub/flutter_flow/flutter_flow_util.dart';
|
||||
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
|
||||
|
@ -395,7 +388,7 @@ Widget scheduleVisit(BuildContext context,
|
|||
.bodyMediumFamily),
|
||||
lineHeight: 1.8,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
textAlign: TextAlign.start,
|
||||
validator: _model.textController1Validator
|
||||
.asValidator(context)),
|
||||
),
|
||||
|
@ -490,13 +483,15 @@ Widget scheduleVisit(BuildContext context,
|
|||
FlutterFlowTheme.of(context)
|
||||
.primaryBackground,
|
||||
pickerForegroundColor:
|
||||
FlutterFlowTheme.of(context)
|
||||
.primaryText,
|
||||
FlutterFlowTheme.of(context).info,
|
||||
selectedDateTimeBackgroundColor:
|
||||
FlutterFlowTheme.of(context)
|
||||
.primary,
|
||||
selectedDateTimeForegroundColor:
|
||||
FlutterFlowTheme.of(context).info,
|
||||
pickerDialForegroundColor:
|
||||
FlutterFlowTheme.of(context)
|
||||
.primaryText,
|
||||
actionButtonForegroundColor:
|
||||
FlutterFlowTheme.of(context)
|
||||
.primaryText,
|
||||
|
@ -520,7 +515,7 @@ Widget scheduleVisit(BuildContext context,
|
|||
}
|
||||
safeSetState(() {
|
||||
_model.textController1?.text = dateTimeFormat(
|
||||
'd/M/y H:mm:ss',
|
||||
'dd/MM/yyyy HH:mm:ss',
|
||||
_model.datePicked1,
|
||||
locale: FFLocalizations.of(context)
|
||||
.languageCode,
|
||||
|
@ -642,7 +637,7 @@ Widget scheduleVisit(BuildContext context,
|
|||
.bodyMediumFamily),
|
||||
lineHeight: 1.8,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
textAlign: TextAlign.start,
|
||||
validator: _model.textController2Validator
|
||||
.asValidator(context),
|
||||
),
|
||||
|
@ -738,13 +733,15 @@ Widget scheduleVisit(BuildContext context,
|
|||
FlutterFlowTheme.of(context)
|
||||
.primaryBackground,
|
||||
pickerForegroundColor:
|
||||
FlutterFlowTheme.of(context)
|
||||
.primaryText,
|
||||
FlutterFlowTheme.of(context).info,
|
||||
selectedDateTimeBackgroundColor:
|
||||
FlutterFlowTheme.of(context)
|
||||
.primary,
|
||||
selectedDateTimeForegroundColor:
|
||||
FlutterFlowTheme.of(context).info,
|
||||
pickerDialForegroundColor:
|
||||
FlutterFlowTheme.of(context)
|
||||
.primaryText,
|
||||
actionButtonForegroundColor:
|
||||
FlutterFlowTheme.of(context)
|
||||
.primaryText,
|
||||
|
@ -768,7 +765,7 @@ Widget scheduleVisit(BuildContext context,
|
|||
}
|
||||
safeSetState(() {
|
||||
_model.textController2?.text = dateTimeFormat(
|
||||
'd/M/y H:mm:ss',
|
||||
'dd/MM/yyyy HH:mm:ss',
|
||||
_model.datePicked2,
|
||||
locale: FFLocalizations.of(context)
|
||||
.languageCode,
|
||||
|
@ -1431,12 +1428,11 @@ Widget scheduleVisit(BuildContext context,
|
|||
),
|
||||
),
|
||||
),
|
||||
Switch.adaptive(
|
||||
Switch(
|
||||
value: _model.switchValue!,
|
||||
onChanged: (newValue) async {
|
||||
safeSetState(() => _model.switchValue = newValue);
|
||||
},
|
||||
applyCupertinoTheme: false,
|
||||
focusColor: FlutterFlowTheme.of(context).primary,
|
||||
trackColor: WidgetStateProperty.resolveWith(
|
||||
(states) {
|
||||
|
|
|
@ -1,22 +1,19 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:hub/shared/utils/dialog_util.dart';
|
||||
import 'package:hub/shared/utils/log_util.dart';
|
||||
|
||||
import '/backend/api_requests/api_calls.dart';
|
||||
import '/components/molecular_components/throw_exception/throw_exception_widget.dart';
|
||||
import '/flutter_flow/flutter_flow_icon_button.dart';
|
||||
import '/flutter_flow/flutter_flow_theme.dart';
|
||||
import '/flutter_flow/flutter_flow_util.dart';
|
||||
import '/flutter_flow/flutter_flow_widgets.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:hub/pages/schedule_provisional_visit_page/schedule_provisional_visit_page_model.dart';
|
||||
import 'package:hub/shared/utils/dialog_util.dart';
|
||||
import 'package:hub/shared/utils/log_util.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '/backend/api_requests/api_calls.dart';
|
||||
import '/flutter_flow/flutter_flow_icon_button.dart';
|
||||
import '/flutter_flow/flutter_flow_theme.dart';
|
||||
import '/flutter_flow/flutter_flow_util.dart';
|
||||
import '/flutter_flow/flutter_flow_widgets.dart';
|
||||
|
||||
class ScheduleProvisionalVisitPageWidget extends StatefulWidget {
|
||||
const ScheduleProvisionalVisitPageWidget({super.key});
|
||||
|
||||
|
@ -722,11 +719,15 @@ class _ScheduleProvisionalVisitPageWidgetState
|
|||
pickerForegroundColor:
|
||||
FlutterFlowTheme.of(
|
||||
context)
|
||||
.primaryText,
|
||||
.info,
|
||||
selectedDateTimeBackgroundColor:
|
||||
FlutterFlowTheme.of(
|
||||
context)
|
||||
.primary,
|
||||
pickerDialForegroundColor:
|
||||
FlutterFlowTheme.of(
|
||||
context)
|
||||
.primaryText,
|
||||
selectedDateTimeForegroundColor:
|
||||
FlutterFlowTheme.of(
|
||||
context)
|
||||
|
@ -979,16 +980,16 @@ class _ScheduleProvisionalVisitPageWidgetState
|
|||
_model.provVisitSchedule = await PhpGroup
|
||||
.postProvVisitSchedulingCall
|
||||
.call(
|
||||
devUUID: AppState().devUUID,
|
||||
userUUID: AppState().userUUID,
|
||||
cliID: AppState().cliUUID,
|
||||
devUUID: FFAppState().devUUID,
|
||||
userUUID: FFAppState().userUUID,
|
||||
cliID: FFAppState().cliUUID,
|
||||
atividade: 'putAgendamentoProv',
|
||||
data:
|
||||
_model.dateTimeTextController.text,
|
||||
motivo: _model.notesTextController.text,
|
||||
nome: _model
|
||||
.personNameTextController.text,
|
||||
proID: AppState().ownerUUID,
|
||||
proID: FFAppState().ownerUUID,
|
||||
);
|
||||
|
||||
if (PhpGroup.postProvVisitSchedulingCall
|
||||
|
|
|
@ -1,123 +1,189 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hub/actions/actions.dart';
|
||||
import 'package:hub/app_state.dart';
|
||||
import 'package:hub/backend/api_requests/api_calls.dart';
|
||||
import 'package:hub/backend/api_requests/api_manager.dart';
|
||||
import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.dart';
|
||||
import 'package:hub/components/templates_components/details_component/details_component_action.dart';
|
||||
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: AppState().devUUID,
|
||||
userUUID: AppState().userUUID,
|
||||
cliID: AppState().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,
|
||||
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")),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
else if (_hasData == true || _pageNumber >= 1)
|
||||
Expanded(
|
||||
child: 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(),
|
||||
controller: _scrollController,
|
||||
itemCount: _visitWrap.length,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == visitaWrap.length) {
|
||||
_loadMoreVisits();
|
||||
return Center(
|
||||
final item = _visitWrap[index];
|
||||
return _item(context, item);
|
||||
});
|
||||
},
|
||||
)),
|
||||
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)),
|
||||
);
|
||||
}
|
||||
|
||||
final visitaWrapItem = visitaWrap[index];
|
||||
|
||||
Widget _item(BuildContext context, dynamic visitaWrapItem) {
|
||||
return CardItemTemplateComponentWidget(
|
||||
imagePath:
|
||||
'https://freaccess.com.br/freaccess/getImage.php?devUUID=${AppState().devUUID}&userUUID=${AppState().userUUID}&cliID=${AppState().cliUUID}&atividade=getFoto&Documento=${visitaWrapItem['VTE_DOCUMENTO'] ?? ''}&tipo=E',
|
||||
'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'] ?? '',
|
||||
'${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)
|
||||
|
@ -178,21 +244,20 @@ class _VisitHistoryWidgetState extends State<VisitHistoryWidget> {
|
|||
);
|
||||
},
|
||||
).whenComplete(() {
|
||||
// updateVisitFuture();
|
||||
_fetchVisits().then((response) {
|
||||
safeSetState(() {
|
||||
visitaWrap = PhpGroup.getVisitsCall
|
||||
.visitasList(response!.jsonBody)
|
||||
?.toList() ??
|
||||
[];
|
||||
visitFuture = Future.value(response);
|
||||
_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;
|
||||
});
|
||||
});
|
||||
}).catchError((err, stack) {});
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
62
pubspec.lock
62
pubspec.lock
|
@ -174,9 +174,11 @@ packages:
|
|||
description:
|
||||
name: cross_file
|
||||
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
|
||||
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.4+2"
|
||||
version: "0.3.4+2"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -230,9 +232,11 @@ packages:
|
|||
description:
|
||||
name: device_info_plus_platform_interface
|
||||
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
|
||||
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
version: "7.0.1"
|
||||
dropdown_button2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -270,9 +274,11 @@ packages:
|
|||
description:
|
||||
name: ffi
|
||||
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
|
||||
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
version: "2.1.3"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -318,9 +324,11 @@ packages:
|
|||
description:
|
||||
name: file_selector_windows
|
||||
sha256: "2ad726953f6e8affbc4df8dc78b77c3b4a060967a291e528ef72ae846c60fb69"
|
||||
sha256: "2ad726953f6e8affbc4df8dc78b77c3b4a060967a291e528ef72ae846c60fb69"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.3+2"
|
||||
version: "0.9.3+2"
|
||||
firebase_analytics:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -358,17 +366,21 @@ packages:
|
|||
description:
|
||||
name: firebase_core_platform_interface
|
||||
sha256: "3c3a1e92d6f4916c32deea79c4a7587aa0e9dbbe5889c7a16afcf005a485ee02"
|
||||
sha256: "3c3a1e92d6f4916c32deea79c4a7587aa0e9dbbe5889c7a16afcf005a485ee02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.2.0"
|
||||
version: "5.2.0"
|
||||
firebase_core_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
sha256: e8d1e22de72cb21cdcfc5eed7acddab3e99cd83f3b317f54f7a96c32f25fd11e
|
||||
sha256: e8d1e22de72cb21cdcfc5eed7acddab3e99cd83f3b317f54f7a96c32f25fd11e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.17.4"
|
||||
version: "2.17.4"
|
||||
firebase_crashlytics:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -451,9 +463,11 @@ packages:
|
|||
description:
|
||||
name: flutter_expandable_fab
|
||||
sha256: f4692d1949cda81e10ca0c3e75aea1e14e29ecc12d9328996321b96e9747a955
|
||||
sha256: f4692d1949cda81e10ca0c3e75aea1e14e29ecc12d9328996321b96e9747a955
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.2.0"
|
||||
flutter_inappwebview:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -637,6 +651,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
fluttertoast:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fluttertoast
|
||||
sha256: "95f349437aeebe524ef7d6c9bde3e6b4772717cf46a0eb6a3ceaddc740b297cc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.2.8"
|
||||
font_awesome_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -810,17 +832,21 @@ packages:
|
|||
description:
|
||||
name: leak_tracker
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.5"
|
||||
version: "10.0.5"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
version: "3.0.5"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -842,25 +868,31 @@ packages:
|
|||
description:
|
||||
name: local_auth
|
||||
sha256: "434d854cf478f17f12ab29a76a02b3067f86a63a6d6c4eb8fbfdcfe4879c1b7b"
|
||||
sha256: "434d854cf478f17f12ab29a76a02b3067f86a63a6d6c4eb8fbfdcfe4879c1b7b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.3.0"
|
||||
local_auth_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_android
|
||||
sha256: e99c44ca0bce08f26f25e2a2e07d3b443d69986e1c3acf67c1449f7d847e3625
|
||||
sha256: e99c44ca0bce08f26f25e2a2e07d3b443d69986e1c3acf67c1449f7d847e3625
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.43"
|
||||
version: "1.0.43"
|
||||
local_auth_darwin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_darwin
|
||||
sha256: "7ba5738c874ca2b910d72385d00d2bebad9d4e807612936cf5e32bc01a048c71"
|
||||
sha256: "7ba5738c874ca2b910d72385d00d2bebad9d4e807612936cf5e32bc01a048c71"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
version: "1.4.0"
|
||||
local_auth_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -874,9 +906,11 @@ packages:
|
|||
description:
|
||||
name: local_auth_windows
|
||||
sha256: bc4e66a29b0fdf751aafbec923b5bed7ad6ed3614875d8151afe2578520b2ab5
|
||||
sha256: bc4e66a29b0fdf751aafbec923b5bed7ad6ed3614875d8151afe2578520b2ab5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.11"
|
||||
version: "1.0.11"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -898,9 +932,11 @@ packages:
|
|||
description:
|
||||
name: material_color_utilities
|
||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.1"
|
||||
version: "0.11.1"
|
||||
maybe_just_nothing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -914,9 +950,11 @@ packages:
|
|||
description:
|
||||
name: meta
|
||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
version: "1.15.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -954,9 +992,11 @@ packages:
|
|||
description:
|
||||
name: octo_image
|
||||
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
|
||||
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.0"
|
||||
page_transition:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1026,9 +1066,11 @@ packages:
|
|||
description:
|
||||
name: path_provider_windows
|
||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.3.0"
|
||||
percent_indicator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1074,9 +1116,11 @@ packages:
|
|||
description:
|
||||
name: permission_handler_platform_interface
|
||||
sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea
|
||||
sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.2"
|
||||
version: "4.2.2"
|
||||
permission_handler_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1130,9 +1174,11 @@ packages:
|
|||
description:
|
||||
name: qr
|
||||
sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
|
||||
sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
version: "3.0.2"
|
||||
qr_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1335,9 +1381,11 @@ packages:
|
|||
description:
|
||||
name: test_api
|
||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
version: "0.7.2"
|
||||
timeago:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1383,9 +1431,11 @@ packages:
|
|||
description:
|
||||
name: url_launcher_linux
|
||||
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
|
||||
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
version: "3.2.0"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1407,25 +1457,31 @@ packages:
|
|||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
|
||||
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
version: "2.3.3"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
|
||||
sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
version: "3.1.2"
|
||||
uuid:
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: uuid
|
||||
sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
|
||||
sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.4.2"
|
||||
version: "4.4.2"
|
||||
vector_graphics:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1503,9 +1559,11 @@ packages:
|
|||
description:
|
||||
name: vm_service
|
||||
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
|
||||
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.4"
|
||||
version: "14.2.4"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1527,9 +1585,11 @@ packages:
|
|||
description:
|
||||
name: webview_flutter_android
|
||||
sha256: c66651fba15f9d7ddd31daec42da8d6bce46c85610a7127e3ebcb39a4395c3c9
|
||||
sha256: c66651fba15f9d7ddd31daec42da8d6bce46c85610a7127e3ebcb39a4395c3c9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.16.6"
|
||||
version: "3.16.6"
|
||||
webview_flutter_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1559,9 +1619,11 @@ packages:
|
|||
description:
|
||||
name: win32_registry
|
||||
sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6"
|
||||
sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.4"
|
||||
version: "1.1.4"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -3,6 +3,8 @@ description: A new Flutter project.
|
|||
|
||||
publish_to: "none"
|
||||
|
||||
publish_to: "none"
|
||||
|
||||
version: 1.0.0+3
|
||||
|
||||
environment:
|
||||
|
|
Loading…
Reference in New Issue