feat: Refactor employee detail navigation and add employee profile screen with tabbed interface
This commit is contained in:
parent
334023bf1b
commit
2133dedfae
@ -139,7 +139,7 @@ class _UserDocumentsPageState extends State<UserDocumentsPage> {
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_forward_ios, color: Colors.black54),
|
||||
onPressed: () {/* future actions */},
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -257,14 +257,19 @@ class _UserDocumentsPageState extends State<UserDocumentsPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Conditionally show AppBar (example: hide if employee view)
|
||||
final bool showAppBar = !widget.isEmployee;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF1F1F1),
|
||||
appBar: CustomAppBar(
|
||||
title: 'Documents',
|
||||
onBackPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
appBar: showAppBar
|
||||
? CustomAppBar(
|
||||
title: 'Documents',
|
||||
onBackPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
)
|
||||
: null,
|
||||
body: _buildBody(context),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
@ -289,17 +294,13 @@ class _UserDocumentsPageState extends State<UserDocumentsPage> {
|
||||
);
|
||||
|
||||
if (success) {
|
||||
// ✅ Only close on success
|
||||
Navigator.pop(context);
|
||||
|
||||
// Refresh list
|
||||
docController.fetchDocuments(
|
||||
entityTypeId: entityTypeId,
|
||||
entityId: resolvedEntityId,
|
||||
reset: true,
|
||||
);
|
||||
} else {
|
||||
// ❌ Don’t close, show error
|
||||
Get.snackbar("Error", "Upload failed, please try again");
|
||||
}
|
||||
},
|
||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:marco/controller/employee/employees_screen_controller.dart';
|
||||
import 'package:marco/controller/project_controller.dart';
|
||||
import 'package:marco/helpers/widgets/custom_app_bar.dart';
|
||||
import 'package:marco/helpers/widgets/avatar.dart';
|
||||
import 'package:marco/helpers/widgets/my_spacing.dart';
|
||||
import 'package:marco/helpers/widgets/my_text.dart';
|
||||
@ -15,6 +15,7 @@ import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
|
||||
class EmployeeDetailPage extends StatefulWidget {
|
||||
final String employeeId;
|
||||
final bool fromProfile;
|
||||
|
||||
const EmployeeDetailPage({
|
||||
super.key,
|
||||
required this.employeeId,
|
||||
@ -30,6 +31,7 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
|
||||
Get.put(EmployeesScreenController());
|
||||
final PermissionController _permissionController =
|
||||
Get.find<PermissionController>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -60,7 +62,6 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Row builder with email/phone tap & copy support
|
||||
Widget _buildLabelValueRow(String label, String value,
|
||||
{bool isMultiLine = false}) {
|
||||
final lowerLabel = label.toLowerCase();
|
||||
@ -91,9 +92,8 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
|
||||
fontWeight: FontWeight.normal,
|
||||
color: (isEmail || isPhone) ? Colors.indigo : Colors.black54,
|
||||
fontSize: 14,
|
||||
decoration: (isEmail || isPhone)
|
||||
? TextDecoration.underline
|
||||
: TextDecoration.none,
|
||||
decoration:
|
||||
(isEmail || isPhone) ? TextDecoration.underline : TextDecoration.none,
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -147,7 +147,6 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
|
||||
);
|
||||
}
|
||||
|
||||
/// Info card
|
||||
Widget _buildInfoCard(employee) {
|
||||
return Card(
|
||||
elevation: 3,
|
||||
@ -188,73 +187,22 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bool showAppBar = !widget.fromProfile;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF1F1F1),
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(72),
|
||||
child: AppBar(
|
||||
backgroundColor: const Color(0xFFF5F5F5),
|
||||
elevation: 0.5,
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 0,
|
||||
title: Padding(
|
||||
padding: MySpacing.xy(16, 0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios_new,
|
||||
color: Colors.black, size: 20),
|
||||
onPressed: () {
|
||||
if (widget.fromProfile) {
|
||||
Get.back();
|
||||
} else {
|
||||
Get.offNamed('/dashboard/employees');
|
||||
}
|
||||
},
|
||||
),
|
||||
MySpacing.width(8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
MyText.titleLarge(
|
||||
'Employee Details',
|
||||
fontWeight: 700,
|
||||
color: Colors.black,
|
||||
),
|
||||
MySpacing.height(2),
|
||||
GetBuilder<ProjectController>(
|
||||
builder: (projectController) {
|
||||
final projectName =
|
||||
projectController.selectedProject?.name ??
|
||||
'Select Project';
|
||||
return Row(
|
||||
children: [
|
||||
const Icon(Icons.work_outline,
|
||||
size: 14, color: Colors.grey),
|
||||
MySpacing.width(4),
|
||||
Expanded(
|
||||
child: MyText.bodySmall(
|
||||
projectName,
|
||||
fontWeight: 600,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
appBar: showAppBar
|
||||
? CustomAppBar(
|
||||
title: 'Employee Details',
|
||||
onBackPressed: () {
|
||||
if (widget.fromProfile) {
|
||||
Get.back();
|
||||
} else {
|
||||
Get.offNamed('/dashboard/employees');
|
||||
}
|
||||
},
|
||||
)
|
||||
: null,
|
||||
body: Obx(() {
|
||||
if (controller.isLoadingEmployeeDetails.value) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
|
80
lib/view/employees/employee_profile_screen.dart
Normal file
80
lib/view/employees/employee_profile_screen.dart
Normal file
@ -0,0 +1,80 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:marco/view/employees/employee_detail_screen.dart';
|
||||
import 'package:marco/view/document/user_document_screen.dart';
|
||||
import 'package:marco/helpers/widgets/custom_app_bar.dart';
|
||||
|
||||
class EmployeeProfilePage extends StatefulWidget {
|
||||
final String employeeId;
|
||||
|
||||
const EmployeeProfilePage({super.key, required this.employeeId});
|
||||
|
||||
@override
|
||||
State<EmployeeProfilePage> createState() => _EmployeeProfilePageState();
|
||||
}
|
||||
|
||||
class _EmployeeProfilePageState extends State<EmployeeProfilePage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late TabController _tabController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_tabController = TabController(length: 2, vsync: this);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF1F1F1),
|
||||
appBar: CustomAppBar(
|
||||
title: "Employee Profile",
|
||||
onBackPressed: () => Get.back(),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
// ---------------- TabBar outside AppBar ----------------
|
||||
Container(
|
||||
color: Colors.white,
|
||||
child: TabBar(
|
||||
controller: _tabController,
|
||||
labelColor: Colors.black,
|
||||
unselectedLabelColor: Colors.grey,
|
||||
indicatorColor: Colors.red,
|
||||
tabs: const [
|
||||
Tab(text: "Details"),
|
||||
Tab(text: "Documents"),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// ---------------- TabBarView ----------------
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: _tabController,
|
||||
children: [
|
||||
// Details Tab
|
||||
EmployeeDetailPage(
|
||||
employeeId: widget.employeeId,
|
||||
fromProfile: true,
|
||||
),
|
||||
|
||||
// Documents Tab
|
||||
UserDocumentsPage(
|
||||
entityId: widget.employeeId,
|
||||
isEmployee: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -9,10 +9,9 @@ import 'package:marco/helpers/widgets/my_text.dart';
|
||||
import 'package:marco/helpers/widgets/avatar.dart';
|
||||
import 'package:marco/model/employees/employee_info.dart';
|
||||
import 'package:marco/controller/auth/mpin_controller.dart';
|
||||
import 'package:marco/view/employees/employee_detail_screen.dart';
|
||||
import 'package:marco/view/employees/employee_profile_screen.dart';
|
||||
import 'package:marco/view/document/user_document_screen.dart';
|
||||
|
||||
|
||||
class UserProfileBar extends StatefulWidget {
|
||||
final bool isCondensed;
|
||||
const UserProfileBar({Key? key, this.isCondensed = false}) : super(key: key);
|
||||
@ -182,7 +181,7 @@ class _UserProfileBarState extends State<UserProfileBar>
|
||||
_menuItemRow(
|
||||
icon: LucideIcons.file_text,
|
||||
label: 'My Documents',
|
||||
onTap: _onDocumentsTap,
|
||||
onTap: _onDocumentsTap,
|
||||
),
|
||||
SizedBox(height: spacingHeight),
|
||||
_menuItemRow(
|
||||
@ -246,15 +245,14 @@ class _UserProfileBarState extends State<UserProfileBar>
|
||||
}
|
||||
|
||||
void _onProfileTap() {
|
||||
Get.to(() => EmployeeDetailPage(
|
||||
Get.to(() => EmployeeProfilePage(
|
||||
employeeId: employeeInfo.id,
|
||||
fromProfile: true,
|
||||
));
|
||||
}
|
||||
|
||||
void _onDocumentsTap() {
|
||||
Get.to(() => UserDocumentsPage(
|
||||
entityId: "${employeeInfo.id}",
|
||||
entityId: "${employeeInfo.id}",
|
||||
isEmployee: true,
|
||||
));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user