update theme

This commit is contained in:
Phuoc Nguyen
2025-12-02 15:20:54 +07:00
parent 12bd70479c
commit 49a41d24eb
78 changed files with 3263 additions and 2756 deletions

View File

@@ -9,7 +9,6 @@ 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
@@ -24,18 +23,19 @@ class LoyaltyPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final colorScheme = Theme.of(context).colorScheme;
final loyaltyPoints = ref.watch(loyaltyPointsProvider);
return Scaffold(
backgroundColor: const Color(0xFFF4F6F8),
backgroundColor: colorScheme.surfaceContainerLowest,
appBar: AppBar(
title: const Text(
title: Text(
'Hội viên thân thiết',
style: TextStyle(color: Colors.black),
style: TextStyle(color: colorScheme.onSurface),
),
elevation: AppBarSpecs.elevation,
backgroundColor: AppColors.white,
foregroundColor: AppColors.grey900,
backgroundColor: colorScheme.surface,
foregroundColor: colorScheme.onSurface,
centerTitle: false,
automaticallyImplyLeading: false,
),
@@ -50,17 +50,17 @@ class LoyaltyPage extends ConsumerWidget {
const SizedBox(height: 16),
// Progress Card
_buildProgressCard(),
_buildProgressCard(colorScheme),
const SizedBox(height: 16),
// Loyalty Features Menu
..._buildLoyaltyMenu(context),
..._buildLoyaltyMenu(context, colorScheme),
const SizedBox(height: 16),
// Current Benefits Card
_buildBenefitsCard(),
_buildBenefitsCard(colorScheme),
],
),
),
@@ -201,7 +201,7 @@ class LoyaltyPage extends ConsumerWidget {
}
/// Build Progress Card
Widget _buildProgressCard() {
Widget _buildProgressCard(ColorScheme colorScheme) {
return Card(
elevation: 5,
margin: EdgeInsets.zero,
@@ -211,12 +211,12 @@ class LoyaltyPage extends ConsumerWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
Text(
'Tiến trình lên hạng',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
const SizedBox(height: 16),
@@ -227,11 +227,11 @@ class LoyaltyPage extends ConsumerWidget {
children: [
Text(
'Hạng hiện tại: DIAMOND',
style: TextStyle(fontSize: 13, color: AppColors.grey500),
style: TextStyle(fontSize: 13, color: colorScheme.onSurfaceVariant),
),
Text(
'Hạng kế tiếp: PLATINUM',
style: TextStyle(fontSize: 13, color: AppColors.grey500),
style: TextStyle(fontSize: 13, color: colorScheme.onSurfaceVariant),
),
],
),
@@ -244,7 +244,7 @@ class LoyaltyPage extends ConsumerWidget {
child: LinearProgressIndicator(
value: 0.65,
minHeight: 8,
backgroundColor: AppColors.grey100,
backgroundColor: colorScheme.surfaceContainerHighest,
valueColor: const AlwaysStoppedAnimation<Color>(
Color(0xFF4A00E0),
),
@@ -257,18 +257,18 @@ class LoyaltyPage extends ConsumerWidget {
Center(
child: RichText(
textAlign: TextAlign.center,
text: const TextSpan(
style: TextStyle(fontSize: 13, color: AppColors.grey500),
text: TextSpan(
style: TextStyle(fontSize: 13, color: colorScheme.onSurfaceVariant),
children: [
TextSpan(text: 'Còn '),
const TextSpan(text: 'Còn '),
TextSpan(
text: '2,250 điểm',
style: TextStyle(
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
TextSpan(text: ' nữa để lên hạng Platinum'),
const TextSpan(text: ' nữa để lên hạng Platinum'),
],
),
),
@@ -280,7 +280,7 @@ class LoyaltyPage extends ConsumerWidget {
}
/// Build Loyalty Menu Items
List<Widget> _buildLoyaltyMenu(BuildContext context) {
List<Widget> _buildLoyaltyMenu(BuildContext context, ColorScheme colorScheme) {
final menuItems = [
{
'icon': FontAwesomeIcons.gift,
@@ -326,7 +326,7 @@ class LoyaltyPage extends ConsumerWidget {
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: const BorderSide(color: AppColors.grey100),
side: BorderSide(color: colorScheme.surfaceContainerHighest),
),
child: InkWell(
onTap: () {
@@ -348,12 +348,12 @@ class LoyaltyPage extends ConsumerWidget {
width: 48,
height: 48,
decoration: BoxDecoration(
color: AppColors.primaryBlue.withValues(alpha: 0.1),
color: colorScheme.primary.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(
item['icon'] as IconData,
color: AppColors.primaryBlue,
color: colorScheme.primary,
size: 24,
),
),
@@ -367,18 +367,18 @@ class LoyaltyPage extends ConsumerWidget {
children: [
Text(
item['title'] as String,
style: const TextStyle(
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
const SizedBox(height: 2),
Text(
item['subtitle'] as String,
style: const TextStyle(
style: TextStyle(
fontSize: 13,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
],
@@ -386,9 +386,9 @@ class LoyaltyPage extends ConsumerWidget {
),
// Arrow
const Icon(
Icon(
FontAwesomeIcons.chevronRight,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
size: 20,
),
],
@@ -400,7 +400,7 @@ class LoyaltyPage extends ConsumerWidget {
}
/// Build Benefits Card
Widget _buildBenefitsCard() {
Widget _buildBenefitsCard(ColorScheme colorScheme) {
return Card(
elevation: 1,
margin: EdgeInsets.zero,
@@ -410,22 +410,23 @@ class LoyaltyPage extends ConsumerWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
Text(
'Quyền lợi hạng Diamond',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
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('Chiết khấu 15% cho tất cả sản phẩm', colorScheme),
_buildBenefitItem('Giao hàng miễn phí cho đơn từ 5 triệu', colorScheme),
_buildBenefitItem('Ưu tiên xử lý đơn hàng', colorScheme),
_buildBenefitItem('Tặng 500 điểm vào ngày sinh nhật', colorScheme),
_buildBenefitItem('Tư vấn thiết kế miễn phí', colorScheme),
_buildBenefitItem(
'Mời tham gia sự kiện VIP độc quyền',
colorScheme,
isLast: true,
),
],
@@ -435,7 +436,7 @@ class LoyaltyPage extends ConsumerWidget {
}
/// Build Benefit Item
Widget _buildBenefitItem(String text, {bool isLast = false}) {
Widget _buildBenefitItem(String text, ColorScheme colorScheme, {bool isLast = false}) {
return Padding(
padding: EdgeInsets.only(bottom: isLast ? 0 : 12),
child: Row(
@@ -446,9 +447,9 @@ class LoyaltyPage extends ConsumerWidget {
Expanded(
child: Text(
text,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey900,
color: colorScheme.onSurface,
height: 1.4,
),
),

View File

@@ -27,22 +27,23 @@ class PointsHistoryPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final colorScheme = Theme.of(context).colorScheme;
final historyAsync = ref.watch(pointsHistoryProvider);
return Scaffold(
backgroundColor: const Color(0xFFF4F6F8),
backgroundColor: colorScheme.surfaceContainerLowest,
appBar: AppBar(
leading: IconButton(
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
icon: FaIcon(FontAwesomeIcons.arrowLeft, color: colorScheme.onSurface, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
title: Text(
'Lịch sử điểm',
style: TextStyle(color: Colors.black),
style: TextStyle(color: colorScheme.onSurface),
),
elevation: AppBarSpecs.elevation,
backgroundColor: AppColors.white,
foregroundColor: AppColors.grey900,
backgroundColor: colorScheme.surface,
foregroundColor: colorScheme.onSurface,
centerTitle: false,
),
body: RefreshIndicator(
@@ -52,7 +53,7 @@ class PointsHistoryPage extends ConsumerWidget {
child: historyAsync.when(
data: (entries) {
if (entries.isEmpty) {
return _buildEmptyState();
return _buildEmptyState(colorScheme);
}
return SingleChildScrollView(
@@ -61,27 +62,27 @@ class PointsHistoryPage extends ConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Filter Section
_buildFilterSection(),
_buildFilterSection(colorScheme),
const SizedBox(height: 16),
// Transaction List
...entries.map(
(entry) => _buildTransactionCard(context, ref, entry),
(entry) => _buildTransactionCard(context, ref, entry, colorScheme),
),
],
),
);
},
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stack) => _buildErrorState(error),
error: (error, stack) => _buildErrorState(error, colorScheme),
),
),
);
}
/// Build filter section
Widget _buildFilterSection() {
Widget _buildFilterSection(ColorScheme colorScheme) {
return Card(
elevation: 1,
margin: EdgeInsets.zero,
@@ -94,21 +95,21 @@ class PointsHistoryPage extends ConsumerWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
Text(
'Bộ lọc',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
FaIcon(FontAwesomeIcons.sliders, color: AppColors.primaryBlue, size: 18),
FaIcon(FontAwesomeIcons.sliders, color: colorScheme.primary, size: 18),
],
),
const SizedBox(height: 8),
const Text(
Text(
'Thời gian hiệu lực: 01/01/2023 - 31/12/2023',
style: TextStyle(fontSize: 12, color: AppColors.grey500),
style: TextStyle(fontSize: 12, color: colorScheme.onSurfaceVariant),
),
],
),
@@ -121,6 +122,7 @@ class PointsHistoryPage extends ConsumerWidget {
BuildContext context,
WidgetRef ref,
LoyaltyPointEntryModel entry,
ColorScheme colorScheme,
) {
final dateFormatter = DateFormat('dd/MM/yyyy HH:mm:ss');
final currencyFormatter = NumberFormat.currency(
@@ -155,10 +157,10 @@ class PointsHistoryPage extends ConsumerWidget {
// Description
Text(
entry.description,
style: const TextStyle(
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color: AppColors.primaryBlue,
color: colorScheme.primary,
),
),
const SizedBox(height: 4),
@@ -166,9 +168,9 @@ class PointsHistoryPage extends ConsumerWidget {
// Timestamp
Text(
'Thời gian: ${dateFormatter.format(entry.timestamp)}',
style: const TextStyle(
style: TextStyle(
fontSize: 12,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
@@ -177,9 +179,9 @@ class PointsHistoryPage extends ConsumerWidget {
const SizedBox(height: 2),
Text(
'Giao dịch: ${currencyFormatter.format(transactionAmount)}',
style: const TextStyle(
style: TextStyle(
fontSize: 12,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
],
@@ -203,8 +205,8 @@ class PointsHistoryPage extends ConsumerWidget {
horizontal: 12,
vertical: 6,
),
side: const BorderSide(color: AppColors.grey500),
foregroundColor: AppColors.grey900,
side: BorderSide(color: colorScheme.onSurfaceVariant),
foregroundColor: colorScheme.onSurface,
textStyle: const TextStyle(fontSize: 12),
minimumSize: const Size(0, 32),
shape: RoundedRectangleBorder(
@@ -235,7 +237,7 @@ class PointsHistoryPage extends ConsumerWidget {
? AppColors.success
: entry.points < 0
? AppColors.danger
: AppColors.grey900,
: colorScheme.onSurface,
),
),
const SizedBox(height: 2),
@@ -243,9 +245,9 @@ class PointsHistoryPage extends ConsumerWidget {
// New balance
Text(
'Điểm mới: ${entry.balanceAfter}',
style: const TextStyle(
style: TextStyle(
fontSize: 12,
color: AppColors.primaryBlue,
color: colorScheme.primary,
),
),
],
@@ -259,7 +261,7 @@ class PointsHistoryPage extends ConsumerWidget {
}
/// Build empty state
Widget _buildEmptyState() {
Widget _buildEmptyState(ColorScheme colorScheme) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
@@ -267,21 +269,21 @@ class PointsHistoryPage extends ConsumerWidget {
FaIcon(
FontAwesomeIcons.clockRotateLeft,
size: 80,
color: AppColors.grey500.withValues(alpha: 0.5),
color: colorScheme.onSurfaceVariant.withValues(alpha: 0.5),
),
const SizedBox(height: 16),
const Text(
Text(
'Chưa có lịch sử điểm',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 8),
const Text(
Text(
'Kéo xuống để làm mới',
style: TextStyle(fontSize: 14, color: AppColors.grey500),
style: TextStyle(fontSize: 14, color: colorScheme.onSurfaceVariant),
),
],
),
@@ -289,7 +291,7 @@ class PointsHistoryPage extends ConsumerWidget {
}
/// Build error state
Widget _buildErrorState(Object error) {
Widget _buildErrorState(Object error, ColorScheme colorScheme) {
print(error.toString());
return Center(
child: Column(
@@ -301,18 +303,18 @@ class PointsHistoryPage extends ConsumerWidget {
color: AppColors.danger.withValues(alpha: 0.7),
),
const SizedBox(height: 16),
const Text(
Text(
'Có lỗi xảy ra',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
const SizedBox(height: 8),
Text(
error.toString(),
style: const TextStyle(fontSize: 14, color: AppColors.grey500),
style: TextStyle(fontSize: 14, color: colorScheme.onSurfaceVariant),
textAlign: TextAlign.center,
),
],

View File

@@ -19,30 +19,31 @@ class PointsRecordsPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final colorScheme = Theme.of(context).colorScheme;
final recordsAsync = ref.watch(filteredPointsRecordsProvider);
final filter = ref.watch(pointsRecordsFilterProvider);
final selectedStatus = filter.selectedStatus;
return Scaffold(
backgroundColor: const Color(0xFFF4F6F8),
backgroundColor: colorScheme.surfaceContainerLowest,
appBar: AppBar(
leading: IconButton(
icon: const FaIcon(
icon: FaIcon(
FontAwesomeIcons.arrowLeft,
color: Colors.black,
color: colorScheme.onSurface,
size: 20,
),
onPressed: () => context.pop(),
),
title: const Text(
title: Text(
'Danh sách Ghi nhận điểm',
style: TextStyle(color: Colors.black),
style: TextStyle(color: colorScheme.onSurface),
),
actions: [
IconButton(
icon: const FaIcon(
icon: FaIcon(
FontAwesomeIcons.plus,
color: Colors.black,
color: colorScheme.onSurface,
size: 20,
),
onPressed: () {
@@ -57,7 +58,7 @@ class PointsRecordsPage extends ConsumerWidget {
const SizedBox(width: AppSpacing.sm),
],
elevation: AppBarSpecs.elevation,
backgroundColor: AppColors.white,
backgroundColor: colorScheme.surface,
centerTitle: false,
),
body: Column(
@@ -68,16 +69,16 @@ class PointsRecordsPage extends ConsumerWidget {
child: TextField(
decoration: InputDecoration(
hintText: 'Mã yêu cầu',
prefixIcon: const Icon(Icons.search, color: AppColors.grey500),
prefixIcon: Icon(Icons.search, color: colorScheme.onSurfaceVariant),
filled: true,
fillColor: AppColors.white,
fillColor: colorScheme.surface,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: AppColors.grey100),
borderSide: BorderSide(color: colorScheme.surfaceContainerHighest),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: AppColors.grey100),
borderSide: BorderSide(color: colorScheme.surfaceContainerHighest),
),
),
onChanged: (value) {
@@ -95,6 +96,7 @@ class PointsRecordsPage extends ConsumerWidget {
_buildFilterChip(
context,
ref,
colorScheme,
label: 'Tất cả',
isSelected: selectedStatus == null,
onTap: () =>
@@ -107,6 +109,7 @@ class PointsRecordsPage extends ConsumerWidget {
child: _buildFilterChip(
context,
ref,
colorScheme,
label: status.displayName,
isSelected: selectedStatus == status,
onTap: () =>
@@ -134,28 +137,28 @@ class PointsRecordsPage extends ConsumerWidget {
children: [
SizedBox(
height: MediaQuery.of(context).size.height * 0.5,
child: const Center(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FaIcon(
FontAwesomeIcons.folderOpen,
size: 64,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
SizedBox(height: 16),
const SizedBox(height: 16),
Text(
'Không có ghi nhận điểm nào',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
SizedBox(height: 8),
const SizedBox(height: 8),
Text(
'Không tìm thấy ghi nhận điểm phù hợp',
style: TextStyle(color: AppColors.grey500),
style: TextStyle(color: colorScheme.onSurfaceVariant),
),
],
),
@@ -175,7 +178,7 @@ class PointsRecordsPage extends ConsumerWidget {
itemCount: records.length,
itemBuilder: (context, index) {
final record = records[index];
return _buildRecordCard(context, record);
return _buildRecordCard(context, colorScheme, record);
},
),
);
@@ -202,24 +205,24 @@ class PointsRecordsPage extends ConsumerWidget {
color: AppColors.danger,
),
const SizedBox(height: 16),
const Text(
Text(
'Có lỗi xảy ra',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
const SizedBox(height: 8),
Text(
error.toString(),
style: const TextStyle(color: AppColors.grey500),
style: TextStyle(color: colorScheme.onSurfaceVariant),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
const Text(
Text(
'Kéo xuống để thử lại',
style: TextStyle(color: AppColors.grey500),
style: TextStyle(color: colorScheme.onSurfaceVariant),
),
],
),
@@ -237,7 +240,8 @@ class PointsRecordsPage extends ConsumerWidget {
Widget _buildFilterChip(
BuildContext context,
WidgetRef ref, {
WidgetRef ref,
ColorScheme colorScheme, {
required String label,
required bool isSelected,
required VoidCallback onTap,
@@ -247,16 +251,16 @@ class PointsRecordsPage extends ConsumerWidget {
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: isSelected ? AppColors.primaryBlue : AppColors.white,
color: isSelected ? colorScheme.primary : colorScheme.surface,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isSelected ? AppColors.primaryBlue : AppColors.grey100,
color: isSelected ? colorScheme.primary : colorScheme.surfaceContainerHighest,
),
),
child: Text(
label,
style: TextStyle(
color: isSelected ? AppColors.white : AppColors.grey900,
color: isSelected ? colorScheme.surface : colorScheme.onSurface,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
),
),
@@ -264,7 +268,7 @@ class PointsRecordsPage extends ConsumerWidget {
);
}
Widget _buildRecordCard(BuildContext context, PointsRecord record) {
Widget _buildRecordCard(BuildContext context, ColorScheme colorScheme, PointsRecord record) {
final currencyFormat = NumberFormat.currency(
locale: 'vi_VN',
symbol: '',
@@ -293,29 +297,29 @@ class PointsRecordsPage extends ConsumerWidget {
children: [
Text(
'#${record.recordId}',
style: const TextStyle(
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
_buildStatusBadge(record.status),
_buildStatusBadge(colorScheme, record.status),
],
),
const SizedBox(height: 8),
Text(
'Ngày gửi: ${DateFormat('dd/MM/yyyy').format(record.submittedAt)}',
style: const TextStyle(
style: TextStyle(
fontSize: 13,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 4),
Text(
'Giá trị đơn hàng: ${currencyFormat.format(record.invoiceAmount)}',
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
if (record.rejectReason != null) ...[
@@ -354,7 +358,7 @@ class PointsRecordsPage extends ConsumerWidget {
);
}
Widget _buildStatusBadge(PointsStatus status) {
Widget _buildStatusBadge(ColorScheme colorScheme, PointsStatus status) {
final color = _getStatusColor(status);
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),

View File

@@ -28,28 +28,29 @@ class RewardsPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final colorScheme = Theme.of(context).colorScheme;
final filteredGifts = ref.watch(filteredGiftsProvider);
final selectedCategory = ref.watch(selectedGiftCategoryProvider);
return Scaffold(
backgroundColor: const Color(0xFFF4F6F8),
backgroundColor: colorScheme.surfaceContainerLowest,
appBar: AppBar(
leading: IconButton(
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
icon: FaIcon(FontAwesomeIcons.arrowLeft, color: colorScheme.onSurface, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
title: Text(
'Đổi quà tặng',
style: TextStyle(color: Colors.black),
style: TextStyle(color: colorScheme.onSurface),
),
elevation: AppBarSpecs.elevation,
backgroundColor: AppColors.white,
foregroundColor: AppColors.grey900,
backgroundColor: colorScheme.surface,
foregroundColor: colorScheme.onSurface,
centerTitle: false,
actions: [
IconButton(
icon: const FaIcon(FontAwesomeIcons.circleInfo, color: Colors.black, size: 20),
onPressed: () => _showInfoDialog(context),
icon: FaIcon(FontAwesomeIcons.circleInfo, color: colorScheme.onSurface, size: 20),
onPressed: () => _showInfoDialog(context, colorScheme),
),
const SizedBox(width: AppSpacing.sm),
],
@@ -71,14 +72,14 @@ class RewardsPage extends ConsumerWidget {
// Category Filter Pills
SliverToBoxAdapter(
child: _buildCategoryFilter(context, ref, selectedCategory),
child: _buildCategoryFilter(context, ref, selectedCategory, colorScheme),
),
// Rewards Grid
SliverPadding(
padding: const EdgeInsets.fromLTRB(12, 8, 12, 24),
sliver: filteredGifts.isEmpty
? _buildEmptyState()
? _buildEmptyState(colorScheme)
: SliverGrid(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
@@ -91,7 +92,7 @@ class RewardsPage extends ConsumerWidget {
final gift = filteredGifts[index];
return RewardCard(
gift: gift,
onRedeem: () => _handleRedeemGift(context, ref, gift),
onRedeem: () => _handleRedeemGift(context, ref, gift, colorScheme),
);
}, childCount: filteredGifts.length),
),
@@ -103,7 +104,7 @@ class RewardsPage extends ConsumerWidget {
}
/// Show info dialog with usage instructions
void _showInfoDialog(BuildContext context) {
void _showInfoDialog(BuildContext context, ColorScheme colorScheme) {
showDialog<void>(
context: context,
builder: (context) => AlertDialog(
@@ -123,18 +124,23 @@ class RewardsPage extends ConsumerWidget {
const SizedBox(height: 12),
_buildInfoItem(
'Sử dụng điểm tích lũy của bạn để đổi các phần quà giá trị trong danh mục.',
colorScheme,
),
_buildInfoItem(
'Bấm vào một phần quà để xem chi tiết và điều kiện áp dụng.',
colorScheme,
),
_buildInfoItem(
'Khi xác nhận đổi quà, bạn có thể chọn "Nhận hàng tại Showroom".',
colorScheme,
),
_buildInfoItem(
'Nếu chọn "Nhận hàng tại Showroom", bạn sẽ cần chọn Showroom bạn muốn đến nhận từ danh sách thả xuống.',
colorScheme,
),
_buildInfoItem(
'Quà đã đổi sẽ được chuyển vào mục "Quà của tôi" (trong trang Hội viên).',
colorScheme,
),
],
),
@@ -143,8 +149,8 @@ class RewardsPage extends ConsumerWidget {
ElevatedButton(
onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
foregroundColor: Colors.white,
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
minimumSize: const Size(double.infinity, 44),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
@@ -161,19 +167,19 @@ class RewardsPage extends ConsumerWidget {
}
/// Build info item with bullet point
Widget _buildInfoItem(String text) {
Widget _buildInfoItem(String text, ColorScheme colorScheme) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.only(top: 6),
child: FaIcon(FontAwesomeIcons.solidCircle, size: 6, color: AppColors.grey500),
Padding(
padding: const EdgeInsets.only(top: 6),
child: FaIcon(FontAwesomeIcons.solidCircle, size: 6, color: colorScheme.onSurfaceVariant),
),
const SizedBox(width: 12),
Expanded(
child: Text(text, style: TextStyle(fontSize: 14, height: 1.5)),
child: Text(text, style: const TextStyle(fontSize: 14, height: 1.5)),
),
],
),
@@ -185,6 +191,7 @@ class RewardsPage extends ConsumerWidget {
BuildContext context,
WidgetRef ref,
GiftCategory? selectedCategory,
ColorScheme colorScheme,
) {
return Container(
height: 48,
@@ -201,6 +208,7 @@ class RewardsPage extends ConsumerWidget {
onTap: () {
ref.read(selectedGiftCategoryProvider.notifier).clearSelection();
},
colorScheme: colorScheme,
),
const SizedBox(width: 8),
@@ -215,6 +223,7 @@ class RewardsPage extends ConsumerWidget {
.read(selectedGiftCategoryProvider.notifier)
.setCategory(GiftCategory.voucher);
},
colorScheme: colorScheme,
),
const SizedBox(width: 8),
@@ -229,6 +238,7 @@ class RewardsPage extends ConsumerWidget {
.read(selectedGiftCategoryProvider.notifier)
.setCategory(GiftCategory.product);
},
colorScheme: colorScheme,
),
const SizedBox(width: 8),
@@ -243,6 +253,7 @@ class RewardsPage extends ConsumerWidget {
.read(selectedGiftCategoryProvider.notifier)
.setCategory(GiftCategory.service);
},
colorScheme: colorScheme,
),
const SizedBox(width: 8),
@@ -257,6 +268,7 @@ class RewardsPage extends ConsumerWidget {
.read(selectedGiftCategoryProvider.notifier)
.setCategory(GiftCategory.discount);
},
colorScheme: colorScheme,
),
],
),
@@ -270,13 +282,14 @@ class RewardsPage extends ConsumerWidget {
required String label,
required bool isSelected,
required VoidCallback onTap,
required ColorScheme colorScheme,
}) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: isSelected ? AppColors.primaryBlue : AppColors.grey100,
color: isSelected ? colorScheme.primary : colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(20),
),
child: Center(
@@ -285,7 +298,7 @@ class RewardsPage extends ConsumerWidget {
style: TextStyle(
fontSize: 14,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
color: isSelected ? Colors.white : AppColors.grey900,
color: isSelected ? colorScheme.onPrimary : colorScheme.onSurface,
),
),
),
@@ -294,7 +307,7 @@ class RewardsPage extends ConsumerWidget {
}
/// Build empty state
Widget _buildEmptyState() {
Widget _buildEmptyState(ColorScheme colorScheme) {
return SliverFillRemaining(
child: Center(
child: Column(
@@ -303,21 +316,21 @@ class RewardsPage extends ConsumerWidget {
FaIcon(
FontAwesomeIcons.gift,
size: 64,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
const SizedBox(height: 16),
const Text(
Text(
'Không có quà tặng nào',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 8),
const Text(
Text(
'Vui lòng thử lại sau',
style: TextStyle(fontSize: 14, color: AppColors.grey500),
style: TextStyle(fontSize: 14, color: colorScheme.onSurfaceVariant),
),
],
),
@@ -330,6 +343,7 @@ class RewardsPage extends ConsumerWidget {
BuildContext context,
WidgetRef ref,
GiftCatalog gift,
ColorScheme colorScheme,
) {
final numberFormat = NumberFormat('#,###', 'vi_VN');
final pointsState = ref.read(loyaltyPointsProvider);
@@ -342,15 +356,15 @@ class RewardsPage extends ConsumerWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
const Text(
'Bạn có chắc muốn đổi quà này?',
style: const TextStyle(fontSize: 14),
style: TextStyle(fontSize: 14),
),
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColors.grey50,
color: colorScheme.surfaceContainerLowest,
borderRadius: BorderRadius.circular(8),
),
child: Column(
@@ -370,10 +384,10 @@ class RewardsPage extends ConsumerWidget {
const Text('Chi phí:', style: TextStyle(fontSize: 13)),
Text(
'${numberFormat.format(gift.pointsCost)} điểm',
style: const TextStyle(
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: AppColors.primaryBlue,
color: colorScheme.primary,
),
),
],
@@ -411,8 +425,8 @@ class RewardsPage extends ConsumerWidget {
_processRedemption(context, ref, gift);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
foregroundColor: Colors.white,
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
),
child: const Text('Xác nhận'),
),