feat: enhance notification action handling and add refresh indicators in ServiceProjectDetailsScreen

This commit is contained in:
Vaibhav Surve 2025-11-22 16:17:17 +05:30
parent e9075dcdf5
commit 516d6b0489
2 changed files with 95 additions and 70 deletions

View File

@ -414,12 +414,17 @@ class NotificationActionHandler {
required String notFoundMessage, required String notFoundMessage,
required String successMessage, required String successMessage,
}) { }) {
if (!Get.isRegistered<T>()) {
_logger.w(notFoundMessage);
return;
}
try { try {
final controller = Get.find<T>(); final controller = Get.find<T>();
onFound(controller); onFound(controller);
_logger.i(successMessage); _logger.i(successMessage);
} catch (e) { } catch (e) {
_logger.w(notFoundMessage); _logger.w('⚠️ Error updating controller: $e');
} }
} }
} }

View File

@ -12,12 +12,14 @@ import 'package:on_field_work/helpers/widgets/avatar.dart';
import 'package:on_field_work/model/service_project/service_project_allocation_bottomsheet.dart'; import 'package:on_field_work/model/service_project/service_project_allocation_bottomsheet.dart';
import 'package:on_field_work/model/employees/employee_model.dart'; import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:on_field_work/view/service_project/jobs_tab.dart'; import 'package:on_field_work/view/service_project/jobs_tab.dart';
import 'package:on_field_work/helpers/widgets/my_refresh_indicator.dart';
class ServiceProjectDetailsScreen extends StatefulWidget { class ServiceProjectDetailsScreen extends StatefulWidget {
final String projectId; final String projectId;
final String? projectName; final String? projectName;
const ServiceProjectDetailsScreen({super.key, required this.projectId , this.projectName}); const ServiceProjectDetailsScreen(
{super.key, required this.projectId, this.projectName});
@override @override
State<ServiceProjectDetailsScreen> createState() => State<ServiceProjectDetailsScreen> createState() =>
@ -174,13 +176,20 @@ class _ServiceProjectDetailsScreenState
Widget _buildProfileTab() { Widget _buildProfileTab() {
final project = controller.projectDetail.value; final project = controller.projectDetail.value;
if (project == null) { if (project == null) {
return Center(child: MyText.bodyMedium("No project data")); return Center(child: MyText.bodyMedium("No project data"));
} }
return Padding( return MyRefreshIndicator(
padding: MySpacing.all(12), onRefresh: () async {
await controller.fetchProjectDetail();
},
backgroundColor: Colors.indigo,
color: Colors.white,
child: SingleChildScrollView( child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
padding: MySpacing.all(12),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
@ -335,13 +344,19 @@ class _ServiceProjectDetailsScreenState
return Center(child: MyText.bodyMedium("No team members found")); return Center(child: MyText.bodyMedium("No team members found"));
} }
// Group team members by their role ID // Group team members by role
final Map<String, List> roleGroups = {}; final Map<String, List> roleGroups = {};
for (var team in controller.teamList) { for (var team in controller.teamList) {
roleGroups.putIfAbsent(team.teamRole.id, () => []).add(team); roleGroups.putIfAbsent(team.teamRole.id, () => []).add(team);
} }
return ListView.separated( return MyRefreshIndicator(
onRefresh: () async {
await controller.fetchProjectTeams();
},
backgroundColor: Colors.indigo,
color: Colors.white,
child: ListView.separated(
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
itemCount: roleGroups.keys.length, itemCount: roleGroups.keys.length,
separatorBuilder: (_, __) => const SizedBox(height: 12), separatorBuilder: (_, __) => const SizedBox(height: 12),
@ -351,8 +366,8 @@ class _ServiceProjectDetailsScreenState
final roleName = teamMembers.first.teamRole.name; final roleName = teamMembers.first.teamRole.name;
return Card( return Card(
shape: shape: RoundedRectangleBorder(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), borderRadius: BorderRadius.circular(8)),
elevation: 3, elevation: 3,
shadowColor: Colors.black26, shadowColor: Colors.black26,
child: Padding( child: Padding(
@ -377,7 +392,8 @@ class _ServiceProjectDetailsScreenState
firstName: team.employee.firstName, firstName: team.employee.firstName,
lastName: team.employee.lastName, lastName: team.employee.lastName,
size: 32, size: 32,
imageUrl: (team.employee.photo?.isNotEmpty ?? false) imageUrl:
(team.employee.photo?.isNotEmpty ?? false)
? team.employee.photo ? team.employee.photo
: null, : null,
), ),
@ -406,6 +422,7 @@ class _ServiceProjectDetailsScreenState
), ),
); );
}, },
),
); );
}); });
} }
@ -457,7 +474,10 @@ class _ServiceProjectDetailsScreenState
controller: _tabController, controller: _tabController,
children: [ children: [
_buildProfileTab(), _buildProfileTab(),
JobsTab(scrollController: _jobScrollController, projectName: widget.projectName ?? '',), JobsTab(
scrollController: _jobScrollController,
projectName: widget.projectName ?? '',
),
_buildTeamsTab(), _buildTeamsTab(),
], ],
); );