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,
pageNumber: pageNumber.value,
pageSize: pageSize,
isActive: !showInactive.value, // 👈 active or inactive
isActive: !showInactive.value,
);
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/notes_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';
/// Handles incoming FCM notification actions and updates UI/controllers.
@ -197,47 +198,57 @@ class NotificationActionHandler {
}
/// ---------------------- DOCUMENT HANDLER ----------------------
static void _handleDocumentModified(Map<String, dynamic> data) {
final entityTypeId = data['EntityTypeId'];
final entityId = data['EntityId'];
/// ---------------------- DOCUMENT HANDLER ----------------------
static void _handleDocumentModified(Map<String, dynamic> data) {
late String entityTypeId;
late String entityId;
String? documentId = data['DocumentId'];
if (entityTypeId == null || entityId == null) {
_logger.w(
"⚠️ Document update received without EntityTypeId/EntityId: $data");
return;
}
// Refresh document list
_safeControllerUpdate<DocumentController>(
onFound: (controller) async {
await controller.fetchDocuments(
entityTypeId: entityTypeId,
entityId: entityId,
reset: true,
);
},
notFoundMessage: '⚠️ DocumentController not found, cannot refresh list.',
successMessage: '✅ DocumentController refreshed from notification.',
);
// Refresh document details (if open and matches)
// Refresh document details (if open and matches)
final documentId = data['DocumentId'];
if (documentId != null) {
_safeControllerUpdate<DocumentDetailsController>(
onFound: (controller) async {
if (controller.documentDetails.value?.data?.id == documentId) {
await controller.fetchDocumentDetails(documentId);
_logger.i(
"✅ DocumentDetailsController refreshed for Document $documentId");
}
},
notFoundMessage: ' DocumentDetailsController not active, skipping.',
successMessage: '✅ DocumentDetailsController checked for refresh.',
);
}
if (data['Keyword'] == 'Employee_Document_Modified') {
entityTypeId = Permissions.employeeEntity;
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;
}
if (entityId.isEmpty) {
_logger.w("⚠️ Document update missing entityId: $data");
return;
}
// 🔹 Refresh document list
_safeControllerUpdate<DocumentController>(
onFound: (controller) async {
await controller.fetchDocuments(
entityTypeId: entityTypeId,
entityId: entityId,
reset: true,
);
},
notFoundMessage: '⚠️ DocumentController not found, cannot refresh list.',
successMessage: '✅ DocumentController refreshed from notification.',
);
// 🔹 Refresh document details (if opened)
if (documentId != null) {
_safeControllerUpdate<DocumentDetailsController>(
onFound: (controller) async {
if (controller.documentDetails.value?.data?.id == documentId) {
await controller.fetchDocumentDetails(documentId);
_logger.i("✅ DocumentDetailsController refreshed for Document $documentId");
}
},
notFoundMessage: ' DocumentDetailsController not active, skipping.',
successMessage: '✅ DocumentDetailsController checked for refresh.',
);
}
}
/// ---------------------- DIRECTORY HANDLERS ----------------------
static void _handleContactModified(Map<String, dynamic> data) {

View File

@ -206,46 +206,6 @@ class _DocumentUploadBottomSheetState extends State<DocumentUploadBottomSheet> {
children: [
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
Obx(() {
if (controller.isLoading.value &&
@ -287,7 +247,47 @@ class _DocumentUploadBottomSheetState extends State<DocumentUploadBottomSheet> {
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
AttachmentSectionSingle(