From 8d470bec18ad6a0defe235a0fccc9a6aef7581ac Mon Sep 17 00:00:00 2001 From: SurendarSuri30 Date: Wed, 2 Jul 2025 16:28:28 +0530 Subject: [PATCH] CD Tab Added --- .env.development | 1 + lib/hrDashboard.dart | 1 + lib/models/environment.dart | 4 + lib/service/api_service.dart | 13 + lib/service/hrDashboardTabs/cd.dart | 401 +++++++++++++++++- macos/Flutter/GeneratedPluginRegistrant.swift | 2 - 6 files changed, 418 insertions(+), 4 deletions(-) diff --git a/.env.development b/.env.development index 367bc8a..405ac18 100755 --- a/.env.development +++ b/.env.development @@ -1,3 +1,4 @@ API_URL=https://venbait.in/enrollment/employeeRest/ +API_URL_POST=https://venbait.in/nhance/dev/employeeRest/ BASE_HREF=/nhance/app/dev/ ENV=development \ No newline at end of file diff --git a/lib/hrDashboard.dart b/lib/hrDashboard.dart index 045a3a3..eb6e406 100755 --- a/lib/hrDashboard.dart +++ b/lib/hrDashboard.dart @@ -215,6 +215,7 @@ class _hrDashboardState extends State empClientId: empClientId, empClientBranchId: empClientBranchId, empHrId: empHrId, + postToken: _postToken, )); } if (empAllowed_modules.contains(4)) { diff --git a/lib/models/environment.dart b/lib/models/environment.dart index e6331b2..9ddaeec 100755 --- a/lib/models/environment.dart +++ b/lib/models/environment.dart @@ -23,6 +23,10 @@ class Environment { return dotenv.env['API_URL'] ?? 'API_URL not found!'; } + static String get apiUrlPost { + return dotenv.env['API_URL_POST'] ?? 'API_URL not found!'; + } + static String get baseHref { return dotenv.env['BASE_HREF'] ?? 'BASE_HREF not found!'; } diff --git a/lib/service/api_service.dart b/lib/service/api_service.dart index 91b602a..ec64aeb 100755 --- a/lib/service/api_service.dart +++ b/lib/service/api_service.dart @@ -430,6 +430,19 @@ class ApiService { return response; } + Future> getCDPoliciesToApi( + String clintID, String hr_id, String token) async { + print("getCashDepositDetailsToApi1"); + final url = Uri.parse( + '${Environment.apiUrlPost}cdSummaryData?client_id=$clintID&hr_id=$hr_id'); + + final headers = { + 'Authorization': 'Bearer $token' ?? '', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + Future> getEmployeeAndDependenceToApi( String clintID, String getPolicyNo, String empRefId) async { print(_hrtoken); diff --git a/lib/service/hrDashboardTabs/cd.dart b/lib/service/hrDashboardTabs/cd.dart index 5545d9b..47b208a 100644 --- a/lib/service/hrDashboardTabs/cd.dart +++ b/lib/service/hrDashboardTabs/cd.dart @@ -1,29 +1,426 @@ +import 'dart:convert'; + +import 'package:csv/csv.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; +import 'package:universal_html/html.dart' as html; + +import '../../models/environment.dart'; +import '../api_service.dart'; +import 'package:collection/collection.dart'; class CdPolicies extends StatefulWidget { final String empClientId; final String empClientBranchId; final String empHrId; + final String postToken; const CdPolicies( {Key? key, required this.empClientId, required this.empClientBranchId, - required this.empHrId}); + required this.empHrId, required this.postToken + }); @override State createState() => _CdPolicieState(); } class _CdPolicieState extends State { + + Uint8List? fileBytes; + List> getCDPolicies = []; + bool isLoading = false; + bool _isLoading = false; + // dynamic clintID; + late TabController _tabController; + // List dataPolicy = []; + List reversedDataPolicy = []; + List> originalData = []; // Original data source + List> filteredData = []; // Filtered data source + dynamic argumentsData; + dynamic policyType; + dynamic policyName; + dynamic clientPolicyId; + dynamic clientId; + dynamic empRefId; + int inceptionType = 0; + TextEditingController searchController = TextEditingController(); + late ApiService apiService; + + @override + void initState() { + super.initState(); + apiService = ApiService(context); // Initialize ApiService here + getCDPoliciesDetails(); + } + + @override + void dispose() { + super.dispose(); + } + + Future getCDPoliciesDetails() async { + print('9'); + setState(() { + isLoading = true; + }); + try { + print('10'); + final response = await apiService.getCDPoliciesToApi(widget.empClientId,widget.empHrId,widget.postToken); + if (response['status'] == 'success') { + setState(() { + // isLoading = false; + }); + setState(() { + getCDPolicies = List>.from(response['data']); + originalData = getCDPolicies; + filteredData = List.from(originalData); + print('filteredData'); + print(filteredData); + }); + } else { + setState(() { + // isLoading = false; + }); + + // ToastHelper.showWarningToast( + // context, 'Request failed with status: ${response.statusCode}'); + print('Request failed with status: ${response['code']}'); + } + } catch (e) { + setState(() { + // isLoading = false; + }); + print('Exception occurred: $e'); + } finally { + setState(() { + // _isLoading = false; + }); + } + } + + void search(String query) { + print(query); + // Check if the query is empty + if (query.isEmpty) { + // If search query is empty, show all data + setState(() { + filteredData = List.from(originalData); + }); + } else { + // Filter the original data based on the search query + setState(() { + filteredData = originalData.where((row) { + // Implement your filter logic here + // For example, check if any field in the row contains the query + // Adjust this logic based on your data structure + return row['insurer_name'] + .toString() + .toLowerCase() + .contains(query.toLowerCase()) || + row['cd_master_account_no'] + .toString() + .toLowerCase() + .contains(query.toLowerCase()) || + row['balance'] + .toString() + .toLowerCase() + .contains(query.toLowerCase()); + }).toList(); + }); + } + print(filteredData.length); + } + + void exportToCsv(List> data) { + List> rows = []; + + // Header + rows.add(['Insurer Name', 'CD Account number', 'Current Balance']); + + // Data rows + for (var item in data) { + rows.add([ + item['insurer_name'] ?? '', + item['cd_master_account_no'] ?? '', + '₹${item['balance'] ?? '0'}', + ]); + } + + // Convert to CSV string + String csvData = const ListToCsvConverter().convert(rows); + + // For Web: Create download + final bytes = utf8.encode(csvData); + final blob = html.Blob([bytes]); + final url = html.Url.createObjectUrlFromBlob(blob); + final anchor = html.AnchorElement(href: url) + ..setAttribute("download", "CD_Policies.csv") + ..click(); + html.Url.revokeObjectUrl(url); + } + @override Widget build(BuildContext context) { // TODO: implement build return Container( - child: Text("Cd policy data"), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), // 👈 set your desired radius + ), + // height: 400, + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + Row( + children: [ + Expanded( + flex: 4, + child: Align( + alignment: Alignment.centerLeft, + child: Container( + width: 400, + height: 37, + decoration: BoxDecoration( + color: Color(0xFFF0F0F0), + borderRadius: BorderRadius.circular(8), + ), + child: TextField( + decoration: InputDecoration( + hintText: 'Search', + prefixIcon: Icon(Icons.search, size: 18), + contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), + border: InputBorder.none, // No border since Container handles it + ), + controller: searchController, + onChanged: search, + style: TextStyle(fontSize: 14), + ), + ), + ), + ), + SizedBox(width: 12), + Expanded( + flex: 2, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SizedBox( + width: 116, + height: 37, + child: ElevatedButton( + onPressed: () { + exportToCsv(filteredData); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFFE26728), + padding: EdgeInsets.all(10), // Internal padding + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), // Border radius + side: BorderSide( + color: Colors.transparent, // Optional border color + width: 1, // Border width + ), + ), + elevation: 0, + ), + child: Text( + 'Export', + style: TextStyle(fontSize: 16,color: Color(0xFFFFFFFF),fontWeight: FontWeight.w700,letterSpacing: 1), + ), + ), + ), + + ], + ), + ), + ], + ), + SizedBox(height: 20), + Row( + children: [ + Expanded( + child: SingleChildScrollView( + child: _buildCDDataTable(context), + ), + ) + ], + ), + ], + ), ); } + + Widget _buildCDDataTable(BuildContext context) { + if (filteredData.isEmpty) { + return const SizedBox( + height: 50, + child: Center(child: Text('No available data')), + ); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header row + Container( + decoration: BoxDecoration( + color: Color(0xFF00A6A6), + borderRadius: BorderRadius.circular(6), + ), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + child: Row( + children: const [ + Expanded( + flex: 4, + child: Text( + 'Insurer Name', + style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), + ), + ), + Expanded( + flex: 3, + child: Text( + 'CD Account number', + style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), + ), + ), + Expanded( + flex: 2, + child: Text( + 'Current Balance', + style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), + ), + ), + Expanded( + flex: 1, + child: Text( + 'Action', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), + ), + ), + ], + ), + ), + + const SizedBox(height: 6), + + // Table body rows + ...filteredData.mapIndexed((index, item) { + return Container( + margin: const EdgeInsets.only(bottom: 8), + padding: const EdgeInsets.symmetric(vertical: 5 , horizontal: 16), + decoration: BoxDecoration( + color: index % 2 == 0 ? Color(0xFFE6FAFB) : Colors.white, + borderRadius: BorderRadius.circular(6), + ), + child: Row( + children: [ + Expanded( + flex: 4, + child: Text( + item['insurer_name'] ?? '-', + style: TextStyle( + color: Color(0xFF000000) + ), + ), + ), + Expanded( + flex: 3, + child: Text( + item['cd_master_account_no'] ?? '-', + style: TextStyle( + color: Color(0xFF000000) + ), + ), + ), + Expanded( + flex: 2, + child: Text( + "₹${item['balance'] ?? '0'}", + style: TextStyle( + color: Color(0xFF000000) + ), + ), + ), + Expanded( + flex: 1, + child: Center( + child: IconButton( + icon: const Icon(Icons.remove_red_eye_outlined), + onPressed: () { + // Add your logic here + }, + ), + ), + ), + ], + ), + ); + }).toList(), + ], + ); + } + + + } + +class _DependenceDataSource0 extends DataTableSource { + final List> _data; + final BuildContext context; + + _DependenceDataSource0(this._data, this.context); + + @override + DataRow getRow(int index) { + // Calculate real row index (even: actual data, odd: spacer) + final realIndex = index ~/ 2; + + // Add spacing after each row + if (index.isOdd) { + return DataRow( + color: MaterialStateProperty.all(Colors.transparent), + cells: [ + DataCell(SizedBox(height: 10)), // empty spacer cell + DataCell(SizedBox(height: 10)), + DataCell(SizedBox(height: 10)), + ], + ); + } + + final row = _data[realIndex]; + return DataRow( + color: MaterialStateColor.resolveWith((states) => Color(0xFFE0F7F9)), + cells: [ + DataCell(Text(row['insurer_name'] ?? '-')), + DataCell(Text(row['cd_master_account_no'] ?? '-')), + DataCell(Text('₹${row['balance'] ?? '0'}')), + ], + ); + } + + @override + bool get isRowCountApproximate => false; + + @override + int get rowCount => _data.length * 2; // double the rows for gaps + + @override + int get selectedRowCount => 0; +} + + +// Sample Data class representing each element in the array +class Data { + final dynamic value; + final int row; + final int column; + final String sheet; + + Data(this.value, this.row, this.column, this.sheet); +} \ No newline at end of file diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index ff40429..2ce5852 100755 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,7 +5,6 @@ import FlutterMacOS import Foundation -import file_picker import firebase_auth import firebase_core import google_sign_in_ios @@ -15,7 +14,6 @@ import smart_auth import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))