update theme
This commit is contained in:
@@ -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,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
],
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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'),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user