313 lines
11 KiB
Dart
313 lines
11 KiB
Dart
/// Page: Home Page
|
||
///
|
||
/// Main dashboard screen of the Worker app.
|
||
/// Displays member card, promotions, and quick action sections.
|
||
library;
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import 'package:worker/core/theme/colors.dart';
|
||
import 'package:worker/features/home/presentation/providers/member_card_provider.dart';
|
||
import 'package:worker/features/home/presentation/providers/promotions_provider.dart';
|
||
import 'package:worker/features/home/presentation/widgets/member_card_widget.dart';
|
||
import 'package:worker/features/home/presentation/widgets/promotion_slider.dart';
|
||
import 'package:worker/features/home/presentation/widgets/quick_action_section.dart';
|
||
|
||
/// Home Page
|
||
///
|
||
/// Main entry point of the app after login.
|
||
/// Shows:
|
||
/// - Member card (Diamond/Platinum/Gold)
|
||
/// - Promotional banners
|
||
/// - Quick action sections
|
||
/// - Bottom navigation
|
||
/// - Floating action button (Chat)
|
||
class HomePage extends ConsumerWidget {
|
||
const HomePage({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context, WidgetRef ref) {
|
||
// Watch member card state
|
||
final memberCardAsync = ref.watch(memberCardProvider);
|
||
|
||
// Watch promotions state
|
||
final promotionsAsync = ref.watch(promotionsProvider);
|
||
|
||
return Scaffold(
|
||
backgroundColor: AppColors.grey50,
|
||
body: RefreshIndicator(
|
||
onRefresh: () async {
|
||
// Refresh both member card and promotions
|
||
await Future.wait<void>([
|
||
ref.read(memberCardProvider.notifier).refresh(),
|
||
ref.read(promotionsProvider.notifier).refresh(),
|
||
]);
|
||
},
|
||
child: CustomScrollView(
|
||
slivers: [
|
||
// App Bar
|
||
const SliverAppBar(
|
||
floating: true,
|
||
snap: true,
|
||
backgroundColor: AppColors.primaryBlue,
|
||
title: Text('Trang ch<63>'),
|
||
centerTitle: true,
|
||
),
|
||
|
||
// Member Card Section
|
||
SliverToBoxAdapter(
|
||
child: memberCardAsync.when(
|
||
data: (memberCard) => MemberCardWidget(memberCard: memberCard),
|
||
loading: () => Container(
|
||
margin: const EdgeInsets.all(16),
|
||
height: 200,
|
||
decoration: BoxDecoration(
|
||
color: AppColors.grey100,
|
||
borderRadius: BorderRadius.circular(16),
|
||
),
|
||
child: const Center(
|
||
child: CircularProgressIndicator(),
|
||
),
|
||
),
|
||
error: (error, stack) => Container(
|
||
margin: const EdgeInsets.all(16),
|
||
padding: const EdgeInsets.all(16),
|
||
decoration: BoxDecoration(
|
||
color: AppColors.danger.withOpacity(0.1),
|
||
borderRadius: BorderRadius.circular(16),
|
||
),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
const Icon(
|
||
Icons.error_outline,
|
||
color: AppColors.danger,
|
||
size: 48,
|
||
),
|
||
const SizedBox(height: 8),
|
||
Text(
|
||
'Kh<EFBFBD>ng th<74> t<>i th<74> th<74>nh vi<76>n',
|
||
style: TextStyle(
|
||
color: AppColors.danger,
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
),
|
||
const SizedBox(height: 4),
|
||
Text(
|
||
error.toString(),
|
||
style: TextStyle(
|
||
color: AppColors.grey500,
|
||
fontSize: 12,
|
||
),
|
||
textAlign: TextAlign.center,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
|
||
// Promotions Section
|
||
SliverToBoxAdapter(
|
||
child: promotionsAsync.when(
|
||
data: (promotions) => promotions.isNotEmpty
|
||
? Padding(
|
||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||
child: PromotionSlider(
|
||
promotions: promotions,
|
||
onPromotionTap: (promotion) {
|
||
// TODO: Navigate to promotion details
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(
|
||
content: Text('Xem chi ti<74>t: ${promotion.title}'),
|
||
),
|
||
);
|
||
},
|
||
),
|
||
)
|
||
: const SizedBox.shrink(),
|
||
loading: () => const Padding(
|
||
padding: EdgeInsets.all(16),
|
||
child: Center(child: CircularProgressIndicator()),
|
||
),
|
||
error: (error, stack) => const SizedBox.shrink(),
|
||
),
|
||
),
|
||
|
||
// Quick Action Sections
|
||
SliverToBoxAdapter(
|
||
child: Column(
|
||
children: [
|
||
const SizedBox(height: 8),
|
||
// Products & Cart Section
|
||
QuickActionSection(
|
||
title: 'S<EFBFBD>n ph<70>m & Gi<47> h<>ng',
|
||
actions: [
|
||
QuickAction(
|
||
icon: Icons.grid_view,
|
||
label: 'S<EFBFBD>n ph<70>m',
|
||
onTap: () => _showComingSoon(context, 'S<EFBFBD>n ph<70>m'),
|
||
),
|
||
QuickAction(
|
||
icon: Icons.shopping_cart,
|
||
label: 'Gi<EFBFBD> h<>ng',
|
||
badge: '3',
|
||
onTap: () => _showComingSoon(context, 'Gi<EFBFBD> h<>ng'),
|
||
),
|
||
QuickAction(
|
||
icon: Icons.favorite,
|
||
label: 'Y<EFBFBD>u th<74>ch',
|
||
onTap: () => _showComingSoon(context, 'Y<EFBFBD>u th<74>ch'),
|
||
),
|
||
],
|
||
),
|
||
|
||
// Loyalty Section
|
||
QuickActionSection(
|
||
title: 'Kh<EFBFBD>ch h<>ng th<74>n thi<68>t',
|
||
actions: [
|
||
QuickAction(
|
||
icon: Icons.card_giftcard,
|
||
label: '<10>i qu<71>',
|
||
onTap: () => _showComingSoon(context, '<10>i qu<71>'),
|
||
),
|
||
QuickAction(
|
||
icon: Icons.history,
|
||
label: 'L<EFBFBD>ch s<> i<>m',
|
||
onTap: () => _showComingSoon(context, 'L<EFBFBD>ch s<> i<>m'),
|
||
),
|
||
QuickAction(
|
||
icon: Icons.person_add,
|
||
label: 'Gi<EFBFBD>i thi<68>u b<>n',
|
||
onTap: () => _showComingSoon(context, 'Gi<EFBFBD>i thi<68>u b<>n'),
|
||
),
|
||
],
|
||
),
|
||
|
||
// Quote Requests Section
|
||
QuickActionSection(
|
||
title: 'Y<EFBFBD>u c<>u b<>o gi<67> & b<>o gi<67>',
|
||
actions: [
|
||
QuickAction(
|
||
icon: Icons.description,
|
||
label: 'Y<EFBFBD>u c<>u b<>o gi<67>',
|
||
onTap: () => _showComingSoon(context, 'Y<EFBFBD>u c<>u b<>o gi<67>'),
|
||
),
|
||
QuickAction(
|
||
icon: Icons.receipt_long,
|
||
label: 'B<EFBFBD>o gi<67>',
|
||
onTap: () => _showComingSoon(context, 'B<EFBFBD>o gi<67>'),
|
||
),
|
||
],
|
||
),
|
||
|
||
// Orders & Payments Section
|
||
QuickActionSection(
|
||
title: '<10>n h<>ng & thanh to<74>n',
|
||
actions: [
|
||
QuickAction(
|
||
icon: Icons.inventory_2,
|
||
label: '<10>n h<>ng',
|
||
onTap: () => _showComingSoon(context, '<10>n h<>ng'),
|
||
),
|
||
QuickAction(
|
||
icon: Icons.payment,
|
||
label: 'Thanh to<74>n',
|
||
onTap: () => _showComingSoon(context, 'Thanh to<74>n'),
|
||
),
|
||
],
|
||
),
|
||
|
||
// Sample Houses & News Section
|
||
QuickActionSection(
|
||
title: 'Nh<EFBFBD> m<>u, d<> <20>n & tin t<>c',
|
||
actions: [
|
||
QuickAction(
|
||
icon: Icons.home_work,
|
||
label: 'Nh<EFBFBD> m<>u',
|
||
onTap: () => _showComingSoon(context, 'Nh<EFBFBD> m<>u'),
|
||
),
|
||
QuickAction(
|
||
icon: Icons.business,
|
||
label: 'ng k<> d<> <20>n',
|
||
onTap: () => _showComingSoon(context, 'ng k<> d<> <20>n'),
|
||
),
|
||
QuickAction(
|
||
icon: Icons.article,
|
||
label: 'Tin t<>c',
|
||
onTap: () => _showComingSoon(context, 'Tin t<>c'),
|
||
),
|
||
],
|
||
),
|
||
|
||
// Bottom Padding (for FAB clearance)
|
||
const SizedBox(height: 80),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
|
||
// Floating Action Button (Chat)
|
||
floatingActionButton: FloatingActionButton(
|
||
onPressed: () => _showComingSoon(context, 'Chat'),
|
||
backgroundColor: AppColors.accentCyan,
|
||
child: const Icon(Icons.chat_bubble),
|
||
),
|
||
|
||
// Bottom Navigation Bar
|
||
bottomNavigationBar: BottomNavigationBar(
|
||
type: BottomNavigationBarType.fixed,
|
||
currentIndex: 0,
|
||
items: const [
|
||
BottomNavigationBarItem(
|
||
icon: Icon(Icons.home),
|
||
label: 'Trang ch<63>',
|
||
),
|
||
BottomNavigationBarItem(
|
||
icon: Icon(Icons.loyalty),
|
||
label: 'H<EFBFBD>i vi<76>n',
|
||
),
|
||
BottomNavigationBarItem(
|
||
icon: Icon(Icons.local_offer),
|
||
label: 'Khuy<EFBFBD>n m<>i',
|
||
),
|
||
BottomNavigationBarItem(
|
||
icon: Badge(
|
||
label: Text('5'),
|
||
child: Icon(Icons.notifications),
|
||
),
|
||
label: 'Th<EFBFBD>ng b<>o',
|
||
),
|
||
BottomNavigationBarItem(
|
||
icon: Icon(Icons.account_circle),
|
||
label: 'C<EFBFBD>i <11>t',
|
||
),
|
||
],
|
||
onTap: (index) {
|
||
// TODO: Implement navigation
|
||
final labels = [
|
||
'Trang ch<63>',
|
||
'H<EFBFBD>i vi<76>n',
|
||
'Khuy<EFBFBD>n m<>i',
|
||
'Th<EFBFBD>ng b<>o',
|
||
'C<EFBFBD>i <11>t'
|
||
];
|
||
_showComingSoon(context, labels[index]);
|
||
},
|
||
),
|
||
);
|
||
}
|
||
|
||
/// Show coming soon message
|
||
void _showComingSoon(BuildContext context, String feature) {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(
|
||
content: Text('$feature - S<>p ra m<>t'),
|
||
duration: const Duration(seconds: 1),
|
||
),
|
||
);
|
||
}
|
||
}
|