feat: Add designation field to contact model and update add contact functionality

This commit is contained in:
Vaibhav Surve 2025-09-29 16:03:03 +05:30
parent 8576448a32
commit b286ab854a
3 changed files with 84 additions and 16 deletions

View File

@ -94,8 +94,9 @@ class AddContactController extends GetxController {
required List<Map<String, String>> phones, required List<Map<String, String>> phones,
required String address, required String address,
required String description, required String description,
String? designation,
}) async { }) async {
if (isSubmitting.value) return; if (isSubmitting.value) return;
isSubmitting.value = true; isSubmitting.value = true;
final categoryId = categoriesMap[selectedCategory.value]; final categoryId = categoriesMap[selectedCategory.value];
@ -156,6 +157,8 @@ class AddContactController extends GetxController {
if (phones.isNotEmpty) "contactPhones": phones, if (phones.isNotEmpty) "contactPhones": phones,
if (address.trim().isNotEmpty) "address": address.trim(), if (address.trim().isNotEmpty) "address": address.trim(),
if (description.trim().isNotEmpty) "description": description.trim(), if (description.trim().isNotEmpty) "description": description.trim(),
if (designation != null && designation.trim().isNotEmpty)
"designation": designation.trim(),
}; };
logSafe("${id != null ? 'Updating' : 'Creating'} contact"); logSafe("${id != null ? 'Updating' : 'Creating'} contact");

View File

