updated branding & added analytics
This commit is contained in:
@@ -59,6 +59,7 @@ class AccountProvider extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
return ApiResponse.failure(_accountError!);
|
||||
} catch (e, s) {
|
||||
logger.e(e);
|
||||
logger.e(s);
|
||||
_isLoadingAccount = false;
|
||||
_accountError = 'An unexpected error occurred. Please try again.';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
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';
|
||||
@@ -21,19 +22,21 @@ class AccountBalanceWidget extends StatefulWidget {
|
||||
class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
|
||||
late AccountProvider _accountProvider;
|
||||
|
||||
bool _isLoggedIn = false;
|
||||
String? _phoneNumber;
|
||||
|
||||
AccountModel? _usdAccount;
|
||||
AccountModel? _zwgAccount;
|
||||
bool _isLoadingUsd = false;
|
||||
bool _isLoadingZwG = false;
|
||||
String? _usdError;
|
||||
String? _zwgError;
|
||||
String? _phoneNumber;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_accountProvider = AccountProvider();
|
||||
_loadBalances();
|
||||
_loadAuthStateAndBalances();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -42,11 +45,21 @@ class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _loadBalances() async {
|
||||
Future<void> _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;
|
||||
if (_phoneNumber == null || _phoneNumber!.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_isLoadingUsd = true;
|
||||
@@ -84,6 +97,67 @@ class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// If both fetches failed, mark as not logged in
|
||||
if (mounted &&
|
||||
!usdResult.isSuccess &&
|
||||
!zwgResult.isSuccess &&
|
||||
_isLoggedIn) {
|
||||
setState(() {
|
||||
_isLoggedIn = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _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
|
||||
@@ -91,6 +165,10 @@ class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
|
||||
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();
|
||||
}
|
||||
@@ -143,7 +221,7 @@ class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
|
||||
onPressed: _isLoadingUsd || _isLoadingZwG
|
||||
? null
|
||||
: () {
|
||||
_loadBalances();
|
||||
_refreshBalances();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.refresh_rounded,
|
||||
@@ -176,6 +254,70 @@ class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 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,
|
||||
|
||||
@@ -393,15 +393,10 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!_isLoggedIn) ...[
|
||||
_buildLoginPrompt(theme, isDark),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
if (_isLoggedIn)
|
||||
AccountBalanceWidget(
|
||||
selectedCurrency: _selectedCurrency,
|
||||
onCurrencySelected: _onCurrencySelected,
|
||||
),
|
||||
AccountBalanceWidget(
|
||||
selectedCurrency: _selectedCurrency,
|
||||
onCurrencySelected: _onCurrencySelected,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@@ -669,67 +664,6 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
||||
);
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// Login Prompt
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
Widget _buildLoginPrompt(ThemeData theme, bool isDark) {
|
||||
return 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),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// Logout Dialog
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user