sorted the log view and removed close button

This commit is contained in:
Vaibhav Surve 2025-05-06 18:08:47 +05:30
parent 488a921f45
commit 6871eb3c92
2 changed files with 211 additions and 186 deletions

View File

@ -260,20 +260,28 @@ class AttendanceController extends GetxController {
} }
} }
Future<void> fetchLogsView(String? id) async { Future<void> fetchLogsView(String? id) async {
if (id == null) return; if (id == null) return;
isLoading.value = true; isLoading.value = true;
final response = await ApiService.getAttendanceLogView(id); final response = await ApiService.getAttendanceLogView(id);
isLoading.value = false; isLoading.value = false;
if (response != null) { if (response != null) {
attendenceLogsView = attendenceLogsView = response
response.map((json) => AttendanceLogViewModel.fromJson(json)).toList(); .map((json) => AttendanceLogViewModel.fromJson(json))
log.i("Attendance log view fetched for ID: $id"); .toList();
update();
} else { // Sort by activityTime field (latest first)
log.e("Failed to fetch attendance log view for ID $id"); attendenceLogsView.sort((a, b) {
} if (a.activityTime == null || b.activityTime == null) return 0; // Handle null values if any
return b.activityTime!.compareTo(a.activityTime!); // Sort descending (latest first)
});
log.i("Attendance log view fetched for ID: $id");
update();
} else {
log.e("Failed to fetch attendance log view for ID $id");
} }
} }
}

View File

