nhance_partner/lib/presentation/screens/UserManagement/Agent/agentIncentiveFile.dart
2026-04-03 15:04:34 +05:30

1047 lines
40 KiB
Dart

// import 'dart:io' as html;
// import 'dart:nativewrappers/_internal/vm/lib/typed_data_patch.dart';
import 'dart:convert';
import 'dart:typed_data'; // Import for Uint8List
import 'package:dropdown_search/dropdown_search.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:nhance_partner/data/utils/toastNotification.dart';
import 'package:nhance_partner/presentation/themes/indicators/text_field_theme.dart';
import 'package:toastification/toastification.dart';
import 'package:universal_html/html.dart' as html;
import '../../../../core/config/env.dart';
import '../../../../core/services/api_service.dart';
import '../../../../data/services/auth_service.dart';
import '../../../../data/utils/validators.dart';
import '../../../providers/manager_provider.dart';
import '../../../themes/indicators/customizd_file_upload.dart';
import '../../../themes/indicators/input_field_decoration.dart';
import '../../../themes/indicators/month_field_theme.dart';
import '../../../themes/indicators/search_field_theme.dart';
// import '../../../themes/indicators/upload_doc_theme.dart';
/// function to open the modal
void showUploadIncentiveModal(BuildContext context) {
showDialog(
context: context,
builder: (context) => const UploadIncentiveModal(),
);
}
class UploadIncentiveModal extends ConsumerStatefulWidget {
const UploadIncentiveModal({super.key});
@override
ConsumerState<UploadIncentiveModal> createState() =>
UploadIncentiveModalState();
}
class UploadIncentiveModalState extends ConsumerState<UploadIncentiveModal> {
late ApiService apiService;
bool isLoading = false;
final _formKey = GlobalKey<FormState>();
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
List<Map<String, dynamic>> getAgentData = [];
List<Map<String, dynamic>> filteredData = [];
List<Map<String, dynamic>> getAgentIncentiveFileData = [];
List<Map<String, dynamic>> filteredIncentiveData = [];
Map<String, TextEditingController> controllers = {};
// html.File? passportFile;
List<PlatformFile> selectedFiles = [];
String? selectedFileNames;
List<String> tabHeader = ['name', 'agentId', 'date', 'search'];
String? _token;
dynamic userId;
dynamic managerId;
dynamic agentId;
Map<String, dynamic> dataDetails() {
final selectedDate = controllers["date"]?.text;
final data = {
"agent_id": agentId,
"incentive_month": selectedDate,
"created_by": userId,
"file_type": "incentive",
};
return data;
}
@override
void initState() {
super.initState();
apiService = ApiService();
for (String field in tabHeader) {
controllers[field] = TextEditingController();
}
Future.microtask(() {
managerId = ref.watch(managerIdProvider);
userId = ref.watch(userIdProvider);
if (managerId != null) {
getAgentList(managerId);
}
});
_initializeToken();
// getAgentList();
}
Future<void> _initializeToken() async {
_token = await AuthService.getToken();
print("APISERTOKEN - $_token");
}
@override
void dispose() {
for (var controller in controllers.values) {
controller.dispose();
}
controllers['date']?.dispose();
controllers['code']?.dispose();
super.dispose();
}
Future<void> refresh() async {
setState(() {
// reset file fields
selectedFiles = [];
// selectedFileNames = "";
selectedFileNames = null;
// getAgentData = [];
// filteredData = [];
getAgentIncentiveFileData = [];
filteredIncentiveData = [];
// clear all text controllers
for (var controller in controllers.values) {
controller.clear();
}
dropDownKey.currentState?.clear(); // 👈 clear selected agent
controllers['agentId']?.clear(); // clear text field value too
controllers['uploadFile']?.clear();
});
}
void filterData(String query) {
print("FilterDAta - $query");
setState(() {
filteredIncentiveData = getAgentIncentiveFileData.where((item) {
return (item['incentive_month'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
);
}).toList();
});
}
Future<void> getAgentList(int id) async {
print('getClaimList called');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchAgentUserList(managerId);
if (response['status'] == 'success') {
print('getAgentListData - ${response['data']}');
setState(() {
getAgentData = List<Map<String, dynamic>>.from(response['data']);
print('API Data - $getAgentData');
filteredData = List.from(getAgentData);
// print('originalData - $filteredData');
});
} else {
getAgentData = [];
filteredData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> getAgentIncenctiveFileList(agentId) async {
print('getClaimList agentId - $agentId');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchAgentIncentiveList(agentId, type: 'incentive');
if (response['status'] == 'success') {
print('AgentIncentive - ${response['data']}');
setState(() {
getAgentIncentiveFileData = List<Map<String, dynamic>>.from(
response['data'],
);
print('API AgentIncentive - $getAgentIncentiveFileData');
filteredIncentiveData = List.from(getAgentIncentiveFileData);
// print('originalData - $filteredIncentiveData');
});
} else {
getAgentIncentiveFileData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> handleSave() async {
if (agentId == null) {
ToastHelper.showErrorToast(context, 'Select Partner Name');
} else {
if (!_formKey.currentState!.validate()) return;
print("Handl1");
final dataSet = dataDetails();
print("dataSetAgent - $dataSet");
print("Handl13f");
if (selectedFiles.isEmpty) {
print("❌ No file selected!");
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Please select a file before submitting"),
),
);
return;
}
setState(() {
uploadIncentiveData(dataSet);
});
print("Handl2");
}
}
Future<void> uploadIncentiveData(Map<String, dynamic> dataSet) async {
final uri = Uri.parse('${Env.apiUrl}agent/uploadAgentIncentiveFile');
if (_token == null) {
throw Exception('Token not found. Please log in.');
}
// Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] = Env.App_Signature;
print("USerDAta - $dataSet");
// dataSet.forEach((key, value) {
// request.fields[key] = value.toString();
// print("✅ Encoded travel_details2: ${request.fields[key]}");
// });
dataSet.forEach((key, value) {
if (key != 'incentive_file_name') {
request.fields[key] = value.toString();
print("✅ Encoded $key: ${request.fields[key]}");
}
});
if (selectedFiles.isNotEmpty) {
for (final file in selectedFiles) {
try {
if (file.bytes != null) {
final multipartFile = http.MultipartFile.fromBytes(
'incentive_file_name',
file.bytes!,
filename: file.name,
);
request.files.add(multipartFile);
} else if (file.path != null) {
final multipartFile = await http.MultipartFile.fromPath(
'incentive_file_name',
file.path!,
filename: file.name,
);
request.files.add(multipartFile);
}
print("📎 File attached: ${file.name}");
} catch (e) {
print("❌ Failed to attach file ${file.name}: $e");
}
}
}
// Attach file if selected
// if (passportFile != null) {
// try {
// final reader = html.FileReader();
// reader.readAsArrayBuffer(passportFile! as html.Blob);
// await reader.onLoad.first;
//
// final data = reader.result as Uint8List;
//
// final multipartFile = http.MultipartFile.fromBytes(
// 'incentive_file_name',
// data,
// filename: passportFile!.name,
// );
//
// request.files.add(multipartFile);
// print("📎 File attached: ${passportFile!.name}");
// } catch (e) {
// print("❌ Failed to read file: $e");
// }
// } else {
// print("⚠️ No passport file selected.");
// }
print("🚀 Sending request with fields: ${request.fields}");
try {
final streamedResponse = await request.send();
final response = await http.Response.fromStream(streamedResponse);
print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");
final responseBody = json.decode(response.body);
if (response.statusCode == 200 || response.statusCode == 201) {
// dispose();
print("✅ Partner submitted successfully!");
print("📨 Response: ${response.body}");
final data = dataDetails();
final agentId = data["agent_id"];
final status = responseBody['status'];
final message = responseBody['data'] ?? '';
if (status == 'success') {
ToastHelper.showSuccessToast(context, 'File uploaded successfully!');
getAgentIncenctiveFileList(agentId);
} else {
ToastHelper.showErrorToast(
context,
message.isNotEmpty ? message : 'Something went wrong!',
);
}
// context.go(AppRoutes.agentLst);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else {
print("❌ Submission failed. Status: ${response.statusCode}");
print("📨 Body: ${response.body}");
String errorMessage = 'There was a problem in creating user. Please try again.';
try {
if (responseBody['data'] is String &&
(responseBody['data'] as String).isNotEmpty) {
final parsedData = json.decode(responseBody['data']);
if (parsedData is Map<String, dynamic> &&
parsedData['message'] != null) {
errorMessage = parsedData['message'].toString();
}
} else if (responseBody['message'] != null) {
errorMessage = responseBody['message'].toString();
}
} catch (_) {
// keep fallback message
}
ToastHelper.showErrorToast(context, errorMessage);
}
} catch (e) {
print("🔥 Error submitting user: $e");
}
}
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
final isCompact = screenWidth < 1000;
final dialogWidth = isCompact ? screenWidth * 0.95 : screenWidth * 0.55;
final dialogHeight = isCompact ? screenHeight * 0.82 : screenHeight * 0.7;
final fieldWidth = isCompact ? dialogWidth * 0.9 : screenWidth * 0.27;
return SelectionArea(
child:AlertDialog(
backgroundColor: Colors.white,
content: Container(
width: dialogWidth,
height: dialogHeight,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
"Incentive Files",
style: GoogleFonts.poppins(
fontSize: 14,
color: Color(0xFF50A398),
fontWeight: FontWeight.w500,
),
),
Spacer(),
Tooltip(
message: 'Refresh',
child: IconButton(
icon: const Icon(
Icons.refresh,
size: 18,
color: Color(0xFF2E7D6E),
// color: Color(0xFF425B5B),
),
onPressed: () {
refresh();
},
splashRadius: 28,
hoverColor: Colors.black12,
padding: const EdgeInsets.all(8),
constraints: const BoxConstraints(),
),
),
Tooltip(
message: 'Close',
child: IconButton(
icon: const Icon(
Icons.close,
size: 18,
// color: Color(0xFF425B5B),
color: Color(0xFF2E7D6E),
),
onPressed: () {
Navigator.pop(context);
},
splashRadius: 28,
hoverColor: Colors.black12,
padding: const EdgeInsets.all(8),
constraints: const BoxConstraints(),
),
),
],
),
const SizedBox(height: 5),
isCompact
? Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Partner Name', style: _labelStyle),
SizedBox(height: 5),
Container(
width: fieldWidth,
height: 40,
child: DropdownSearch<Map<String, dynamic>>(
key: dropDownKey,
selectedItem: null,
items: (filter, infiniteScrollProps) {
return filteredData; // pass the whole object
},
itemAsString: (agent) =>
agent['name'].toString(), // what to show
compareFn: (item, selectedItem) =>
item['id'] ==
selectedItem['id'], // ✅ compare by id
decoratorProps: DropDownDecoratorProps(
decoration:
AppInputDecorations.dropdownDecoration(
label: "Select Partner",
).copyWith(
hintStyle: GoogleFonts.inter(
fontSize: 12,
color: Colors.black,
),
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFE2E8F0),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFE2E8F0),
width: 1.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 6,
),
),
),
popupProps: PopupProps.menu(
fit: FlexFit.loose,
menuProps:
MenuProps(backgroundColor: Colors.white),
showSearchBox: true,
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search partner...",
hintStyle: GoogleFonts.inter(
fontSize: 12,
color: Colors.black,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFEDF6F5),
width: 1,
),
),
),
),
itemBuilder:
(
context,
item,
isDisabled,
isSelected,
) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 3,
),
child: Text(
item['name'].toString(),
style: GoogleFonts.inter(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
onChanged: (agent) {
if (agent != null) {
print("Selected Partner Name: ${agent['name']}");
print("Agent Code: ${agent['agent_code']}");
print("Agent Id: ${agent['id']}");
getAgentIncenctiveFileList(agent['id']);
controllers['agentId']?.text =
agent['agent_code'];
agentId = agent['id'];
}
},
),
),
],
),
SizedBox(height: 10),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Partner ID', style: _labelStyle),
SizedBox(height: 5),
ThemedFormField(
controller: controllers['agentId']!,
txtwidth: fieldWidth,
txtheight: 40,
borderColor: Color(0xFFE2E8F0),
highlightColor: Color(0xFF50A398),
readOnly: true,
),
],
),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Partner Name', style: _labelStyle),
SizedBox(height: 5),
Container(
width: fieldWidth,
height: 40,
child: DropdownSearch<Map<String, dynamic>>(
key: dropDownKey,
selectedItem: null,
items: (filter, infiniteScrollProps) {
return filteredData; // pass the whole object
},
// itemAsString: (agent) => agent['name'],
// items: (filter, infiniteScrollProps) {
// return getAgentData
// .map((agent) => agent['name'].toString())
// .toList();
// },
itemAsString: (agent) =>
agent['name'].toString(), // what to show
compareFn: (item, selectedItem) =>
item['id'] == selectedItem['id'], // ✅ compare by id
decoratorProps: DropDownDecoratorProps(
decoration:
AppInputDecorations.dropdownDecoration(
label: "Select Partner",
).copyWith(
hintStyle: GoogleFonts.inter(
fontSize: 12,
color: Colors.black,
),
filled: true,
fillColor: Colors
.white, // 👈 makes the dropdown input white
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFE2E8F0),
// color: Colors.white,
), // 👈 Normal border
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFE2E8F0),
// color: Colors.white,
width: 1.5,
), // 👈 Focused border
),
contentPadding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 6,
),
),
),
popupProps: PopupProps.menu(
fit: FlexFit.loose,
menuProps: MenuProps(backgroundColor: Colors.white),
showSearchBox: true,
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search partner...",
hintStyle: GoogleFonts.inter(
fontSize: 12,
color: Colors.black,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
// color: Colors.blue,
color: Color(0xFFEDF6F5),
width: 1,
),
),
),
),
// constraints: BoxConstraints(),
itemBuilder: (context, item, isDisabled, isSelected) {
return Container(
// color: isSelected ? Colors.blue.withOpacity(0.1) : null,
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 3,
),
child: Text(
item['name'].toString(),
style: GoogleFonts.inter(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
onChanged: (agent) {
if (agent != null) {
print("Selected Partner Name: ${agent['name']}");
print("Agent Code: ${agent['agent_code']}");
print("Agent Id: ${agent['id']}");
getAgentIncenctiveFileList(agent['id']);
controllers['agentId']?.text = agent['agent_code'];
agentId = agent['id'];
}
},
),
),
],
),
SizedBox(width: 10),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Partner ID', style: _labelStyle),
SizedBox(height: 5),
ThemedFormField(
controller: controllers['agentId']!,
txtwidth: fieldWidth,
txtheight: 40,
borderColor: Color(0xFFE2E8F0),
highlightColor: Color(0xFF50A398),
// backgroundColor: Color(0xFFECECEC),
readOnly: true,
// backgroundColor: Color(0xFFCBCBCB),
),
],
),
],
),
const SizedBox(height: 20),
Text("Upload Documents", style: _labelHeaderStyle),
const SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Form(
key: _formKey,
child: Row(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Month',
style: _labelStyle,
),
SizedBox(height: 5),
ThemedMonthField(
hintText: "Select Month",
txtwidth: MediaQuery.of(context).size.width * 0.27,
txtheight: 40,
validator: (value) =>
Validators.requiredField(value, "date"),
borderColor: Color(0xFFE2E8F0),
highlightColor: Color(0xFF50A398),
controller: controllers['date']!,
onDateSelected: (date) {
print("Picked Date: $date");
},
),
],
),
SizedBox(width: 15),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text('Upload Files', style: _labelStyle),
],
),
SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ThemedUploadField(
key: ValueKey(selectedFileNames),
allowMultiple: true,
// hintText: "Upload Document",
txtheight: 40,
// validator: (value) => Validators.requiredField(
// value,
// "Upload Document",
// ),
// validator: (value) {
// if (passportFile == null) {
// return "Please upload a file";
// }
// return null;
// },
// backgroundColor: Color(0xFFECECEC),
backgroundColor: Colors.white,
borderColor: Color(0xFFE2E8F0),
allowedExtensions: null,
hintText:
(selectedFileNames == null ||
selectedFileNames!.isEmpty)
? "Upload Document"
: selectedFileNames,
txtwidth: isCompact
? fieldWidth * 0.71
: MediaQuery.of(context).size.width * 0.19,
onFilesSelected: (fileNames, files) {
print("Files picked: ${fileNames.join(', ')}");
// print("Size: ${file.size}");
// print(
// "Path: ${file.path}",
// ); // works on mobile/desktop
// print("Bytes: ${file.bytes}");
setState(() {
selectedFiles = files;
selectedFileNames = fileNames.join(', ');
});
},
),
SizedBox(width: 15),
Container(
width: isCompact
? fieldWidth * 0.25
: MediaQuery.of(context).size.width * 0.068,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
// backgroundColor: Color(0xFF425B5B),
backgroundColor: Color(0xFF2E7D6E),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
6,
), // 👈 reduce radius (default ~20)
),
),
onPressed: () {
handleSave();
// Navigator.pop(context);
},
child: Text(
"Submit",
style: GoogleFonts.poppins(fontSize: 12),
),
),
),
],
),
],
),
],
),
),
],
),
const SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Files', style: _labelHeaderStyle),
ThemedSearchField(
hintText: 'Search',
backgroundColor: Colors.white,
// backgroundColor: Color(0xFFECECEC),
onChanged: filterData,
// onChanged: null,
controller: controllers['search']!,
txtwidth: MediaQuery.of(context).size.width * 0.15,
txtHeight: 30,
),
],
),
const SizedBox(height: 10),
Expanded(
child: isLoading
? const Center(child: CircularProgressIndicator())
: filteredIncentiveData.isEmpty
? const Center(child: Text("No files found"))
: LayoutBuilder(
builder: (context, constraints) {
final fileAreaWidth = constraints.maxWidth;
final crossAxisCount =
fileAreaWidth < 520 ? 1 : 2;
const spacing = 10.0;
final tileWidth = (fileAreaWidth -
spacing * (crossAxisCount - 1) -
16) /
crossAxisCount;
const targetTileHeight = 70.0;
final aspectRatio = (tileWidth / targetTileHeight)
.clamp(3.2, 12.0);
return GridView.builder(
padding: const EdgeInsets.all(8),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
crossAxisSpacing: spacing,
mainAxisSpacing: spacing,
childAspectRatio: aspectRatio,
),
itemCount: filteredIncentiveData.length,
itemBuilder: (context, index) {
final file = filteredIncentiveData[index];
return IncentiveFileRow(
fileName:
file['incentive_file_name'] ?? "Unknown",
date: file['incentive_month'] ?? "-",
onUpload: () {
print("Upload ${file['id']}");
final selectedId = file['id'];
final path =
'agent/downloadAgentIncentiveFile?id=$selectedId';
apiService.getPdfDownload(path, selectedId);
},
onDelete: () async {
print("Delete ${file['id']}");
final selectedId = file['id'];
final response = await apiService
.deleteAgentIncentiveFile(selectedId);
print("res - $response");
if (response['status'] == 'success') {
print("DELTED");
final data =
dataDetails(); // Map<String, dynamic>
final agentId = data["agent_id"];
getAgentIncenctiveFileList(agentId);
} else {
// Fluttertoast.showToast(
// msg: "Something went wrong",
// toastLength: Toast.LENGTH_SHORT,
// gravity: ToastGravity.BOTTOM,
// );
}
},
);
},
);
},
),
),
],
),
),
),);
}
}
final _labelStyle = GoogleFonts.poppins(
color: Colors.black,
fontWeight: FontWeight.w400,
fontSize: 12,
);
final _labelHeaderStyle = GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
);
class IncentiveFileRow extends StatelessWidget {
final String fileName;
final String date;
final VoidCallback? onUpload;
final VoidCallback? onDelete;
const IncentiveFileRow({
super.key,
required this.fileName,
required this.date,
this.onUpload,
this.onDelete,
});
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFFE3E3E3)),
borderRadius: BorderRadius.circular(6),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(6.0),
decoration: BoxDecoration(
color: const Color(0xFFF4F6F8),
borderRadius: BorderRadius.circular(6.0),
border: Border.all(color: const Color(0xFFE3E3E3)),
),
child: const Icon(
Icons.file_present,
color: Color(0xFF838587),
size: 18,
),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
fileName,
style: GoogleFonts.poppins(
fontWeight: FontWeight.w400,
fontSize: 12,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
const SizedBox(height: 2),
Text(
date,
style: GoogleFonts.poppins(
color: const Color(0xFF6E6E6E),
fontSize: 10,
),
),
],
),
),
const SizedBox(width: 8),
Material(
color: Colors.transparent,
child: InkWell(
onTap: onUpload,
borderRadius: BorderRadius.circular(20),
child: const Padding(
padding: EdgeInsets.all(6),
child: Icon(
Icons.file_download_outlined,
color: Color(0xFF6E6E6E),
size: 20,
),
),
),
),
Material(
color: Colors.transparent,
child: InkWell(
onTap: onDelete,
borderRadius: BorderRadius.circular(20),
child: const Padding(
padding: EdgeInsets.all(6),
child: Icon(
Icons.delete_outlined,
color: Color(0xFF6E6E6E),
size: 20,
),
),
),
),
],
),
);
}
}