7.2 KiB
Loyalty Rewards Screen Integration Guide
Overview
The loyalty rewards screen ("Đổi quà") has been successfully created following the HTML design specification from html/loyalty-rewards.html.
Files Created
1. Providers
-
providers/loyalty_points_provider.dart- Manages user's loyalty points balance- Shows available points: 9,750
- Shows expiring points: 1,200 on 31/12/2023
- Methods:
refresh(),deductPoints(),addPoints(),hasEnoughPoints()
-
providers/gifts_provider.dart- Manages gift catalog- 6 mock gifts matching HTML design
- Category filtering (All, Voucher, Product, Service, Discount)
- Filtered gifts provider for category-based display
2. Widgets
-
widgets/points_balance_card.dart- Gradient card displaying points- Blue gradient background (135deg, #005B9A → #38B6FF)
- Shows available points with proper formatting
- Displays expiration warning
-
widgets/reward_card.dart- Individual gift card- 120px image with CachedNetworkImage
- Gift name, description, points cost
- "Đổi quà" button (enabled if enough points)
- "Không đủ điểm" button (disabled if insufficient points)
3. Pages
pages/rewards_page.dart- Main rewards screen- AppBar with title "Đổi quà tặng"
- Points balance card
- Horizontal scrollable category filter pills
- 2-column gift grid (GridView)
- Pull-to-refresh
- Redemption confirmation dialog
- Success snackbar notification
Mock Data
Gift Catalog (6 items)
- Voucher 500.000đ - 2,500 points
- Bộ keo chà ron cao cấp - 3,000 points
- Tư vấn thiết kế miễn phí - 5,000 points
- Gạch trang trí Premium - 8,000 points
- Áo thun EuroTile - 1,500 points
- Nâng hạng thẻ Platinum - 15,000 points (disabled - not enough points)
User Points
- Available: 9,750 points
- Expiring: 1,200 points on 31/12/2023
Usage
Navigation
Add to your router configuration:
GoRoute(
path: '/loyalty/rewards',
builder: (context, state) => const RewardsPage(),
),
Direct Navigation
// From loyalty page or home
context.push('/loyalty/rewards');
// Or using named route
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const RewardsPage()),
);
Accessing Providers
// Watch points balance
final pointsState = ref.watch(loyaltyPointsProvider);
print('Available points: ${pointsState.availablePoints}');
// Check if user has enough points
final hasEnough = ref.watch(hasEnoughPointsProvider(5000));
if (hasEnough) {
// Show enabled button
}
// Get filtered gifts
final gifts = ref.watch(filteredGiftsProvider);
// Change category filter
ref.read(selectedGiftCategoryProvider.notifier).setCategory(GiftCategory.voucher);
// Clear filter (show all)
ref.read(selectedGiftCategoryProvider.notifier).clearSelection();
Features Implemented
1. Points Balance Display
- Gradient card with blue to light blue
- Large points number (36px, bold)
- Formatted with Vietnamese locale (9,750)
- Expiration warning with info icon
2. Category Filtering
- 5 filter options: Tất cả, Voucher, Sản phẩm, Dịch vụ, Ưu đãi đặc biệt
- Active state: blue background, white text
- Inactive state: grey background, dark text
- Smooth transitions between filters
3. Gift Grid
- 2-column responsive grid
- 0.75 aspect ratio for cards
- 12px spacing between cards
- Proper image loading with CachedNetworkImage
- Shimmer placeholder for loading
- Error fallback icon
4. Redemption Flow
- User clicks "Đổi quà" button
- Confirmation dialog appears with:
- Gift name
- Points cost
- Balance after redemption
- User confirms
- Points are deducted
- Success snackbar shown
- Can navigate to "My Gifts" page (TODO)
5. Smart Button State
- Enabled (blue): User has enough points and gift is available
- Disabled (grey): User doesn't have enough points
- Button text changes automatically
- Icon changes color based on state
Design Details
Colors
- Gradient Start: #005B9A (primaryBlue)
- Gradient End: #38B6FF (lightBlue)
- Primary Button: #005B9A
- Success: #28a745
- Grey Disabled: #e9ecef
- Background: #F4F6F8
Typography
- Points: 36px, bold, white
- Gift Name: 14px, semibold, grey900
- Description: 12px, regular, grey500
- Points Cost: 14px, bold, primaryBlue
- Button Text: 13px, semibold
Spacing
- Card padding: 12px
- Grid spacing: 12px
- Page padding: 16px
- Image height: 120px
Dependencies Required
Ensure these packages are in pubspec.yaml:
dependencies:
flutter:
sdk: flutter
flutter_riverpod: ^2.6.1
riverpod_annotation: ^2.5.0
go_router: ^14.6.2
cached_network_image: ^3.4.1
intl: ^0.19.0
dev_dependencies:
build_runner: ^2.4.13
riverpod_generator: ^2.5.0
Next Steps (TODO)
-
Backend Integration
- Replace mock data with actual API calls
- Implement gift redemption endpoint
- Add error handling for network failures
-
Gift Code Display
- Create page to show redeemed gift code
- Add copy-to-clipboard functionality
- Show gift usage instructions
-
My Gifts Page
- Navigate to My Gifts after successful redemption
- Show active, used, and expired gifts
- Add filter tabs
-
Enhanced UX
- Add skeleton loaders during fetch
- Implement optimistic updates
- Add redemption animation
- Show gift popularity indicators
-
Analytics
- Track gift view events
- Track redemption events
- Track category filter usage
Testing
Manual Testing Checklist
- Page loads with points and gifts
- Category filters work correctly
- "Tất cả" shows all gifts
- Each category shows only relevant gifts
- Pull-to-refresh works
- Cards display correctly in grid
- Images load properly
- Points are formatted correctly (9,750)
- Expiration info displays correctly
- Button is enabled when enough points
- Button is disabled when not enough points
- Confirmation dialog appears on redeem
- Points are deducted after confirmation
- Success message appears
- Back button works
Widget Tests (TODO)
testWidgets('RewardsPage displays points balance', (tester) async {
// Test implementation
});
testWidgets('RewardCard shows correct button state', (tester) async {
// Test implementation
});
testWidgets('Category filter changes gift list', (tester) async {
// Test implementation
});
Screenshots Match HTML
The implementation matches the HTML design exactly:
- ✅ AppBar layout and styling
- ✅ Gradient points balance card
- ✅ Category filter pills design
- ✅ 2-column gift grid
- ✅ Gift card layout and styling
- ✅ Button states (enabled/disabled)
- ✅ Color scheme and typography
- ✅ Spacing and padding
Support
For issues or questions about the rewards screen:
- Check provider state with Riverpod DevTools
- Verify mock data in
gifts_provider.dart - Check console for CachedNetworkImage errors
- Ensure build_runner generated files exist
Created: October 24, 2025
Design Reference: /Users/ssg/project/worker/html/loyalty-rewards.html
Status: ✅ Complete with mock data