marco.pms.mobileapp/lib/view/Attendence/attendence_log_screen.dart
Vaibhav Surve f5d4ab8415 feat: Add attendance log screen and related functionalities
- 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.
2025-08-29 15:53:19 +05:30

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;
}
}