diff --git a/lib/helpers/widgets/my_team_model_sheet.dart b/lib/helpers/widgets/my_team_model_sheet.dart index b3f7c3c..f879073 100644 --- a/lib/helpers/widgets/my_team_model_sheet.dart +++ b/lib/helpers/widgets/my_team_model_sheet.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:marco/helpers/widgets/avatar.dart'; import 'package:marco/helpers/widgets/my_text.dart'; +import 'package:marco/helpers/widgets/my_spacing.dart'; +import 'package:marco/helpers/utils/base_bottom_sheet.dart'; class TeamBottomSheet { static void show({ @@ -9,46 +11,61 @@ class TeamBottomSheet { }) { showModalBottomSheet( context: context, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(top: Radius.circular(12)), - ), - backgroundColor: Colors.white, - builder: (_) => Padding( - padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Title and Close Icon - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - MyText.bodyLarge("Team Members", fontWeight: 600), - IconButton( - icon: const Icon(Icons.close, size: 20, color: Colors.black54), - onPressed: () => Navigator.pop(context), - ), - ], - ), - const Divider(thickness: 1.2), - // Team Member Rows - ...teamMembers.map((member) => _buildTeamMemberRow(member)), - ], - ), - ), - ); - } - - static Widget _buildTeamMemberRow(dynamic member) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - children: [ - Avatar(firstName: member.firstName, lastName: '', size: 36), - const SizedBox(width: 10), - MyText.bodyMedium(member.firstName, fontWeight: 500), - ], - ), + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (_) { + return BaseBottomSheet( + title: 'Team Members', + onCancel: () => Navigator.pop(context), + onSubmit: () {}, + showButtons: false, + child: _TeamMemberList(teamMembers: teamMembers), + ); + }, + ); + } +} + +class _TeamMemberList extends StatelessWidget { + final List teamMembers; + + const _TeamMemberList({required this.teamMembers}); + + @override + Widget build(BuildContext context) { + if (teamMembers.isEmpty) { + return Center( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: MyText.bodySmall( + "No team members found.", + fontWeight: 600, + color: Colors.grey, + ), + ), + ); + } + + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: teamMembers.length, + separatorBuilder: (_, __) => const Divider(thickness: 0.8, height: 12), + itemBuilder: (_, index) { + final member = teamMembers[index]; + final String name = member.firstName ?? 'Unnamed'; + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Row( + children: [ + Avatar(firstName: member.firstName, lastName: '', size: 36), + MySpacing.width(10), + MyText.bodyMedium(name, fontWeight: 500), + ], + ), + ); + }, ); } } diff --git a/lib/helpers/widgets/team_members_bottom_sheet.dart b/lib/helpers/widgets/team_members_bottom_sheet.dart index ff1ff5c..949f870 100644 --- a/lib/helpers/widgets/team_members_bottom_sheet.dart +++ b/lib/helpers/widgets/team_members_bottom_sheet.dart @@ -3,6 +3,7 @@ import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/helpers/widgets/avatar.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/model/directory/contact_bucket_list_model.dart'; +import 'package:marco/helpers/utils/base_bottom_sheet.dart'; class TeamMembersBottomSheet { static void show( @@ -14,7 +15,7 @@ class TeamMembersBottomSheet { }) { final ownerId = bucket.createdBy.id; - // Ensure owner is first + // Ensure owner is listed first members.sort((a, b) { if (a.id == ownerId) return -1; if (b.id == ownerId) return 1; @@ -25,59 +26,59 @@ class TeamMembersBottomSheet { context: context, isScrollControlled: true, backgroundColor: Colors.transparent, - isDismissible: true, - enableDrag: true, - builder: (context) { - return SafeArea( - child: Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.vertical(top: Radius.circular(16)), - ), - child: DraggableScrollableSheet( - expand: false, - initialChildSize: 0.75, - minChildSize: 0.55, - maxChildSize: 0.95, - builder: (context, scrollController) { - return Column( - children: [ - MySpacing.height(8), - _buildGrabHandle(), - MySpacing.height(10), - MyText.titleMedium('Bucket Details', fontWeight: 700), - MySpacing.height(12), - _buildHeader(bucket, canEdit, onEdit), - _buildInfo(bucket, members.length, canEdit), - MySpacing.height(6), - _buildMembersTitle(), - MySpacing.height(4), - Expanded(child: _buildMemberList(members, ownerId, scrollController)), - MySpacing.height(8), - ], - ); - }, - ), + builder: (_) { + return BaseBottomSheet( + title: 'Bucket Details', + onCancel: () => Navigator.pop(context), + onSubmit: () {}, // Not used, but required + showButtons: false, + child: _TeamContent( + bucket: bucket, + members: members, + canEdit: canEdit, + onEdit: onEdit, + ownerId: ownerId, ), ); }, ); } +} - static Widget _buildGrabHandle() { - return Container( - width: 36, - height: 4, - decoration: BoxDecoration( - color: Colors.grey.shade300, - borderRadius: BorderRadius.circular(2), - ), +class _TeamContent extends StatelessWidget { + final ContactBucket bucket; + final List members; + final bool canEdit; + final VoidCallback? onEdit; + final String ownerId; + + const _TeamContent({ + required this.bucket, + required this.members, + required this.canEdit, + this.onEdit, + required this.ownerId, + }); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildHeader(), + _buildInfo(), + _buildMembersTitle(), + MySpacing.height(8), + SizedBox( + height: 300, + child: _buildMemberList(), + ), + ], ); } - static Widget _buildHeader(ContactBucket bucket, bool canEdit, VoidCallback? onEdit) { + Widget _buildHeader() { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.symmetric(horizontal: 4), child: Row( children: [ Expanded( @@ -94,9 +95,9 @@ class TeamMembersBottomSheet { ); } - static Widget _buildInfo(ContactBucket bucket, int totalMembers, bool canEdit) { + Widget _buildInfo() { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.only(bottom: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -121,7 +122,7 @@ class TeamMembersBottomSheet { const Icon(Icons.ios_share_outlined, size: 14, color: Colors.grey), const SizedBox(width: 4), MyText.labelSmall( - 'Shared with ($totalMembers)', + 'Shared with (${members.length})', fontWeight: 600, color: Colors.indigo, ), @@ -139,21 +140,21 @@ class TeamMembersBottomSheet { ), ], ), - MySpacing.height(8), + MySpacing.height(12), const Divider(thickness: 1), ], ), ); } - static Widget _buildMembersTitle() { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), + Widget _buildMembersTitle() { + return Align( + alignment: Alignment.centerLeft, child: MyText.labelLarge('Shared with', fontWeight: 700, color: Colors.black), ); } - static Widget _buildMemberList(List members, String ownerId, ScrollController scrollController) { + Widget _buildMemberList() { if (members.isEmpty) { return Center( child: MyText.bodySmall( @@ -165,10 +166,8 @@ class TeamMembersBottomSheet { } return ListView.separated( - controller: scrollController, itemCount: members.length, - padding: const EdgeInsets.symmetric(horizontal: 16), - separatorBuilder: (_, __) => const SizedBox(height: 4), + separatorBuilder: (_, __) => const SizedBox(height: 6), itemBuilder: (context, index) { final member = members[index]; final firstName = member.firstName ?? ''; diff --git a/lib/model/dailyTaskPlaning/assign_task_bottom_sheet .dart b/lib/model/dailyTaskPlaning/assign_task_bottom_sheet .dart index f42826c..3eaa40c 100644 --- a/lib/model/dailyTaskPlaning/assign_task_bottom_sheet .dart +++ b/lib/model/dailyTaskPlaning/assign_task_bottom_sheet .dart @@ -70,9 +70,6 @@ class _AssignTaskBottomSheetState extends State { onCancel: () => Get.back(), onSubmit: _onAssignTaskPressed, isSubmitting: controller.isAssigningTask.value, - submitText: "Assign Task", - submitIcon: Icons.check_circle_outline, - submitColor: Colors.indigo, )); } diff --git a/lib/model/dailyTaskPlaning/daily_progress_report_filter.dart b/lib/model/dailyTaskPlaning/daily_progress_report_filter.dart index 11b41c3..586a0d2 100644 --- a/lib/model/dailyTaskPlaning/daily_progress_report_filter.dart +++ b/lib/model/dailyTaskPlaning/daily_progress_report_filter.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:marco/controller/permission_controller.dart'; -import 'package:marco/controller/dashboard/daily_task_controller.dart'; import 'package:intl/intl.dart'; +import 'package:marco/controller/dashboard/daily_task_controller.dart'; +import 'package:marco/controller/permission_controller.dart'; +import 'package:marco/helpers/utils/base_bottom_sheet.dart'; import 'package:marco/helpers/widgets/my_text.dart'; -class DailyProgressReportFilter extends StatefulWidget { +class DailyProgressReportFilter extends StatelessWidget { final DailyTaskController controller; final PermissionController permissionController; @@ -14,20 +15,9 @@ class DailyProgressReportFilter extends StatefulWidget { required this.permissionController, }); - @override - State createState() => - _DailyProgressReportFilterState(); -} - -class _DailyProgressReportFilterState extends State { - @override - void initState() { - super.initState(); - } - String getLabelText() { - final startDate = widget.controller.startDateTask; - final endDate = widget.controller.endDateTask; + final startDate = controller.startDateTask; + final endDate = controller.endDateTask; if (startDate != null && endDate != null) { final start = DateFormat('dd MM yyyy').format(startDate); final end = DateFormat('dd MM yyyy').format(endDate); @@ -38,105 +28,55 @@ class _DailyProgressReportFilterState extends State { @override Widget build(BuildContext context) { - return SafeArea( - child: Padding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).viewInsets.bottom, - ), - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.only(top: 12, bottom: 8), - child: Center( - child: Container( - width: 40, - height: 4, - decoration: BoxDecoration( - color: Colors.grey[400], - borderRadius: BorderRadius.circular(4), - ), - ), - ), + return BaseBottomSheet( + title: "Filter Tasks", + onCancel: () => Navigator.pop(context), + + onSubmit: () { + Navigator.pop(context, { + 'startDate': controller.startDateTask, + 'endDate': controller.endDateTask, + }); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MyText.titleSmall("Select Date Range", fontWeight: 600), + const SizedBox(height: 8), + InkWell( + borderRadius: BorderRadius.circular(10), + onTap: () => controller.selectDateRangeForTaskData( + context, + controller, + ), + child: Ink( + decoration: BoxDecoration( + color: Colors.grey.shade100, + border: Border.all(color: Colors.grey.shade400), + borderRadius: BorderRadius.circular(10), ), - const Divider(), - Padding( - padding: EdgeInsets.fromLTRB(16, 12, 16, 4), - child: Align( - alignment: Alignment.centerLeft, - child: MyText.titleSmall( - "Select Date Range", - fontWeight: 600, - ), - ), - ), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: InkWell( - borderRadius: BorderRadius.circular(10), - onTap: () => widget.controller.selectDateRangeForTaskData( - context, - widget.controller, - ), - child: Ink( - decoration: BoxDecoration( - color: Colors.grey.shade100, - border: Border.all(color: Colors.grey.shade400), - borderRadius: BorderRadius.circular(10), - ), - padding: const EdgeInsets.symmetric( - horizontal: 16, vertical: 14), - child: Row( - children: [ - Icon(Icons.date_range, color: Colors.blue.shade600), - const SizedBox(width: 12), - Expanded( - child: Text( - getLabelText(), - style: const TextStyle( - fontSize: 16, - color: Colors.black87, - fontWeight: FontWeight.w500, - ), - overflow: TextOverflow.ellipsis, - ), - ), - const Icon(Icons.arrow_drop_down, color: Colors.grey), - ], - ), - ), - ), - ), - const Divider(), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - child: SizedBox( - width: double.infinity, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 12), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), + child: Row( + children: [ + Icon(Icons.date_range, color: Colors.blue.shade600), + const SizedBox(width: 12), + Expanded( + child: Text( + getLabelText(), + style: const TextStyle( + fontSize: 16, + color: Colors.black87, + fontWeight: FontWeight.w500, ), + overflow: TextOverflow.ellipsis, ), - child: const Text('Apply Filter'), - onPressed: () { - WidgetsBinding.instance.addPostFrameCallback((_) { - Navigator.pop(context, { - 'startDate': widget.controller.startDateTask, - 'endDate': widget.controller.endDateTask, - }); - }); - }, ), - ), + const Icon(Icons.arrow_drop_down, color: Colors.grey), + ], ), - ], + ), ), - ), + ], ), ); } diff --git a/lib/view/taskPlaning/daily_progress.dart b/lib/view/taskPlaning/daily_progress.dart index 365c257..487a105 100644 --- a/lib/view/taskPlaning/daily_progress.dart +++ b/lib/view/taskPlaning/daily_progress.dart @@ -205,29 +205,27 @@ class _DailyProgressReportScreenState extends State } Future _openFilterSheet() async { - final result = await showModalBottomSheet>( - context: context, - isScrollControlled: true, - backgroundColor: Colors.white, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(top: Radius.circular(12)), - ), - builder: (context) => DailyProgressReportFilter( - controller: dailyTaskController, - permissionController: permissionController, - ), - ); + final result = await showModalBottomSheet>( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => DailyProgressReportFilter( + controller: dailyTaskController, + permissionController: permissionController, + ), + ); - if (result != null) { - final selectedProjectId = result['projectId'] as String?; - if (selectedProjectId != null && - selectedProjectId != dailyTaskController.selectedProjectId) { - dailyTaskController.selectedProjectId = selectedProjectId; - await dailyTaskController.fetchTaskData(selectedProjectId); - dailyTaskController.update(['daily_progress_report_controller']); - } + if (result != null) { + final selectedProjectId = result['projectId'] as String?; + if (selectedProjectId != null && + selectedProjectId != dailyTaskController.selectedProjectId) { + dailyTaskController.selectedProjectId = selectedProjectId; + await dailyTaskController.fetchTaskData(selectedProjectId); + dailyTaskController.update(['daily_progress_report_controller']); } } +} + Future _refreshData() async { final projectId = dailyTaskController.selectedProjectId;