made chnages in employee details screen
This commit is contained in:
parent
910bb5e6b4
commit
eb46194679
@ -33,6 +33,143 @@ class SkeletonLoaders {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Employee Detail Skeleton Loader
|
||||||
|
static Widget employeeDetailSkeletonLoader() {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.fromLTRB(12, 20, 12, 80),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
// Header skeleton (avatar + name + role)
|
||||||
|
MyCard(
|
||||||
|
borderRadiusAll: 8,
|
||||||
|
paddingAll: 16,
|
||||||
|
margin: MySpacing.bottom(16),
|
||||||
|
shadow: MyShadow(elevation: 2),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
// Avatar
|
||||||
|
Container(
|
||||||
|
width: 45,
|
||||||
|
height: 45,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
MySpacing.width(16),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: 14,
|
||||||
|
width: 120,
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
MySpacing.height(6),
|
||||||
|
Container(
|
||||||
|
height: 12,
|
||||||
|
width: 80,
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Sections skeleton
|
||||||
|
...List.generate(
|
||||||
|
4,
|
||||||
|
(_) => Column(
|
||||||
|
children: [
|
||||||
|
MyCard(
|
||||||
|
borderRadiusAll: 8,
|
||||||
|
paddingAll: 16,
|
||||||
|
margin: MySpacing.bottom(16),
|
||||||
|
shadow: MyShadow(elevation: 2),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Section header
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
MySpacing.width(8),
|
||||||
|
Container(
|
||||||
|
width: 120,
|
||||||
|
height: 14,
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
MySpacing.height(8),
|
||||||
|
const Divider(color: Colors.grey),
|
||||||
|
|
||||||
|
// 2 rows placeholder
|
||||||
|
...List.generate(
|
||||||
|
2,
|
||||||
|
(_) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 12),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
MySpacing.width(16),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: 12,
|
||||||
|
width: 100,
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
MySpacing.height(4),
|
||||||
|
Container(
|
||||||
|
height: 12,
|
||||||
|
width: 150,
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Daily Progress Planning - Infra (Expanded) Skeleton Loader
|
// Daily Progress Planning - Infra (Expanded) Skeleton Loader
|
||||||
static Widget dailyProgressPlanningInfraSkeleton() {
|
static Widget dailyProgressPlanningInfraSkeleton() {
|
||||||
return Column(
|
return Column(
|
||||||
|
|||||||
@ -6,14 +6,11 @@ import 'package:marco/helpers/widgets/custom_app_bar.dart';
|
|||||||
import 'package:marco/helpers/widgets/avatar.dart';
|
import 'package:marco/helpers/widgets/avatar.dart';
|
||||||
import 'package:marco/helpers/widgets/my_spacing.dart';
|
import 'package:marco/helpers/widgets/my_spacing.dart';
|
||||||
import 'package:marco/helpers/widgets/my_text.dart';
|
import 'package:marco/helpers/widgets/my_text.dart';
|
||||||
import 'package:marco/view/employees/assign_employee_bottom_sheet.dart';
|
|
||||||
import 'package:marco/helpers/utils/launcher_utils.dart';
|
import 'package:marco/helpers/utils/launcher_utils.dart';
|
||||||
import 'package:marco/controller/permission_controller.dart';
|
|
||||||
import 'package:marco/helpers/utils/permission_constants.dart';
|
|
||||||
import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
|
import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
|
||||||
import 'package:marco/model/employees/add_employee_bottom_sheet.dart';
|
import 'package:marco/model/employees/add_employee_bottom_sheet.dart';
|
||||||
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
||||||
|
import 'package:marco/helpers/widgets/my_custom_skeleton.dart';
|
||||||
|
|
||||||
class EmployeeDetailPage extends StatefulWidget {
|
class EmployeeDetailPage extends StatefulWidget {
|
||||||
final String employeeId;
|
final String employeeId;
|
||||||
@ -32,8 +29,6 @@ class EmployeeDetailPage extends StatefulWidget {
|
|||||||
class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
|
class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
|
||||||
final EmployeesScreenController controller =
|
final EmployeesScreenController controller =
|
||||||
Get.put(EmployeesScreenController());
|
Get.put(EmployeesScreenController());
|
||||||
final PermissionController permissionController =
|
|
||||||
Get.put(PermissionController());
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -65,124 +60,112 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLabelValueRow(String label, String value,
|
Widget _buildDetailRow({
|
||||||
{bool isMultiLine = false}) {
|
required IconData icon,
|
||||||
final lowerLabel = label.toLowerCase();
|
required String label,
|
||||||
final isEmail = lowerLabel == 'email';
|
required String value,
|
||||||
final isPhone =
|
VoidCallback? onTap,
|
||||||
lowerLabel == 'phone number' || lowerLabel == 'emergency phone number';
|
VoidCallback? onLongPress,
|
||||||
|
bool isActionable = false,
|
||||||
void handleTap() {
|
}) {
|
||||||
if (value == 'NA') return;
|
return Padding(
|
||||||
if (isEmail) {
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
LauncherUtils.launchEmail(value);
|
child: InkWell(
|
||||||
} else if (isPhone) {
|
onTap: isActionable && value != 'NA' ? onTap : null,
|
||||||
LauncherUtils.launchPhone(value);
|
onLongPress: isActionable && value != 'NA' ? onLongPress : null,
|
||||||
}
|
borderRadius: BorderRadius.circular(5),
|
||||||
}
|
child: Row(
|
||||||
|
|
||||||
void handleLongPress() {
|
|
||||||
if (value == 'NA') return;
|
|
||||||
LauncherUtils.copyToClipboard(value, typeLabel: label);
|
|
||||||
}
|
|
||||||
|
|
||||||
final valueWidget = GestureDetector(
|
|
||||||
onTap: (isEmail || isPhone) ? handleTap : null,
|
|
||||||
onLongPress: (isEmail || isPhone) ? handleLongPress : null,
|
|
||||||
child: Text(
|
|
||||||
value,
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.normal,
|
|
||||||
color: (isEmail || isPhone) ? Colors.indigo : Colors.black54,
|
|
||||||
fontSize: 14,
|
|
||||||
decoration: (isEmail || isPhone)
|
|
||||||
? TextDecoration.underline
|
|
||||||
: TextDecoration.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (isMultiLine) ...[
|
Container(
|
||||||
Text(
|
padding: const EdgeInsets.all(8),
|
||||||
label,
|
decoration: BoxDecoration(
|
||||||
style: const TextStyle(
|
color: contentTheme.primary.withOpacity(0.1),
|
||||||
fontWeight: FontWeight.bold,
|
borderRadius: BorderRadius.circular(5),
|
||||||
color: Colors.black87,
|
),
|
||||||
fontSize: 14,
|
child: Icon(
|
||||||
|
icon,
|
||||||
|
size: 20,
|
||||||
|
color: contentTheme.primary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
MySpacing.height(4),
|
MySpacing.width(16),
|
||||||
valueWidget,
|
Expanded(
|
||||||
] else
|
|
||||||
GestureDetector(
|
|
||||||
onTap: (isEmail || isPhone) ? handleTap : null,
|
|
||||||
onLongPress: (isEmail || isPhone) ? handleLongPress : null,
|
|
||||||
child: RichText(
|
|
||||||
text: TextSpan(
|
|
||||||
text: "$label: ",
|
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.black87,
|
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: value,
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.normal,
|
|
||||||
color:
|
|
||||||
(isEmail || isPhone) ? Colors.indigo : Colors.black54,
|
|
||||||
decoration: (isEmail || isPhone)
|
|
||||||
? TextDecoration.underline
|
|
||||||
: TextDecoration.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
MySpacing.height(10),
|
|
||||||
Divider(color: Colors.grey[300], height: 1),
|
|
||||||
MySpacing.height(10),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildInfoCard(employee) {
|
|
||||||
return Card(
|
|
||||||
elevation: 3,
|
|
||||||
shadowColor: Colors.black12,
|
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(12, 16, 12, 16),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
MySpacing.height(12),
|
Text(
|
||||||
_buildLabelValueRow('Email', _getDisplayValue(employee.email)),
|
label,
|
||||||
_buildLabelValueRow(
|
style: TextStyle(
|
||||||
'Phone Number', _getDisplayValue(employee.phoneNumber)),
|
fontSize: 12,
|
||||||
_buildLabelValueRow('Emergency Contact Person',
|
color: Colors.grey[600],
|
||||||
_getDisplayValue(employee.emergencyContactPerson)),
|
fontWeight: FontWeight.w500,
|
||||||
_buildLabelValueRow('Emergency Phone Number',
|
|
||||||
_getDisplayValue(employee.emergencyPhoneNumber)),
|
|
||||||
_buildLabelValueRow('Gender', _getDisplayValue(employee.gender)),
|
|
||||||
_buildLabelValueRow('Birth Date', _formatDate(employee.birthDate)),
|
|
||||||
_buildLabelValueRow(
|
|
||||||
'Joining Date', _formatDate(employee.joiningDate)),
|
|
||||||
_buildLabelValueRow(
|
|
||||||
'Current Address',
|
|
||||||
_getDisplayValue(employee.currentAddress),
|
|
||||||
isMultiLine: true,
|
|
||||||
),
|
),
|
||||||
_buildLabelValueRow(
|
|
||||||
'Permanent Address',
|
|
||||||
_getDisplayValue(employee.permanentAddress),
|
|
||||||
isMultiLine: true,
|
|
||||||
),
|
),
|
||||||
|
MySpacing.height(4),
|
||||||
|
Text(
|
||||||
|
value,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: isActionable && value != 'NA'
|
||||||
|
? contentTheme.primary
|
||||||
|
: Colors.black87,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
decoration: isActionable && value != 'NA'
|
||||||
|
? TextDecoration.underline
|
||||||
|
: TextDecoration.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (isActionable && value != 'NA')
|
||||||
|
Icon(
|
||||||
|
Icons.chevron_right,
|
||||||
|
color: Colors.grey[400],
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSectionCard({
|
||||||
|
required String title,
|
||||||
|
required IconData titleIcon,
|
||||||
|
required List<Widget> children,
|
||||||
|
}) {
|
||||||
|
return Card(
|
||||||
|
elevation: 2,
|
||||||
|
shadowColor: Colors.black12,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
titleIcon,
|
||||||
|
size: 20,
|
||||||
|
color: contentTheme.primary,
|
||||||
|
),
|
||||||
|
MySpacing.width(8),
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black87,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
MySpacing.height(8),
|
||||||
|
const Divider(),
|
||||||
|
...children,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -209,7 +192,7 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
|
|||||||
: null,
|
: null,
|
||||||
body: Obx(() {
|
body: Obx(() {
|
||||||
if (controller.isLoadingEmployeeDetails.value) {
|
if (controller.isLoadingEmployeeDetails.value) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return SkeletonLoaders.employeeDetailSkeletonLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
final employee = controller.selectedEmployeeDetails.value;
|
final employee = controller.selectedEmployeeDetails.value;
|
||||||
@ -228,14 +211,23 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
// Header Section
|
||||||
|
Card(
|
||||||
|
elevation: 2,
|
||||||
|
shadowColor: Colors.black12,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Avatar(
|
Avatar(
|
||||||
firstName: employee.firstName,
|
firstName: employee.firstName,
|
||||||
lastName: employee.lastName,
|
lastName: employee.lastName,
|
||||||
size: 45,
|
size: 45,
|
||||||
),
|
),
|
||||||
MySpacing.width(12),
|
MySpacing.width(16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -253,11 +245,11 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon:
|
icon: Icon(Icons.edit,
|
||||||
Icon(Icons.edit, size: 24, color: contentTheme.primary),
|
size: 24, color: contentTheme.primary),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final result =
|
final result = await showModalBottomSheet<
|
||||||
await showModalBottomSheet<Map<String, dynamic>>(
|
Map<String, dynamic>>(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
@ -274,55 +266,164 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
|
|||||||
'job_role_id': employee.jobRoleId,
|
'job_role_id': employee.jobRoleId,
|
||||||
'joining_date':
|
'joining_date':
|
||||||
employee.joiningDate?.toIso8601String(),
|
employee.joiningDate?.toIso8601String(),
|
||||||
'organization_id': employee.organizationId,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
controller.fetchEmployeeDetails(widget.employeeId);
|
controller
|
||||||
|
.fetchEmployeeDetails(widget.employeeId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
MySpacing.height(14),
|
),
|
||||||
_buildInfoCard(employee),
|
),
|
||||||
|
MySpacing.height(16),
|
||||||
|
|
||||||
|
// Contact Information Section
|
||||||
|
_buildSectionCard(
|
||||||
|
title: 'Contact Information',
|
||||||
|
titleIcon: Icons.contact_phone,
|
||||||
|
children: [
|
||||||
|
_buildDetailRow(
|
||||||
|
icon: Icons.email_outlined,
|
||||||
|
label: 'Email',
|
||||||
|
value: _getDisplayValue(employee.email),
|
||||||
|
isActionable: true,
|
||||||
|
onTap: () {
|
||||||
|
if (employee.email != null &&
|
||||||
|
employee.email.toString().trim().isNotEmpty) {
|
||||||
|
LauncherUtils.launchEmail(employee.email!);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
if (employee.email != null &&
|
||||||
|
employee.email.toString().trim().isNotEmpty) {
|
||||||
|
LauncherUtils.copyToClipboard(employee.email!,
|
||||||
|
typeLabel: 'Email');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_buildDetailRow(
|
||||||
|
icon: Icons.phone_outlined,
|
||||||
|
label: 'Phone Number',
|
||||||
|
value: _getDisplayValue(employee.phoneNumber),
|
||||||
|
isActionable: true,
|
||||||
|
onTap: () {
|
||||||
|
if (employee.phoneNumber.trim().isNotEmpty) {
|
||||||
|
LauncherUtils.launchPhone(employee.phoneNumber);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
if (employee.phoneNumber.trim().isNotEmpty) {
|
||||||
|
LauncherUtils.copyToClipboard(
|
||||||
|
employee.phoneNumber,
|
||||||
|
typeLabel: 'Phone Number',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
MySpacing.height(16),
|
||||||
|
|
||||||
|
// Emergency Contact Section
|
||||||
|
_buildSectionCard(
|
||||||
|
title: 'Emergency Contact',
|
||||||
|
titleIcon: Icons.emergency,
|
||||||
|
children: [
|
||||||
|
_buildDetailRow(
|
||||||
|
icon: Icons.person_outline,
|
||||||
|
label: 'Contact Person',
|
||||||
|
value:
|
||||||
|
_getDisplayValue(employee.emergencyContactPerson),
|
||||||
|
isActionable: false,
|
||||||
|
),
|
||||||
|
_buildDetailRow(
|
||||||
|
icon: Icons.phone_in_talk_outlined,
|
||||||
|
label: 'Emergency Phone',
|
||||||
|
value: _getDisplayValue(employee.emergencyPhoneNumber),
|
||||||
|
isActionable: true,
|
||||||
|
onTap: () {
|
||||||
|
if (employee.emergencyPhoneNumber != null &&
|
||||||
|
employee.emergencyPhoneNumber
|
||||||
|
.toString()
|
||||||
|
.trim()
|
||||||
|
.isNotEmpty) {
|
||||||
|
LauncherUtils.launchPhone(
|
||||||
|
employee.emergencyPhoneNumber!);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
if (employee.emergencyPhoneNumber != null &&
|
||||||
|
employee.emergencyPhoneNumber
|
||||||
|
.toString()
|
||||||
|
.trim()
|
||||||
|
.isNotEmpty) {
|
||||||
|
LauncherUtils.copyToClipboard(
|
||||||
|
employee.emergencyPhoneNumber!,
|
||||||
|
typeLabel: 'Emergency Phone');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
MySpacing.height(16),
|
||||||
|
|
||||||
|
// Personal Information Section
|
||||||
|
_buildSectionCard(
|
||||||
|
title: 'Personal Information',
|
||||||
|
titleIcon: Icons.person,
|
||||||
|
children: [
|
||||||
|
_buildDetailRow(
|
||||||
|
icon: Icons.wc_outlined,
|
||||||
|
label: 'Gender',
|
||||||
|
value: _getDisplayValue(employee.gender),
|
||||||
|
isActionable: false,
|
||||||
|
),
|
||||||
|
_buildDetailRow(
|
||||||
|
icon: Icons.cake_outlined,
|
||||||
|
label: 'Birth Date',
|
||||||
|
value: _formatDate(employee.birthDate),
|
||||||
|
isActionable: false,
|
||||||
|
),
|
||||||
|
_buildDetailRow(
|
||||||
|
icon: Icons.work_outline,
|
||||||
|
label: 'Joining Date',
|
||||||
|
value: _formatDate(employee.joiningDate),
|
||||||
|
isActionable: false,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
MySpacing.height(16),
|
||||||
|
|
||||||
|
// Address Information Section
|
||||||
|
_buildSectionCard(
|
||||||
|
title: 'Address Information',
|
||||||
|
titleIcon: Icons.location_on,
|
||||||
|
children: [
|
||||||
|
_buildDetailRow(
|
||||||
|
icon: Icons.home_outlined,
|
||||||
|
label: 'Current Address',
|
||||||
|
value: _getDisplayValue(employee.currentAddress),
|
||||||
|
isActionable: false,
|
||||||
|
),
|
||||||
|
_buildDetailRow(
|
||||||
|
icon: Icons.home_work_outlined,
|
||||||
|
label: 'Permanent Address',
|
||||||
|
value: _getDisplayValue(employee.permanentAddress),
|
||||||
|
isActionable: false,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
floatingActionButton: Obx(() {
|
|
||||||
if (!permissionController.hasPermission(Permissions.assignToProject)) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
if (controller.isLoadingEmployeeDetails.value ||
|
|
||||||
controller.selectedEmployeeDetails.value == null) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
final employee = controller.selectedEmployeeDetails.value!;
|
|
||||||
return FloatingActionButton.extended(
|
|
||||||
onPressed: () {
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
isScrollControlled: true,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
builder: (context) => AssignProjectBottomSheet(
|
|
||||||
employeeId: widget.employeeId,
|
|
||||||
jobRoleId: employee.jobRoleId,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
backgroundColor: contentTheme.primary,
|
|
||||||
icon: const Icon(Icons.assignment),
|
|
||||||
label: const Text(
|
|
||||||
'Assign to Project',
|
|
||||||
style: TextStyle(fontSize: 13, fontWeight: FontWeight.w500),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user