import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:marco/controller/directory/manage_bucket_controller.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/model/directory/contact_bucket_list_model.dart'; import 'package:marco/model/employee_model.dart'; import 'package:marco/controller/directory/directory_controller.dart'; import 'package:collection/collection.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; class EditBucketBottomSheet { static void show(BuildContext context, ContactBucket bucket, List allEmployees) { final ManageBucketController controller = Get.find(); final nameController = TextEditingController(text: bucket.name); final descController = TextEditingController(text: bucket.description); final searchController = TextEditingController(); final selectedIds = RxSet({...bucket.employeeIds}); final searchText = ''.obs; InputDecoration _inputDecoration(String label) { return InputDecoration( labelText: label, hintStyle: TextStyle(color: Colors.grey.shade500, fontSize: 14), filled: true, fillColor: Colors.grey.shade100, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade300), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade300), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: Colors.blueAccent, width: 1.5), ), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), isDense: true, ); } showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) { return SingleChildScrollView( padding: MediaQuery.of(context).viewInsets, child: Container( decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: const BorderRadius.vertical(top: Radius.circular(24)), boxShadow: const [ BoxShadow( color: Colors.black12, blurRadius: 12, offset: Offset(0, -2), ), ], ), padding: const EdgeInsets.fromLTRB(20, 16, 20, 32), child: Column( mainAxisSize: MainAxisSize.min, children: [ Center( child: Container( width: 40, height: 5, decoration: BoxDecoration( color: Colors.grey.shade300, borderRadius: BorderRadius.circular(10), ), ), ), MySpacing.height(12), Center( child: MyText.titleMedium('Edit Bucket', fontWeight: 700), ), MySpacing.height(24), // Bucket Name TextField( controller: nameController, decoration: _inputDecoration('Bucket Name'), ), MySpacing.height(16), // Description TextField( controller: descController, maxLines: 2, decoration: _inputDecoration('Description'), ), MySpacing.height(20), // Shared With Align( alignment: Alignment.centerLeft, child: MyText.labelLarge('Shared With', fontWeight: 600), ), MySpacing.height(8), // Search Obx(() => TextField( controller: searchController, onChanged: (value) => searchText.value = value.toLowerCase(), decoration: InputDecoration( hintText: 'Search employee...', prefixIcon: const Icon(Icons.search, size: 20), suffixIcon: searchText.value.isNotEmpty ? IconButton( icon: const Icon(Icons.clear, size: 18), onPressed: () { searchController.clear(); searchText.value = ''; }, ) : null, isDense: true, contentPadding: const EdgeInsets.symmetric( horizontal: 12, vertical: 8), filled: true, fillColor: Colors.grey.shade100, border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: Colors.grey.shade300), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: Colors.grey.shade300), ), focusedBorder: const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10)), borderSide: BorderSide(color: Colors.blueAccent, width: 1.5), ), ), )), MySpacing.height(8), // Employee list Obx(() { final filtered = allEmployees.where((emp) { final fullName = '${emp.firstName} ${emp.lastName}'.toLowerCase(); return fullName.contains(searchText.value); }).toList(); return SizedBox( height: 180, child: ListView.builder( itemCount: filtered.length, itemBuilder: (context, index) { final emp = filtered[index]; final fullName = '${emp.firstName} ${emp.lastName}'.trim(); return Obx(() => Theme( data: Theme.of(context).copyWith( checkboxTheme: CheckboxThemeData( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4), ), side: const BorderSide( color: Colors.black, width: 2), fillColor: MaterialStateProperty.resolveWith( (states) { if (states .contains(MaterialState.selected)) { return Colors.blueAccent; } return Colors.transparent; }), checkColor: MaterialStateProperty.all(Colors.white), ), ), child: CheckboxListTile( dense: true, contentPadding: EdgeInsets.zero, visualDensity: const VisualDensity(vertical: -4), controlAffinity: ListTileControlAffinity.leading, value: selectedIds.contains(emp.id), onChanged: (val) { if (val == true) { selectedIds.add(emp.id); } else { selectedIds.remove(emp.id); } }, title: Text( fullName.isNotEmpty ? fullName : 'Unnamed', style: const TextStyle(fontSize: 13), ), ), )); }, ), ); }), MySpacing.height(24), // Action Buttons Row( children: [ Expanded( child: OutlinedButton.icon( onPressed: () => Get.back(), icon: const Icon(Icons.close, color: Colors.red), label: MyText.bodyMedium("Cancel", color: Colors.red, fontWeight: 600), style: OutlinedButton.styleFrom( side: const BorderSide(color: Colors.red), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 12), ), ), ), MySpacing.width(12), Expanded( child: ElevatedButton.icon( onPressed: () async { final newName = nameController.text.trim(); final newDesc = descController.text.trim(); final newEmployeeIds = selectedIds.toList()..sort(); final originalEmployeeIds = [...bucket.employeeIds] ..sort(); final nameChanged = newName != bucket.name; final descChanged = newDesc != bucket.description; final employeeChanged = !(ListEquality() .equals(newEmployeeIds, originalEmployeeIds)); if (!nameChanged && !descChanged && !employeeChanged) { showAppSnackbar( title: "No Changes", message: "No changes were made to update the bucket.", type: SnackbarType.warning, ); return; } final success = await controller.updateBucket( id: bucket.id, name: newName, description: newDesc, employeeIds: newEmployeeIds, originalEmployeeIds: originalEmployeeIds, ); if (success) { final directoryController = Get.find(); await directoryController.fetchBuckets(); Navigator.of(context).pop(); } }, icon: const Icon(Icons.check_circle_outline, color: Colors.white), label: MyText.bodyMedium("Save", color: Colors.white, fontWeight: 600), style: ElevatedButton.styleFrom( backgroundColor: Colors.indigo, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 12), ), ), ), ], ), ], ), ), ); }, ); } }