sorted the log view and removed close button
This commit is contained in:
parent
488a921f45
commit
6871eb3c92
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user