@ -462,8 +462,19 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
MyText.titleMedium("Attendance Log Details", Row(
fontWeight: 700), mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MyText.titleMedium(
"Attendance Log Details",
fontWeight: 700,
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.pop(context),
),
],
),
const SizedBox(height: 16), const SizedBox(height: 16),
if (attendanceController if (attendanceController
.attendenceLogsView.isNotEmpty) ...[ .attendenceLogsView.isNotEmpty) ...[
@ -602,14 +613,6 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
], ],
), ),
)), )),
const SizedBox(height: 16),
Align(
alignment: Alignment.centerRight,
child: ElevatedButton(
onPressed: () => Navigator.pop(context),
child: const Text("Close"),
),
),
], ],
), ),
), ),
@ -860,108 +863,114 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
} }
Widget regularizationTab(BuildContext context) { Widget regularizationTab(BuildContext context) {
final attendanceController = Get.find<AttendanceController>(); final attendanceController = Get.find<AttendanceController>();
final columns = [ final columns = [
DataColumn(label: MyText.labelLarge('Name', color: contentTheme.primary)), DataColumn(label: MyText.labelLarge('Name', color: contentTheme.primary)),
DataColumn( DataColumn(
label: MyText.labelLarge('Check-In', color: contentTheme.primary)), label: MyText.labelLarge('Check-In', color: contentTheme.primary)),
DataColumn( DataColumn(
label: MyText.labelLarge('Check-Out', color: contentTheme.primary)), label: MyText.labelLarge('Check-Out', color: contentTheme.primary)),
DataColumn( DataColumn(
label: MyText.labelLarge('Action', color: contentTheme.primary)), label: MyText.labelLarge('Action', color: contentTheme.primary)),
]; ];
final rows = attendanceController.regularizationLogs final rows =
.mapIndexed((index, log) { attendanceController.regularizationLogs.mapIndexed((index, log) {
final uniqueLogKey = '${log.id}-${log.employeeId}'; // Unique key for each log final uniqueLogKey =
final isUploading = attendanceController.uploadingStates[uniqueLogKey]?.value ?? false; // Check the upload state '${log.id}-${log.employeeId}'; // Unique key for each log
final isUploading =
attendanceController.uploadingStates[uniqueLogKey]?.value ??
false; // Check the upload state
return DataRow(cells: [ return DataRow(cells: [
DataCell( DataCell(
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
MyText.bodyMedium(log.name, fontWeight: 600), MyText.bodyMedium(log.name, fontWeight: 600),
SizedBox(height: 2), SizedBox(height: 2),
MyText.bodySmall(log.role, color: Colors.grey), MyText.bodySmall(log.role, color: Colors.grey),
], ],
),
), ),
DataCell( ),
Column( DataCell(
mainAxisAlignment: MainAxisAlignment.center, Column(
crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center,
children: [ crossAxisAlignment: CrossAxisAlignment.start,
MyText.bodyMedium( children: [
log.checkIn != null MyText.bodyMedium(
? DateFormat('dd/MMM/yyyy').format(log.checkIn!) log.checkIn != null
: '-', ? DateFormat('dd/MMM/yyyy').format(log.checkIn!)
fontWeight: 600, : '-',
), fontWeight: 600,
MyText.bodyMedium( ),
log.checkIn != null MyText.bodyMedium(
? DateFormat('hh:mm a').format(log.checkIn!) log.checkIn != null
: '', ? DateFormat('hh:mm a').format(log.checkIn!)
fontWeight: 600, : '',
), fontWeight: 600,
], ),
), ],
), ),
DataCell( ),
Column( DataCell(
mainAxisAlignment: MainAxisAlignment.center, Column(
crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center,
children: [ crossAxisAlignment: CrossAxisAlignment.start,
MyText.bodyMedium( children: [
log.checkOut != null MyText.bodyMedium(
? DateFormat('dd MMM yyyy').format(log.checkOut!) log.checkOut != null
: '-', ? DateFormat('dd MMM yyyy').format(log.checkOut!)
fontWeight: 600, : '-',
), fontWeight: 600,
MyText.bodyMedium( ),
log.checkOut != null MyText.bodyMedium(
? DateFormat('hh:mm a').format(log.checkOut!) log.checkOut != null
: '', ? DateFormat('hh:mm a').format(log.checkOut!)
fontWeight: 600, : '',
), fontWeight: 600,
], ),
), ],
), ),
DataCell( ),
Row( DataCell(
children: [ Row(
// Approve Button children: [
ElevatedButton( // Approve Button
onPressed: isUploading // Disable button if uploading ElevatedButton(
? null onPressed: isUploading // Disable button if uploading
: () async { ? null
if (attendanceController.selectedProjectId == null) { : () async {
ScaffoldMessenger.of(context).showSnackBar( if (attendanceController.selectedProjectId == null) {
const SnackBar(content: Text("Please select a project first")),
);
return;
}
attendanceController.uploadingStates[uniqueLogKey]?.value = true; // Start loading
final success = await attendanceController.captureAndUploadAttendance(
log.id,
log.employeeId,
attendanceController.selectedProjectId!,
comment: "Accepted",
action: 4, // Approve action
imageCapture: false,
);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Please select a project first")),
);
return;
}
attendanceController.uploadingStates[uniqueLogKey]
?.value = true; // Start loading
final success = await attendanceController
.captureAndUploadAttendance(
log.id,
log.employeeId,
attendanceController.selectedProjectId!,
comment: "Accepted",
action: 4, // Approve action
imageCapture: false,
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text(success content: Text(success
? 'Approval marked successfully!' ? 'Approval marked successfully!'
: 'Failed to mark approval.')), : 'Failed to mark approval.')),
); );
if (success) { if (success) {
attendanceController.fetchEmployeesByProject( attendanceController.fetchEmployeesByProject(
attendanceController.selectedProjectId!); attendanceController.selectedProjectId!);
attendanceController.fetchAttendanceLogs( attendanceController.fetchAttendanceLogs(
@ -970,57 +979,63 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
attendanceController.selectedProjectId!); attendanceController.selectedProjectId!);
await attendanceController.fetchProjectData( await attendanceController.fetchProjectData(
attendanceController.selectedProjectId!); attendanceController.selectedProjectId!);
} }
attendanceController.uploadingStates[uniqueLogKey]?.value = false; // End loading attendanceController.uploadingStates[uniqueLogKey]
}, ?.value = false; // End loading
style: ElevatedButton.styleFrom( },
backgroundColor: AttendanceActionColors style: ElevatedButton.styleFrom(
.colors[ButtonActions.approve], backgroundColor:
padding: const EdgeInsets.symmetric( AttendanceActionColors.colors[ButtonActions.approve],
vertical: 4, horizontal: 6), padding:
minimumSize: const Size(60, 20), const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
textStyle: const TextStyle(fontSize: 12), minimumSize: const Size(60, 20),
), textStyle: const TextStyle(fontSize: 12),
child: isUploading
? const CircularProgressIndicator(strokeWidth: 2) // Show loading indicator while uploading
: const Text("Approve"),
), ),
child: isUploading
? const CircularProgressIndicator(
strokeWidth:
2) // Show loading indicator while uploading
: const Text("Approve"),
),
// Space between buttons // Space between buttons
const SizedBox(width: 8), const SizedBox(width: 8),
// Reject Button
ElevatedButton(
onPressed: isUploading // Disable button if uploading
? null
: () async {
if (attendanceController.selectedProjectId == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Please select a project first")),
);
return;
}
attendanceController.uploadingStates[uniqueLogKey]?.value = true; // Start loading
final success = await attendanceController.captureAndUploadAttendance(
log.id,
log.employeeId,
attendanceController.selectedProjectId!,
comment: "Rejected",
action: 5, // Reject action
imageCapture: false,
);
// Reject Button
ElevatedButton(
onPressed: isUploading // Disable button if uploading
? null
: () async {
if (attendanceController.selectedProjectId == null) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Please select a project first")),
);
return;
}
attendanceController.uploadingStates[uniqueLogKey]
?.value = true; // Start loading
final success = await attendanceController
.captureAndUploadAttendance(
log.id,
log.employeeId,
attendanceController.selectedProjectId!,
comment: "Rejected",
action: 5, // Reject action
imageCapture: false,
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text(success content: Text(success
? 'Attendance marked as Rejected!' ? 'Attendance marked as Rejected!'
: 'Failed to mark attendance.')), : 'Failed to mark attendance.')),
); );
if (success) { if (success) {
attendanceController.fetchEmployeesByProject( attendanceController.fetchEmployeesByProject(
attendanceController.selectedProjectId!); attendanceController.selectedProjectId!);
attendanceController.fetchAttendanceLogs( attendanceController.fetchAttendanceLogs(
@ -1029,53 +1044,55 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
attendanceController.selectedProjectId!); attendanceController.selectedProjectId!);
await attendanceController.fetchProjectData( await attendanceController.fetchProjectData(
attendanceController.selectedProjectId!); attendanceController.selectedProjectId!);
} }
attendanceController.uploadingStates[uniqueLogKey]?.value = false; // End loading attendanceController.uploadingStates[uniqueLogKey]
}, ?.value = false; // End loading
style: ElevatedButton.styleFrom( },
backgroundColor: style: ElevatedButton.styleFrom(
AttendanceActionColors.colors[ButtonActions.reject], backgroundColor:
padding: const EdgeInsets.symmetric( AttendanceActionColors.colors[ButtonActions.reject],
vertical: 4, horizontal: 6), padding:
minimumSize: const Size(60, 20), const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
textStyle: const TextStyle(fontSize: 12), minimumSize: const Size(60, 20),
), textStyle: const TextStyle(fontSize: 12),
child: isUploading
? const CircularProgressIndicator(strokeWidth: 2) // Show loading indicator while uploading
: const Text("Reject"),
), ),
], child: isUploading
), ? const CircularProgressIndicator(
strokeWidth:
2) // Show loading indicator while uploading
: const Text("Reject"),
),
],
), ),
]); ),
}) ]);
.toList(); }).toList();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
), ),
if (attendanceController.regularizationLogs.isEmpty) if (attendanceController.regularizationLogs.isEmpty)
Expanded( Expanded(
child: Center( child: Center(
child: MyText.bodySmall("No Regularization Records Found", child: MyText.bodySmall("No Regularization Records Found",
fontWeight: 600), fontWeight: 600),
), ),
) )
else else
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(
child: MyPaginatedTable( child: MyPaginatedTable(
columns: columns, columns: columns,
rows: rows, rows: rows,
columnSpacing: 15.0, columnSpacing: 15.0,
),
), ),
), ),
), ],
], );
); }
}
} }