import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; import 'package:qpay/screens/accounts/account_provider.dart'; import 'package:qpay/screens/accounts/models/account_model.dart'; import 'package:shared_preferences/shared_preferences.dart'; class AccountBalanceWidget extends StatefulWidget { final String? selectedCurrency; final ValueChanged? onCurrencySelected; const AccountBalanceWidget({ super.key, this.selectedCurrency, this.onCurrencySelected, }); @override State createState() => _AccountBalanceWidgetState(); } class _AccountBalanceWidgetState extends State { late AccountProvider _accountProvider; bool _isLoggedIn = false; String? _phoneNumber; AccountModel? _usdAccount; AccountModel? _zwgAccount; bool _isLoadingUsd = false; bool _isLoadingZwG = false; String? _usdError; String? _zwgError; @override void initState() { super.initState(); _accountProvider = AccountProvider(); _loadAuthStateAndBalances(); } @override void dispose() { _accountProvider.dispose(); super.dispose(); } Future _loadAuthStateAndBalances() async { final prefs = await SharedPreferences.getInstance(); // Determine login state from persisted token if (prefs.getString("token") != null) { setState(() { _isLoggedIn = true; }); } _phoneNumber = prefs.getString('phone'); if (_phoneNumber == null || _phoneNumber!.isEmpty) { return; } setState(() { _isLoadingUsd = true; _isLoadingZwG = true; }); // Fetch USD balance final usdResult = await _accountProvider.fetchAccount( 'USD$_phoneNumber', ); if (mounted) { setState(() { _isLoadingUsd = false; if (usdResult.isSuccess && usdResult.data != null) { _usdAccount = usdResult.data; _usdError = null; } else { _usdError = usdResult.error; } }); } // Fetch ZWG balance final zwgResult = await _accountProvider.fetchAccount( 'ZWG$_phoneNumber', ); if (mounted) { setState(() { _isLoadingZwG = false; if (zwgResult.isSuccess && zwgResult.data != null) { _zwgAccount = zwgResult.data; _zwgError = null; } else { _zwgError = zwgResult.error; } }); } // If both fetches failed, mark as not logged in if (mounted && !usdResult.isSuccess && !zwgResult.isSuccess && _isLoggedIn) { setState(() { _isLoggedIn = false; }); } } Future _refreshBalances() async { final prefs = await SharedPreferences.getInstance(); _phoneNumber = prefs.getString('phone'); if (_phoneNumber == null || _phoneNumber!.isEmpty) return; setState(() { _isLoadingUsd = true; _isLoadingZwG = true; }); final usdResult = await _accountProvider.fetchAccount( 'USD$_phoneNumber', ); if (mounted) { setState(() { _isLoadingUsd = false; if (usdResult.isSuccess && usdResult.data != null) { _usdAccount = usdResult.data; _usdError = null; } else { _usdError = usdResult.error; } }); } final zwgResult = await _accountProvider.fetchAccount( 'ZWG$_phoneNumber', ); if (mounted) { setState(() { _isLoadingZwG = false; if (zwgResult.isSuccess && zwgResult.data != null) { _zwgAccount = zwgResult.data; _zwgError = null; } else { _zwgError = zwgResult.error; } }); } if (mounted && !usdResult.isSuccess && !zwgResult.isSuccess && _isLoggedIn) { setState(() { _isLoggedIn = false; }); } } @override Widget build(BuildContext context) { final theme = Theme.of(context); final isDark = theme.brightness == Brightness.dark; if (!_isLoggedIn) { return _buildLoginPrompt(theme, isDark); } if (_phoneNumber == null || _phoneNumber!.isEmpty) { return const SizedBox.shrink(); } return Padding( padding: const EdgeInsets.only(bottom: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: _buildCompactCard( theme: theme, isDark: isDark, currencyCode: 'USD', flagAsset: 'united-states.png', balance: _usdAccount?.balance, isLoading: _isLoadingUsd, error: _usdError, isSelected: widget.selectedCurrency == 'USD', gradientColors: [ const Color(0xFF0D47A1), const Color(0xFF1976D2), ], ), ), const SizedBox(width: 10), Expanded( child: _buildCompactCard( theme: theme, isDark: isDark, currencyCode: 'ZWG', flagAsset: 'zimbabwe.png', balance: _zwgAccount?.balance, isLoading: _isLoadingZwG, error: _zwgError, isSelected: widget.selectedCurrency == 'ZWG', gradientColors: [ const Color(0xFF1B5E20), const Color(0xFF388E3C), ], ), ), ], ), const SizedBox(height: 6), Center( child: TextButton.icon( onPressed: _isLoadingUsd || _isLoadingZwG ? null : () { _refreshBalances(); }, icon: Icon( Icons.refresh_rounded, size: 14, color: _isLoadingUsd || _isLoadingZwG ? (isDark ? Colors.white24 : Colors.grey.shade400) : theme.colorScheme.primary, ), label: Text( _isLoadingUsd || _isLoadingZwG ? 'Refreshing...' : 'Refresh', style: TextStyle( fontSize: 11, fontWeight: FontWeight.w600, color: _isLoadingUsd || _isLoadingZwG ? (isDark ? Colors.white24 : Colors.grey.shade400) : theme.colorScheme.primary, ), ), style: TextButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), minimumSize: Size.zero, tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), ), ), ], ), ); } // ────────────────────────────────────────────────────────────── // Login Prompt // ────────────────────────────────────────────────────────────── Widget _buildLoginPrompt(ThemeData theme, bool isDark) { return Padding( padding: const EdgeInsets.only(bottom: 12), child: Container( width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 14, horizontal: 18), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ theme.colorScheme.primary.withValues(alpha: 0.12), theme.colorScheme.primary.withValues(alpha: 0.04), ], ), borderRadius: BorderRadius.circular(16), border: Border.all( color: theme.colorScheme.primary.withValues(alpha: 0.15), width: 1, ), ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Register or Login for more features', style: TextStyle( fontSize: 14, color: isDark ? Colors.white : Colors.black87, ), ), ], ), ), ElevatedButton( onPressed: () { context.push('/onboarding/landing'); }, style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primary, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), elevation: 0, ), child: const Text( 'Get Started', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600), ), ), ], ), ), ); } Widget _buildCompactCard({ required ThemeData theme, required bool isDark, required String currencyCode, required String flagAsset, double? balance, required bool isLoading, String? error, required bool isSelected, required List gradientColors, }) { return GestureDetector( onTap: () { widget.onCurrencySelected?.call(currencyCode); }, child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.all(12), decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), gradient: LinearGradient( colors: gradientColors, begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( color: gradientColors[0].withValues(alpha: isSelected ? 0.5 : 0.25), blurRadius: isSelected ? 12 : 6, offset: Offset(0, isSelected ? 4 : 2), ), ], border: isSelected ? Border.all( color: Colors.white.withValues(alpha: 0.8), width: 2, ) : Border.all( color: Colors.white.withValues(alpha: 0.15), width: 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ // Top row: flag + currency code Row( children: [ Container( width: 22, height: 22, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: Colors.white.withValues(alpha: 0.3), width: 1.5, ), ), child: ClipOval( child: Image.asset( 'assets/$flagAsset', fit: BoxFit.cover, errorBuilder: (_, __, ___) => Icon( Icons.monetization_on_outlined, size: 12, color: Colors.white.withValues(alpha: 0.8), ), ), ), ), const SizedBox(width: 6), Expanded( child: Text( currencyCode, style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w700, color: Colors.white, letterSpacing: 0.5, ), ), ), if (isSelected) Container( width: 18, height: 18, decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.3), shape: BoxShape.circle, ), child: const Icon( Icons.check_rounded, size: 12, color: Colors.white, ), ), ], ), const SizedBox(height: 10), // Balance amount if (isLoading) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 70, height: 12, decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(4), ), ), ], ) else if (error != null) Row( children: [ Icon( Icons.error_outline_rounded, color: Colors.white.withValues(alpha: 0.7), size: 16, ), const SizedBox(width: 4), Text( 'Unavailable', style: TextStyle( fontSize: 10, fontWeight: FontWeight.w500, color: Colors.white.withValues(alpha: 0.7), ), ), ], ) else ...[ Text( _formatBalance(balance ?? 0.0), style: const TextStyle( fontSize: 17, fontWeight: FontWeight.w800, color: Colors.white, letterSpacing: 0.5, height: 1.1, ), ), ], ], ), ), ); } String _formatBalance(double balance) { final formatter = NumberFormat('#,##0.00', 'en_US'); return '\$${formatter.format(balance)}'; } }