resolved directory data update issues #55
@ -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<DirectoryController>();
|
||||
await directoryController.fetchCommentsForContact(contactId);
|
||||
|
||||
final notesController = Get.find<NotesController>();
|
||||
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);
|
||||
|
@ -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<bool> deleteBucket(String id) async {
|
||||
final endpoint = "${ApiEndpoints.updateBucket}/$id";
|
||||
|
||||
|
@ -11,7 +11,8 @@ import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
|
||||
class EditBucketBottomSheet {
|
||||
static void show(BuildContext context, ContactBucket bucket,
|
||||
List<EmployeeModel> allEmployees) {
|
||||
List<EmployeeModel> 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),
|
||||
|
@ -77,18 +77,17 @@ String _convertDeltaToHtml(dynamic delta) {
|
||||
class _ContactDetailScreenState extends State<ContactDetailScreen> {
|
||||
late final DirectoryController directoryController;
|
||||
late final ProjectController projectController;
|
||||
late ContactModel contact;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
directoryController = Get.find<DirectoryController>();
|
||||
projectController = Get.find<ProjectController>();
|
||||
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<ContactDetailScreen> {
|
||||
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<ContactDetailScreen> {
|
||||
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<ContactDetailScreen> {
|
||||
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<ContactDetailScreen> {
|
||||
}
|
||||
|
||||
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<String>()
|
||||
.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<ContactDetailScreen> {
|
||||
.join(", ") ??
|
||||
"-";
|
||||
|
||||
final category = widget.contact.contactCategory?.name ?? "-";
|
||||
final category = contact.contactCategory?.name ?? "-";
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
@ -270,12 +270,11 @@ class _ContactDetailScreenState extends State<ContactDetailScreen> {
|
||||
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<ContactDetailScreen> {
|
||||
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<ContactDetailScreen> {
|
||||
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<ContactDetailScreen> {
|
||||
|
||||
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<ContactDetailScreen> {
|
||||
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<ContactDetailScreen> {
|
||||
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(
|
||||
|
@ -194,7 +194,8 @@ class _ManageBucketsScreenState extends State<ManageBucketsScreen> {
|
||||
Future.delayed(const Duration(milliseconds: 300),
|
||||
() {
|
||||
EditBucketBottomSheet.show(context, bucket,
|
||||
manageBucketController.allEmployees);
|
||||
manageBucketController.allEmployees,
|
||||
ownerId: bucket.createdBy.id);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user