Files
worker/lib/features/loyalty/presentation/REWARDS_INTEGRATION.md
Phuoc Nguyen 860a8788b6 loyalty
2025-10-24 17:35:39 +07:00

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)

  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:

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

  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:

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)

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