feat: integrate subscription cards and support program-specific reward point validation
This commit is contained in:
parent
e0b959b858
commit
b25f9e151a
@ -11,7 +11,8 @@ class RewardsScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _RewardsScreenState extends State<RewardsScreen> {
|
||||
double _userPoints = 0.0;
|
||||
double _userPoints = 0.0; // Main loyalty points balance shown in the top banner
|
||||
Map<int, double> _programPoints = {}; // Maps programId to card points
|
||||
List<dynamic> _rewards = [];
|
||||
bool _isLoading = true;
|
||||
|
||||
@ -26,30 +27,64 @@ class _RewardsScreenState extends State<RewardsScreen> {
|
||||
setState(() => _isLoading = true);
|
||||
|
||||
try {
|
||||
final cards = await OdooService().getLoyaltyCards(widget.partnerId);
|
||||
// Fetch both loyalty cards and subscription cards in parallel
|
||||
final results = await Future.wait([
|
||||
OdooService().getLoyaltyCards(widget.partnerId),
|
||||
OdooService().getSubscriptionCards(widget.partnerId),
|
||||
]);
|
||||
|
||||
double totalPoints = 0.0;
|
||||
List<dynamic> rawRewards = [];
|
||||
final loyaltyCards = results[0];
|
||||
final subscriptionCards = results[1];
|
||||
|
||||
if (cards.isNotEmpty) {
|
||||
totalPoints = safeDouble(cards.first['points']);
|
||||
final prog = cards.first['program_id'];
|
||||
int? programId;
|
||||
double loyaltyPoints = 0.0;
|
||||
final Map<int, double> pointsMap = {};
|
||||
final List<int> programIds = [];
|
||||
|
||||
// 1. Process main loyalty card
|
||||
if (loyaltyCards.isNotEmpty) {
|
||||
loyaltyPoints = safeDouble(loyaltyCards.first['points']);
|
||||
final prog = loyaltyCards.first['program_id'];
|
||||
int? progId;
|
||||
if (prog is List && prog.isNotEmpty) {
|
||||
programId = prog[0] as int?;
|
||||
progId = prog[0] as int?;
|
||||
} else if (prog is int) {
|
||||
programId = prog;
|
||||
progId = prog;
|
||||
}
|
||||
if (progId != null) {
|
||||
pointsMap[progId] = loyaltyPoints;
|
||||
programIds.add(progId);
|
||||
}
|
||||
}
|
||||
|
||||
if (programId != null) {
|
||||
rawRewards = await OdooService().getLoyaltyRewards(programId);
|
||||
// 2. Process active subscription cards
|
||||
for (final card in subscriptionCards) {
|
||||
final pts = safeDouble(card['points']);
|
||||
final prog = card['program_id'];
|
||||
int? progId;
|
||||
if (prog is List && prog.isNotEmpty) {
|
||||
progId = prog[0] as int?;
|
||||
} else if (prog is int) {
|
||||
progId = prog;
|
||||
}
|
||||
if (progId != null) {
|
||||
pointsMap[progId] = pts;
|
||||
if (!programIds.contains(progId)) {
|
||||
programIds.add(progId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fetch rewards for all resolved program IDs
|
||||
List<dynamic> fetchedRewards = [];
|
||||
if (programIds.isNotEmpty) {
|
||||
fetchedRewards = await OdooService().getLoyaltyRewards(programIds);
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_userPoints = totalPoints;
|
||||
_rewards = rawRewards;
|
||||
_userPoints = loyaltyPoints;
|
||||
_programPoints = pointsMap;
|
||||
_rewards = fetchedRewards;
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
@ -195,10 +230,28 @@ class _RewardsScreenState extends State<RewardsScreen> {
|
||||
itemBuilder: (context, index) {
|
||||
final reward = _rewards[index];
|
||||
final reqPoints = safeDouble(reward['required_points']);
|
||||
final isAvailable = _userPoints >= reqPoints;
|
||||
final String desc = safeString(reward['description']) ?? 'Loyalty Reward';
|
||||
final String type = safeString(reward['reward_type']) ?? 'product';
|
||||
|
||||
// Resolve reward's program ID and name
|
||||
final progVal = reward['program_id'];
|
||||
int? rewardProgramId;
|
||||
String programName = 'Reward';
|
||||
if (progVal is List && progVal.isNotEmpty) {
|
||||
rewardProgramId = progVal[0] as int?;
|
||||
if (progVal.length > 1) {
|
||||
programName = progVal[1] as String;
|
||||
}
|
||||
} else if (progVal is int) {
|
||||
rewardProgramId = progVal;
|
||||
}
|
||||
|
||||
// Determine point balance and availability based on the specific program
|
||||
final currentCardPoints = rewardProgramId != null
|
||||
? (_programPoints[rewardProgramId] ?? 0.0)
|
||||
: 0.0;
|
||||
final isAvailable = currentCardPoints >= reqPoints;
|
||||
|
||||
// Decide icon based on reward type
|
||||
IconData iconData = Icons.local_offer_rounded;
|
||||
if (type == 'product') {
|
||||
@ -279,6 +332,16 @@ class _RewardsScreenState extends State<RewardsScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Program Source Name
|
||||
Text(
|
||||
programName.toUpperCase(),
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
color: colorScheme.primary.withValues(alpha: 0.65),
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 1.0,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -357,7 +420,7 @@ class _RewardsScreenState extends State<RewardsScreen> {
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'Need ${(reqPoints - _userPoints).toStringAsFixed(0)} more pts',
|
||||
'Need ${(reqPoints - currentCardPoints).toStringAsFixed(0)} more pts',
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: colorScheme.error,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user