import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import '../../../common/theme/theme.dart'; // Models class Reward { final String id; final String name; final String image; final int pointsUsed; final String description; final DateTime redeemedAt; final RewardStatus status; final String? couponCode; final String? validUntil; final String? termsAndConditions; final String categoryName; final String categoryIcon; Reward({ required this.id, required this.name, required this.image, required this.pointsUsed, required this.description, required this.redeemedAt, required this.status, required this.categoryName, required this.categoryIcon, this.couponCode, this.validUntil, this.termsAndConditions, }); String get statusText { switch (status) { case RewardStatus.active: return "Aktif"; case RewardStatus.used: return "Sudah Digunakan"; case RewardStatus.expired: return "Kadaluarsa"; } } Color get statusColor { switch (status) { case RewardStatus.active: return AppColor.success; case RewardStatus.used: return AppColor.textSecondary; case RewardStatus.expired: return AppColor.error; } } } enum RewardStatus { active, used, expired } @RoutePage() class RewardPage extends StatefulWidget { const RewardPage({super.key}); @override State createState() => _RewardPageState(); } class _RewardPageState extends State with SingleTickerProviderStateMixin { late TabController _tabController; // Sample reward data final List rewards = [ Reward( id: "r1", name: "Es Teh Manis", image: "🧊", pointsUsed: 1500, description: "Teh manis dingin segar", redeemedAt: DateTime.now().subtract(Duration(hours: 2)), status: RewardStatus.active, categoryName: "Minuman", categoryIcon: "🥤", couponCode: "ETM123456", validUntil: "31 Des 2025", termsAndConditions: "Berlaku untuk dine-in dan take away. Tidak dapat digabung dengan promo lain.", ), Reward( id: "r2", name: "Diskon 50%", image: "🏷️", pointsUsed: 5000, description: "Potongan harga 50% untuk semua menu", redeemedAt: DateTime.now().subtract(Duration(days: 1)), status: RewardStatus.used, categoryName: "Voucher", categoryIcon: "🎟️", couponCode: "DISC50789", validUntil: "15 Des 2025", termsAndConditions: "Berlaku untuk pembelian minimum Rp 50.000. Tidak berlaku untuk menu promo.", ), Reward( id: "r3", name: "Nasi Gudeg", image: "🍛", pointsUsed: 4000, description: "Gudeg Jogja autentik", redeemedAt: DateTime.now().subtract(Duration(days: 3)), status: RewardStatus.active, categoryName: "Makanan", categoryIcon: "🍽️", couponCode: "GUDEG456", validUntil: "25 Des 2025", termsAndConditions: "Berlaku untuk 1 porsi. Dapat dimakan di tempat atau dibawa pulang.", ), Reward( id: "r4", name: "Gratis Ongkir", image: "🚚", pointsUsed: 2000, description: "Bebas ongkos kirim untuk pesanan apapun", redeemedAt: DateTime.now().subtract(Duration(days: 15)), status: RewardStatus.expired, categoryName: "Voucher", categoryIcon: "🎟️", validUntil: "20 Agu 2025", termsAndConditions: "Berlaku untuk area Jabodetabek. Minimum pembelian Rp 25.000.", ), Reward( id: "r5", name: "Kopi Susu", image: "☕", pointsUsed: 2000, description: "Kopi dengan susu creamy", redeemedAt: DateTime.now().subtract(Duration(days: 7)), status: RewardStatus.used, categoryName: "Minuman", categoryIcon: "🥤", couponCode: "KOPI987654", validUntil: "30 Nov 2025", termsAndConditions: "Berlaku untuk size regular. Dapat request level manis.", ), ]; @override void initState() { super.initState(); _tabController = TabController(length: 4, vsync: this); } List get filteredRewards { switch (_tabController.index) { case 0: return rewards; // Semua case 1: return rewards.where((r) => r.status == RewardStatus.active).toList(); case 2: return rewards.where((r) => r.status == RewardStatus.used).toList(); case 3: return rewards.where((r) => r.status == RewardStatus.expired).toList(); default: return rewards; } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColor.backgroundLight, appBar: AppBar(title: Text("Reward Saya"), centerTitle: true), body: Column( children: [ _buildCleanTabBar(), Expanded( child: TabBarView( controller: _tabController, children: [ _buildRewardList(), // Semua _buildRewardList(), // Aktif _buildRewardList(), // Digunakan _buildRewardList(), // Kadaluarsa ], ), ), ], ), ); } Widget _buildCleanTabBar() { final activeCount = rewards .where((r) => r.status == RewardStatus.active) .length; final usedCount = rewards .where((r) => r.status == RewardStatus.used) .length; final expiredCount = rewards .where((r) => r.status == RewardStatus.expired) .length; return Container( margin: EdgeInsets.symmetric(horizontal: 20, vertical: 12), decoration: BoxDecoration( color: AppColor.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 20, offset: Offset(0, 4), ), ], ), child: TabBar( controller: _tabController, indicatorSize: TabBarIndicatorSize.tab, isScrollable: true, tabAlignment: TabAlignment.start, dividerColor: Colors.transparent, onTap: (index) => setState(() {}), tabs: [ _buildCleanTab("Semua", rewards.length), _buildCleanTab("Aktif", activeCount), _buildCleanTab("Terpakai", usedCount), _buildCleanTab("Expired", expiredCount), ], ), ); } Widget _buildCleanTab(String label, int count) { return Container(height: 44, child: Center(child: Text("$label ($count)"))); } Widget _buildRewardList() { final filteredData = filteredRewards; if (filteredData.isEmpty) { return _buildEmptyState(); } return ListView.builder( padding: EdgeInsets.symmetric(horizontal: 20, vertical: 8), itemCount: filteredData.length, itemBuilder: (context, index) { final reward = filteredData[index]; return _buildCleanRewardCard(reward); }, ); } Widget _buildEmptyState() { String message; String icon; switch (_tabController.index) { case 1: message = "Belum ada reward aktif"; icon = "🎯"; break; case 2: message = "Belum ada reward yang digunakan"; icon = "✅"; break; case 3: message = "Tidak ada reward yang kadaluarsa"; icon = "⏰"; break; default: message = "Belum ada reward"; icon = "🎁"; } return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(icon, style: TextStyle(fontSize: 64)), SizedBox(height: 16), Text( message, style: AppStyle.lg.copyWith( color: AppColor.textSecondary, fontWeight: FontWeight.w600, ), ), SizedBox(height: 8), Text( "Tukar poin Anda untuk mendapatkan reward menarik", style: AppStyle.sm.copyWith(color: AppColor.textLight), textAlign: TextAlign.center, ), SizedBox(height: 24), ElevatedButton( onPressed: () => context.router.back(), style: ElevatedButton.styleFrom( backgroundColor: AppColor.primary, foregroundColor: AppColor.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12), elevation: 0, ), child: Text( "Tukar Poin Sekarang", style: AppStyle.sm.copyWith( fontWeight: FontWeight.w600, color: AppColor.white, ), ), ), ], ), ); } Widget _buildCleanRewardCard(Reward reward) { return Container( margin: EdgeInsets.only(bottom: 12), decoration: BoxDecoration( color: AppColor.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 20, offset: Offset(0, 4), ), ], ), child: InkWell( onTap: () {}, borderRadius: BorderRadius.circular(16), child: Padding( padding: EdgeInsets.all(20), child: Row( children: [ // Product Image - Simplified Container( width: 56, height: 56, decoration: BoxDecoration( color: AppColor.backgroundLight, borderRadius: BorderRadius.circular(14), ), child: Center( child: Text(reward.image, style: TextStyle(fontSize: 24)), ), ), SizedBox(width: 16), // Reward Info - Cleaner layout Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( reward.name, style: AppStyle.md.copyWith( fontWeight: FontWeight.w600, color: AppColor.textPrimary, ), ), ), _buildStatusBadge(reward), ], ), SizedBox(height: 4), Text( reward.description, style: AppStyle.sm.copyWith( color: AppColor.textSecondary, ), ), SizedBox(height: 8), Row( children: [ Icon( Icons.access_time, size: 12, color: AppColor.textLight, ), SizedBox(width: 4), Text( _formatDate(reward.redeemedAt), style: AppStyle.xs.copyWith( color: AppColor.textLight, ), ), Spacer(), Icon(Icons.stars, size: 14, color: AppColor.warning), SizedBox(width: 4), Text( "${reward.pointsUsed}", style: AppStyle.xs.copyWith( color: AppColor.textSecondary, fontWeight: FontWeight.w600, ), ), ], ), ], ), ), ], ), ), ), ); } Widget _buildStatusBadge(Reward reward) { return Container( padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: reward.statusColor.withOpacity(0.1), borderRadius: BorderRadius.circular(6), ), child: Text( reward.statusText, style: AppStyle.xs.copyWith( color: reward.statusColor, fontWeight: FontWeight.w600, ), ), ); } String _formatDate(DateTime date) { final months = [ '', 'Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des', ]; final now = DateTime.now(); final difference = now.difference(date); if (difference.inDays == 0) { if (difference.inHours == 0) { return "${difference.inMinutes} menit lalu"; } return "${difference.inHours} jam lalu"; } else if (difference.inDays == 1) { return "Kemarin"; } else if (difference.inDays < 7) { return "${difference.inDays} hari lalu"; } else { return "${date.day} ${months[date.month]} ${date.year}"; } } @override void dispose() { _tabController.dispose(); super.dispose(); } }