1409 lines
67 KiB
Dart
Executable File
1409 lines
67 KiB
Dart
Executable File
import 'dart:typed_data';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
import 'package:google_fonts/google_fonts.dart';
|
|
import 'package:jwt_decode/jwt_decode.dart';
|
|
import 'package:nhancepolicy/customAppBar/customAppBar.dart';
|
|
import 'dart:convert';
|
|
import 'dart:async';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:nhancepolicy/customAppBar/toastHelper.dart';
|
|
import 'package:nhancepolicy/hrPolicyDetails.dart';
|
|
import 'package:nhancepolicy/models/environment.dart';
|
|
import 'package:nhancepolicy/service/api_service.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:universal_html/html.dart' as html;
|
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
|
import 'package:excel/excel.dart';
|
|
import 'dart:io';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:csv/csv.dart';
|
|
|
|
import 'package:spreadsheet_decoder/spreadsheet_decoder.dart';
|
|
|
|
import 'customAppBar/customFooter.dart';
|
|
|
|
class excelVerify extends StatefulWidget {
|
|
final String ClientId;
|
|
final String policyTypeId;
|
|
final String ClientPoliyId;
|
|
final String clientBranchId;
|
|
final String Token;
|
|
final String TokenType;
|
|
final String cardType;
|
|
final String cardPolicyNo;
|
|
final String cardInsurer_name;
|
|
final String cardPolicy_name;
|
|
final String cardPolicy_ExpDate;
|
|
const excelVerify(
|
|
{Key? key,
|
|
required this.ClientId,
|
|
required this.policyTypeId,
|
|
required this.ClientPoliyId,
|
|
required this.clientBranchId,
|
|
required this.Token,
|
|
required this.TokenType,
|
|
required this.cardType,
|
|
required this.cardPolicyNo,
|
|
required this.cardInsurer_name,
|
|
required this.cardPolicy_name,
|
|
required this.cardPolicy_ExpDate})
|
|
: super(key: key);
|
|
|
|
@override
|
|
State<excelVerify> createState() => _excelVerifyState();
|
|
}
|
|
|
|
class _excelVerifyState extends State<excelVerify> {
|
|
Uint8List? fileBytes;
|
|
Uint8List? fileBytes2;
|
|
late String _token;
|
|
dynamic getPolicyNo;
|
|
bool _isLoading = false;
|
|
dynamic getPolicyNameDetails;
|
|
dynamic clintID;
|
|
String? fileName;
|
|
int _currentStep = 0; // Step index tracker
|
|
List<dynamic> dataPolicy = [];
|
|
dynamic validationArray = [];
|
|
dynamic missingColumnErrorMsg = 0;
|
|
dynamic columnIndexMismatchCount = 0;
|
|
dynamic columnMissingCount = 0;
|
|
List<Map<String, dynamic>> extractedData = [];
|
|
dynamic argumentsData;
|
|
List<Map<String, dynamic>> originalData = []; // Original data source
|
|
List<Map<String, dynamic>> filteredData = []; // Filtered data source
|
|
List<Map<String, dynamic>> tableData = []; // Filtered data source
|
|
|
|
List<Map<String, dynamic>> nonExcelFilteredData = [];
|
|
dynamic invalidRelationships = 0;
|
|
dynamic dobAgeCheckCount = 0;
|
|
dynamic empRefId;
|
|
List<String> excelHeader = [];
|
|
List<List<Map<String, dynamic>>> excelData = [];
|
|
late int excelValidationStaus = 1;
|
|
bool isSuccess = false;
|
|
String successContent = '';
|
|
bool isLoading = false;
|
|
late ApiService apiService;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
apiService = ApiService(context);
|
|
_loadToken();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
super.dispose();
|
|
html.window.localStorage.remove('fileBytes');
|
|
}
|
|
|
|
Future<void> _loadToken() async {
|
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
// final token = prefs.getString('hrtoken');
|
|
final token = widget.Token;
|
|
if (token != null && token.isNotEmpty) {
|
|
setState(() {
|
|
_token = token;
|
|
});
|
|
Map<String, dynamic>? decodedToken = Jwt.parseJwt(token);
|
|
print('decodedToken $decodedToken');
|
|
} else {
|
|
// Token is empty or null, handle accordingly (e.g., navigate to login screen)
|
|
// For now, let's navigate to the login screen
|
|
ToastHelper.showErrorToast(context, 'Session Out');
|
|
Navigator.pushReplacementNamed(context, 'hrLogin');
|
|
}
|
|
}
|
|
|
|
// Future<void> getPolicyDetails() async {
|
|
// setState(() {
|
|
// clientPolicyId = argumentsData['client_policy_id'];
|
|
// clientId = argumentsData['client_id'];
|
|
// policyType = argumentsData['type'];
|
|
// policy_name = argumentsData['policy_name'];
|
|
// });
|
|
// }
|
|
|
|
// Future<void> _uploadFile1(importPolicyName) async {
|
|
// FilePickerResult? result = await FilePicker.platform.pickFiles(
|
|
// type: FileType.custom,
|
|
// allowedExtensions: ['xlsx', 'xls', 'csv'],
|
|
// );
|
|
//
|
|
// if (result != null) {
|
|
// PlatformFile file = result.files.first;
|
|
// Uint8List fileBytes = file.bytes!;
|
|
// // Use the fileBytes as needed
|
|
// print('File name: ${file.name}');
|
|
// print('File size: ${file.size}');
|
|
// print('File bytes: $fileBytes');
|
|
// _processExcelData(fileBytes);
|
|
// } else {
|
|
// // User canceled the picker
|
|
// }
|
|
// }
|
|
|
|
void _uploadFile(importPolicyName) async {
|
|
print('Test');
|
|
if (kIsWeb) {
|
|
print('kIsWeb');
|
|
final input = html.FileUploadInputElement();
|
|
input.accept = '.xlsx,.xls,.csv';
|
|
input.click();
|
|
input.onChange.listen((event) async {
|
|
final file = input.files!.first;
|
|
final reader = html.FileReader();
|
|
reader.readAsArrayBuffer(file);
|
|
await reader.onLoadEnd.first; // Wait for the file to be loaded
|
|
if (reader.readyState == html.FileReader.DONE) {
|
|
Uint8List? fileBytes = reader.result as Uint8List?;
|
|
if (fileBytes != null) {
|
|
setState(() {
|
|
fileName = file.name;
|
|
});
|
|
// Save fileBytes to local storage
|
|
final jsonString = json.encode(fileBytes);
|
|
html.window.localStorage['fileBytes'] = jsonString;
|
|
print('File Name: $fileName');
|
|
print('File Bytes: $fileBytes');
|
|
sendExcelFIleTOAPI(fileBytes, fileName);
|
|
// Call the function to process Excel data here
|
|
// _processExcelData(fileBytes, fileName);
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
// Handle non-web platforms here (e.g., show an error message)
|
|
print('File upload is only supported on web platforms.');
|
|
}
|
|
}
|
|
|
|
void _processExcelData(Uint8List fileBytes, fileName) {
|
|
List<List<Data>> dataArray;
|
|
if (fileName.endsWith('.xlsx')) {
|
|
dataArray = decodeExcelData(fileBytes);
|
|
} else if (fileName.endsWith('.xls')) {
|
|
dataArray = decodeXLSData(fileBytes);
|
|
} else if (fileName.endsWith('.csv')) {
|
|
print('csv');
|
|
dataArray = decodeCSVData(fileBytes);
|
|
} else {
|
|
throw UnsupportedError('Unsupported file format: $fileName');
|
|
}
|
|
|
|
print('_processExcelData');
|
|
// Decode the Excel file and extract relevant data
|
|
// Assuming dataArray is your array containing Excel data
|
|
// List<List<Data>> dataArray = decodeExcelData(fileBytes);
|
|
print(dataArray);
|
|
// print(dataArray[0].toString());
|
|
// Extract Name, Age, and City from the array
|
|
print(dataArray[0].length);
|
|
|
|
if (dataArray[0].length == 11) {
|
|
for (int i = 0; i < dataArray.length; i++) {
|
|
Map<String, dynamic> dataMap = {
|
|
"Sno": dataArray[i][0].value,
|
|
"Emp_Code": dataArray[i][1].value,
|
|
"Name": dataArray[i][2].value,
|
|
"DOJ": dataArray[i][3].value,
|
|
"Gender": dataArray[i][4].value,
|
|
"Relation": dataArray[i][5].value,
|
|
"DOB": dataArray[i][6].value,
|
|
"Mail": dataArray[i][7].value,
|
|
"Mobile": dataArray[i][8].value,
|
|
"SI": dataArray[i][9].value,
|
|
"Grade": dataArray[i][10].value,
|
|
};
|
|
if (i == 0) {
|
|
// print(dataMap);
|
|
validationArray.add(dataMap);
|
|
} else {
|
|
// print(dataMap);
|
|
extractedData.add(dataMap);
|
|
}
|
|
}
|
|
// Do something with extracted data (e.g., display in UI)
|
|
originalData = extractedData;
|
|
filteredData = List.from(originalData);
|
|
print('filteredData');
|
|
print(filteredData);
|
|
print(validationArray);
|
|
|
|
validationArray[0].forEach((key, value) {
|
|
print(key);
|
|
print(value);
|
|
if (key.toString().trim().toLowerCase() !=
|
|
value.toString().trim().toLowerCase()) {
|
|
// If key and value are not equal, increment mismatch count
|
|
columnIndexMismatchCount++;
|
|
print('columnIndexMismatchCount: $value');
|
|
}
|
|
if (value.toString() == 'null') {
|
|
// If value is null, increment missing count
|
|
columnMissingCount++;
|
|
print('Value: $value');
|
|
}
|
|
});
|
|
|
|
print('columnIndexMismatchCount: $columnIndexMismatchCount');
|
|
print('columnMissingCount: $columnMissingCount');
|
|
|
|
nonExcelFilteredData = filteredData.where((item) {
|
|
final relation = item['Relation'];
|
|
return relation != null &&
|
|
relation.toString().trim().toLowerCase() != 'self';
|
|
}).toList();
|
|
print('nonExcelFilteredData');
|
|
|
|
print(nonExcelFilteredData);
|
|
print(nonExcelFilteredData.length);
|
|
if (argumentsData['type'] == 'GPA') {
|
|
if (nonExcelFilteredData.length > 0) {
|
|
print('nonSelf');
|
|
invalidRelationships = nonExcelFilteredData.length;
|
|
} else {
|
|
print('Self');
|
|
invalidRelationships = nonExcelFilteredData.length;
|
|
}
|
|
print('invalidRelationships: $invalidRelationships');
|
|
} else {
|
|
invalidRelationships = 0;
|
|
}
|
|
|
|
int invalidDobCount = countInvalidDobs(filteredData);
|
|
|
|
print('Number of invalid DOBs: $invalidDobCount');
|
|
|
|
dobAgeCheckCount = invalidDobCount;
|
|
} else {
|
|
print('Some Column is Missing');
|
|
var columnMissingCount = 11 - dataArray[0].length;
|
|
missingColumnErrorMsg = columnMissingCount;
|
|
print(missingColumnErrorMsg);
|
|
}
|
|
}
|
|
|
|
// bool checkAllSelf(List<Map<String, dynamic>> dataList) {
|
|
// // Check if any value of 'Relation' key is not 'Self'
|
|
// bool allSelf = dataList.every((data) => data['Relation'] == 'Self');
|
|
// // If all values are 'Self', return true; otherwise, return false
|
|
// return allSelf;
|
|
// }
|
|
|
|
// Placeholder function for decoding Excel data
|
|
List<List<Data>> decodeExcelData(Uint8List fileBytes) {
|
|
print('decodeExcelData');
|
|
|
|
// Create an Excel instance from the fileBytes
|
|
final excel = Excel.decodeBytes(fileBytes);
|
|
print('decodeExcelData');
|
|
print(excel);
|
|
|
|
// Assuming there's only one sheet in the Excel file
|
|
final sheet = excel.tables.keys.first;
|
|
final table = excel.tables[sheet]!;
|
|
|
|
// Convert Excel table to a List<List<Data>>
|
|
// Convert Excel table to a List<List<Data>>
|
|
List<List<Data>> dataArray = [];
|
|
for (int rowIdx = 0; rowIdx < table.rows.length; rowIdx++) {
|
|
List<Data> rowData = [];
|
|
for (int colIdx = 0; colIdx < table.rows[rowIdx].length; colIdx++) {
|
|
var value = table.rows[rowIdx][colIdx]?.value;
|
|
rowData.add(Data(value, rowIdx, colIdx, sheet));
|
|
}
|
|
dataArray.add(rowData);
|
|
}
|
|
return dataArray;
|
|
}
|
|
|
|
List<List<Data>> decodeXLSData(Uint8List fileBytes) {
|
|
final Excel excelData = Excel.decodeBytes(fileBytes);
|
|
final sheet = excelData.tables.keys.first;
|
|
final table = excelData.tables[sheet]!;
|
|
List<List<Data>> dataArray = [];
|
|
for (int rowIdx = 0; rowIdx < table.rows.length; rowIdx++) {
|
|
List<Data> rowData = [];
|
|
for (int colIdx = 0; colIdx < table.rows[rowIdx].length; colIdx++) {
|
|
var value = table.rows[rowIdx][colIdx]?.value;
|
|
rowData.add(Data(value, rowIdx, colIdx, sheet));
|
|
}
|
|
dataArray.add(rowData);
|
|
}
|
|
return dataArray;
|
|
}
|
|
|
|
List<List<Data>> decodeCSVData(Uint8List fileBytes) {
|
|
String csvString = utf8.decode(fileBytes);
|
|
List<List<dynamic>> csvData = const CsvToListConverter().convert(csvString);
|
|
List<List<Data>> dataArray = [];
|
|
|
|
// Skip the header row (if it exists) and start from index 1
|
|
for (int i = 1; i < csvData.length; i++) {
|
|
List<Data> rowData = [];
|
|
for (int j = 0; j < csvData[i].length; j++) {
|
|
// Assuming the CSV data is of type String
|
|
rowData.add(Data(csvData[i][j].toString(), i, j, 'Sheet1'));
|
|
}
|
|
dataArray.add(rowData);
|
|
}
|
|
return dataArray;
|
|
}
|
|
|
|
int countInvalidDobs(List<Map<String, dynamic>> data) {
|
|
int invalidCount = 0;
|
|
|
|
for (var entry in data) {
|
|
DateTime dob;
|
|
|
|
// if (entry['DOB'] is String) {
|
|
dob = DateTime.parse(entry['DOB'].toString());
|
|
// } else if (entry['DOB'] is DateTime) {
|
|
// dob = entry['DOB'];
|
|
// } else {
|
|
// // Invalid DOB format, skip this entry
|
|
// continue;
|
|
// }
|
|
print(entry['Relation']);
|
|
if ((entry['Relation'].toString() == 'Son' ||
|
|
entry['Relation'].toString() == 'Daughter')) {
|
|
if (DateTime.now().difference(dob).inDays > 25 * 365) {
|
|
print('child $dob');
|
|
invalidCount++;
|
|
}
|
|
} else if ((entry['Relation'] != 'Son' &&
|
|
entry['Relation'] != 'Daughter')) {
|
|
if (DateTime.now().difference(dob).inDays < 18 * 365) {
|
|
print('others $dob');
|
|
invalidCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return invalidCount;
|
|
}
|
|
|
|
void _dragAndDropFile(html.File file) async {
|
|
print('file');
|
|
print(file);
|
|
// Prepare form data
|
|
final formData = html.FormData();
|
|
formData.appendBlob('file', file);
|
|
|
|
// Send formData to API endpoint
|
|
final response = await html.HttpRequest.request(
|
|
'your_api_endpoint_here',
|
|
method: 'POST',
|
|
sendData: formData,
|
|
);
|
|
|
|
// Handle response as needed
|
|
print(response.responseText);
|
|
}
|
|
|
|
void _retrieveAndUploadFile() {
|
|
final jsonString = html.window.localStorage['fileBytes'];
|
|
if (jsonString != null) {
|
|
final decodedBytes = json.decode(jsonString);
|
|
if (decodedBytes is List<dynamic>) {
|
|
setState(() {
|
|
fileName = fileName ??
|
|
'Retrieved File'; // Provide a default name if fileName is null
|
|
});
|
|
sendExcelFIleTOAPI(
|
|
Uint8List.fromList(decodedBytes.cast<int>()),
|
|
fileName!,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> sendExcelFIleTOAPI(Uint8List fileBytes, fileName) async {
|
|
// Future.delayed(Duration(seconds: 3), () {
|
|
// setState(() {
|
|
isLoading = true;
|
|
// });
|
|
// });
|
|
print('submit');
|
|
print(fileBytes);
|
|
if (fileBytes == null) {
|
|
print('return');
|
|
return; // No file selected
|
|
} else {
|
|
print('else');
|
|
// // Prepare form data
|
|
// final formData = html.FormData();
|
|
// formData.appendBlob('file', html.Blob([fileBytes]), fileName);
|
|
|
|
// URL of the API where you want to send the file
|
|
final apiUrl = Environment.apiUrl + 'employeeUpload';
|
|
print('else');
|
|
// Create a multipart request
|
|
final request = http.MultipartRequest('POST', Uri.parse(apiUrl));
|
|
print('else');
|
|
// Attach the file to the request
|
|
// Set authorization token in headers
|
|
request.headers['Authorization'] = 'Bearer $_token';
|
|
// request.files.add(http.MultipartFile.fromBytes('file', fileBytes,
|
|
// filename: fileName));
|
|
print('Filename: $fileName');
|
|
request.files.add(http.MultipartFile.fromBytes(
|
|
'file',
|
|
fileBytes,
|
|
filename: fileName ?? 'default_filename.xlsx',
|
|
));
|
|
print('clintID: $clintID');
|
|
request.fields['client_id'] = widget.ClientId;
|
|
// if (policyFirstPart == 'GPA') {
|
|
request.fields['policy_id'] = widget.ClientPoliyId;
|
|
request.fields['client_branch_id'] = widget.clientBranchId;
|
|
// } else {
|
|
// request.fields['policy_id'] = '3';
|
|
// }
|
|
print('request : $request');
|
|
// Send the request
|
|
final response = await request.send();
|
|
print('else');
|
|
// Read response stream as a string
|
|
final responseString = await response.stream.bytesToString();
|
|
print('else');
|
|
// Check the status code of the response
|
|
if (response.statusCode == 200) {
|
|
isLoading = false;
|
|
Map<String, dynamic> data = json.decode(responseString);
|
|
if (data['status'] == 'success') {
|
|
ToastHelper.showSuccessToast(context, data['message']);
|
|
print('Table');
|
|
|
|
setState(() {
|
|
isSuccess = true;
|
|
successContent = data['message'];
|
|
excelValidationStaus = 0;
|
|
// excelHeader = List<String>.from(data['data']['excel_header']);
|
|
// print('excelHeader : $excelHeader');
|
|
// excelData = (data['data']['excel_data'] as List)
|
|
// .map<List<Map<String, dynamic>>>((row) => row
|
|
// .map<Map<String, dynamic>>(
|
|
// (cell) => Map<String, dynamic>.from(cell))
|
|
// .toList())
|
|
// .toList();
|
|
// print('excelHeader : $excelHeader');
|
|
});
|
|
handleImportAction();
|
|
} else {
|
|
setState(() {
|
|
isLoading = false;
|
|
});
|
|
ToastHelper.showErrorToast(context, data['message']);
|
|
print('Table');
|
|
|
|
setState(() {
|
|
isSuccess = false;
|
|
excelValidationStaus = 1;
|
|
excelHeader = List<String>.from(data['data']['excel_header']);
|
|
print('excelHeader : $excelHeader');
|
|
excelData = (data['data']['excel_data'] as List)
|
|
.map<List<Map<String, dynamic>>>((row) => row
|
|
.map<Map<String, dynamic>>(
|
|
(cell) => Map<String, dynamic>.from(cell))
|
|
.toList())
|
|
.toList();
|
|
print('excelData : $excelData');
|
|
print('excelHeader : $excelHeader');
|
|
});
|
|
}
|
|
} else {
|
|
setState(() {
|
|
isLoading = false;
|
|
});
|
|
// ToastHelper.showSuccessToast(
|
|
// context, 'Failed to upload file: ${response.reasonPhrase}');
|
|
ToastHelper.showErrorToast(context, 'Something went wrong');
|
|
print('Failed to upload file: ${response.reasonPhrase}');
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> handleImportAction() async {
|
|
print('handleImportAction');
|
|
|
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
final postId = prefs.getString('empHrId');
|
|
final preId = prefs.getString('enrollmentEmpPrimaryId');
|
|
var activity = "import_enrollempdata";
|
|
|
|
dynamic response;
|
|
|
|
print('postId - $postId');
|
|
print('preId - $preId');
|
|
print('activity - $activity');
|
|
|
|
try {
|
|
print('10');
|
|
|
|
response = await apiService.getImportLogHrActivity(
|
|
postId!, preId!, widget.Token, activity);
|
|
|
|
if (response['status'] == 'success') {
|
|
print('Request success');
|
|
} else {
|
|
// ToastHelper.showWarningToast(
|
|
// context, 'Request failed with status: ${response.statusCode}');
|
|
print('Request failed with status: ${response['code']}');
|
|
}
|
|
} catch (e) {
|
|
print('Exception occurred: $e');
|
|
}
|
|
}
|
|
|
|
void search(String query) {
|
|
setState(() {
|
|
if (query.isEmpty) {
|
|
// If search query is empty, show all data
|
|
filteredData = List.from(originalData);
|
|
} else {
|
|
// Filter the data based on the search query
|
|
filteredData = originalData.where((item) {
|
|
// Implement your filter logic here, for example:
|
|
return item['Emp_Code'].toLowerCase().contains(query.toLowerCase());
|
|
}).toList();
|
|
}
|
|
});
|
|
}
|
|
|
|
downloadSampleFile() {
|
|
final anchor = html.AnchorElement(href: 'assets/assets/Template_File.xlsx');
|
|
anchor.download = 'Template_File.xlsx'; // Set the filename
|
|
anchor.click(); // Trigger a click on the anchor element
|
|
}
|
|
|
|
resetErrorCount() {
|
|
setState(() {
|
|
fileBytes = null;
|
|
fileName = null;
|
|
_currentStep = 0;
|
|
excelHeader.clear();
|
|
excelData.clear();
|
|
|
|
// extractedData = [];
|
|
// originalData = [];
|
|
// filteredData = [];
|
|
// validationArray = [];
|
|
// nonExcelFilteredData = [];
|
|
// print('filteredData');
|
|
// print(filteredData);
|
|
// print(validationArray);
|
|
//
|
|
// missingColumnErrorMsg = 0;
|
|
// print(missingColumnErrorMsg);
|
|
// columnMissingCount = 0;
|
|
// print(columnMissingCount);
|
|
// columnIndexMismatchCount = 0;
|
|
// print(columnIndexMismatchCount);
|
|
// invalidRelationships = 0;
|
|
// dobAgeCheckCount = 0;
|
|
//
|
|
// html.window.localStorage.remove('fileBytes');
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: CustomAppBar(),
|
|
body: Stack(children: [
|
|
SafeArea(
|
|
child: Theme(
|
|
data: ThemeData(
|
|
canvasColor: Color(0xFFF4F7FE),
|
|
colorScheme: Theme.of(context).colorScheme.copyWith(
|
|
primary: Color(0xFF00999E),
|
|
background: Colors.red,
|
|
secondary: Color(0xFF00999E),
|
|
),
|
|
),
|
|
child: Container(
|
|
padding: const EdgeInsets.all(20),
|
|
color: Color(0xFFEFF3F6),
|
|
child: Card(
|
|
elevation: 0,
|
|
color: Colors.white,
|
|
child: Column(
|
|
children: [
|
|
Expanded(
|
|
child: Stepper(
|
|
type: StepperType.horizontal,
|
|
currentStep: _currentStep,
|
|
controlsBuilder:
|
|
(BuildContext context, ControlsDetails controls) {
|
|
return Container(
|
|
alignment: Alignment.bottomCenter,
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.spaceBetween,
|
|
children: <Widget>[
|
|
ElevatedButton(
|
|
onPressed: () {
|
|
html.window.localStorage
|
|
.remove('fileBytes');
|
|
fileBytes = null;
|
|
fileName = null;
|
|
_currentStep = 0;
|
|
excelHeader.clear();
|
|
excelData.clear();
|
|
// missingColumnErrorMsg = 0;
|
|
// columnIndexMismatchCount = 0;
|
|
// columnMissingCount = 0;
|
|
// invalidRelationships = 0;
|
|
// dobAgeCheckCount = 0;
|
|
// nonExcelFilteredData = [];
|
|
// Navigator.pushNamed(
|
|
// context, 'hrPolicyDetails',
|
|
// arguments: argumentsData);
|
|
|
|
Navigator.pop(context);
|
|
},
|
|
child: Text(
|
|
'Close',
|
|
style:
|
|
TextStyle(color: Color(0xFFE26728)),
|
|
),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.white,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(5),
|
|
side: BorderSide(
|
|
color: Color(0xFFE26728)),
|
|
),
|
|
),
|
|
),
|
|
// SizedBox(width: 10),
|
|
// if (fileName != null)
|
|
// ElevatedButton(
|
|
// onPressed: () {
|
|
// // Reset localStorage and fileBytes
|
|
// setState(() {
|
|
// html.window.localStorage
|
|
// .remove('fileBytes');
|
|
// fileBytes = null;
|
|
// fileName = null;
|
|
// _currentStep = 0;
|
|
// });
|
|
// },
|
|
// child: Text(
|
|
// 'Reselect File',
|
|
// style: TextStyle(color: Color(0xFFE26728)),
|
|
// ),
|
|
// style: ElevatedButton.styleFrom(
|
|
// backgroundColor: Colors.white,
|
|
// shape: RoundedRectangleBorder(
|
|
// borderRadius: BorderRadius.circular(5),
|
|
// side:
|
|
// BorderSide(color: Color(0xFFE26728)),
|
|
// ),
|
|
// ),
|
|
// ),
|
|
Spacer(),
|
|
SizedBox(
|
|
width:
|
|
10), // This pushes the buttons to the right
|
|
if (_currentStep != 0)
|
|
ElevatedButton(
|
|
onPressed: () {
|
|
controls.onStepCancel!();
|
|
},
|
|
child: Text(
|
|
'Previous',
|
|
style:
|
|
TextStyle(color: Color(0xFFE26728)),
|
|
),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.white,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius:
|
|
BorderRadius.circular(5),
|
|
side: BorderSide(
|
|
color: Color(0xFFE26728)),
|
|
),
|
|
),
|
|
),
|
|
SizedBox(width: 10),
|
|
ElevatedButton(
|
|
child: const Text(
|
|
'NEXT',
|
|
style: TextStyle(color: Colors.white),
|
|
),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Color(0xFFE26728),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(5),
|
|
),
|
|
),
|
|
// Disable button if excelValidationStatus is 1
|
|
// Use ternary operator to conditionally set onPressed to null
|
|
onPressed: (_currentStep == 0 &&
|
|
fileName == null) ||
|
|
(_currentStep == 1 &&
|
|
excelValidationStaus == 1)
|
|
? null
|
|
: () {
|
|
if (_currentStep == 0) {
|
|
// For Step 0: Enable continue if fileName is not null
|
|
if (fileName != null) {
|
|
controls.onStepContinue!();
|
|
}
|
|
} else if (_currentStep == 1) {
|
|
// For Step 1: Check excelValidationStatus
|
|
if (excelValidationStaus == 0) {
|
|
// Navigate to hrPolicyDetails page
|
|
// Navigator.pushNamed(
|
|
// context, 'hrPolicyDetails',
|
|
// arguments: argumentsData);
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (context) =>
|
|
hrPolicyDetails(
|
|
ClientId: widget
|
|
.ClientId,
|
|
policyTypeId: widget
|
|
.policyTypeId, // <-- from map
|
|
ClientPoliyId:
|
|
widget.ClientPoliyId,
|
|
clientBranchId:
|
|
widget.clientBranchId,
|
|
Token: widget.Token,
|
|
TokenType:
|
|
widget.TokenType,
|
|
cardType: widget.cardType,
|
|
cardPolicyNo:
|
|
widget.cardPolicyNo,
|
|
cardInsurer_name: widget
|
|
.cardInsurer_name,
|
|
cardPolicy_name: widget
|
|
.cardPolicy_name,
|
|
cardPolicy_ExpDate: widget
|
|
.cardPolicy_ExpDate,
|
|
|
|
// Token: widget.Token,
|
|
// ClientId: widget.ClientId,
|
|
// ClientPolicyId : widget.ClientPoliyId,
|
|
// PolicyName: widget.cardPolicy_name,
|
|
// PolicyNo: widget.cardPolicyNo,
|
|
// ClientBranchId: widget.HrId,
|
|
// PolicyType: widget.cardType,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
// If excelValidationStatus is 1, button will be disabled (do nothing)
|
|
}
|
|
},
|
|
),
|
|
SizedBox(width: 10),
|
|
// if (_currentStep == 2)
|
|
// ElevatedButton(
|
|
// onPressed: () {
|
|
// _retrieveAndUploadFile();
|
|
// },
|
|
// child: Text(
|
|
// 'Submit',
|
|
// style: TextStyle(color: Colors.white),
|
|
// ),
|
|
// style: ElevatedButton.styleFrom(
|
|
// backgroundColor: Color(0xFFE26728),
|
|
// shape: RoundedRectangleBorder(
|
|
// borderRadius: BorderRadius.circular(5),
|
|
// ),
|
|
// ),
|
|
// ),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
onStepContinue: _currentStep == 2
|
|
? null
|
|
: () {
|
|
if (_currentStep == 0) {
|
|
// For the first step, allow continue if fileName is not null
|
|
if (fileName != null) {
|
|
setState(() {
|
|
_currentStep += 1;
|
|
});
|
|
}
|
|
} else if (_currentStep == 1) {
|
|
// For the second step, allow continue if both errors are 0
|
|
if (missingColumnErrorMsg == 0 &&
|
|
columnIndexMismatchCount == 0 &&
|
|
invalidRelationships == 0 &&
|
|
dobAgeCheckCount == 0) {
|
|
setState(() {
|
|
_currentStep += 1;
|
|
});
|
|
}
|
|
}
|
|
// setState(() {
|
|
// // Increment the current step when the user clicks continue
|
|
// if (_currentStep < 2) {
|
|
// _currentStep += 1;
|
|
// }
|
|
// });
|
|
},
|
|
onStepCancel: () {
|
|
setState(() {
|
|
// Decrement the current step when the user clicks cancel
|
|
if (_currentStep > 0) {
|
|
_currentStep -= 1;
|
|
}
|
|
});
|
|
},
|
|
steps: [
|
|
Step(
|
|
title: Container(
|
|
child: Text(
|
|
'Import Excel',
|
|
style: GoogleFonts.poppins(
|
|
color: Color(0xFF00999E),
|
|
),
|
|
),
|
|
),
|
|
content: Container(
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Expanded(
|
|
flex: 12,
|
|
child: Column(
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.center,
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
'${widget.cardPolicy_name} - (${widget.cardType})',
|
|
textAlign: TextAlign.center,
|
|
style: const TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight
|
|
.w600, // Adjust the font size as needed
|
|
color: Color(
|
|
0xFF181818), // Adjust the text color as needed
|
|
),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
SizedBox(height: 20),
|
|
Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.center,
|
|
children: [
|
|
Expanded(
|
|
child: Container(
|
|
margin: EdgeInsets.symmetric(
|
|
horizontal: 150),
|
|
alignment: Alignment.center,
|
|
color: Colors.grey[200],
|
|
height:
|
|
250, // Adjust height as needed
|
|
child: DragTarget(
|
|
onAccept: (html.File
|
|
droppedFile) {
|
|
setState(() {
|
|
fileName =
|
|
droppedFile.name;
|
|
});
|
|
_dragAndDropFile(
|
|
droppedFile);
|
|
},
|
|
builder:
|
|
(BuildContext context,
|
|
List<String?>
|
|
candidateData,
|
|
List<dynamic>
|
|
rejectedData) {
|
|
return Container(
|
|
alignment:
|
|
Alignment.center,
|
|
child: Column(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment
|
|
.center,
|
|
children: [
|
|
// if (fileName == null)
|
|
// ElevatedButton(
|
|
// onPressed: () => {},
|
|
// child: Icon(
|
|
// Icons.download,
|
|
// color: Colors
|
|
// .grey), // You can replace the Icon with your custom button child
|
|
// style:
|
|
// ElevatedButton
|
|
// .styleFrom(
|
|
// shape:
|
|
// CircleBorder(), // Makes the button round
|
|
// padding:
|
|
// EdgeInsets.all(
|
|
// 18), // Change the button color as needed
|
|
// ),
|
|
// ),
|
|
// SizedBox(height: 20),
|
|
// if (fileName == null)
|
|
// Text(
|
|
// 'Drag and drop file to import',
|
|
// style: TextStyle(
|
|
// fontSize: 16,
|
|
// fontWeight:
|
|
// FontWeight
|
|
// .w600),
|
|
// ), // Add spacing between texts
|
|
// SizedBox(height: 20),
|
|
fileName != null
|
|
? Column(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment
|
|
.center,
|
|
children: [
|
|
Icon(
|
|
Icons
|
|
.upload_file, // Choose the appropriate icon
|
|
size:
|
|
35,
|
|
color: Color(
|
|
0xFFE26728), // Adjust the size as needed
|
|
),
|
|
SizedBox(
|
|
height:
|
|
15), // Add some space between the icon and text
|
|
Text(
|
|
'$fileName',
|
|
style: TextStyle(
|
|
fontSize:
|
|
16),
|
|
),
|
|
SizedBox(
|
|
height:
|
|
25), // Add some space between the icon and text
|
|
MouseRegion(
|
|
cursor:
|
|
SystemMouseCursors.click, // Set cursor to pointer on hover
|
|
child:
|
|
GestureDetector(
|
|
onTap:
|
|
() {
|
|
resetErrorCount();
|
|
},
|
|
child:
|
|
const Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
Icons.delete_forever, // Choose the remove icon
|
|
size: 20, // Adjust the size as needed
|
|
color: Colors.red, // Set the color of the remove icon
|
|
),
|
|
SizedBox(width: 1), // Add some space between the icon and text
|
|
Text(
|
|
'Remove',
|
|
style: TextStyle(fontSize: 13, color: Color(0xFF727272)),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
)
|
|
],
|
|
)
|
|
: ElevatedButton(
|
|
onPressed: () => _uploadFile('Policy Name'),
|
|
child: Text(
|
|
'Select File',
|
|
style: TextStyle(
|
|
color:
|
|
Colors.white),
|
|
),
|
|
style: ElevatedButton
|
|
.styleFrom(
|
|
backgroundColor:
|
|
Color(
|
|
0xFFE26728),
|
|
),
|
|
),
|
|
SizedBox(
|
|
height: 20),
|
|
if (fileName ==
|
|
null)
|
|
Text(
|
|
'Supported Files : XLSX')
|
|
// Add more Text widgets for additional lines of text
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.start,
|
|
children: [
|
|
Expanded(
|
|
child: Column(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment
|
|
.start,
|
|
children: [
|
|
Text(
|
|
'Ensure that the import file is in the correct format by comparing it with our template file.',
|
|
textAlign:
|
|
TextAlign.center,
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight:
|
|
FontWeight.w400,
|
|
)),
|
|
MouseRegion(
|
|
cursor: SystemMouseCursors
|
|
.click,
|
|
child: GestureDetector(
|
|
onTap: () {
|
|
downloadSampleFile();
|
|
},
|
|
child: Text(
|
|
'Template File',
|
|
style: TextStyle(
|
|
fontSize: 15,
|
|
color: Color(
|
|
0xFF00999E), // Add underline decoration
|
|
),
|
|
),
|
|
),
|
|
)
|
|
]))
|
|
],
|
|
)
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
isActive: _currentStep == 0,
|
|
),
|
|
|
|
Step(
|
|
title: Text(
|
|
'Excel Validation',
|
|
style: TextStyle(color: Color(0xFF00999E)),
|
|
),
|
|
content: isSuccess
|
|
? Center(
|
|
child: Text(
|
|
successContent,
|
|
style: TextStyle(
|
|
fontSize: 20, color: Colors.green),
|
|
),
|
|
)
|
|
: excelHeader.isNotEmpty &&
|
|
excelData.isNotEmpty
|
|
? SingleChildScrollView(
|
|
scrollDirection: Axis.vertical,
|
|
child: SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
child: DataTable(
|
|
columns: excelHeader
|
|
.map((header) => DataColumn(
|
|
label: Text(header)))
|
|
.toList(),
|
|
rows: excelData
|
|
.map((row) => DataRow(
|
|
cells: row
|
|
.map(
|
|
(cell) =>
|
|
DataCell(
|
|
cell.containsKey(
|
|
'error')
|
|
? Row(
|
|
children: [
|
|
Text(cell['value'] ?? ''),
|
|
SizedBox(width: 5),
|
|
IconButton(
|
|
icon: Icon(
|
|
Icons.error_outline,
|
|
color: Colors.red,
|
|
size: 16,
|
|
),
|
|
onPressed: () {
|
|
showDialog(
|
|
context: context,
|
|
builder: (context) {
|
|
return AlertDialog(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(30.0),
|
|
),
|
|
elevation: 0,
|
|
backgroundColor: Colors.white,
|
|
title: Text('Error Details'),
|
|
content: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: (cell['error'] as List).map((e) => Text(e)).toList(),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () {
|
|
Navigator.of(context).pop();
|
|
},
|
|
child: Text('OK'),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
],
|
|
)
|
|
: Text(cell['value'] ??
|
|
''),
|
|
))
|
|
.toList(),
|
|
))
|
|
.toList(),
|
|
),
|
|
),
|
|
)
|
|
: Center(
|
|
child: CircularProgressIndicator()),
|
|
isActive: _currentStep == 1,
|
|
),
|
|
// Step(
|
|
// title: Text(
|
|
// 'Preview',
|
|
// style: TextStyle(color: Color(0xFFE26728)),
|
|
// ),
|
|
// content: Column(
|
|
// children: [
|
|
// Row(
|
|
// children: [
|
|
// Expanded(
|
|
// flex: 10,
|
|
// child: Container(
|
|
// alignment: Alignment.centerLeft,
|
|
// child: Container(
|
|
// width:
|
|
// 350, // Set your desired width here
|
|
// height:
|
|
// 40, // Set your desired height here
|
|
// decoration: BoxDecoration(
|
|
// boxShadow: [
|
|
// BoxShadow(
|
|
// color: Color.fromRGBO(
|
|
// 255,
|
|
// 255,
|
|
// 255,
|
|
// 0.5), // Shadow color with opacity
|
|
// offset: Offset(5,
|
|
// 5), // Shadow position (horizontal, vertical)
|
|
// blurRadius: 10, // Blur radius
|
|
// spreadRadius:
|
|
// 0, // Spread radius
|
|
// ),
|
|
// ],
|
|
// borderRadius:
|
|
// BorderRadius.circular(5),
|
|
// ),
|
|
// child: TextField(
|
|
// textAlignVertical: TextAlignVertical
|
|
// .center, // Center the text vertically
|
|
// decoration: InputDecoration(
|
|
// hintText: 'Search',
|
|
// suffixIcon: Icon(Icons.search),
|
|
// contentPadding: EdgeInsets.all(
|
|
// 10), // Adjust the horizontal padding
|
|
// border: OutlineInputBorder(
|
|
// borderSide: BorderSide(
|
|
// color: Color(
|
|
// 0xFFf5f5f7)), // Set border color to gray
|
|
// ),
|
|
// ),
|
|
// onChanged:
|
|
// search, // Call the search method on text change
|
|
// ),
|
|
// )),
|
|
// ),
|
|
// ],
|
|
// ),
|
|
// SizedBox(height: 20),
|
|
// Row(
|
|
// children: [
|
|
// Expanded(
|
|
// child: SingleChildScrollView(
|
|
// child: _buildDataTable(),
|
|
// ),
|
|
// )
|
|
// ],
|
|
// ),
|
|
// ],
|
|
// ),
|
|
// isActive: _currentStep == 2,
|
|
// ),
|
|
],
|
|
),
|
|
),
|
|
// SizedBox(height: 20),
|
|
// if (_currentStep == 2)
|
|
// Align(
|
|
// alignment: Alignment.bottomRight,
|
|
// child: ElevatedButton(
|
|
// onPressed: () {
|
|
// sendExcelFIleTOAPI();
|
|
// },
|
|
// child: Text(
|
|
// 'Complete',
|
|
// style: TextStyle(color: Colors.white),
|
|
// ),
|
|
// style: ElevatedButton.styleFrom(
|
|
// backgroundColor: Color(0xFFE26728),
|
|
// ),
|
|
// ),
|
|
// ),
|
|
// SizedBox(height: 20),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
if (isLoading)
|
|
Container(
|
|
color: Color(0x98FFFCE5), // Semi-transparent background
|
|
child: Center(
|
|
child: // Your GIF loader widget
|
|
Image.asset(
|
|
height: 60,
|
|
width: 60,
|
|
'assets/nhance-loader.gif'), // Adjust path to your GIF loader
|
|
),
|
|
),
|
|
Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: Container(
|
|
width: double.infinity, // Make the footer full width
|
|
child: CustomFooter(),
|
|
),
|
|
),
|
|
]));
|
|
}
|
|
|
|
Widget _buildDataTable() {
|
|
if (filteredData.isEmpty) {
|
|
SizedBox(height: 25);
|
|
return Text('No available data');
|
|
} else {
|
|
return Card(
|
|
elevation: 0, // Set elevation to 0 for no shadow
|
|
child: PaginatedDataTable(
|
|
rowsPerPage: 25, // Adjust rows per page as needed
|
|
columns: [
|
|
DataColumn(label: Text('S.No')),
|
|
DataColumn(label: Text('Employee ID')),
|
|
DataColumn(label: Text('Name')),
|
|
DataColumn(label: Text('Date of Joining')),
|
|
DataColumn(label: Text('Gender')),
|
|
DataColumn(label: Text('Relationship')),
|
|
DataColumn(label: Text('Date of Birth')),
|
|
DataColumn(label: Text('Mail')),
|
|
DataColumn(label: Text('Mobile No')),
|
|
DataColumn(label: Text('SI')),
|
|
DataColumn(label: Text('Grade')),
|
|
],
|
|
source: _DependenceDataSource0(filteredData),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
Widget _buildRowWithIcon(IconData iconData, String text,
|
|
{Color iconColor = Colors.black}) {
|
|
return Row(
|
|
children: [
|
|
Icon(
|
|
iconData,
|
|
color: iconColor, // Set color based on the parameter
|
|
),
|
|
SizedBox(width: 8), // Add some space between icon and text
|
|
Text(text), // Text widget
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class Data {
|
|
final dynamic value;
|
|
final int row;
|
|
final int column;
|
|
final String sheet;
|
|
|
|
Data(this.value, this.row, this.column, this.sheet);
|
|
}
|
|
|
|
class _DependenceDataSource0 extends DataTableSource {
|
|
final List<Map<String, dynamic>> _data;
|
|
_DependenceDataSource0(this._data);
|
|
|
|
@override
|
|
DataRow getRow(int index) {
|
|
final row = _data[index];
|
|
|
|
String dob = row['DOB'] != null ? formatDate(row['DOB']) : 'N/A';
|
|
String doj = row['DOJ'] != null ? formatDate(row['DOJ']) : 'N/A';
|
|
|
|
return DataRow(cells: [
|
|
DataCell(Text(row['Sno'].toString())),
|
|
DataCell(Text(row['Emp_Code'].toString())),
|
|
DataCell(Text(row['Name'].toString())),
|
|
DataCell(Text(doj)),
|
|
DataCell(Text(row['Gender']?.toString() ?? 'N/A')),
|
|
DataCell(Text(row['Relation']?.toString() ?? 'N/A')),
|
|
DataCell(Text(dob)),
|
|
DataCell(Text(row['Mail']?.toString() ?? 'N/A')),
|
|
DataCell(Text(row['Mobile']?.toString() ?? 'N/A')),
|
|
DataCell(Text(row['SI']?.toString() ?? 'N/A')),
|
|
DataCell(Text(row['Grade']?.toString() ?? 'N/A')),
|
|
]);
|
|
}
|
|
|
|
@override
|
|
bool get isRowCountApproximate => false;
|
|
|
|
@override
|
|
int get rowCount => _data.length;
|
|
|
|
@override
|
|
int get selectedRowCount => 0;
|
|
|
|
String formatDate(dynamic dateValue) {
|
|
if (dateValue is String) {
|
|
// If the date is already in string format
|
|
DateTime dateTime = DateTime.parse(dateValue);
|
|
return DateFormat('dd-MM-yyyy').format(dateTime);
|
|
} else if (dateValue is DateCellValue) {
|
|
// If dateValue is an instance of DateCellValue
|
|
return DateFormat('dd-MM-yyyy')
|
|
.format(DateTime.parse(dateValue.toString()));
|
|
} else {
|
|
// Handle other cases or null values
|
|
return 'N/A';
|
|
}
|
|
}
|
|
}
|