/// Rewards Page /// /// Displays gift catalog where users can redeem rewards with loyalty points. library; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; import 'package:worker/core/constants/ui_constants.dart'; import 'package:worker/core/theme/colors.dart'; import 'package:worker/features/loyalty/domain/entities/gift_catalog.dart'; import 'package:worker/features/loyalty/presentation/providers/gifts_provider.dart'; import 'package:worker/features/loyalty/presentation/providers/loyalty_points_provider.dart'; import 'package:worker/features/loyalty/presentation/widgets/points_balance_card.dart'; import 'package:worker/features/loyalty/presentation/widgets/reward_card.dart'; /// Rewards Page /// /// Features: /// - Points balance card with gradient /// - Category filter pills /// - Gift catalog grid (2 columns) /// - Redemption functionality class RewardsPage extends ConsumerWidget { const RewardsPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final filteredGifts = ref.watch(filteredGiftsProvider); final selectedCategory = ref.watch(selectedGiftCategoryProvider); return Scaffold( backgroundColor: const Color(0xFFF4F6F8), appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () => context.pop(), ), title: const Text('Đổi quà tặng', style: TextStyle(color: Colors.black)), elevation: AppBarSpecs.elevation, backgroundColor: AppColors.white, foregroundColor: AppColors.grey900, centerTitle: false, actions: const [ SizedBox(width: AppSpacing.sm), ], ), body: RefreshIndicator( onRefresh: () async { await ref.read(giftsProvider.notifier).refresh(); await ref.read(loyaltyPointsProvider.notifier).refresh(); }, child: CustomScrollView( slivers: [ // Points Balance Card const SliverToBoxAdapter( child: Padding( padding: EdgeInsets.all(16), child: PointsBalanceCard(), ), ), // Category Filter Pills SliverToBoxAdapter( child: _buildCategoryFilter(context, ref, selectedCategory), ), // Rewards Grid SliverPadding( padding: const EdgeInsets.fromLTRB(12, 8, 12, 24), sliver: filteredGifts.isEmpty ? _buildEmptyState() : SliverGrid( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 0.7, crossAxisSpacing: 0, mainAxisSpacing: 0, ), delegate: SliverChildBuilderDelegate( (context, index) { final gift = filteredGifts[index]; return RewardCard( gift: gift, onRedeem: () => _handleRedeemGift( context, ref, gift, ), ); }, childCount: filteredGifts.length, ), ), ), ], ), ), ); } /// Build category filter pills Widget _buildCategoryFilter( BuildContext context, WidgetRef ref, GiftCategory? selectedCategory, ) { return Container( height: 48, padding: const EdgeInsets.symmetric(horizontal: 16), child: ListView( scrollDirection: Axis.horizontal, children: [ // "Tất cả" (All) filter _buildFilterChip( context: context, ref: ref, label: 'Tất cả', isSelected: selectedCategory == null, onTap: () { ref.read(selectedGiftCategoryProvider.notifier).clearSelection(); }, ), const SizedBox(width: 8), // Voucher filter _buildFilterChip( context: context, ref: ref, label: 'Voucher', isSelected: selectedCategory == GiftCategory.voucher, onTap: () { ref .read(selectedGiftCategoryProvider.notifier) .setCategory(GiftCategory.voucher); }, ), const SizedBox(width: 8), // Product filter _buildFilterChip( context: context, ref: ref, label: 'Sản phẩm', isSelected: selectedCategory == GiftCategory.product, onTap: () { ref .read(selectedGiftCategoryProvider.notifier) .setCategory(GiftCategory.product); }, ), const SizedBox(width: 8), // Service filter _buildFilterChip( context: context, ref: ref, label: 'Dịch vụ', isSelected: selectedCategory == GiftCategory.service, onTap: () { ref .read(selectedGiftCategoryProvider.notifier) .setCategory(GiftCategory.service); }, ), const SizedBox(width: 8), // Special offers filter _buildFilterChip( context: context, ref: ref, label: 'Ưu đãi đặc biệt', isSelected: selectedCategory == GiftCategory.discount, onTap: () { ref .read(selectedGiftCategoryProvider.notifier) .setCategory(GiftCategory.discount); }, ), ], ), ); } /// Build individual filter chip Widget _buildFilterChip({ required BuildContext context, required WidgetRef ref, required String label, required bool isSelected, required VoidCallback onTap, }) { return GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: isSelected ? AppColors.primaryBlue : AppColors.grey100, borderRadius: BorderRadius.circular(20), ), child: Center( child: Text( label, style: TextStyle( fontSize: 14, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected ? Colors.white : AppColors.grey900, ), ), ), ), ); } /// Build empty state Widget _buildEmptyState() { return SliverFillRemaining( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.card_giftcard_outlined, size: 64, color: AppColors.grey500, ), const SizedBox(height: 16), const Text( 'Không có quà tặng nào', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, color: AppColors.grey500, ), ), const SizedBox(height: 8), const Text( 'Vui lòng thử lại sau', style: TextStyle( fontSize: 14, color: AppColors.grey500, ), ), ], ), ), ); } /// Handle gift redemption void _handleRedeemGift( BuildContext context, WidgetRef ref, GiftCatalog gift, ) { final numberFormat = NumberFormat('#,###', 'vi_VN'); final pointsState = ref.read(loyaltyPointsProvider); showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Xác nhận đổi quà'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Bạn có chắc muốn đổi quà này?', style: const TextStyle(fontSize: 14), ), const SizedBox(height: 16), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppColors.grey50, borderRadius: BorderRadius.circular(8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( gift.name, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Chi phí:', style: TextStyle(fontSize: 13), ), Text( '${numberFormat.format(gift.pointsCost)} điểm', style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: AppColors.primaryBlue, ), ), ], ), const SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Số dư sau khi đổi:', style: TextStyle(fontSize: 13), ), Text( '${numberFormat.format(pointsState.availablePoints - gift.pointsCost)} điểm', style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w600, ), ), ], ), ], ), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Hủy'), ), ElevatedButton( onPressed: () { Navigator.pop(context); _processRedemption(context, ref, gift); }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primaryBlue, foregroundColor: Colors.white, ), child: const Text('Xác nhận'), ), ], ), ); } /// Process gift redemption void _processRedemption( BuildContext context, WidgetRef ref, GiftCatalog gift, ) { // Deduct points ref.read(loyaltyPointsProvider.notifier).deductPoints(gift.pointsCost); // Show success message ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row( children: [ const Icon(Icons.check_circle, color: Colors.white), const SizedBox(width: 12), Expanded( child: Text('Đổi quà "${gift.name}" thành công!'), ), ], ), backgroundColor: AppColors.success, behavior: SnackBarBehavior.floating, duration: const Duration(seconds: 3), ), ); // TODO: Navigate to gift code display page // context.push('/loyalty/my-gifts'); } }