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