From 422ec9a6e1444e95d591f88e6ad567bad5ee5e77 Mon Sep 17 00:00:00 2001 From: Aiman Hafiz <121177088+RoninBonin@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:06:48 +0800 Subject: [PATCH] Added Profile page and improved UI for list items --- lib/screens/profile/profile_screen.dart | 162 ++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 lib/screens/profile/profile_screen.dart diff --git a/lib/screens/profile/profile_screen.dart b/lib/screens/profile/profile_screen.dart new file mode 100644 index 0000000..12bdd13 --- /dev/null +++ b/lib/screens/profile/profile_screen.dart @@ -0,0 +1,162 @@ +import 'package:flutter/material.dart'; +import 'package:inventory_system/screens/bottom_nav_bar.dart'; +import 'package:inventory_system/screens/title_bar.dart'; +import 'package:inventory_system/services/auth_service.dart'; +import 'package:inventory_system/screens/nav_bar.dart'; +import 'package:inventory_system/services/session_manager.dart'; + +class ProfileScreen extends StatefulWidget { + const ProfileScreen({super.key}); + + @override + State createState() => _ProfileScreenState(); +} + +class _ProfileScreenState extends State { + final AuthService _authService = AuthService(); + late Future> _userProfileFuture; + + @override + void initState() { + super.initState(); + _userProfileFuture = _authService.fetchUserProfile(); + } + + @override + Widget build(BuildContext context) { + final isAdmin = SessionManager.instance.currentUser?['isAdmin'] ?? false; + + return Scaffold( + backgroundColor: const Color(0xFFF5F5F7), + appBar: const TitleBar(title: 'Profile'), + drawer: NavBar(isAdmin: isAdmin, selectedScreen: AppScreen.profile), + body: FutureBuilder>( + future: _userProfileFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } + if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); + } + + final data = snapshot.data; + if (data == null || data['success'] != true) { + return Center(child: Text(data?['message'] ?? 'Failed to load profile')); + } + + final userInfo = data['data']; + + return SingleChildScrollView( + padding: const EdgeInsets.all(24.0), + child: Column( + children: [ + const SizedBox(height: 20), + // Avatar + Container( + width: 100, + height: 100, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 10, + offset: const Offset(0, 5), + ), + ], + ), + child: const Icon(Icons.person, size: 60, color: Colors.grey), + ), + const SizedBox(height: 30), + + _buildInfoCard(userInfo), + ], + ), + ); + }, + ), + bottomNavigationBar: BottomNavBar( + selectedIndex: 2, + onItemTapped: (index) { + // Handled by BottomNavBar internal logic + }, + ), + ); + } + + Widget _buildInfoCard(Map user) { + final email = user['email'] ?? 'N/A'; + final company = user['company'] ?? 'N/A'; + final departmentObj = user['department']; + String deptName = 'N/A'; + if (departmentObj != null) { + deptName = departmentObj['departmentName'] ?? 'N/A'; + } + final roles = user['role'] as List?; + final roleStr = roles?.join(', ') ?? 'N/A'; + + return Container( + width: double.infinity, + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 15, + offset: const Offset(0, 5), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildInfoRow('Email', email, Icons.email_outlined), + const Divider(height: 32), + _buildInfoRow('Company', company, Icons.business_outlined), + const Divider(height: 32), + _buildInfoRow('Department', deptName, Icons.meeting_room_outlined), + const Divider(height: 32), + _buildInfoRow('Role', roleStr, Icons.admin_panel_settings_outlined), + ], + ), + ); + } + + Widget _buildInfoRow(String label, String value, IconData icon) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(icon, color: Colors.blue.shade700, size: 24), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade500, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 4), + Text( + value, + style: const TextStyle( + fontSize: 16, + color: Colors.black87, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ], + ); + } +}