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> {
|
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 = [];
|
List<dynamic> _rewards = [];
|
||||||
bool _isLoading = true;
|
bool _isLoading = true;
|
||||||
|
|
||||||
@ -26,30 +27,64 @@ class _RewardsScreenState extends State<RewardsScreen> {
|
|||||||
setState(() => _isLoading = true);
|
setState(() => _isLoading = true);
|
||||||
|
|
||||||
try {
|
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;
|
final loyaltyCards = results[0];
|
||||||
List<dynamic> rawRewards = [];
|
final subscriptionCards = results[1];
|
||||||
|
|
||||||
if (cards.isNotEmpty) {
|
double loyaltyPoints = 0.0;
|
||||||
totalPoints = safeDouble(cards.first['points']);
|
final Map<int, double> pointsMap = {};
|
||||||
final prog = cards.first['program_id'];
|
final List<int> programIds = [];
|
||||||
int? programId;
|
|
||||||
|
// 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) {
|
if (prog is List && prog.isNotEmpty) {
|
||||||
programId = prog[0] as int?;
|
progId = prog[0] as int?;
|
||||||
} else if (prog is int) {
|
} else if (prog is int) {
|
||||||
programId = prog;
|
progId = prog;
|
||||||
}
|
}
|
||||||
|
if (progId != null) {
|
||||||
|
pointsMap[progId] = loyaltyPoints;
|
||||||
|
programIds.add(progId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (programId != null) {
|
// 2. Process active subscription cards
|
||||||
rawRewards = await OdooService().getLoyaltyRewards(programId);
|
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) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_userPoints = totalPoints;
|
_userPoints = loyaltyPoints;
|
||||||
_rewards = rawRewards;
|
_programPoints = pointsMap;
|
||||||
|
_rewards = fetchedRewards;
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -195,10 +230,28 @@ class _RewardsScreenState extends State<RewardsScreen> {
|
|||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final reward = _rewards[index];
|
final reward = _rewards[index];
|
||||||
final reqPoints = safeDouble(reward['required_points']);
|
final reqPoints = safeDouble(reward['required_points']);
|
||||||
final isAvailable = _userPoints >= reqPoints;
|
|
||||||
final String desc = safeString(reward['description']) ?? 'Loyalty Reward';
|
final String desc = safeString(reward['description']) ?? 'Loyalty Reward';
|
||||||
final String type = safeString(reward['reward_type']) ?? 'product';
|
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
|
// Decide icon based on reward type
|
||||||
IconData iconData = Icons.local_offer_rounded;
|
IconData iconData = Icons.local_offer_rounded;
|
||||||
if (type == 'product') {
|
if (type == 'product') {
|
||||||
@ -279,6 +332,16 @@ class _RewardsScreenState extends State<RewardsScreen> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
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(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -357,7 +420,7 @@ class _RewardsScreenState extends State<RewardsScreen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
'Need ${(reqPoints - _userPoints).toStringAsFixed(0)} more pts',
|
'Need ${(reqPoints - currentCardPoints).toStringAsFixed(0)} more pts',
|
||||||
style: theme.textTheme.bodySmall?.copyWith(
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
color: colorScheme.error,
|
color: colorScheme.error,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user