@ -24,6 +24,7 @@ class _AddContactBottomSheetState extends State<AddContactBottomSheet> {
final nameCtrl = TextEditingController(); final nameCtrl = TextEditingController();
final orgCtrl = TextEditingController(); final orgCtrl = TextEditingController();
final designationCtrl = TextEditingController();
final addrCtrl = TextEditingController(); final addrCtrl = TextEditingController();
final descCtrl = TextEditingController(); final descCtrl = TextEditingController();
final tagCtrl = TextEditingController(); final tagCtrl = TextEditingController();
@ -49,6 +50,7 @@ class _AddContactBottomSheetState extends State<AddContactBottomSheet> {
if (c != null) { if (c != null) {
nameCtrl.text = c.name; nameCtrl.text = c.name;
orgCtrl.text = c.organization; orgCtrl.text = c.organization;
designationCtrl.text = c.designation ?? '';
addrCtrl.text = c.address; addrCtrl.text = c.address;
descCtrl.text = c.description; descCtrl.text = c.description;
@ -109,6 +111,7 @@ class _AddContactBottomSheetState extends State<AddContactBottomSheet> {
void dispose() { void dispose() {
nameCtrl.dispose(); nameCtrl.dispose();
orgCtrl.dispose(); orgCtrl.dispose();
designationCtrl.dispose();
addrCtrl.dispose(); addrCtrl.dispose();
descCtrl.dispose(); descCtrl.dispose();
tagCtrl.dispose(); tagCtrl.dispose();
@ -118,6 +121,20 @@ class _AddContactBottomSheetState extends State<AddContactBottomSheet> {
super.dispose(); super.dispose();
} }
Widget _labelWithStar(String label, {bool required = false}) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
MyText.labelMedium(label),
if (required)
const Text(
" *",
style: TextStyle(color: Colors.red, fontSize: 14),
),
],
);
}
InputDecoration _inputDecoration(String hint) => InputDecoration( InputDecoration _inputDecoration(String hint) => InputDecoration(
hintText: hint, hintText: hint,
hintStyle: MyTextStyle.bodySmall(xMuted: true), hintStyle: MyTextStyle.bodySmall(xMuted: true),
@ -145,7 +162,7 @@ class _AddContactBottomSheetState extends State<AddContactBottomSheet> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
MyText.labelMedium(label), _labelWithStar(label, required: required),
MySpacing.height(8), MySpacing.height(8),
TextFormField( TextFormField(
controller: ctrl, controller: ctrl,
@ -386,6 +403,7 @@ class _AddContactBottomSheetState extends State<AddContactBottomSheet> {
phones: phones, phones: phones,
address: addrCtrl.text.trim(), address: addrCtrl.text.trim(),
description: descCtrl.text.trim(), description: descCtrl.text.trim(),
designation: designationCtrl.text.trim(),
); );
} }
@ -412,7 +430,7 @@ class _AddContactBottomSheetState extends State<AddContactBottomSheet> {
MySpacing.height(16), MySpacing.height(16),
_textField("Organization", orgCtrl, required: true), _textField("Organization", orgCtrl, required: true),
MySpacing.height(16), MySpacing.height(16),
MyText.labelMedium(" Bucket"), _labelWithStar("Bucket", required: true),
MySpacing.height(8), MySpacing.height(8),
Stack( Stack(
children: [ children: [
@ -477,19 +495,62 @@ class _AddContactBottomSheetState extends State<AddContactBottomSheet> {
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
label: const Text("Add Phone"), label: const Text("Add Phone"),
), ),
MySpacing.height(16), Obx(() => showAdvanced.value
MyText.labelMedium("Category"), ? Column(
MySpacing.height(8), crossAxisAlignment: CrossAxisAlignment.start,
_popupSelector(controller.selectedCategory, children: [
controller.categories, "Choose Category"), // Move Designation field here
MySpacing.height(16), _textField("Designation", designationCtrl),
MyText.labelMedium("Tags"), MySpacing.height(16),
MySpacing.height(8),
_tagInput(), _dynamicList(
MySpacing.height(16), emailCtrls,
_textField("Address", addrCtrl), emailLabels,
MySpacing.height(16), "Email",
_textField("Description", descCtrl), ["Office", "Personal", "Other"],
TextInputType.emailAddress,
),
TextButton.icon(
onPressed: () {
emailCtrls.add(TextEditingController());
emailLabels.add("Office".obs);
},
icon: const Icon(Icons.add),
label: const Text("Add Email"),
),
_dynamicList(
phoneCtrls,
phoneLabels,
"Phone",
["Work", "Mobile", "Other"],
TextInputType.phone,
),
TextButton.icon(
onPressed: () {
phoneCtrls.add(TextEditingController());
phoneLabels.add("Work".obs);
},
icon: const Icon(Icons.add),
label: const Text("Add Phone"),
),
MyText.labelMedium("Category"),
MySpacing.height(8),
_popupSelector(
controller.selectedCategory,
controller.categories,
"Choose Category",
),
MySpacing.height(16),
MyText.labelMedium("Tags"),
MySpacing.height(8),
_tagInput(),
MySpacing.height(16),
_textField("Address", addrCtrl),
MySpacing.height(16),
_textField("Description", descCtrl),
],
)
: const SizedBox.shrink()),
], ],
) )
: const SizedBox.shrink()), : const SizedBox.shrink()),

View File

@ -2,6 +2,7 @@ class ContactModel {
final String id; final String id;
final List<String>? projectIds; final List<String>? projectIds;
final String name; final String name;
final String? designation;
final List<ContactPhone> contactPhones; final List<ContactPhone> contactPhones;
final List<ContactEmail> contactEmails; final List<ContactEmail> contactEmails;
final ContactCategory? contactCategory; final ContactCategory? contactCategory;
@ -15,6 +16,7 @@ class ContactModel {
required this.id, required this.id,
required this.projectIds, required this.projectIds,
required this.name, required this.name,
this.designation,
required this.contactPhones, required this.contactPhones,
required this.contactEmails, required this.contactEmails,
required this.contactCategory, required this.contactCategory,
@ -30,6 +32,7 @@ class ContactModel {
id: json['id'], id: json['id'],
projectIds: (json['projectIds'] as List?)?.map((e) => e as String).toList(), projectIds: (json['projectIds'] as List?)?.map((e) => e as String).toList(),
name: json['name'], name: json['name'],
designation: json['designation'],
contactPhones: (json['contactPhones'] as List) contactPhones: (json['contactPhones'] as List)
.map((e) => ContactPhone.fromJson(e)) .map((e) => ContactPhone.fromJson(e))
.toList(), .toList(),
@ -48,6 +51,7 @@ class ContactModel {
} }
} }
class ContactPhone { class ContactPhone {
final String id; final String id;
final String label; final String label;