feat(comment): improve comment submission feedback and validation messages

This commit is contained in:
Vaibhav Surve 2025-07-08 13:17:21 +05:30
parent 77e27ff98e
commit a8c890a60d
2 changed files with 62 additions and 69 deletions

View File

@ -15,14 +15,15 @@ class AddCommentController extends GetxController {
Future<void> submitComment() async { Future<void> submitComment() async {
if (note.value.trim().isEmpty) { if (note.value.trim().isEmpty) {
showAppSnackbar( showAppSnackbar(
title: "Validation", title: "Missing Comment",
message: "Comment cannot be empty.", message: "Please enter a comment before submitting.",
type: SnackbarType.warning, type: SnackbarType.warning,
); );
return; return;
} }
isSubmitting.value = true; isSubmitting.value = true;
try { try {
logSafe("Submitting comment for contactId: $contactId"); logSafe("Submitting comment for contactId: $contactId");
@ -34,32 +35,30 @@ class AddCommentController extends GetxController {
if (success) { if (success) {
logSafe("Comment added successfully."); logSafe("Comment added successfully.");
// Get the directory controller // Refresh UI
final directoryController = Get.find<DirectoryController>(); final directoryController = Get.find<DirectoryController>();
// Fetch latest comments for the contact to refresh UI
await directoryController.fetchCommentsForContact(contactId); await directoryController.fetchCommentsForContact(contactId);
Get.back(result: true); Get.back(result: true);
showAppSnackbar( showAppSnackbar(
title: "Success", title: "Comment Added",
message: "Comment added successfully.", message: "Your comment has been successfully added.",
type: SnackbarType.success, type: SnackbarType.success,
); );
} else { } else {
logSafe("Comment submission failed", level: LogLevel.error); logSafe("Comment submission failed", level: LogLevel.error);
showAppSnackbar( showAppSnackbar(
title: "Error", title: "Submission Failed",
message: "Failed to add comment.", message: "Unable to add the comment. Please try again later.",
type: SnackbarType.error, type: SnackbarType.error,
); );
} }
} catch (e) { } catch (e) {
logSafe("Error while submitting comment: $e", level: LogLevel.error); logSafe("Error while submitting comment: $e", level: LogLevel.error);
showAppSnackbar( showAppSnackbar(
title: "Error", title: "Unexpected Error",
message: "Something went wrong.", message: "Something went wrong while adding your comment.",
type: SnackbarType.error, type: SnackbarType.error,
); );
} finally { } finally {

View File

@ -23,7 +23,6 @@ class _AddCommentBottomSheetState extends State<AddCommentBottomSheet> {
void initState() { void initState() {
super.initState(); super.initState();
controller = Get.put(AddCommentController(contactId: widget.contactId)); controller = Get.put(AddCommentController(contactId: widget.contactId));
// Initialize empty editor for new comment
quillController = quill.QuillController.basic(); quillController = quill.QuillController.basic();
} }
@ -43,7 +42,11 @@ class _AddCommentBottomSheetState extends State<AddCommentBottomSheet> {
color: Theme.of(context).cardColor, color: Theme.of(context).cardColor,
borderRadius: const BorderRadius.vertical(top: Radius.circular(24)), borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
boxShadow: const [ boxShadow: const [
BoxShadow(color: Colors.black12, blurRadius: 12, offset: Offset(0, -2)), BoxShadow(
color: Colors.black12,
blurRadius: 12,
offset: Offset(0, -2),
),
], ],
), ),
child: Padding( child: Padding(
@ -67,12 +70,11 @@ class _AddCommentBottomSheetState extends State<AddCommentBottomSheet> {
CommentEditorCard( CommentEditorCard(
controller: quillController, controller: quillController,
onCancel: () => Get.back(), onCancel: () => Get.back(),
onSave: (controller) async { onSave: (editorController) async {
final delta = controller.document.toDelta(); final delta = editorController.document.toDelta();
final htmlOutput = _convertDeltaToHtml(delta); final htmlOutput = _convertDeltaToHtml(delta);
this.controller.updateNote(htmlOutput); controller.updateNote(htmlOutput);
await this.controller.submitComment(); await controller.submitComment();
if (mounted) Get.back();
}, },
), ),
], ],
@ -81,62 +83,54 @@ class _AddCommentBottomSheetState extends State<AddCommentBottomSheet> {
), ),
); );
} }
}
String _convertDeltaToHtml(dynamic delta) { String _convertDeltaToHtml(dynamic delta) {
final buffer = StringBuffer(); final buffer = StringBuffer();
bool inList = false; bool inList = false;
for (var op in delta.toList()) { for (var op in delta.toList()) {
final data = op.data?.toString() ?? ''; final data = op.data?.toString() ?? '';
final attr = op.attributes ?? {}; final attr = op.attributes ?? {};
final isListItem = attr.containsKey('list'); final isListItem = attr.containsKey('list');
final trimmedData = data.trim();
// Start <ul> if list item starts if (isListItem && !inList) {
if (isListItem && !inList) { buffer.write('<ul>');
buffer.write('<ul>'); inList = true;
inList = true; }
if (!isListItem && inList) {
buffer.write('</ul>');
inList = false;
}
if (isListItem && trimmedData.isEmpty) continue;
if (isListItem) buffer.write('<li>');
if (attr.containsKey('bold')) buffer.write('<strong>');
if (attr.containsKey('italic')) buffer.write('<em>');
if (attr.containsKey('underline')) buffer.write('<u>');
if (attr.containsKey('strike')) buffer.write('<s>');
if (attr.containsKey('link')) buffer.write('<a href="${attr['link']}">');
buffer.write(trimmedData.replaceAll('\n', ''));
if (attr.containsKey('link')) buffer.write('</a>');
if (attr.containsKey('strike')) buffer.write('</s>');
if (attr.containsKey('underline')) buffer.write('</u>');
if (attr.containsKey('italic')) buffer.write('</em>');
if (attr.containsKey('bold')) buffer.write('</strong>');
if (isListItem) {
buffer.write('</li>');
} else if (data.contains('\n')) {
buffer.write('<br>');
}
} }
// Close <ul> if list ended if (inList) buffer.write('</ul>');
if (!isListItem && inList) { return buffer.toString();
buffer.write('</ul>');
inList = false;
}
// Skip empty list items
final trimmedData = data.trim();
if (isListItem && trimmedData.isEmpty) {
// don't write empty <li>
continue;
}
if (isListItem) buffer.write('<li>');
if (attr.containsKey('bold')) buffer.write('<strong>');
if (attr.containsKey('italic')) buffer.write('<em>');
if (attr.containsKey('underline')) buffer.write('<u>');
if (attr.containsKey('strike')) buffer.write('<s>');
if (attr.containsKey('link')) buffer.write('<a href="${attr['link']}">');
// Use trimmedData instead of raw data (removes trailing/leading spaces/newlines)
buffer.write(trimmedData.replaceAll('\n', ''));
if (attr.containsKey('link')) buffer.write('</a>');
if (attr.containsKey('strike')) buffer.write('</s>');
if (attr.containsKey('underline')) buffer.write('</u>');
if (attr.containsKey('italic')) buffer.write('</em>');
if (attr.containsKey('bold')) buffer.write('</strong>');
if (isListItem) {
buffer.write('</li>');
} else if (data.contains('\n')) {
buffer.write('<br>');
}
} }
if (inList) buffer.write('</ul>');
return buffer.toString();
} }