feat: Refactor document upload UI; reposition and revalidate Document ID and Name fields

This commit is contained in:
Vaibhav Surve 2025-09-17 17:17:57 +05:30
parent ef1403bec9
commit 7d5d2b5bf4
3 changed files with 91 additions and 80 deletions

View File

@ -133,7 +133,7 @@ class DocumentController extends GetxController {
searchString: searchString ?? searchQuery.value, searchString: searchString ?? searchQuery.value,
pageNumber: pageNumber.value, pageNumber: pageNumber.value,
pageSize: pageSize, pageSize: pageSize,
isActive: !showInactive.value, // 👈 active or inactive isActive: !showInactive.value,
); );
if (response != null && response.success) { if (response != null && response.success) {

View File

@ -9,6 +9,7 @@ import 'package:marco/controller/expense/expense_detail_controller.dart';
import 'package:marco/controller/directory/directory_controller.dart'; import 'package:marco/controller/directory/directory_controller.dart';
import 'package:marco/controller/directory/notes_controller.dart'; import 'package:marco/controller/directory/notes_controller.dart';
import 'package:marco/controller/document/user_document_controller.dart'; import 'package:marco/controller/document/user_document_controller.dart';
import 'package:marco/helpers/utils/permission_constants.dart';
import 'package:marco/controller/document/document_details_controller.dart'; import 'package:marco/controller/document/document_details_controller.dart';
/// Handles incoming FCM notification actions and updates UI/controllers. /// Handles incoming FCM notification actions and updates UI/controllers.
@ -197,17 +198,29 @@ class NotificationActionHandler {
} }
/// ---------------------- DOCUMENT HANDLER ---------------------- /// ---------------------- DOCUMENT HANDLER ----------------------
/// ---------------------- DOCUMENT HANDLER ----------------------
static void _handleDocumentModified(Map<String, dynamic> data) { static void _handleDocumentModified(Map<String, dynamic> data) {
final entityTypeId = data['EntityTypeId']; late String entityTypeId;
final entityId = data['EntityId']; late String entityId;
String? documentId = data['DocumentId'];
if (entityTypeId == null || entityId == null) { if (data['Keyword'] == 'Employee_Document_Modified') {
_logger.w( entityTypeId = Permissions.employeeEntity;
"⚠️ Document update received without EntityTypeId/EntityId: $data"); entityId = data['EmployeeId'] ?? '';
} else if (data['Keyword'] == 'Project_Document_Modified') {
entityTypeId = Permissions.projectEntity;
entityId = data['ProjectId'] ?? '';
} else {
_logger.w("⚠️ Document update received with unknown keyword: $data");
return; return;
} }
// Refresh document list if (entityId.isEmpty) {
_logger.w("⚠️ Document update missing entityId: $data");
return;
}
// 🔹 Refresh document list
_safeControllerUpdate<DocumentController>( _safeControllerUpdate<DocumentController>(
onFound: (controller) async { onFound: (controller) async {
await controller.fetchDocuments( await controller.fetchDocuments(
@ -220,16 +233,13 @@ class NotificationActionHandler {
successMessage: '✅ DocumentController refreshed from notification.', successMessage: '✅ DocumentController refreshed from notification.',
); );
// Refresh document details (if open and matches) // 🔹 Refresh document details (if opened)
// Refresh document details (if open and matches)
final documentId = data['DocumentId'];
if (documentId != null) { if (documentId != null) {
_safeControllerUpdate<DocumentDetailsController>( _safeControllerUpdate<DocumentDetailsController>(
onFound: (controller) async { onFound: (controller) async {
if (controller.documentDetails.value?.data?.id == documentId) { if (controller.documentDetails.value?.data?.id == documentId) {
await controller.fetchDocumentDetails(documentId); await controller.fetchDocumentDetails(documentId);
_logger.i( _logger.i("✅ DocumentDetailsController refreshed for Document $documentId");
"✅ DocumentDetailsController refreshed for Document $documentId");
} }
}, },
notFoundMessage: ' DocumentDetailsController not active, skipping.', notFoundMessage: ' DocumentDetailsController not active, skipping.',
@ -238,6 +248,7 @@ class NotificationActionHandler {
} }
} }
/// ---------------------- DIRECTORY HANDLERS ---------------------- /// ---------------------- DIRECTORY HANDLERS ----------------------
static void _handleContactModified(Map<String, dynamic> data) { static void _handleContactModified(Map<String, dynamic> data) {

View File

@ -206,46 +206,6 @@ class _DocumentUploadBottomSheetState extends State<DocumentUploadBottomSheet> {
children: [ children: [
MySpacing.height(16), MySpacing.height(16),
/// Document ID
LabeledInput(
label: "Document ID",
hint: "Enter Document ID",
controller: _docIdController,
validator: (value) {
if (value == null || value.trim().isEmpty) {
return "Required";
}
// Regex validation if enabled
final selectedType = controller.selectedType;
if (selectedType != null &&
selectedType.isValidationRequired &&
selectedType.regexExpression != null &&
selectedType.regexExpression!.isNotEmpty) {
final regExp = RegExp(selectedType.regexExpression!);
if (!regExp.hasMatch(value.trim())) {
return "Invalid ${selectedType.name} format";
}
}
return null;
},
isRequired: true,
),
MySpacing.height(16),
/// Document Name
LabeledInput(
label: "Document Name",
hint: "e.g., PAN Card",
controller: _docNameController,
validator: (value) =>
value == null || value.trim().isEmpty ? "Required" : null,
isRequired: true,
),
MySpacing.height(16),
/// Document Category /// Document Category
Obx(() { Obx(() {
if (controller.isLoading.value && if (controller.isLoading.value &&
@ -287,7 +247,47 @@ class _DocumentUploadBottomSheetState extends State<DocumentUploadBottomSheet> {
isRequired: true, isRequired: true,
); );
}), }),
MySpacing.height(24), MySpacing.height(12),
/// Document ID
LabeledInput(
label: "Document ID",
hint: "Enter Document ID",
controller: _docIdController,
validator: (value) {
if (value == null || value.trim().isEmpty) {
return "Required";
}
// Regex validation if enabled
final selectedType = controller.selectedType;
if (selectedType != null &&
selectedType.isValidationRequired &&
selectedType.regexExpression != null &&
selectedType.regexExpression!.isNotEmpty) {
final regExp = RegExp(selectedType.regexExpression!);
if (!regExp.hasMatch(value.trim())) {
return "Invalid ${selectedType.name} format";
}
}
return null;
},
isRequired: true,
),
MySpacing.height(16),
/// Document Name
LabeledInput(
label: "Document Name",
hint: "e.g., PAN Card",
controller: _docNameController,
validator: (value) =>
value == null || value.trim().isEmpty ? "Required" : null,
isRequired: true,
),
MySpacing.height(16),
/// Single Attachment Section /// Single Attachment Section
AttachmentSectionSingle( AttachmentSectionSingle(