/// Account Page /// /// Displays user account information and settings menu. /// Features: /// - User profile card with avatar, name, role, tier, and phone /// - Account menu section (personal info, orders, addresses, etc.) /// - Support section (contact, FAQ, about) /// - Logout button library; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:worker/core/constants/ui_constants.dart'; import 'package:worker/core/database/hive_initializer.dart'; import 'package:worker/core/database/models/enums.dart'; import 'package:worker/core/router/app_router.dart'; import 'package:worker/core/theme/colors.dart'; import 'package:worker/features/account/domain/entities/user_info.dart' as domain; import 'package:worker/features/account/presentation/providers/user_info_provider.dart' hide UserInfo; import 'package:worker/features/account/presentation/widgets/account_menu_item.dart'; import 'package:worker/features/auth/presentation/providers/auth_provider.dart'; /// Account Page /// /// Main account/settings page accessible from the bottom navigation bar. class AccountPage extends ConsumerWidget { const AccountPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final userInfoAsync = ref.watch(userInfoProvider); return Scaffold( backgroundColor: const Color(0xFFF4F6F8), body: SafeArea( child: userInfoAsync.when( loading: () => const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(color: AppColors.primaryBlue), SizedBox(height: AppSpacing.md), Text( 'Đang tải thông tin...', style: TextStyle( fontSize: 14, color: AppColors.grey500, ), ), ], ), ), error: (error, stack) => Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const FaIcon( FontAwesomeIcons.circleExclamation, size: 64, color: AppColors.danger, ), const SizedBox(height: AppSpacing.lg), const Text( 'Không thể tải thông tin tài khoản', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, ), textAlign: TextAlign.center, ), const SizedBox(height: AppSpacing.md), Text( error.toString(), style: const TextStyle( fontSize: 14, color: AppColors.grey500, ), textAlign: TextAlign.center, ), const SizedBox(height: AppSpacing.lg), ElevatedButton.icon( onPressed: () => ref.read(userInfoProvider.notifier).refresh(), icon: const FaIcon(FontAwesomeIcons.arrowsRotate, size: 16), label: const Text('Thử lại'), style: ElevatedButton.styleFrom( backgroundColor: AppColors.primaryBlue, foregroundColor: AppColors.white, ), ), ], ), ), data: (userInfo) => RefreshIndicator( onRefresh: () async { await ref.read(userInfoProvider.notifier).refresh(); }, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: Column( spacing: AppSpacing.md, children: [ // Simple Header _buildHeader(), // User Profile Card with API data _buildProfileCard(context, userInfo), // Account Menu Section _buildAccountMenu(context), // Support Section _buildSupportSection(context), // Logout Button _buildLogoutButton(context, ref), const SizedBox(height: AppSpacing.lg), ], ), ), ), ), ), ); } /// Build simple header with title Widget _buildHeader() { return Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), decoration: BoxDecoration( color: Colors.white, boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: const Text( 'Tài khoản', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFF212121), ), ), ); } /// Build user profile card with avatar and info Widget _buildProfileCard( BuildContext context, domain.UserInfo userInfo, ) { return Container( margin: const EdgeInsets.symmetric(horizontal: AppSpacing.md), padding: const EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(AppRadius.card), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Row( children: [ // Avatar with API data or gradient fallback userInfo.avatarUrl != null ? ClipOval( child: CachedNetworkImage( imageUrl: userInfo.avatarUrl!, width: 80, height: 80, fit: BoxFit.cover, placeholder: (context, url) => Container( width: 80, height: 80, decoration: const BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( colors: [Color(0xFF005B9A), Color(0xFF38B6FF)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: const Center( child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ), ), errorWidget: (context, url, error) => Container( width: 80, height: 80, decoration: const BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( colors: [Color(0xFF005B9A), Color(0xFF38B6FF)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Center( child: Text( userInfo.initials, style: const TextStyle( color: Colors.white, fontSize: 32, fontWeight: FontWeight.w700, ), ), ), ), ), ) : Container( width: 80, height: 80, decoration: const BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( colors: [Color(0xFF005B9A), Color(0xFF38B6FF)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Center( child: Text( userInfo.initials, style: const TextStyle( color: Colors.white, fontSize: 32, fontWeight: FontWeight.w700, ), ), ), ), const SizedBox(width: AppSpacing.md), // User info from API Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, spacing: AppSpacing.xs, children: [ Text( userInfo.fullName, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColors.grey900, ), ), Text( '${_getRoleDisplayName(userInfo.role)} · Hạng ${userInfo.tierDisplayName}', style: const TextStyle( fontSize: 13, color: AppColors.grey500, ), ), if (userInfo.phoneNumber != null) Text( userInfo.phoneNumber!, style: const TextStyle( fontSize: 13, color: AppColors.primaryBlue, ), ), ], ), ), ], ), ); } /// Build account menu section Widget _buildAccountMenu(BuildContext context) { return Container( margin: const EdgeInsets.symmetric(horizontal: AppSpacing.md), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(AppRadius.card), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( children: [ AccountMenuItem( icon: FontAwesomeIcons.penToSquare, title: 'Thông tin cá nhân', subtitle: 'Cập nhật thông tin tài khoản', onTap: () { context.push(RouteNames.profile); }, ), AccountMenuItem( icon: FontAwesomeIcons.clockRotateLeft, title: 'Lịch sử đơn hàng', subtitle: 'Xem các đơn hàng đã đặt', onTap: () { context.push(RouteNames.orders); }, ), AccountMenuItem( icon: FontAwesomeIcons.locationDot, title: 'Địa chỉ đã lưu', subtitle: 'Quản lý địa chỉ giao hàng', onTap: () { context.push(RouteNames.addresses); }, ), AccountMenuItem( icon: FontAwesomeIcons.bell, title: 'Cài đặt thông báo', subtitle: 'Quản lý thông báo đẩy', onTap: () { _showComingSoon(context); }, ), AccountMenuItem( icon: FontAwesomeIcons.lock, title: 'Đổi mật khẩu', subtitle: 'Cập nhật mật khẩu mới', onTap: () { context.push(RouteNames.changePassword); }, ), AccountMenuItem( icon: FontAwesomeIcons.language, title: 'Ngôn ngữ', subtitle: 'Tiếng Việt', onTap: () { _showComingSoon(context); }, ), ], ), ); } /// Build support section Widget _buildSupportSection(BuildContext context) { return Container( margin: const EdgeInsets.symmetric(horizontal: AppSpacing.md), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(AppRadius.card), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Section title Padding( padding: const EdgeInsets.fromLTRB( AppSpacing.md, AppSpacing.md, AppSpacing.md, AppSpacing.sm, ), child: const Text( 'Hỗ trợ', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColors.grey900, ), ), ), // Support menu items AccountMenuItem( icon: FontAwesomeIcons.headset, title: 'Liên hệ hỗ trợ', subtitle: 'Hotline: 1900 1234', trailing: const FaIcon( FontAwesomeIcons.phone, size: 18, color: AppColors.grey500, ), onTap: () { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Hotline: 1900 1234'), duration: Duration(seconds: 2), ), ); }, ), AccountMenuItem( icon: FontAwesomeIcons.circleQuestion, title: 'Câu hỏi thường gặp', onTap: () { _showComingSoon(context); }, ), AccountMenuItem( icon: FontAwesomeIcons.circleInfo, title: 'Về ứng dụng', subtitle: 'Phiên bản 1.0.0', onTap: () { _showAboutDialog(context); }, ), ], ), ); } /// Build logout button Widget _buildLogoutButton(BuildContext context, WidgetRef ref) { return Container( margin: const EdgeInsets.symmetric(horizontal: AppSpacing.md), width: double.infinity, child: OutlinedButton.icon( onPressed: () { _showLogoutConfirmation(context, ref); }, icon: const FaIcon(FontAwesomeIcons.arrowRightFromBracket, size: 18), label: const Text('Đăng xuất'), style: OutlinedButton.styleFrom( foregroundColor: AppColors.danger, side: const BorderSide(color: AppColors.danger, width: 1.5), padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppRadius.button), ), ), ), ); } /// Show coming soon message void _showComingSoon(BuildContext context) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Tính năng đang phát triển'), duration: Duration(seconds: 1), ), ); } /// Show about dialog void _showAboutDialog(BuildContext context) { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Về ứng dụng'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'EuroTile & Vasta Stone Worker', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), ), const SizedBox(height: 8), const Text('Phiên bản: 1.0.0'), const SizedBox(height: 8), Text( 'Ứng dụng dành cho thầu thợ, kiến trúc sư, đại lý và môi giới trong ngành gạch ốp lát và nội thất.', style: TextStyle(fontSize: 14, color: AppColors.grey500), ), ], ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Đóng'), ), ], ), ); } /// Show logout confirmation dialog void _showLogoutConfirmation(BuildContext context, WidgetRef ref) { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Đăng xuất'), content: const Text('Bạn có chắc chắn muốn đăng xuất?'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Hủy'), ), TextButton( onPressed: () => _performLogout(context, ref), style: TextButton.styleFrom(foregroundColor: AppColors.danger), child: const Text('Đăng xuất'), ), ], ), ); } /// Perform logout operation /// /// Handles the complete logout process: /// 1. Close confirmation dialog /// 2. Show loading indicator /// 3. Clear Hive local data /// 4. Call auth provider logout (clears session, gets new public session) /// 5. Navigate to login screen (handled by router redirect) /// 6. Show success message Future _performLogout(BuildContext context, WidgetRef ref) async { // Close confirmation dialog Navigator.of(context).pop(); // Show loading dialog showDialog( context: context, barrierDismissible: false, builder: (context) => const Center( child: Card( child: Padding( padding: EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, children: [ CircularProgressIndicator(), SizedBox(height: 16), Text('Đang đăng xuất...'), ], ), ), ), ), ); try { // Clear Hive local data (cart, favorites, cached data) await HiveInitializer.logout(); // Call auth provider logout // This will: // - Clear FlutterSecureStorage session // - Clear FrappeAuthService session // - Get new public session for login/registration // - Update auth state to null (logged out) await ref.read(authProvider.notifier).logout(); // Close loading dialog if (context.mounted) { Navigator.of(context).pop(); } // Show success message if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Đã đăng xuất thành công'), duration: Duration(seconds: 2), backgroundColor: AppColors.success, ), ); } // Navigation to login screen is handled automatically by GoRouter redirect // when auth state becomes null } catch (e) { // Close loading dialog if (context.mounted) { Navigator.of(context).pop(); } // Show error message if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Lỗi đăng xuất: ${e.toString()}'), duration: const Duration(seconds: 3), backgroundColor: AppColors.danger, ), ); } } } /// Get Vietnamese display name for user role String _getRoleDisplayName(UserRole role) { switch (role) { case UserRole.customer: return 'Khách hàng'; case UserRole.distributor: return 'Đại lý phân phối'; case UserRole.admin: return 'Quản trị viên'; case UserRole.staff: return 'Nhân viên'; } } }