feat: Refactor employee detail navigation and add employee profile screen with tabbed interface

This commit is contained in:
Vaibhav Surve 2025-09-04 17:41:11 +05:30
parent 334023bf1b
commit 2133dedfae
4 changed files with 115 additions and 88 deletions

View File

@ -139,7 +139,7 @@ class _UserDocumentsPageState extends State<UserDocumentsPage> {
), ),
IconButton( IconButton(
icon: const Icon(Icons.arrow_forward_ios, color: Colors.black54), icon: const Icon(Icons.arrow_forward_ios, color: Colors.black54),
onPressed: () {/* future actions */}, onPressed: () {},
), ),
], ],
), ),
@ -257,14 +257,19 @@ class _UserDocumentsPageState extends State<UserDocumentsPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Conditionally show AppBar (example: hide if employee view)
final bool showAppBar = !widget.isEmployee;
return Scaffold( return Scaffold(
backgroundColor: const Color(0xFFF1F1F1), backgroundColor: const Color(0xFFF1F1F1),
appBar: CustomAppBar( appBar: showAppBar
? CustomAppBar(
title: 'Documents', title: 'Documents',
onBackPressed: () { onBackPressed: () {
Get.back(); Get.back();
}, },
), )
: null,
body: _buildBody(context), body: _buildBody(context),
floatingActionButton: FloatingActionButton.extended( floatingActionButton: FloatingActionButton.extended(
onPressed: () { onPressed: () {
@ -289,17 +294,13 @@ class _UserDocumentsPageState extends State<UserDocumentsPage> {
); );
if (success) { if (success) {
// Only close on success
Navigator.pop(context); Navigator.pop(context);
// Refresh list
docController.fetchDocuments( docController.fetchDocuments(
entityTypeId: entityTypeId, entityTypeId: entityTypeId,
entityId: resolvedEntityId, entityId: resolvedEntityId,
reset: true, reset: true,
); );
} else { } else {
// Dont close, show error
Get.snackbar("Error", "Upload failed, please try again"); Get.snackbar("Error", "Upload failed, please try again");
} }
}, },

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:marco/controller/employee/employees_screen_controller.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/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';
@ -15,6 +15,7 @@ import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
class EmployeeDetailPage extends StatefulWidget { class EmployeeDetailPage extends StatefulWidget {
final String employeeId; final String employeeId;
final bool fromProfile; final bool fromProfile;
const EmployeeDetailPage({ const EmployeeDetailPage({
super.key, super.key,
required this.employeeId, required this.employeeId,
@ -30,6 +31,7 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
Get.put(EmployeesScreenController()); Get.put(EmployeesScreenController());
final PermissionController _permissionController = final PermissionController _permissionController =
Get.find<PermissionController>(); Get.find<PermissionController>();
@override @override
void initState() { void initState() {
super.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, Widget _buildLabelValueRow(String label, String value,
{bool isMultiLine = false}) { {bool isMultiLine = false}) {
final lowerLabel = label.toLowerCase(); final lowerLabel = label.toLowerCase();
@ -91,9 +92,8 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
color: (isEmail || isPhone) ? Colors.indigo : Colors.black54, color: (isEmail || isPhone) ? Colors.indigo : Colors.black54,
fontSize: 14, fontSize: 14,
decoration: (isEmail || isPhone) decoration:
? TextDecoration.underline (isEmail || isPhone) ? TextDecoration.underline : TextDecoration.none,
: TextDecoration.none,
), ),
), ),
); );
@ -147,7 +147,6 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
); );
} }
/// Info card
Widget _buildInfoCard(employee) { Widget _buildInfoCard(employee) {
return Card( return Card(
elevation: 3, elevation: 3,
@ -188,73 +187,22 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final bool showAppBar = !widget.fromProfile;
return Scaffold( return Scaffold(
backgroundColor: const Color(0xFFF1F1F1), backgroundColor: const Color(0xFFF1F1F1),
appBar: PreferredSize( appBar: showAppBar
preferredSize: const Size.fromHeight(72), ? CustomAppBar(
child: AppBar( title: 'Employee Details',
backgroundColor: const Color(0xFFF5F5F5), onBackPressed: () {
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) { if (widget.fromProfile) {
Get.back(); Get.back();
} else { } else {
Get.offNamed('/dashboard/employees'); Get.offNamed('/dashboard/employees');
} }
}, },
), )
MySpacing.width(8), : null,
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],
),
),
],
);
},
),
],
),
),
],
),
),
),
),
body: Obx(() { body: Obx(() {
if (controller.isLoadingEmployeeDetails.value) { if (controller.isLoadingEmployeeDetails.value) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());

View 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,
),
],
),
),
],
),
);
}
}

View File

@ -9,10 +9,9 @@ import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/avatar.dart'; import 'package:marco/helpers/widgets/avatar.dart';
import 'package:marco/model/employees/employee_info.dart'; import 'package:marco/model/employees/employee_info.dart';
import 'package:marco/controller/auth/mpin_controller.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'; import 'package:marco/view/document/user_document_screen.dart';
class UserProfileBar extends StatefulWidget { class UserProfileBar extends StatefulWidget {
final bool isCondensed; final bool isCondensed;
const UserProfileBar({Key? key, this.isCondensed = false}) : super(key: key); const UserProfileBar({Key? key, this.isCondensed = false}) : super(key: key);
@ -246,9 +245,8 @@ class _UserProfileBarState extends State<UserProfileBar>
} }
void _onProfileTap() { void _onProfileTap() {
Get.to(() => EmployeeDetailPage( Get.to(() => EmployeeProfilePage(
employeeId: employeeInfo.id, employeeId: employeeInfo.id,
fromProfile: true,
)); ));
} }