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/commons/actions/api_calls.dart'; import 'package:hub/commons/actions/api_manager.dart'; import 'package:hub/commons/components/molecules/card/widget.dart'; import 'package:hub/modals/filters/options/widget.dart'; import 'package:rxdart/rxdart.dart'; import '/commons/widgets/custom_functions.dart' as functions; import '/commons/widgets/flutter_flow_icon_button.dart'; import '/commons/widgets/flutter_flow_theme.dart'; import '/commons/widgets/flutter_flow_util.dart'; import 'model.dart'; export 'model.dart'; @immutable class AcessHistoryPageWidget extends StatefulWidget { late Map opt = { 'personType': '.*', 'accessType': '.*', 'search': '.*', }; AcessHistoryPageWidget({super.key, required this.opt}); @override State createState() => _AcessHistoryPageWidgetState(opt); } class AccessHistoryItemWidget extends StatelessWidget { final dynamic accessHistoryItem; const AccessHistoryItemWidget({Key? key, required this.accessHistoryItem}) : super(key: key); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(8.0), child: Column(), ); } } class _AcessHistoryPageWidgetState extends State { late AcessHistoryPageModel _model; final BehaviorSubject> selectedTypeSubject; bool _isSubjectClosed = false; final scaffoldKey = GlobalKey(); _AcessHistoryPageWidgetState(Map opt) : selectedTypeSubject = BehaviorSubject.seeded(opt) { selectedTypeSubject.listen((value) { log("selectedTypeSubject changed: $value"); }); } @override void initState() { super.initState(); _model = createModel(context, () => AcessHistoryPageModel()); log("initState called in _AcessHistoryPageWidgetState"); } @override void dispose() { selectedTypeSubject.close(); _isSubjectClosed = true; super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( key: scaffoldKey, backgroundColor: FlutterFlowTheme.of(context).primaryBackground, appBar: _appBarOrganismWidget(context), body: _accessHistoryListOrganismWidget(context)); } // AppBar Widgets PreferredSizeWidget _appBarOrganismWidget(BuildContext context) { final theme = FlutterFlowTheme.of(context); return AppBar( backgroundColor: theme.primaryBackground, automaticallyImplyLeading: false, leading: _appBarBackButtonAtomWidget(context, theme), title: _appBarTitleMoleculeWidget(context, theme), centerTitle: true, elevation: 0.0, actions: [ _appBarFilterButtonAtomWidget(context), ], ); } Widget _appBarBackButtonAtomWidget( BuildContext context, FlutterFlowTheme theme) { return FlutterFlowIconButton( borderColor: Colors.transparent, borderRadius: 30.0, borderWidth: 1.0, buttonSize: 60.0, icon: Icon( Icons.keyboard_arrow_left, color: theme.primaryText, size: 30.0, ), onPressed: () => Navigator.of(context).pop(), ); } Widget _appBarTitleMoleculeWidget( BuildContext context, FlutterFlowTheme theme) { return Text( FFLocalizations.of(context).getText('ch8qymga'), style: theme.headlineMedium.override( fontFamily: theme.headlineMediumFamily, color: theme.primaryText, fontSize: 16.0, letterSpacing: 0.0, useGoogleFonts: GoogleFonts.asMap().containsKey(theme.headlineMediumFamily), ), ); } Widget _appBarFilterButtonAtomWidget(BuildContext context) { log('selectedTypeSubject: ${selectedTypeSubject.value}'); return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ IconButton( icon: const Icon(Icons.filter_list), padding: EdgeInsets.fromLTRB(0, 0, 10, 0), onPressed: () async { final Map? selectedFilter = await showModalBottomSheet>( isScrollControlled: true, backgroundColor: Colors.transparent, context: context, builder: (context) => OptModalWidget( defaultAccessType: selectedTypeSubject.value['accessType'] ?? '.*', defaultPersonType: selectedTypeSubject.value['personType'] ?? '.*', ), ); if (selectedFilter != null) { log('Selected Filter: $selectedFilter'); _updateAccessHistoryAction(selectedFilter); } }, ), ], ); } void _updateAccessHistoryAction(Map newType) { if (!_isSubjectClosed) { final currentType = selectedTypeSubject.value; final updatedType = Map.from(currentType); bool needsUpdate = false; newType.forEach((key, newValue) { if (currentType[key] != newValue) { updatedType[key] = newValue; needsUpdate = true; } }); if (needsUpdate) { selectedTypeSubject.add(updatedType); log("updateAccessHistory called with newType: $newType"); safeSetState(() {}); } } } Stream fetchAccessHistoryService(String selectedType) { log('Calling API with type: $selectedType'); switch (selectedType) { case 'E': return _model.accessHistory( requestFn: () => PhpGroup.getAccessCall.call( devUUID: FFAppState().devUUID, userUUID: FFAppState().userUUID, cliID: FFAppState().cliUUID, atividade: 'getAcessos', pageSize: '100', pageNumber: '1', pesTipo: 'E', ), ); case 'O': return _model.accessHistory( requestFn: () => PhpGroup.getAccessCall.call( devUUID: FFAppState().devUUID, userUUID: FFAppState().userUUID, cliID: FFAppState().cliUUID, atividade: 'getAcessos', pageSize: '100', pageNumber: '1', pesTipo: 'O', ), ); default: return _model.accessHistory( requestFn: () => PhpGroup.getAccessCall.call( devUUID: FFAppState().devUUID, userUUID: FFAppState().userUUID, cliID: FFAppState().cliUUID, atividade: 'getAcessos', pageSize: '100', pageNumber: '1', pesTipo: 'T', ), ); } } Widget _accessHistoryListOrganismWidget(BuildContext context) { return SingleChildScrollView( child: Column( children: [ StreamBuilder>( stream: selectedTypeSubject.stream, builder: (context, snapshot) { if (!snapshot.hasData) { return Center(child: CircularProgressIndicator()); } final selected = snapshot.data!; return _cardListViewOrganismWidget(selected); }, ), ], ), ); } Future> fetchCardListViewService( Map select) async { log('Fetching access history'); final response = await fetchAccessHistoryService(select['personType']!).first; log('Response: ${response.jsonBody}'); final List accessHistory = response.jsonBody['acessos'] ?? []; log('Access History Before Filtering: $accessHistory'); log( 'Filtering for: Person Type - ${select['personType']}, Access Type - ${select['accessType']}, Search - ${select['search']}'); return accessHistory.where((item) { final personTypeMatches = select['personType'] == '.*' || item["PES_TIPO"].toString() == select['personType']; final accessTypeMatches = select['accessType'] == '.*' || item["ACE_TIPO"].toString() == select['accessType']; final searchMatches = select['search'] == '.*' || item["PES_NOME"] .toString() .toLowerCase() .contains(select['search']!.toLowerCase()); log('NOMES: ${item["PES_NOME"].toString().toLowerCase()}'); return personTypeMatches && accessTypeMatches && searchMatches; }).toList(); } Widget _cardListViewOrganismWidget(Map selected) { log( 'Selected types in Card: ${selected['personType']}, ${selected['accessType']}'); log('_buildAccessHistoryList called'); return FutureBuilder>( future: fetchCardListViewService(selected), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { log('Waiting for data'); return Center( child: SizedBox( width: 50.0, height: 50.0, child: SpinKitCircle( color: FlutterFlowTheme.of(context).primary, size: 50.0, ), ), ); } else if (snapshot.hasError) { return Text('Error: ${snapshot.error}'); } else { final accessHistory = snapshot.data!; log('Access History: $accessHistory'); return ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: accessHistory.length, itemBuilder: (context, index) { final accessHistoryItem = accessHistory[index]; log( 'Access History Item: ${accessHistoryItem['PES_TIPO']}'); return _accessHistoryCardMoleculeWidget( context, accessHistoryItem); }, ); } }, ); } Widget _accessHistoryCardMoleculeWidget( BuildContext context, dynamic accessHistoryItem) { log('Access History Item: $accessHistoryItem'); return CardItemTemplateComponentWidget( imageHashMap: Map.from({ 'key': accessHistoryItem['PES_ID'] ?? '', 'value': accessHistoryItem['PES_TIPO'] ?? '', }), labelsHashMap: Map.from({ 'Nome:': accessHistoryItem['PES_NOME'] ?? '', 'Acesso:': accessHistoryItem['ACE_DATAHORA'] ?? '', 'Setor:': accessHistoryItem['SET_DESCRICAO'] ?? '', }), statusHashMap: [ accessHistoryItem['PES_TIPO'] == 'O' ? Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Morador', enText: 'Resident', ): FlutterFlowTheme.of(context).alternate2, }) : accessHistoryItem['PES_TIPO'] == 'E' ? Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Visitante', enText: 'Visitor', ): FlutterFlowTheme.of(context).alternate2, }) : Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Desconhecido', enText: 'Unknown', ): FlutterFlowTheme.of(context).alternate2, }), accessHistoryItem['ACE_TIPO'] == '0' ? Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Entrada', enText: 'Entrance', ): FlutterFlowTheme.of(context).success, }) : accessHistoryItem['ACE_TIPO'] == '1' ? Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Saída', enText: 'Exit', ): FlutterFlowTheme.of(context).error, }) : Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Desconhecido', enText: 'Unknown', ): FlutterFlowTheme.of(context).warning, }) ], onTapCardItemAction: () async {}); } } Widget _cardHeaderAtomWidget(BuildContext context, String urlImagem, String tipoPessoa, Color corFundoTipo, accessHistoryItem) { return Row( mainAxisSize: MainAxisSize.max, children: [ Padding( padding: const EdgeInsets.all(10.0), child: ClipRRect( borderRadius: BorderRadius.circular(100.0), child: Image.network( urlImagem, width: 60.0, height: 60.0, fit: BoxFit.cover, ), ), ), Column( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( getJsonField( accessHistoryItem, r'''$.PES_NOME''', ).toString(), style: FlutterFlowTheme.of(context).bodyMedium.override( fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily, letterSpacing: 0.0, useGoogleFonts: GoogleFonts.asMap().containsKey( FlutterFlowTheme.of(context).bodyMediumFamily), ), ), Container( width: 100.0, height: 25.0, decoration: BoxDecoration( color: (() { // Extrai o valor de PES_TIPO, converte para String, remove espaços em branco e aspas final pesTipo = functions .jsonToStr(getJsonField( accessHistoryItem, r'''$.PES_TIPO''', )) .trim() .replaceAll('"', ''); // Remove aspas // Debug: Imprime o valor de PES_TIPO ajustado log('PES_TIPO FOR COLORING: $pesTipo'); // Retorna a cor baseada na condição ajustada return pesTipo == 'E' ? FlutterFlowTheme.of(context).warning : FlutterFlowTheme.of(context).primary; })(), borderRadius: BorderRadius.circular(24.0), ), child: Align( alignment: const AlignmentDirectional(0.0, 0.0), child: Text( getJsonField( accessHistoryItem, r'''$.PES_TIPO''', ).toString() == 'E' ? FFLocalizations.of(context).getText( 'zok7lu4w', ) : FFLocalizations.of(context).getText( 'oonqk812', ), style: FlutterFlowTheme.of(context).bodyMedium.override( fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily, color: FlutterFlowTheme.of(context).info, letterSpacing: 0.0, useGoogleFonts: GoogleFonts.asMap().containsKey( FlutterFlowTheme.of(context).bodyMediumFamily), ), ), ), ), ], ), ] .divide(const SizedBox(width: 20.0)) .addToStart(const SizedBox(width: 5.0)) .addToEnd(const SizedBox(width: 5.0)), ); } Widget _cardDetailsMoleculeWidget( BuildContext context, dynamic accessHistoryItem) { return Row( mainAxisSize: MainAxisSize.max, children: [ Expanded( child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [ Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, children: [ Text( FFLocalizations.of(context).getText( '2odgr6hg', ), style: FlutterFlowTheme.of(context).bodyMedium.override( fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily, fontSize: 12.5, letterSpacing: 0.0, fontWeight: FontWeight.bold, useGoogleFonts: GoogleFonts.asMap().containsKey( FlutterFlowTheme.of(context).bodyMediumFamily), ), ), Text( getJsonField( accessHistoryItem, r'''$.ACE_DATAHORA''', ).toString(), style: FlutterFlowTheme.of(context).bodyMedium.override( fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily, fontSize: 12.5, letterSpacing: 0.0, useGoogleFonts: GoogleFonts.asMap().containsKey( FlutterFlowTheme.of(context).bodyMediumFamily), ), ), ].addToStart(const SizedBox(width: 10.0)), ), Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, children: [ Text( FFLocalizations.of(context).getText( 'zrde3fke', ), style: FlutterFlowTheme.of(context).bodyMedium.override( fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily, fontSize: 12.5, letterSpacing: 0.0, fontWeight: FontWeight.bold, useGoogleFonts: GoogleFonts.asMap().containsKey( FlutterFlowTheme.of(context).bodyMediumFamily), ), ), Text( getJsonField( accessHistoryItem, r'''$.ACI_DESCRICAO''', ).toString(), style: FlutterFlowTheme.of(context).bodyMedium.override( fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily, fontSize: 12.5, letterSpacing: 0.0, useGoogleFonts: GoogleFonts.asMap().containsKey( FlutterFlowTheme.of(context).bodyMediumFamily), ), ), ].addToStart(const SizedBox(width: 10.0)), ), ].divide(const SizedBox(height: 3.0)), ), ), ] .addToStart(const SizedBox(width: 5.0)) .addToEnd(const SizedBox(width: 5.0)), ); } String imageUrlAtomWidget(String document, String type) { return valueOrDefault( "https://freaccess.com.br/freaccess/getImage.php?&cliID=${FFAppState().cliUUID}&atividade=getFoto&Documento=$document&tipo=$type", "https://storage.googleapis.com/flutterflow-io-6f20.appspot.com/projects/flutter-freaccess-hub-0xgz9q/assets/7ftdetkzc3s0/360_F_64676383_LdbmhiNM6Ypzb3FM4PPuFP9rHe7ri8Ju.jpg", ); }