handelled the update expense

This commit is contained in:
Vaibhav Surve 2025-08-06 11:46:12 +05:30
parent aa76ec60cb
commit 63e5caae24
2 changed files with 171 additions and 149 deletions

View File

@ -170,8 +170,14 @@ class AddExpenseController extends GetxController {
// --- Existing Attachments --- // --- Existing Attachments ---
existingAttachments.clear(); existingAttachments.clear();
if (data['attachments'] != null && data['attachments'] is List) { if (data['attachments'] != null && data['attachments'] is List) {
existingAttachments existingAttachments.addAll(
.addAll(List<Map<String, dynamic>>.from(data['attachments'])); List<Map<String, dynamic>>.from(data['attachments']).map((e) {
return {
...e,
'isActive': true, // default
};
}),
);
} }
_logPrefilledData(); _logPrefilledData();
@ -369,15 +375,20 @@ class AddExpenseController extends GetxController {
final projectId = projectsMap[selectedProject.value]!; final projectId = projectsMap[selectedProject.value]!;
final selectedDate = final selectedDate =
selectedTransactionDate.value?.toUtc() ?? DateTime.now().toUtc(); selectedTransactionDate.value?.toUtc() ?? DateTime.now().toUtc();
final existingAttachmentPayloads = existingAttachments final existingAttachmentPayloads = existingAttachments.map((e) {
.map((e) => { final isActive = e['isActive'] ?? true;
return {
"documentId": e['documentId'],
"fileName": e['fileName'], "fileName": e['fileName'],
"contentType": e['contentType'], "contentType": e['contentType'],
"fileSize": 0, // optional or populate if known "fileSize": 0,
"description": "", "description": "",
"url": e['url'], // custom field if your backend accepts "url": e['url'],
}) "isActive": isActive,
.toList(); "base64Data": isActive ? e['base64Data'] : null,
};
}).toList();
final newAttachmentPayloads = final newAttachmentPayloads =
await Future.wait(attachments.map((file) async { await Future.wait(attachments.map((file) async {

View File

@ -44,7 +44,6 @@ class _AddExpenseBottomSheetState extends State<_AddExpenseBottomSheet> {
await showModalBottomSheet( await showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)), borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
), ),
@ -55,8 +54,7 @@ class _AddExpenseBottomSheetState extends State<_AddExpenseBottomSheet> {
// Optional cleanup // Optional cleanup
controller.employeeSearchController.clear(); controller.employeeSearchController.clear();
controller.employeeSearchResults.clear(); controller.employeeSearchResults.clear();
} }
Future<void> _showOptionList<T>( Future<void> _showOptionList<T>(
List<T> options, List<T> options,
@ -277,8 +275,13 @@ class _AddExpenseBottomSheetState extends State<_AddExpenseBottomSheet> {
attachments: controller.attachments, attachments: controller.attachments,
existingAttachments: controller.existingAttachments, existingAttachments: controller.existingAttachments,
onRemoveNew: controller.removeAttachment, onRemoveNew: controller.removeAttachment,
onRemoveExisting: (item) => onRemoveExisting: (item) {
controller.existingAttachments.remove(item), final index = controller.existingAttachments.indexOf(item);
if (index != -1) {
controller.existingAttachments[index]['isActive'] = false;
controller.existingAttachments.refresh();
}
},
onAdd: controller.pickAttachments, onAdd: controller.pickAttachments,
), ),
MySpacing.height(16), MySpacing.height(16),
@ -458,7 +461,7 @@ class _TileContainer extends StatelessWidget {
class _AttachmentsSection extends StatelessWidget { class _AttachmentsSection extends StatelessWidget {
final RxList<File> attachments; final RxList<File> attachments;
final List<Map<String, dynamic>> existingAttachments; final RxList<Map<String, dynamic>> existingAttachments;
final ValueChanged<File> onRemoveNew; final ValueChanged<File> onRemoveNew;
final ValueChanged<Map<String, dynamic>>? onRemoveExisting; final ValueChanged<Map<String, dynamic>>? onRemoveExisting;
final VoidCallback onAdd; final VoidCallback onAdd;
@ -473,10 +476,14 @@ class _AttachmentsSection extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Obx(() => Column( return Obx(() {
final activeExistingAttachments =
existingAttachments.where((doc) => doc['isActive'] != false).toList();
return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (existingAttachments.isNotEmpty) ...[ if (activeExistingAttachments.isNotEmpty) ...[
Text( Text(
"Existing Attachments", "Existing Attachments",
style: const TextStyle(fontWeight: FontWeight.w600), style: const TextStyle(fontWeight: FontWeight.w600),
@ -485,7 +492,7 @@ class _AttachmentsSection extends StatelessWidget {
Wrap( Wrap(
spacing: 8, spacing: 8,
runSpacing: 8, runSpacing: 8,
children: existingAttachments.map((doc) { children: activeExistingAttachments.map((doc) {
final isImage = final isImage =
doc['contentType']?.toString().startsWith('image/') ?? doc['contentType']?.toString().startsWith('image/') ??
false; false;
@ -498,7 +505,7 @@ class _AttachmentsSection extends StatelessWidget {
GestureDetector( GestureDetector(
onTap: () async { onTap: () async {
if (isImage) { if (isImage) {
final imageDocs = existingAttachments final imageDocs = activeExistingAttachments
.where((d) => (d['contentType'] .where((d) => (d['contentType']
?.toString() ?.toString()
.startsWith('image/') ?? .startsWith('image/') ??
@ -516,8 +523,10 @@ class _AttachmentsSection extends StatelessWidget {
); );
} else { } else {
if (url != null && await canLaunchUrlString(url)) { if (url != null && await canLaunchUrlString(url)) {
await launchUrlString(url, await launchUrlString(
mode: LaunchMode.externalApplication); url,
mode: LaunchMode.externalApplication,
);
} else { } else {
showAppSnackbar( showAppSnackbar(
title: 'Error', title: 'Error',
@ -545,8 +554,7 @@ class _AttachmentsSection extends StatelessWidget {
), ),
const SizedBox(width: 7), const SizedBox(width: 7),
ConstrainedBox( ConstrainedBox(
constraints: constraints: const BoxConstraints(maxWidth: 120),
const BoxConstraints(maxWidth: 120),
child: Text( child: Text(
fileName, fileName,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@ -564,7 +572,9 @@ class _AttachmentsSection extends StatelessWidget {
child: IconButton( child: IconButton(
icon: const Icon(Icons.close, icon: const Icon(Icons.close,
color: Colors.red, size: 18), color: Colors.red, size: 18),
onPressed: () => onRemoveExisting!(doc), onPressed: () {
onRemoveExisting?.call(doc);
},
), ),
), ),
], ],
@ -574,7 +584,7 @@ class _AttachmentsSection extends StatelessWidget {
const SizedBox(height: 16), const SizedBox(height: 16),
], ],
// New attachments section - shows preview tiles // New attachments section
Wrap( Wrap(
spacing: 8, spacing: 8,
runSpacing: 8, runSpacing: 8,
@ -599,7 +609,8 @@ class _AttachmentsSection extends StatelessWidget {
], ],
), ),
], ],
)); );
});
} }
} }