refactor: enhance job attendance handling and improve null safety in models

This commit is contained in:
Vaibhav Surve 2025-11-17 18:03:59 +05:30
parent 919310644d
commit 2260382990
4 changed files with 44 additions and 39 deletions

View File

@ -34,7 +34,7 @@ class ServiceProjectDetailsController extends GetxController {
// Inside ServiceProjectDetailsController // Inside ServiceProjectDetailsController
var isTagging = false.obs; var isTagging = false.obs;
var attendanceMessage = ''.obs; var attendanceMessage = ''.obs;
var attendanceLog = Rxn<JobAttendanceResponse>(); var attendanceLog = Rxn<JobAttendanceResponse>();
// -------------------- Lifecycle -------------------- // -------------------- Lifecycle --------------------
@override @override
@ -91,10 +91,11 @@ var attendanceLog = Rxn<JobAttendanceResponse>();
try { try {
final result = final result =
await ApiService.getJobAttendanceLog(attendanceId: attendanceId); await ApiService.getJobAttendanceLog(attendanceId: attendanceId);
if (result != null) { if (result != null) {
attendanceLog.value = result; attendanceLog.value = result;
} else { } else {
attendanceMessage.value = "Failed to fetch attendance log"; attendanceMessage.value = "Attendance log not found or empty";
} }
} catch (e) { } catch (e) {
attendanceMessage.value = "Error fetching attendance log: $e"; attendanceMessage.value = "Error fetching attendance log: $e";

View File

@ -39,7 +39,8 @@ class JobData {
final String dueDate; final String dueDate;
final bool isActive; final bool isActive;
final dynamic taggingAction; final dynamic taggingAction;
final int nextTaggingAction; final String? attendanceId;
final int? nextTaggingAction;
final String createdAt; final String createdAt;
final User createdBy; final User createdBy;
final List<Tag> tags; final List<Tag> tags;
@ -57,7 +58,8 @@ class JobData {
required this.dueDate, required this.dueDate,
required this.isActive, required this.isActive,
this.taggingAction, this.taggingAction,
required this.nextTaggingAction, this.attendanceId,
this.nextTaggingAction,
required this.createdAt, required this.createdAt,
required this.createdBy, required this.createdBy,
required this.tags, required this.tags,
@ -71,22 +73,27 @@ class JobData {
description: json['description'] as String, description: json['description'] as String,
jobTicketUId: json['jobTicketUId'] as String, jobTicketUId: json['jobTicketUId'] as String,
project: Project.fromJson(json['project']), project: Project.fromJson(json['project']),
assignees: (json['assignees'] as List<dynamic>) assignees: (json['assignees'] as List<dynamic>?)
.map((e) => Assignee.fromJson(e)) ?.map((e) => Assignee.fromJson(e))
.toList(), .toList() ??
[],
status: Status.fromJson(json['status']), status: Status.fromJson(json['status']),
startDate: json['startDate'] as String, startDate: json['startDate'] as String,
dueDate: json['dueDate'] as String, dueDate: json['dueDate'] as String,
isActive: json['isActive'] as bool, isActive: json['isActive'] as bool,
taggingAction: json['taggingAction'], taggingAction: json['taggingAction'],
nextTaggingAction: json['nextTaggingAction'] as int, attendanceId: json['attendanceId'] as String?,
nextTaggingAction: json['nextTaggingAction'] as int?,
createdAt: json['createdAt'] as String, createdAt: json['createdAt'] as String,
createdBy: User.fromJson(json['createdBy']), createdBy: User.fromJson(json['createdBy']),
tags: tags: (json['tags'] as List<dynamic>?)
(json['tags'] as List<dynamic>).map((e) => Tag.fromJson(e)).toList(), ?.map((e) => Tag.fromJson(e))
updateLogs: (json['updateLogs'] as List<dynamic>) .toList() ??
.map((e) => UpdateLog.fromJson(e)) [],
.toList(), updateLogs: (json['updateLogs'] as List<dynamic>?)
?.map((e) => UpdateLog.fromJson(e))
.toList() ??
[],
); );
} }
} }
@ -127,8 +134,8 @@ class Assignee {
final String id; final String id;
final String firstName; final String firstName;
final String lastName; final String lastName;
final String email; final String? email;
final String photo; final String? photo;
final String jobRoleId; final String jobRoleId;
final String jobRoleName; final String jobRoleName;
@ -136,8 +143,8 @@ class Assignee {
required this.id, required this.id,
required this.firstName, required this.firstName,
required this.lastName, required this.lastName,
required this.email, this.email,
required this.photo, this.photo,
required this.jobRoleId, required this.jobRoleId,
required this.jobRoleName, required this.jobRoleName,
}); });
@ -147,8 +154,8 @@ class Assignee {
id: json['id'] as String, id: json['id'] as String,
firstName: json['firstName'] as String, firstName: json['firstName'] as String,
lastName: json['lastName'] as String, lastName: json['lastName'] as String,
email: json['email'] as String, email: json['email'] as String?,
photo: json['photo'] as String, photo: json['photo'] as String?,
jobRoleId: json['jobRoleId'] as String, jobRoleId: json['jobRoleId'] as String,
jobRoleName: json['jobRoleName'] as String, jobRoleName: json['jobRoleName'] as String,
); );
@ -182,8 +189,8 @@ class User {
final String id; final String id;
final String firstName; final String firstName;
final String lastName; final String lastName;
final String email; final String? email;
final String photo; final String? photo;
final String jobRoleId; final String jobRoleId;
final String jobRoleName; final String jobRoleName;
@ -191,8 +198,8 @@ class User {
required this.id, required this.id,
required this.firstName, required this.firstName,
required this.lastName, required this.lastName,
required this.email, this.email,
required this.photo, this.photo,
required this.jobRoleId, required this.jobRoleId,
required this.jobRoleName, required this.jobRoleName,
}); });
@ -202,8 +209,8 @@ class User {
id: json['id'] as String, id: json['id'] as String,
firstName: json['firstName'] as String, firstName: json['firstName'] as String,
lastName: json['lastName'] as String, lastName: json['lastName'] as String,
email: json['email'] as String, email: json['email'] as String?,
photo: json['photo'] as String, photo: json['photo'] as String?,
jobRoleId: json['jobRoleId'] as String, jobRoleId: json['jobRoleId'] as String,
jobRoleName: json['jobRoleName'] as String, jobRoleName: json['jobRoleName'] as String,
); );
@ -211,18 +218,15 @@ class User {
} }
class Tag { class Tag {
final String id; final String? id;
final String name; final String? name;
Tag({ Tag({this.id, this.name});
required this.id,
required this.name,
});
factory Tag.fromJson(Map<String, dynamic> json) { factory Tag.fromJson(Map<String, dynamic> json) {
return Tag( return Tag(
id: json['id'] as String, id: json['id'] as String?,
name: json['name'] as String, name: json['name'] as String?,
); );
} }
} }

