Files
worker/lib/features/home/presentation/pages/home_page.dart
Phuoc Nguyen 57bf73e4d1 update
2025-10-17 17:49:01 +07:00

313 lines
11 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// 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),
),
);
}
}