marco.pms.mobileapp/lib/model/employees/employee_detail_bottom_sheet.dart
Vaibhav Surve 34100a4d9e -- Enhance layout with floating action button and navigation improvements
- Added a floating action button to the Layout widget for better accessibility.
- Updated the left bar navigation items for clarity and consistency.
- Introduced Daily Progress Report and Daily Task Planning screens with comprehensive UI.
- Implemented filtering and refreshing functionalities in task planning.
- Improved user experience with better spacing and layout adjustments.
- Updated pubspec.yaml to include new dependencies for image handling and path management.
2025-05-28 17:35:42 +05:30

216 lines
7.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/avatar.dart';
import 'package:intl/intl.dart';
import 'package:marco/controller/dashboard/employees_screen_controller.dart';
class EmployeeDetailBottomSheet extends StatefulWidget {
final String employeeId;
const EmployeeDetailBottomSheet({super.key, required this.employeeId});
@override
State<EmployeeDetailBottomSheet> createState() =>
_EmployeeDetailBottomSheetState();
}
class _EmployeeDetailBottomSheetState extends State<EmployeeDetailBottomSheet> {
final EmployeesScreenController controller =
Get.put(EmployeesScreenController());
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
controller.fetchEmployeeDetails(widget.employeeId);
});
}
@override
void dispose() {
controller.selectedEmployeeDetails.value = null;
super.dispose();
}
String _getDisplayValue(dynamic value) {
if (value == null || value.toString().trim().isEmpty || value == 'null') {
return 'NA';
}
return value.toString();
}
String _formatDate(DateTime? date) {
if (date == null || date == DateTime(1)) return 'NA';
try {
return DateFormat('d/M/yyyy').format(date);
} catch (_) {
return 'NA';
}
}
Widget _buildLabelValueRow(IconData icon, String label, String value) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(icon, size: 20, color: Colors.grey[700]),
MySpacing.width(8),
MyText.bodyMedium('$label:', fontWeight: 600),
MySpacing.width(8),
Expanded(child: MyText.bodyMedium(value, fontWeight: 400)),
],
),
);
}
@override
Widget build(BuildContext context) {
return DraggableScrollableSheet(
expand: false,
maxChildSize: 0.85,
minChildSize: 0.4,
initialChildSize: 0.6,
builder: (_, controllerScroll) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
boxShadow: const [
BoxShadow(
color: Colors.black26,
blurRadius: 10,
offset: Offset(0, -3),
),
],
),
child: Obx(() {
if (controller.isLoadingEmployeeDetails.value) {
return const Center(child: CircularProgressIndicator());
}
final employee = controller.selectedEmployeeDetails.value;
if (employee == null) {
return const Center(child: Text('No employee details found.'));
}
return SingleChildScrollView(
controller: controllerScroll,
padding: MySpacing.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Drag Handle
Container(
width: 50,
height: 5,
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(3),
),
),
MySpacing.height(20),
CircleAvatar(
radius: 40,
backgroundColor: Colors.blueGrey[200],
child: Avatar(
firstName: employee.firstName,
lastName: employee.lastName,
size: 60,
),
),
MySpacing.height(12),
MyText.titleLarge(
'${employee.firstName} ${employee.lastName}',
fontWeight: 700,
textAlign: TextAlign.center,
),
if (employee.jobRole.trim().isNotEmpty &&
employee.jobRole != 'null')
Padding(
padding: const EdgeInsets.only(top: 6),
child: Chip(
label: Text(
employee.jobRole,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
backgroundColor: Colors.blueAccent,
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 6),
),
),
MySpacing.height(10),
// Contact Info Card
_buildInfoCard('Contact Information', [
_buildLabelValueRow(
Icons.email, 'Email', _getDisplayValue(employee.email)),
_buildLabelValueRow(Icons.phone, 'Phone Number',
_getDisplayValue(employee.phoneNumber)),
]),
MySpacing.height(10),
// Emergency Contact Info Card
_buildInfoCard('Emergency Contact', [
_buildLabelValueRow(Icons.person, 'Contact Person',
_getDisplayValue(employee.emergencyContactPerson)),
_buildLabelValueRow(Icons.phone_android, 'Contact Number',
_getDisplayValue(employee.emergencyPhoneNumber)),
]),
MySpacing.height(10),
// Personal Info Card
_buildInfoCard('Personal Information', [
_buildLabelValueRow(Icons.transgender, 'Gender',
_getDisplayValue(employee.gender)),
_buildLabelValueRow(Icons.cake, 'Birth Date',
_formatDate(employee.birthDate)),
_buildLabelValueRow(Icons.work, 'Joining Date',
_formatDate(employee.joiningDate)),
]),
MySpacing.height(10),
// Address Card
_buildInfoCard('Address', [
_buildLabelValueRow(Icons.home, 'Current Address',
_getDisplayValue(employee.currentAddress)),
_buildLabelValueRow(Icons.home_filled, 'Permanent Address',
_getDisplayValue(employee.permanentAddress)),
]),
],
),
);
}),
);
},
);
}
Widget _buildInfoCard(String title, List<Widget> children) {
return Card(
elevation: 1,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.titleMedium(title, fontWeight: 700),
MySpacing.height(12),
...children,
],
),
),
);
}
}