From 47666c789775896897debcce20a6f8418a485144 Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Thu, 18 Sep 2025 16:18:01 +0530 Subject: [PATCH] feat: Enhance contact detail screen; implement reactive contact updates and improve note handling --- .../services/notification_action_handler.dart | 29 ++++++----- lib/view/directory/contact_detail_screen.dart | 48 ++++++++++--------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/lib/helpers/services/notification_action_handler.dart b/lib/helpers/services/notification_action_handler.dart index 776786e..a84f4ee 100644 --- a/lib/helpers/services/notification_action_handler.dart +++ b/lib/helpers/services/notification_action_handler.dart @@ -270,36 +270,41 @@ class NotificationActionHandler { } } + /// ---------------------- DIRECTORY HANDLERS ---------------------- /// ---------------------- DIRECTORY HANDLERS ---------------------- static void _handleContactModified(Map data) { - _safeControllerUpdate( - onFound: (controller) => controller.fetchContacts(), - notFoundMessage: '⚠️ DirectoryController not found, cannot refresh.', - successMessage: '✅ Directory contacts refreshed from notification.', - ); - } - - static void _handleContactNoteModified(Map data) { - final contactId = data['contactId']; + final contactId = data['ContactId']; + // Always refresh the contact list _safeControllerUpdate( onFound: (controller) { + controller.fetchContacts(); + // If a specific contact is provided, refresh its notes as well if (contactId != null) { controller.fetchCommentsForContact(contactId); } }, notFoundMessage: - '⚠️ DirectoryController not found, cannot refresh notes.', - successMessage: '✅ Directory comments refreshed from notification.', + '⚠️ DirectoryController not found, cannot refresh contacts.', + successMessage: + '✅ Directory contacts (and notes if applicable) refreshed from notification.', ); + // Refresh notes globally as well _safeControllerUpdate( onFound: (controller) => controller.fetchNotes(), - notFoundMessage: '⚠️ NotesController not found, cannot refresh.', + notFoundMessage: '⚠️ NotesController not found, cannot refresh notes.', successMessage: '✅ Notes refreshed from notification.', ); } + static void _handleContactNoteModified(Map data) { + final contactId = data['ContactId']; + + // Refresh both contacts and notes when a note is modified + _handleContactModified(data); + } + static void _handleBucketModified(Map data) { _safeControllerUpdate( onFound: (controller) => controller.fetchBuckets(), diff --git a/lib/view/directory/contact_detail_screen.dart b/lib/view/directory/contact_detail_screen.dart index bba51d7..b00856b 100644 --- a/lib/view/directory/contact_detail_screen.dart +++ b/lib/view/directory/contact_detail_screen.dart @@ -63,6 +63,7 @@ String _convertDeltaToHtml(dynamic delta) { class ContactDetailScreen extends StatefulWidget { final ContactModel contact; const ContactDetailScreen({super.key, required this.contact}); + @override State createState() => _ContactDetailScreenState(); } @@ -70,16 +71,25 @@ class ContactDetailScreen extends StatefulWidget { class _ContactDetailScreenState extends State { late final DirectoryController directoryController; late final ProjectController projectController; - late ContactModel contact; + + late Rx contactRx; @override void initState() { super.initState(); directoryController = Get.find(); projectController = Get.find(); - contact = widget.contact; + contactRx = widget.contact.obs; + WidgetsBinding.instance.addPostFrameCallback((_) { - directoryController.fetchCommentsForContact(contact.id); + directoryController.fetchCommentsForContact(contactRx.value.id); + }); + + // Listen to controller's allContacts and update contact if changed + ever(directoryController.allContacts, (_) { + final updated = directoryController.allContacts + .firstWhereOrNull((c) => c.id == contactRx.value.id); + if (updated != null) contactRx.value = updated; }); } @@ -94,12 +104,12 @@ class _ContactDetailScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildSubHeader(), + Obx(() => _buildSubHeader(contactRx.value)), const Divider(height: 1, thickness: 0.5, color: Colors.grey), Expanded( child: TabBarView(children: [ - _buildDetailsTab(), - _buildCommentsTab(context), + Obx(() => _buildDetailsTab(contactRx.value)), + _buildCommentsTab(), ]), ), ], @@ -135,9 +145,9 @@ class _ContactDetailScreenState extends State { MyText.titleLarge('Contact Profile', fontWeight: 700, color: Colors.black), MySpacing.height(2), - GetBuilder( - builder: (p) => ProjectLabel(p.selectedProject?.name), - ), + GetBuilder(builder: (p) { + return ProjectLabel(p.selectedProject?.name); + }), ], ), ), @@ -147,7 +157,7 @@ class _ContactDetailScreenState extends State { ); } - Widget _buildSubHeader() { + Widget _buildSubHeader(ContactModel contact) { final firstName = contact.name.split(" ").first; final lastName = contact.name.split(" ").length > 1 ? contact.name.split(" ").last : ""; @@ -196,7 +206,7 @@ class _ContactDetailScreenState extends State { ); } - Widget _buildDetailsTab() { + Widget _buildDetailsTab(ContactModel contact) { final tags = contact.tags.map((e) => e.name).join(", "); final bucketNames = contact.bucketIds .map((id) => directoryController.contactBuckets @@ -249,7 +259,6 @@ class _ContactDetailScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ MySpacing.height(12), - // BASIC INFO CARD _infoCard("Basic Info", [ multiRows( items: @@ -273,20 +282,17 @@ class _ContactDetailScreenState extends State { ), _iconInfoRow(Icons.location_on, "Address", contact.address), ]), - // ORGANIZATION CARD _infoCard("Organization", [ _iconInfoRow( Icons.business, "Organization", contact.organization), _iconInfoRow(Icons.category, "Category", category), ]), - // META INFO CARD _infoCard("Meta Info", [ _iconInfoRow(Icons.label, "Tags", tags.isNotEmpty ? tags : "-"), _iconInfoRow(Icons.folder_shared, "Contact Buckets", bucketNames.isNotEmpty ? bucketNames : "-"), _iconInfoRow(Icons.work_outline, "Projects", projectNames), ]), - // DESCRIPTION CARD _infoCard("Description", [ MySpacing.height(6), Align( @@ -318,7 +324,7 @@ class _ContactDetailScreenState extends State { final updated = directoryController.allContacts .firstWhereOrNull((c) => c.id == contact.id); if (updated != null) { - setState(() => contact = updated); + contactRx.value = updated; } } }, @@ -331,9 +337,9 @@ class _ContactDetailScreenState extends State { ); } - Widget _buildCommentsTab(BuildContext context) { + Widget _buildCommentsTab() { return Obx(() { - final contactId = contact.id; + final contactId = contactRx.value.id; if (!directoryController.contactCommentsMap.containsKey(contactId)) { return const Center(child: CircularProgressIndicator()); } @@ -355,7 +361,7 @@ class _ContactDetailScreenState extends State { physics: const AlwaysScrollableScrollPhysics(), children: [ SizedBox( - height: MediaQuery.of(context).size.height * 0.6, + height: Get.height * 0.6, child: Center( child: MyText.bodyLarge( "No comments yet.", @@ -375,7 +381,7 @@ class _ContactDetailScreenState extends State { itemBuilder: (_, index) => _buildCommentItem( comments[index], editingId, - contact.id, + contactId, ), ), ), @@ -438,7 +444,6 @@ class _ContactDetailScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Header Row Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -474,7 +479,6 @@ class _ContactDetailScreenState extends State { ), ], ), - // Comment Content if (isEditing && quillController != null) CommentEditorCard( controller: quillController,