- Implemented AttendenceLogScreen to display employee attendance logs. - Created RegularizationRequestsTab to manage regularization requests. - Added TodaysAttendanceTab for viewing today's attendance. - Removed outdated dashboard chart implementation. - Updated dashboard screen to integrate new attendance overview and project progress charts. - Refactored employee detail and employee screens to use updated controllers. - Organized expense-related imports and components for better structure. - Adjusted daily progress report to use the correct controller.
228 lines
9.4 KiB
Dart
228 lines
9.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:marco/helpers/theme/app_theme.dart';
|
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
|
import 'package:marco/helpers/utils/my_shadow.dart';
|
|
import 'package:marco/helpers/widgets/my_breadcrumb.dart';
|
|
import 'package:marco/helpers/widgets/my_breadcrumb_item.dart';
|
|
import 'package:marco/helpers/widgets/my_card.dart';
|
|
import 'package:marco/helpers/widgets/my_container.dart';
|
|
import 'package:marco/helpers/widgets/my_flex.dart';
|
|
import 'package:marco/helpers/widgets/my_flex_item.dart';
|
|
import 'package:marco/helpers/widgets/my_spacing.dart';
|
|
import 'package:marco/helpers/widgets/my_text.dart';
|
|
import 'package:marco/view/layouts/layout.dart';
|
|
import 'package:marco/controller/attendance/attendance_screen_controller.dart';
|
|
import 'package:marco/controller/permission_controller.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:marco/model/attendance/attendence_action_button.dart';
|
|
import 'package:marco/helpers/widgets/avatar.dart';
|
|
import 'package:marco/model/attendance/log_details_view.dart';
|
|
|
|
class AttendenceLogScreen extends StatefulWidget {
|
|
const AttendenceLogScreen({super.key});
|
|
|
|
@override
|
|
State<AttendenceLogScreen> createState() => _AttendenceLogScreenState();
|
|
}
|
|
|
|
class _AttendenceLogScreenState extends State<AttendenceLogScreen>
|
|
with UIMixin {
|
|
final AttendanceController attendanceController =
|
|
Get.put(AttendanceController());
|
|
final PermissionController permissionController =
|
|
Get.put(PermissionController());
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Layout(
|
|
child: GetBuilder(
|
|
init: attendanceController,
|
|
tag: 'attendence_controller',
|
|
builder: (controller) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: MySpacing.x(flexSpacing),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
MyText.titleMedium("Attendence",
|
|
fontSize: 18, fontWeight: 600),
|
|
MyBreadcrumb(
|
|
children: [
|
|
MyBreadcrumbItem(name: 'Dashboard'),
|
|
MyBreadcrumbItem(name: 'Attendence', active: true),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
MySpacing.height(flexSpacing),
|
|
Padding(
|
|
padding: MySpacing.x(flexSpacing / 2),
|
|
child: MyFlex(children: [
|
|
MyFlexItem(sizes: 'lg-12 md-12 sm-12', child: employeeLog()),
|
|
]),
|
|
)
|
|
],
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget employeeLog() {
|
|
return MyCard.bordered(
|
|
borderRadiusAll: 4,
|
|
border: Border.all(color: Colors.grey.withOpacity(0.2)),
|
|
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
|
paddingAll: 8,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
attendanceController.employees.isEmpty
|
|
? MyText.bodySmall("No Employees Assigned to This Project",
|
|
fontWeight: 600)
|
|
: Column(
|
|
children: List.generate(attendanceController.employees.length,
|
|
(index) {
|
|
final employee = attendanceController.employees[index];
|
|
return Column(
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.only(bottom: 16.0),
|
|
child: MyContainer(
|
|
paddingAll: 12,
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Column(
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
children: [
|
|
Avatar(
|
|
firstName: employee.firstName,
|
|
lastName: employee.lastName,
|
|
size: 31,
|
|
)
|
|
],
|
|
),
|
|
MySpacing.width(16),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment:
|
|
CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: MyText.bodyMedium(
|
|
'${employee.name} '
|
|
' (${employee.designation})',
|
|
fontWeight: 600,
|
|
maxLines: null,
|
|
overflow: TextOverflow.visible,
|
|
softWrap: true,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
MySpacing.height(8),
|
|
Row(
|
|
children: [
|
|
MyText.bodySmall("In: ",
|
|
fontWeight: 600),
|
|
MyText.bodySmall(
|
|
employee.checkIn != null
|
|
? DateFormat('hh:mm a')
|
|
.format(employee.checkIn!)
|
|
: '--',
|
|
fontWeight: 600,
|
|
),
|
|
MySpacing.width(16),
|
|
MyText.bodySmall("Out: ",
|
|
fontWeight: 600),
|
|
MyText.bodySmall(
|
|
employee.checkOut != null
|
|
? DateFormat('hh:mm a')
|
|
.format(employee.checkOut!)
|
|
: '--',
|
|
fontWeight: 600,
|
|
),
|
|
],
|
|
),
|
|
MySpacing.height(12),
|
|
Row(
|
|
children: [
|
|
AttendanceLogViewButton(
|
|
employee: employee,
|
|
attendanceController:
|
|
attendanceController,
|
|
),
|
|
MySpacing.width(8),
|
|
AttendanceActionButton(
|
|
employee: employee,
|
|
attendanceController:
|
|
attendanceController,
|
|
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
if (index != attendanceController.employees.length - 1)
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(),
|
|
child: Divider(
|
|
color: Colors.grey.withOpacity(0.3),
|
|
thickness: 1,
|
|
height: 1,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<DateTime?> showTimePickerForRegularization({
|
|
required BuildContext context,
|
|
required DateTime checkInTime,
|
|
}) async {
|
|
final pickedTime = await showTimePicker(
|
|
context: context,
|
|
initialTime: TimeOfDay.fromDateTime(DateTime.now()),
|
|
);
|
|
|
|
if (pickedTime != null) {
|
|
final selectedDateTime = DateTime(
|
|
checkInTime.year,
|
|
checkInTime.month,
|
|
checkInTime.day,
|
|
pickedTime.hour,
|
|
pickedTime.minute,
|
|
);
|
|
|
|
// Ensure selected time is after check-in time
|
|
if (selectedDateTime.isAfter(checkInTime)) {
|
|
return selectedDateTime;
|
|
} else {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text("Please select a time after check-in time.")),
|
|
);
|
|
return null;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|