Refactor attendance button UI and improve feedback messages
This commit is contained in:
parent
5462f0aa24
commit
932cfe81e7
@ -279,9 +279,10 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
.uploadingStates[employee.employeeId]?.value ??
|
||||
false;
|
||||
final controller = attendanceController;
|
||||
return SizedBox(
|
||||
width: 90,
|
||||
height: 25,
|
||||
return ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 100, maxWidth: 140),
|
||||
child: SizedBox(
|
||||
height: 30,
|
||||
child: ElevatedButton(
|
||||
onPressed: isUploading
|
||||
? null
|
||||
@ -291,7 +292,8 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
if (controller.selectedProjectId == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text("Please select a project first")),
|
||||
content:
|
||||
Text("Please select a project first")),
|
||||
);
|
||||
controller.uploadingStates[employee.employeeId] =
|
||||
RxBool(false);
|
||||
@ -336,6 +338,7 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AttendanceActionColors.colors[buttonText],
|
||||
textStyle: const TextStyle(fontSize: 12),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
),
|
||||
child: isUploading
|
||||
? const SizedBox(
|
||||
@ -347,7 +350,15 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
AlwaysStoppedAnimation<Color>(Colors.white),
|
||||
),
|
||||
)
|
||||
: Text(buttonText),
|
||||
: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Text(
|
||||
buttonText,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
@ -645,9 +656,10 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
isApprovedButNotToday: isApprovedButNotToday,
|
||||
);
|
||||
|
||||
return SizedBox(
|
||||
width: 90,
|
||||
height: 25,
|
||||
return ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 100, maxWidth: 150),
|
||||
child: SizedBox(
|
||||
height: 30,
|
||||
child: ElevatedButton(
|
||||
onPressed: isButtonDisabled
|
||||
? null
|
||||
@ -655,13 +667,16 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
attendanceController.uploadingStates[uniqueLogKey] =
|
||||
RxBool(true);
|
||||
|
||||
if (attendanceController.selectedProjectId == null) {
|
||||
if (attendanceController.selectedProjectId ==
|
||||
null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content:
|
||||
Text("Please select a project first")),
|
||||
Text("Please select a project first"),
|
||||
),
|
||||
);
|
||||
attendanceController.uploadingStates[uniqueLogKey] =
|
||||
attendanceController
|
||||
.uploadingStates[uniqueLogKey] =
|
||||
RxBool(false);
|
||||
return;
|
||||
}
|
||||
@ -730,7 +745,7 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
SnackBar(
|
||||
content: Text(success
|
||||
? '${actionText.toLowerCase()} marked successfully!'
|
||||
: 'Failed to ${actionText.toLowerCase()}.'),
|
||||
: 'Failed to ${actionText.toLowerCase()}'),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -748,7 +763,7 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
SnackBar(
|
||||
content: Text(success
|
||||
? '${actionText.toLowerCase()} marked successfully!'
|
||||
: 'Failed to ${actionText.toLowerCase()}.'),
|
||||
: 'Failed to ${actionText.toLowerCase()}'),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -761,7 +776,8 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
attendanceController.selectedProjectId!);
|
||||
attendanceController.fetchAttendanceLogs(
|
||||
attendanceController.selectedProjectId!);
|
||||
await attendanceController.fetchRegularizationLogs(
|
||||
await attendanceController
|
||||
.fetchRegularizationLogs(
|
||||
attendanceController.selectedProjectId!);
|
||||
await attendanceController.fetchProjectData(
|
||||
attendanceController.selectedProjectId!);
|
||||
@ -774,8 +790,8 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
isTodayApproved: isTodayApproved,
|
||||
activity: log.activity,
|
||||
),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4, horizontal: 6),
|
||||
textStyle: const TextStyle(fontSize: 12),
|
||||
),
|
||||
child: isUploading
|
||||
@ -788,18 +804,24 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
AlwaysStoppedAnimation<Color>(Colors.white),
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Text(
|
||||
AttendanceButtonHelper.getButtonText(
|
||||
activity: log.activity,
|
||||
checkIn: log.checkIn,
|
||||
checkOut: log.checkOut,
|
||||
isTodayApproved: isTodayApproved,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
)
|
||||
),
|
||||
]));
|
||||
}
|
||||
});
|
||||
@ -917,27 +939,34 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
Row(
|
||||
children: [
|
||||
// Approve Button
|
||||
ElevatedButton(
|
||||
onPressed: isUploading // Disable button if uploading
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 70, maxWidth: 120),
|
||||
child: SizedBox(
|
||||
height: 30,
|
||||
child: ElevatedButton(
|
||||
onPressed: isUploading
|
||||
? null
|
||||
: () async {
|
||||
if (attendanceController.selectedProjectId == null) {
|
||||
if (attendanceController.selectedProjectId ==
|
||||
null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text("Please select a project first")),
|
||||
content:
|
||||
Text("Please select a project first")),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
attendanceController.uploadingStates[uniqueLogKey]
|
||||
?.value = true; // Start loading
|
||||
attendanceController
|
||||
.uploadingStates[uniqueLogKey]?.value = true;
|
||||
|
||||
final success = await attendanceController
|
||||
.captureAndUploadAttendance(
|
||||
log.id,
|
||||
log.employeeId,
|
||||
attendanceController.selectedProjectId!,
|
||||
comment: "Accepted",
|
||||
action: 4, // Approve action
|
||||
action: 4,
|
||||
imageCapture: false,
|
||||
);
|
||||
|
||||
@ -945,7 +974,8 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
SnackBar(
|
||||
content: Text(success
|
||||
? 'Approval marked successfully!'
|
||||
: 'Failed to mark approval.')),
|
||||
: 'Failed to mark approval.'),
|
||||
),
|
||||
);
|
||||
|
||||
if (success) {
|
||||
@ -953,48 +983,64 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
attendanceController.selectedProjectId!);
|
||||
attendanceController.fetchAttendanceLogs(
|
||||
attendanceController.selectedProjectId!);
|
||||
await attendanceController.fetchRegularizationLogs(
|
||||
await attendanceController
|
||||
.fetchRegularizationLogs(
|
||||
attendanceController.selectedProjectId!);
|
||||
await attendanceController.fetchProjectData(
|
||||
attendanceController.selectedProjectId!);
|
||||
}
|
||||
|
||||
attendanceController.uploadingStates[uniqueLogKey]
|
||||
?.value = false; // End loading
|
||||
attendanceController
|
||||
.uploadingStates[uniqueLogKey]?.value = false;
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
AttendanceActionColors.colors[ButtonActions.approve],
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4, horizontal: 6),
|
||||
minimumSize: const Size(60, 20),
|
||||
textStyle: const TextStyle(fontSize: 12),
|
||||
),
|
||||
child: isUploading
|
||||
? const CircularProgressIndicator(
|
||||
strokeWidth:
|
||||
2) // Show loading indicator while uploading
|
||||
: const Text("Approve"),
|
||||
? const SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: const Text(
|
||||
"Approve",
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Space between buttons
|
||||
const SizedBox(width: 8),
|
||||
|
||||
// Reject Button
|
||||
ElevatedButton(
|
||||
onPressed: isUploading // Disable button if uploading
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 70, maxWidth: 120),
|
||||
child: SizedBox(
|
||||
height: 30,
|
||||
child: ElevatedButton(
|
||||
onPressed: isUploading
|
||||
? null
|
||||
: () async {
|
||||
if (attendanceController.selectedProjectId == null) {
|
||||
if (attendanceController.selectedProjectId ==
|
||||
null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text("Please select a project first")),
|
||||
content:
|
||||
Text("Please select a project first")),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
attendanceController.uploadingStates[uniqueLogKey]
|
||||
?.value = true; // Start loading
|
||||
attendanceController
|
||||
.uploadingStates[uniqueLogKey]?.value = true;
|
||||
|
||||
final success = await attendanceController
|
||||
.captureAndUploadAttendance(
|
||||
@ -1002,7 +1048,7 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
log.employeeId,
|
||||
attendanceController.selectedProjectId!,
|
||||
comment: "Rejected",
|
||||
action: 5, // Reject action
|
||||
action: 5,
|
||||
imageCapture: false,
|
||||
);
|
||||
|
||||
@ -1010,7 +1056,8 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
SnackBar(
|
||||
content: Text(success
|
||||
? 'Attendance marked as Rejected!'
|
||||
: 'Failed to mark attendance.')),
|
||||
: 'Failed to mark attendance.'),
|
||||
),
|
||||
);
|
||||
|
||||
if (success) {
|
||||
@ -1018,28 +1065,39 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
||||
attendanceController.selectedProjectId!);
|
||||
attendanceController.fetchAttendanceLogs(
|
||||
attendanceController.selectedProjectId!);
|
||||
await attendanceController.fetchRegularizationLogs(
|
||||
await attendanceController
|
||||
.fetchRegularizationLogs(
|
||||
attendanceController.selectedProjectId!);
|
||||
await attendanceController.fetchProjectData(
|
||||
attendanceController.selectedProjectId!);
|
||||
}
|
||||
|
||||
attendanceController.uploadingStates[uniqueLogKey]
|
||||
?.value = false; // End loading
|
||||
attendanceController
|
||||
.uploadingStates[uniqueLogKey]?.value = false;
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
AttendanceActionColors.colors[ButtonActions.reject],
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4, horizontal: 6),
|
||||
minimumSize: const Size(60, 20),
|
||||
textStyle: const TextStyle(fontSize: 12),
|
||||
),
|
||||
child: isUploading
|
||||
? const CircularProgressIndicator(
|
||||
strokeWidth:
|
||||
2) // Show loading indicator while uploading
|
||||
: const Text("Reject"),
|
||||
? const SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: const Text(
|
||||
"Reject",
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
Loading…
x
Reference in New Issue
Block a user