Files
worker/lib/features/loyalty/presentation/pages/loyalty_page.dart
Phuoc Nguyen b5f90c364d update icon
2025-11-14 18:02:37 +07:00

461 lines
14 KiB
Dart

/// Page: Loyalty Page
///
/// Main loyalty program page displaying member card, progress, and features.
library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/loyalty/presentation/providers/loyalty_points_provider.dart';
/// Loyalty Page
///
/// Features:
/// - Diamond member card with QR code
/// - Progress bar to next tier
/// - Quick action menu items
/// - Current tier benefits
class LoyaltyPage extends ConsumerWidget {
const LoyaltyPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final loyaltyPoints = ref.watch(loyaltyPointsProvider);
return Scaffold(
backgroundColor: const Color(0xFFF4F6F8),
appBar: AppBar(
title: const Text(
'Hội viên thân thiết',
style: TextStyle(color: Colors.black),
),
elevation: AppBarSpecs.elevation,
backgroundColor: AppColors.white,
foregroundColor: AppColors.grey900,
centerTitle: false,
automaticallyImplyLeading: false,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Member Card
_buildMemberCard(loyaltyPoints),
const SizedBox(height: 16),
// Progress Card
_buildProgressCard(),
const SizedBox(height: 16),
// Loyalty Features Menu
..._buildLoyaltyMenu(context),
const SizedBox(height: 16),
// Current Benefits Card
_buildBenefitsCard(),
],
),
),
);
}
/// Build Diamond Member Card
Widget _buildMemberCard(LoyaltyPointsState loyaltyPoints) {
return Container(
height: 200,
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF4A00E0), Color(0xFF8E2DE2)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: const Color(0xFF4A00E0).withValues(alpha: 0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top Row: Brand and Valid Through
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'EUROTILE',
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.w700,
letterSpacing: 1.2,
),
),
const SizedBox(height: 4),
Text(
'ARCHITECT MEMBERSHIP',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.9),
fontSize: 11,
letterSpacing: 0.5,
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'Valid through',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.8),
fontSize: 11,
),
),
const SizedBox(height: 2),
const Text(
'31/12/2025',
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
],
),
],
),
const Spacer(),
// Bottom Row: User Info and QR Code
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'La Nguyen Quynh',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 4),
Text(
'CLASS: DIAMOND',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.9),
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
Text(
'Points: ${loyaltyPoints.availablePoints}',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.9),
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
],
),
),
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: QrImageView(
data: '0983441099',
version: QrVersions.auto,
size: 60,
backgroundColor: Colors.white,
),
),
],
),
],
),
);
}
/// Build Progress Card
Widget _buildProgressCard() {
return Card(
elevation: 5,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Tiến trình lên hạng',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
),
),
const SizedBox(height: 16),
// Current and Next Tier
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Hạng hiện tại: DIAMOND',
style: TextStyle(fontSize: 13, color: AppColors.grey500),
),
Text(
'Hạng kế tiếp: PLATINUM',
style: TextStyle(fontSize: 13, color: AppColors.grey500),
),
],
),
const SizedBox(height: 12),
// Progress Bar
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator(
value: 0.65,
minHeight: 8,
backgroundColor: AppColors.grey100,
valueColor: const AlwaysStoppedAnimation<Color>(
Color(0xFF4A00E0),
),
),
),
const SizedBox(height: 12),
// Points to Next Tier
Center(
child: RichText(
textAlign: TextAlign.center,
text: const TextSpan(
style: TextStyle(fontSize: 13, color: AppColors.grey500),
children: [
TextSpan(text: 'Còn '),
TextSpan(
text: '2,250 điểm',
style: TextStyle(
fontWeight: FontWeight.w600,
color: AppColors.grey900,
),
),
TextSpan(text: ' nữa để lên hạng Platinum'),
],
),
),
),
],
),
),
);
}
/// Build Loyalty Menu Items
List<Widget> _buildLoyaltyMenu(BuildContext context) {
final menuItems = [
{
'icon': FontAwesomeIcons.gift,
'title': 'Đổi quà tặng',
'subtitle': 'Sử dụng điểm để đổi quà hấp dẫn',
'route': '/loyalty/rewards',
},
{
'icon': FontAwesomeIcons.circlePlus,
'title': 'Ghi nhận điểm',
'subtitle': 'Gửi hóa đơn để nhận điểm thưởng',
'route': null,
},
{
'icon': FontAwesomeIcons.clockRotateLeft,
'title': 'Lịch sử điểm',
'subtitle': 'Xem chi tiết cộng/trừ điểm',
'route': '/loyalty/points-history',
},
{
'icon': FontAwesomeIcons.userPlus,
'title': 'Giới thiệu bạn bè',
'subtitle': 'Nhận thưởng khi giới thiệu thành công',
'route': null,
},
{
'icon': FontAwesomeIcons.boxOpen,
'title': 'Quà của tôi',
'subtitle': 'Xem voucher và quà tặng đã đổi',
'route': null,
},
{
'icon': FontAwesomeIcons.gem,
'title': 'Quyền lợi hội viên',
'subtitle': 'Xem các ưu đãi dành cho hạng của bạn',
'route': null,
},
];
return menuItems.map((item) {
return Card(
margin: const EdgeInsets.only(bottom: 12),
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: const BorderSide(color: AppColors.grey100),
),
child: InkWell(
onTap: () {
if (item['route'] != null) {
context.push(item['route'] as String);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('${item['title']} - Đang phát triển')),
);
}
},
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
// Icon
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: AppColors.primaryBlue.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(
item['icon'] as IconData,
color: AppColors.primaryBlue,
size: 24,
),
),
const SizedBox(width: 16),
// Title and Subtitle
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item['title'] as String,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
),
),
const SizedBox(height: 2),
Text(
item['subtitle'] as String,
style: const TextStyle(
fontSize: 13,
color: AppColors.grey500,
),
),
],
),
),
// Arrow
const Icon(
FontAwesomeIcons.chevronRight,
color: AppColors.grey500,
size: 20,
),
],
),
),
),
);
}).toList();
}
/// Build Benefits Card
Widget _buildBenefitsCard() {
return Card(
elevation: 1,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Quyền lợi hạng Diamond',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
),
),
const SizedBox(height: 16),
_buildBenefitItem('Chiết khấu 15% cho tất cả sản phẩm'),
_buildBenefitItem('Giao hàng miễn phí cho đơn từ 5 triệu'),
_buildBenefitItem('Ưu tiên xử lý đơn hàng'),
_buildBenefitItem('Tặng 500 điểm vào ngày sinh nhật'),
_buildBenefitItem('Tư vấn thiết kế miễn phí'),
_buildBenefitItem(
'Mời tham gia sự kiện VIP độc quyền',
isLast: true,
),
],
),
),
);
}
/// Build Benefit Item
Widget _buildBenefitItem(String text, {bool isLast = false}) {
return Padding(
padding: EdgeInsets.only(bottom: isLast ? 0 : 12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const FaIcon(FontAwesomeIcons.solidCircleCheck, size: 18, color: Color(0xFF4A00E0)),
const SizedBox(width: 12),
Expanded(
child: Text(
text,
style: const TextStyle(
fontSize: 14,
color: AppColors.grey900,
height: 1.4,
),
),
),
],
),
);
}
}