resolved the email and has application acccess is not populated on edit

This commit is contained in:
Vaibhav Surve 2025-10-01 16:59:15 +05:30
parent 843f394ebe
commit a1bd9a3108
4 changed files with 187 additions and 159 deletions

View File

@ -72,42 +72,41 @@ class _AddContactBottomSheetState extends State<AddContactBottomSheet> {
controller.enteredTags.assignAll(c.tags.map((e) => e.name)); controller.enteredTags.assignAll(c.tags.map((e) => e.name));
ever(controller.isInitialized, (bool ready) { ever(controller.isInitialized, (bool ready) {
if (ready) { if (ready) {
final projectIds = c.projectIds; // Buckets - map all
final bucketId = c.bucketIds.firstOrNull; if (c.bucketIds.isNotEmpty) {
final category = c.contactCategory?.name; final names = c.bucketIds.map((id) {
return controller.bucketsMap.entries
if (category != null) controller.selectedCategory.value = category; .firstWhereOrNull((e) => e.value == id)
if (projectIds != null) {
controller.selectedProjects.assignAll(
projectIds
.map((id) => controller.projectsMap.entries
.firstWhereOrNull((e) => e.value == id)
?.key)
.whereType<String>()
.toList(),
);
}
if (bucketId != null) {
final name = controller.bucketsMap.entries
.firstWhereOrNull((e) => e.value == bucketId)
?.key; ?.key;
if (name != null && !controller.selectedBuckets.contains(name)) { }).whereType<String>().toList();
controller.selectedBuckets.add(name); controller.selectedBuckets.assignAll(names);
}
}
} }
}); // Projects and Category mapping - as before
} else { final projectIds = c.projectIds;
emailCtrls.add(TextEditingController()); if (projectIds != null) {
emailLabels.add('Office'.obs); controller.selectedProjects.assignAll(
phoneCtrls.add(TextEditingController()); projectIds
phoneLabels.add('Work'.obs); .map((id) => controller.projectsMap.entries
} .firstWhereOrNull((e) => e.value == id)
?.key)
.whereType<String>()
.toList(),
);
}
final category = c.contactCategory?.name;
if (category != null) controller.selectedCategory.value = category;
}
});
} else {
showAdvanced.value = false; // Optional
emailCtrls.add(TextEditingController());
emailLabels.add('Office'.obs);
phoneCtrls.add(TextEditingController());
phoneLabels.add('Work'.obs);
} }
}
@override @override
void dispose() { void dispose() {
@ -375,112 +374,110 @@ class _AddContactBottomSheetState extends State<AddContactBottomSheet> {
); );
} }
Widget _multiSelectField({ Widget _multiSelectField({
required List<FilterItem> items, required List<FilterItem> items,
required String fallback, required String fallback,
required RxList<String> selectedValues, required RxList<String> selectedValues,
}) { }) {
if (items.isEmpty) return const SizedBox.shrink(); if (items.isEmpty) return const SizedBox.shrink();
return Column( return Obx(() {
crossAxisAlignment: CrossAxisAlignment.start, final selectedNames = items
children: [ .where((f) => selectedValues.contains(f.id))
Obx(() { .map((f) => f.name)
final selectedNames = items .join(", ");
.where((f) => selectedValues.contains(f.id)) final displayText = selectedNames.isNotEmpty ? selectedNames : fallback;
.map((f) => f.name)
.join(", ");
final displayText =
selectedNames.isNotEmpty ? selectedNames : fallback;
return Builder( return Builder(
builder: (context) { builder: (context) {
return GestureDetector( return GestureDetector(
onTap: () async { onTap: () async {
final RenderBox button = final RenderBox button =
context.findRenderObject() as RenderBox; context.findRenderObject() as RenderBox;
final RenderBox overlay = Overlay.of(context) final RenderBox overlay =
.context Overlay.of(context).context.findRenderObject() as RenderBox;
.findRenderObject() as RenderBox; final position = button.localToGlobal(Offset.zero);
final position = button.localToGlobal(Offset.zero); await showMenu(
context: context,
await showMenu( position: RelativeRect.fromLTRB(
context: context, position.dx,
position: RelativeRect.fromLTRB( position.dy + button.size.height,
position.dx, overlay.size.width - position.dx - button.size.width,
position.dy + button.size.height, 0,
overlay.size.width - position.dx - button.size.width, ),
0, items: [
), PopupMenuItem(
items: items.map((f) { enabled: false,
return PopupMenuItem<String>( child: StatefulBuilder(
enabled: false, builder: (context, setState) {
child: StatefulBuilder( return SizedBox(
builder: (context, setState) { width: 250,
final isChecked = selectedValues.contains(f.id); child: SingleChildScrollView(
return CheckboxListTile( child: Column(
dense: true, mainAxisSize: MainAxisSize.min,
value: isChecked, children: items.map((f) {
contentPadding: EdgeInsets.zero, final isChecked = selectedValues.contains(f.id);
controlAffinity: ListTileControlAffinity.leading, return CheckboxListTile(
title: MyText(f.name), dense: true,
checkColor: Colors.white, title: Text(f.name),
side: const BorderSide( value: isChecked,
color: Colors.black, width: 1.5), contentPadding: EdgeInsets.zero,
fillColor: controlAffinity: ListTileControlAffinity.leading,
MaterialStateProperty.resolveWith<Color>( side: const BorderSide(color: Colors.black, width: 1.5),
(states) { fillColor: MaterialStateProperty.resolveWith<Color>((states) {
if (states.contains(MaterialState.selected)) { if (states.contains(MaterialState.selected)) {
return Colors.indigo; return Colors.indigo; // selected color
} }
return Colors.white; return Colors.white; // unselected background
}),
checkColor: Colors.white, // tick color
onChanged: (val) {
if (val == true) {
selectedValues.add(f.id);
} else {
selectedValues.remove(f.id);
}
setState(() {});
}, },
), );
onChanged: (val) { }).toList(),
if (val == true) { ),
selectedValues.add(f.id);
} else {
selectedValues.remove(f.id);
}
setState(() {});
},
);
},
), ),
); );
}).toList(), },
);
},
child: Container(
padding: MySpacing.all(12),
decoration: BoxDecoration(
color: Colors.grey.shade100,
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: MyText(
displayText,
style: const TextStyle(color: Colors.black87),
overflow: TextOverflow.ellipsis,
),
),
const Icon(Icons.arrow_drop_down, color: Colors.grey),
],
), ),
), ),
); ],
}, );
); },
}), child: Container(
MySpacing.height(16), padding: MySpacing.all(12),
], decoration: BoxDecoration(
color: Colors.grey.shade100,
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: MyText(
displayText,
style: const TextStyle(color: Colors.black87),
overflow: TextOverflow.ellipsis,
),
),
const Icon(Icons.arrow_drop_down, color: Colors.grey),
],
),
),
);
},
); );
} });
}
void _handleSubmit() { void _handleSubmit() {
bool valid = formKey.currentState?.validate() ?? false; bool valid = formKey.currentState?.validate() ?? false;

View File

@ -36,7 +36,7 @@ class _AddEmployeeBottomSheetState extends State<AddEmployeeBottomSheet>
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_orgFieldController = TextEditingController();
_joiningDateController = TextEditingController(); _joiningDateController = TextEditingController();
_genderController = TextEditingController(); _genderController = TextEditingController();
_roleController = TextEditingController(); _roleController = TextEditingController();
@ -46,17 +46,33 @@ class _AddEmployeeBottomSheetState extends State<AddEmployeeBottomSheet>
if (widget.employeeData != null) { if (widget.employeeData != null) {
_controller.editingEmployeeData = widget.employeeData; _controller.editingEmployeeData = widget.employeeData;
_controller.prefillFields(); _controller.prefillFields();
// 👇 joining date & gender already handled in your code
// Prepopulate hasApplicationAccess and email
_hasApplicationAccess =
widget.employeeData?['hasApplicationAccess'] ?? false;
final email = widget.employeeData?['email'];
if (email != null && email.toString().isNotEmpty) {
_controller.basicValidator.getController('email')?.text =
email.toString();
}
// Trigger UI rebuild to reflect email & checkbox
setState(() {});
// Joining date
if (_controller.joiningDate != null) { if (_controller.joiningDate != null) {
_joiningDateController.text = _joiningDateController.text =
DateFormat('dd MMM yyyy').format(_controller.joiningDate!); DateFormat('dd MMM yyyy').format(_controller.joiningDate!);
} }
// Gender
if (_controller.selectedGender != null) { if (_controller.selectedGender != null) {
_genderController.text = _genderController.text =
_controller.selectedGender!.name.capitalizeFirst ?? ''; _controller.selectedGender!.name.capitalizeFirst ?? '';
} }
// Important part: fetch roles, then set roleController // Role
_controller.fetchRoles().then((_) { _controller.fetchRoles().then((_) {
if (_controller.selectedRoleId != null) { if (_controller.selectedRoleId != null) {
final roleName = _controller.roles.firstWhereOrNull( final roleName = _controller.roles.firstWhereOrNull(
@ -65,6 +81,7 @@ class _AddEmployeeBottomSheetState extends State<AddEmployeeBottomSheet>
if (roleName != null) { if (roleName != null) {
_roleController.text = roleName; _roleController.text = roleName;
} }
_controller.update();
} }
}); });
} else { } else {

View File

@ -12,15 +12,17 @@ class EmployeeDetailsModel {
final String phoneNumber; final String phoneNumber;
final String? emergencyPhoneNumber; final String? emergencyPhoneNumber;
final String? emergencyContactPerson; final String? emergencyContactPerson;
final String? aadharNumber;
final bool isActive; final bool isActive;
final String? panNumber; final bool isRootUser;
final String? photo;
final String? applicationUserId;
final String jobRoleId;
final bool isSystem; final bool isSystem;
final String jobRole; final String jobRole;
final String jobRoleId;
final String? photo;
final String? applicationUserId;
final bool hasApplicationAccess;
final String? organizationId;
final String? aadharNumber;
final String? panNumber;
EmployeeDetailsModel({ EmployeeDetailsModel({
required this.id, required this.id,
required this.firstName, required this.firstName,
@ -35,14 +37,17 @@ class EmployeeDetailsModel {
required this.phoneNumber, required this.phoneNumber,
this.emergencyPhoneNumber, this.emergencyPhoneNumber,
this.emergencyContactPerson, this.emergencyContactPerson,
this.aadharNumber,
required this.isActive, required this.isActive,
this.panNumber, required this.isRootUser,
this.photo,
this.applicationUserId,
required this.jobRoleId,
required this.isSystem, required this.isSystem,
required this.jobRole, required this.jobRole,
required this.jobRoleId,
this.photo,
this.applicationUserId,
required this.hasApplicationAccess,
this.organizationId,
this.aadharNumber,
this.panNumber,
}); });
factory EmployeeDetailsModel.fromJson(Map<String, dynamic> json) { factory EmployeeDetailsModel.fromJson(Map<String, dynamic> json) {
@ -60,24 +65,20 @@ class EmployeeDetailsModel {
phoneNumber: json['phoneNumber'], phoneNumber: json['phoneNumber'],
emergencyPhoneNumber: json['emergencyPhoneNumber'], emergencyPhoneNumber: json['emergencyPhoneNumber'],
emergencyContactPerson: json['emergencyContactPerson'], emergencyContactPerson: json['emergencyContactPerson'],
aadharNumber: json['aadharNumber'],
isActive: json['isActive'], isActive: json['isActive'],
panNumber: json['panNumber'], isRootUser: json['isRootUser'],
photo: json['photo'],
applicationUserId: json['applicationUserId'],
jobRoleId: json['jobRoleId'],
isSystem: json['isSystem'], isSystem: json['isSystem'],
jobRole: json['jobRole'], jobRole: json['jobRole'],
jobRoleId: json['jobRoleId'],
photo: json['photo'],
applicationUserId: json['applicationUserId'],
hasApplicationAccess: json['hasApplicationAccess'],
organizationId: json['organizationId'],
aadharNumber: json['aadharNumber'],
panNumber: json['panNumber'],
); );
} }
static DateTime? _parseDate(String? dateStr) {
if (dateStr == null || dateStr == "0001-01-01T00:00:00") {
return null;
}
return DateTime.tryParse(dateStr);
}
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'id': id, 'id': id,
@ -93,14 +94,24 @@ class EmployeeDetailsModel {
'phoneNumber': phoneNumber, 'phoneNumber': phoneNumber,
'emergencyPhoneNumber': emergencyPhoneNumber, 'emergencyPhoneNumber': emergencyPhoneNumber,
'emergencyContactPerson': emergencyContactPerson, 'emergencyContactPerson': emergencyContactPerson,
'aadharNumber': aadharNumber,
'isActive': isActive, 'isActive': isActive,
'panNumber': panNumber, 'isRootUser': isRootUser,
'photo': photo,
'applicationUserId': applicationUserId,
'jobRoleId': jobRoleId,
'isSystem': isSystem, 'isSystem': isSystem,
'jobRole': jobRole, 'jobRole': jobRole,
'jobRoleId': jobRoleId,
'photo': photo,
'applicationUserId': applicationUserId,
'hasApplicationAccess': hasApplicationAccess,
'organizationId': organizationId,
'aadharNumber': aadharNumber,
'panNumber': panNumber,
}; };
} }
static DateTime? _parseDate(String? dateStr) {
if (dateStr == null || dateStr == "0001-01-01T00:00:00") {
return null;
}
return DateTime.tryParse(dateStr);
}
} }

View File

@ -261,6 +261,9 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
'first_name': employee.firstName, 'first_name': employee.firstName,
'last_name': employee.lastName, 'last_name': employee.lastName,
'phone_number': employee.phoneNumber, 'phone_number': employee.phoneNumber,
'email': employee.email,
'hasApplicationAccess':
employee.hasApplicationAccess,
'gender': employee.gender.toLowerCase(), 'gender': employee.gender.toLowerCase(),
'job_role_id': employee.jobRoleId, 'job_role_id': employee.jobRoleId,
'joining_date': 'joining_date':