This commit is contained in:
Phuoc Nguyen
2025-10-24 17:35:39 +07:00
parent 82ce30961b
commit 860a8788b6
17 changed files with 2572 additions and 32 deletions

View File

@@ -0,0 +1,269 @@
# 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)
1. **Voucher 500.000đ** - 2,500 points
2. **Bộ keo chà ron cao cấp** - 3,000 points
3. **Tư vấn thiết kế miễn phí** - 5,000 points
4. **Gạch trang trí Premium** - 8,000 points
5. **Áo thun EuroTile** - 1,500 points
6. **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:
```dart
GoRoute(
path: '/loyalty/rewards',
builder: (context, state) => const RewardsPage(),
),
```
### Direct Navigation
```dart
// From loyalty page or home
context.push('/loyalty/rewards');
// Or using named route
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const RewardsPage()),
);
```
### Accessing Providers
```dart
// 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
1. User clicks "Đổi quà" button
2. Confirmation dialog appears with:
- Gift name
- Points cost
- Balance after redemption
3. User confirms
4. Points are deducted
5. Success snackbar shown
6. 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`:
```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)
1. **Backend Integration**
- Replace mock data with actual API calls
- Implement gift redemption endpoint
- Add error handling for network failures
2. **Gift Code Display**
- Create page to show redeemed gift code
- Add copy-to-clipboard functionality
- Show gift usage instructions
3. **My Gifts Page**
- Navigate to My Gifts after successful redemption
- Show active, used, and expired gifts
- Add filter tabs
4. **Enhanced UX**
- Add skeleton loaders during fetch
- Implement optimistic updates
- Add redemption animation
- Show gift popularity indicators
5. **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)
```dart
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:
1. Check provider state with Riverpod DevTools
2. Verify mock data in `gifts_provider.dart`
3. Check console for CachedNetworkImage errors
4. 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