View File

@ -351,7 +351,7 @@ class _ServiceProjectDetailsScreenState
final job = controller.jobList[index]; final job = controller.jobList[index];
return InkWell( return InkWell(
onTap: () { onTap: () {
Get.to(() => JobDetailsScreen(jobId: job.id)); Get.to(() => JobDetailsScreen(jobId: job.id ));
}, },
child: Card( child: Card(
elevation: 3, elevation: 3,

View File

@ -199,7 +199,7 @@ class _JobDetailsScreenState extends State<JobDetailsScreen> with UIMixin {
// Step 3: Perform attendance using controller // Step 3: Perform attendance using controller
await controller.updateJobAttendance( await controller.updateJobAttendance(
jobId: job.id, jobId: job.id,
action: action, action: action == 0 ? 0 : 1,
comment: comment ?? "", comment: comment ?? "",
attachment: attachmentFile, attachment: attachmentFile,
); );
@ -342,7 +342,7 @@ class _JobDetailsScreenState extends State<JobDetailsScreen> with UIMixin {
designation: a.jobRoleName, designation: a.jobRoleName,
jobRole: a.jobRoleName, jobRole: a.jobRoleName,
jobRoleID: a.jobRoleId, jobRoleID: a.jobRoleId,
email: a.email, email: a.email ?? '',
phoneNumber: '', phoneNumber: '',
activity: 0, activity: 0,
action: 0, action: 0,
@ -405,7 +405,7 @@ class _JobDetailsScreenState extends State<JobDetailsScreen> with UIMixin {
children: tags children: tags
.map( .map(
(t) => Chip( (t) => Chip(
label: Text(t.name), label: Text(t.name ?? ''),
onDeleted: editing onDeleted: editing
? () { ? () {
_selectedTags.remove(t); _selectedTags.remove(t);
@ -477,7 +477,7 @@ class _JobDetailsScreenState extends State<JobDetailsScreen> with UIMixin {
isExpanded.value = !isExpanded.value; isExpanded.value = !isExpanded.value;
// Fetch attendance logs only when expanded // Fetch attendance logs only when expanded
if (isExpanded.value && job != null) { if (isExpanded.value && job != null) {
await controller.fetchJobAttendanceLog(job.jobTicketUId); await controller.fetchJobAttendanceLog(job.attendanceId ?? '');
} }
}, },
)), )),