From 4908db35adad3451193bf54de442d49c805a6e4e Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Thu, 17 Jul 2025 17:50:13 +0530 Subject: [PATCH 1/2] resolved directory data update issues --- .../directory/add_comment_controller.dart | 12 ++- .../directory/edit_bucket_bottom_sheet.dart | 19 +++-- lib/view/directory/contact_detail_screen.dart | 82 ++++++++++++------- lib/view/directory/manage_bucket_screen.dart | 3 +- 4 files changed, 71 insertions(+), 45 deletions(-) diff --git a/lib/controller/directory/add_comment_controller.dart b/lib/controller/directory/add_comment_controller.dart index beebff5..fcc3357 100644 --- a/lib/controller/directory/add_comment_controller.dart +++ b/lib/controller/directory/add_comment_controller.dart @@ -3,6 +3,7 @@ import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:marco/controller/directory/directory_controller.dart'; +import 'package:marco/controller/directory/notes_controller.dart'; class AddCommentController extends GetxController { final String contactId; @@ -39,6 +40,10 @@ class AddCommentController extends GetxController { final directoryController = Get.find(); await directoryController.fetchCommentsForContact(contactId); + final notesController = Get.find(); + await notesController.fetchNotes( + pageSize: 1000, pageNumber: 1); // ✅ Fixed here + Get.back(result: true); showAppSnackbar( @@ -46,13 +51,6 @@ class AddCommentController extends GetxController { message: "Your comment has been successfully added.", type: SnackbarType.success, ); - } else { - logSafe("Comment submission failed", level: LogLevel.error); - showAppSnackbar( - title: "Submission Failed", - message: "Unable to add the comment. Please try again later.", - type: SnackbarType.error, - ); } } catch (e) { logSafe("Error while submitting comment: $e", level: LogLevel.error); diff --git a/lib/model/directory/edit_bucket_bottom_sheet.dart b/lib/model/directory/edit_bucket_bottom_sheet.dart index 30bbc3c..f9bb4dc 100644 --- a/lib/model/directory/edit_bucket_bottom_sheet.dart +++ b/lib/model/directory/edit_bucket_bottom_sheet.dart @@ -11,7 +11,8 @@ import 'package:marco/helpers/widgets/my_snackbar.dart'; class EditBucketBottomSheet { static void show(BuildContext context, ContactBucket bucket, - List allEmployees) { + List allEmployees, + {required String ownerId}) { final ManageBucketController controller = Get.find(); final nameController = TextEditingController(text: bucket.name); @@ -192,13 +193,15 @@ class EditBucketBottomSheet { controlAffinity: ListTileControlAffinity.leading, value: selectedIds.contains(emp.id), - onChanged: (val) { - if (val == true) { - selectedIds.add(emp.id); - } else { - selectedIds.remove(emp.id); - } - }, + onChanged: emp.id == ownerId + ? null + : (val) { + if (val == true) { + selectedIds.add(emp.id); + } else { + selectedIds.remove(emp.id); + } + }, title: Text( fullName.isNotEmpty ? fullName : 'Unnamed', style: const TextStyle(fontSize: 13), diff --git a/lib/view/directory/contact_detail_screen.dart b/lib/view/directory/contact_detail_screen.dart index f6e5962..9550f70 100644 --- a/lib/view/directory/contact_detail_screen.dart +++ b/lib/view/directory/contact_detail_screen.dart @@ -77,18 +77,17 @@ String _convertDeltaToHtml(dynamic delta) { class _ContactDetailScreenState extends State { late final DirectoryController directoryController; late final ProjectController projectController; + late ContactModel contact; @override void initState() { super.initState(); directoryController = Get.find(); projectController = Get.find(); + contact = widget.contact; WidgetsBinding.instance.addPostFrameCallback((_) { - if (!directoryController.contactCommentsMap - .containsKey(widget.contact.id)) { - directoryController.fetchCommentsForContact(widget.contact.id); - } + directoryController.fetchCommentsForContact(contact.id); }); } @@ -133,7 +132,8 @@ class _ContactDetailScreenState extends State { IconButton( icon: const Icon(Icons.arrow_back_ios_new, color: Colors.black, size: 20), - onPressed: () => Get.back(), + onPressed: () => + Get.offAllNamed('/dashboard/directory-main-page'), ), MySpacing.width(8), Expanded( @@ -184,9 +184,9 @@ class _ContactDetailScreenState extends State { Row( children: [ Avatar( - firstName: widget.contact.name.split(" ").first, - lastName: widget.contact.name.split(" ").length > 1 - ? widget.contact.name.split(" ").last + firstName: contact.name.split(" ").first, + lastName: contact.name.split(" ").length > 1 + ? contact.name.split(" ").last : "", size: 35, backgroundColor: Colors.indigo, @@ -195,10 +195,10 @@ class _ContactDetailScreenState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - MyText.titleSmall(widget.contact.name, + MyText.titleSmall(contact.name, fontWeight: 600, color: Colors.black), MySpacing.height(2), - MyText.bodySmall(widget.contact.organization, + MyText.bodySmall(contact.organization, fontWeight: 500, color: Colors.grey[700]), ], ), @@ -226,24 +226,24 @@ class _ContactDetailScreenState extends State { } Widget _buildDetailsTab() { - final email = widget.contact.contactEmails.isNotEmpty - ? widget.contact.contactEmails.first.emailAddress + final email = contact.contactEmails.isNotEmpty + ? contact.contactEmails.first.emailAddress : "-"; - final phone = widget.contact.contactPhones.isNotEmpty - ? widget.contact.contactPhones.first.phoneNumber + final phone = contact.contactPhones.isNotEmpty + ? contact.contactPhones.first.phoneNumber : "-"; - final tags = widget.contact.tags.map((e) => e.name).join(", "); + final tags = contact.tags.map((e) => e.name).join(", "); - final bucketNames = widget.contact.bucketIds + final bucketNames = contact.bucketIds .map((id) => directoryController.contactBuckets .firstWhereOrNull((b) => b.id == id) ?.name) .whereType() .join(", "); - final projectNames = widget.contact.projectIds + final projectNames = contact.projectIds ?.map((id) => projectController.projects .firstWhereOrNull((p) => p.id == id) ?.name) @@ -251,7 +251,7 @@ class _ContactDetailScreenState extends State { .join(", ") ?? "-"; - final category = widget.contact.contactCategory?.name ?? "-"; + final category = contact.contactCategory?.name ?? "-"; return Stack( children: [ @@ -270,12 +270,11 @@ class _ContactDetailScreenState extends State { onTap: () => LauncherUtils.launchPhone(phone), onLongPress: () => LauncherUtils.copyToClipboard(phone, typeLabel: "Phone")), - _iconInfoRow( - Icons.location_on, "Address", widget.contact.address), + _iconInfoRow(Icons.location_on, "Address", contact.address), ]), _infoCard("Organization", [ - _iconInfoRow(Icons.business, "Organization", - widget.contact.organization), + _iconInfoRow( + Icons.business, "Organization", contact.organization), _iconInfoRow(Icons.category, "Category", category), ]), _infoCard("Meta Info", [ @@ -289,7 +288,7 @@ class _ContactDetailScreenState extends State { Align( alignment: Alignment.topLeft, child: MyText.bodyMedium( - widget.contact.description, + contact.description, color: Colors.grey[800], maxLines: 10, textAlign: TextAlign.left, @@ -304,12 +303,25 @@ class _ContactDetailScreenState extends State { right: 20, child: FloatingActionButton.extended( backgroundColor: Colors.red, - onPressed: () { - Get.bottomSheet( - AddContactBottomSheet(existingContact: widget.contact), + onPressed: () async { + final result = await Get.bottomSheet( + AddContactBottomSheet(existingContact: contact), isScrollControlled: true, backgroundColor: Colors.transparent, ); + + if (result == true) { + await directoryController.fetchContacts(); + final updated = + directoryController.allContacts.firstWhereOrNull( + (c) => c.id == contact.id, + ); + if (updated != null) { + setState(() { + contact = updated; + }); + } + } }, icon: const Icon(Icons.edit, color: Colors.white), label: const Text( @@ -324,7 +336,7 @@ class _ContactDetailScreenState extends State { Widget _buildCommentsTab(BuildContext context) { return Obx(() { - final contactId = widget.contact.id; + final contactId = contact.id; if (!directoryController.contactCommentsMap.containsKey(contactId)) { return const Center(child: CircularProgressIndicator()); @@ -447,8 +459,15 @@ class _ContactDetailScreenState extends State { final htmlOutput = _convertDeltaToHtml(delta); final updated = comment.copyWith(note: htmlOutput); + await directoryController .updateComment(updated); + + // ✅ Re-fetch comments to get updated list + await directoryController + .fetchCommentsForContact(contactId); + + // ✅ Exit editing mode directoryController.editingCommentId.value = null; }, @@ -479,11 +498,16 @@ class _ContactDetailScreenState extends State { right: 20, child: FloatingActionButton.extended( backgroundColor: Colors.red, - onPressed: () { - Get.bottomSheet( + onPressed: () async { + final result = await Get.bottomSheet( AddCommentBottomSheet(contactId: contactId), isScrollControlled: true, ); + + if (result == true) { + await directoryController + .fetchCommentsForContact(contactId); + } }, icon: const Icon(Icons.add_comment, color: Colors.white), label: const Text( diff --git a/lib/view/directory/manage_bucket_screen.dart b/lib/view/directory/manage_bucket_screen.dart index 3c63ec4..d43bde7 100644 --- a/lib/view/directory/manage_bucket_screen.dart +++ b/lib/view/directory/manage_bucket_screen.dart @@ -194,7 +194,8 @@ class _ManageBucketsScreenState extends State { Future.delayed(const Duration(milliseconds: 300), () { EditBucketBottomSheet.show(context, bucket, - manageBucketController.allEmployees); + manageBucketController.allEmployees, + ownerId: bucket.createdBy.id); }); }, ); From 02daa1e68917cfb1122177ec25cbd1be595f9e78 Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Fri, 18 Jul 2025 10:15:25 +0530 Subject: [PATCH 2/2] fix(api_service): enhance logout handling on token issues --- lib/helpers/services/api_service.dart | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/helpers/services/api_service.dart b/lib/helpers/services/api_service.dart index 260e2b0..230fde7 100644 --- a/lib/helpers/services/api_service.dart +++ b/lib/helpers/services/api_service.dart @@ -20,7 +20,8 @@ class ApiService { final token = await LocalStorage.getJwtToken(); if (token == null) { - logSafe("No JWT token found."); + logSafe("No JWT token found. Logging out..."); + await LocalStorage.logout(); return null; } @@ -31,7 +32,7 @@ class ApiService { if (refreshed) { return await LocalStorage.getJwtToken(); } else { - logSafe("Token refresh failed. Logging out..."); + logSafe("Token refresh failed. Logging out immediately..."); await LocalStorage.logout(); return null; } @@ -47,10 +48,16 @@ class ApiService { final refreshed = await AuthService.refreshToken(); if (refreshed) { return await LocalStorage.getJwtToken(); + } else { + logSafe("Token refresh failed (near expiry). Logging out..."); + await LocalStorage.logout(); + return null; } } } catch (e) { logSafe("Token decoding error: $e", level: LogLevel.error); + await LocalStorage.logout(); + return null; } return token; @@ -107,8 +114,9 @@ class ApiService { }) async { String? token = await _getToken(); if (token == null) { - logSafe("Token is null. Cannot proceed with GET request.", + logSafe("Token is null. Forcing logout from GET request.", level: LogLevel.error); + await LocalStorage.logout(); return null; } @@ -141,8 +149,9 @@ class ApiService { ); } - logSafe("Token refresh failed. Aborting request.", + logSafe("Token refresh failed. Logging out user.", level: LogLevel.error); + await LocalStorage.logout(); } return response; @@ -246,7 +255,7 @@ class ApiService { } /// Directory calling the API - + static Future deleteBucket(String id) async { final endpoint = "${ApiEndpoints.updateBucket}/$id";