476 lines
15 KiB
Dart
476 lines
15 KiB
Dart
/// Promotion Detail Page
|
|
///
|
|
/// Displays full details of a selected promotion including:
|
|
/// - Banner image
|
|
/// - Title and date range
|
|
/// - Program content
|
|
/// - Terms and conditions
|
|
/// - Contact information
|
|
library;
|
|
|
|
import 'package:cached_network_image/cached_network_image.dart';
|
|
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:worker/core/constants/ui_constants.dart';
|
|
import 'package:worker/core/router/app_router.dart';
|
|
import 'package:worker/core/theme/colors.dart';
|
|
import 'package:worker/features/home/domain/entities/promotion.dart';
|
|
import 'package:worker/features/home/presentation/providers/promotions_provider.dart';
|
|
import 'package:worker/features/promotions/presentation/widgets/highlight_box.dart';
|
|
import 'package:worker/features/promotions/presentation/widgets/promotion_section.dart';
|
|
|
|
/// Promotion Detail Page
|
|
///
|
|
/// Full-screen detail view of a promotion with scrollable content
|
|
/// and fixed bottom action bar.
|
|
class PromotionDetailPage extends ConsumerStatefulWidget {
|
|
const PromotionDetailPage({this.promotionId, super.key});
|
|
|
|
/// Promotion ID
|
|
final String? promotionId;
|
|
|
|
@override
|
|
ConsumerState<PromotionDetailPage> createState() =>
|
|
_PromotionDetailPageState();
|
|
}
|
|
|
|
class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
|
|
bool _isBookmarked = false;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
// Watch promotions provider
|
|
final promotionsAsync = ref.watch(promotionsProvider);
|
|
|
|
return promotionsAsync.when(
|
|
data: (promotions) {
|
|
// Find promotion by ID
|
|
final promotion = promotions.firstWhere(
|
|
(p) => p.id == widget.promotionId,
|
|
orElse: () => promotions.first,
|
|
);
|
|
|
|
return _buildDetailContent(promotion);
|
|
},
|
|
loading: () => Scaffold(
|
|
appBar: AppBar(
|
|
leading: IconButton(
|
|
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
|
|
onPressed: () => context.pop(),
|
|
),
|
|
title: const Text(
|
|
'Chi tiết khuyến mãi',
|
|
style: TextStyle(color: Colors.black),
|
|
),
|
|
elevation: AppBarSpecs.elevation,
|
|
backgroundColor: AppColors.white,
|
|
foregroundColor: AppColors.grey900,
|
|
centerTitle: false,
|
|
),
|
|
body: const Center(child: CircularProgressIndicator()),
|
|
),
|
|
error: (error, stack) => Scaffold(
|
|
appBar: AppBar(
|
|
leading: IconButton(
|
|
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
|
|
onPressed: () => context.pop(),
|
|
),
|
|
title: const Text(
|
|
'Chi tiết khuyến mãi',
|
|
style: TextStyle(color: Colors.black),
|
|
),
|
|
elevation: AppBarSpecs.elevation,
|
|
backgroundColor: AppColors.white,
|
|
foregroundColor: AppColors.grey900,
|
|
centerTitle: false,
|
|
),
|
|
body: Center(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
const FaIcon(
|
|
FontAwesomeIcons.circleExclamation,
|
|
size: 64,
|
|
color: AppColors.danger,
|
|
),
|
|
const SizedBox(height: 16),
|
|
const Text(
|
|
'Không thể tải thông tin khuyến mãi',
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
error.toString(),
|
|
style: const TextStyle(fontSize: 14, color: AppColors.grey500),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildDetailContent(Promotion promotion) {
|
|
return Scaffold(
|
|
backgroundColor: Colors.white,
|
|
body: Stack(
|
|
children: [
|
|
// Scrollable Content
|
|
CustomScrollView(
|
|
slivers: [
|
|
// App Bar
|
|
SliverAppBar(
|
|
pinned: true,
|
|
backgroundColor: AppColors.white,
|
|
foregroundColor: AppColors.grey900,
|
|
elevation: AppBarSpecs.elevation,
|
|
leading: IconButton(
|
|
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
|
|
onPressed: () => context.pop(),
|
|
),
|
|
title: const Text(
|
|
'Chi tiết khuyến mãi',
|
|
style: TextStyle(color: Colors.black),
|
|
),
|
|
centerTitle: false,
|
|
actions: [
|
|
// Share Button
|
|
IconButton(
|
|
icon: const FaIcon(FontAwesomeIcons.shareNodes, color: Colors.black, size: 20),
|
|
onPressed: _handleShare,
|
|
),
|
|
|
|
// Bookmark Button
|
|
IconButton(
|
|
icon: FaIcon(
|
|
_isBookmarked ? FontAwesomeIcons.solidBookmark : FontAwesomeIcons.bookmark,
|
|
color: Colors.black,
|
|
size: 20,
|
|
),
|
|
onPressed: _handleBookmark,
|
|
),
|
|
const SizedBox(width: AppSpacing.sm),
|
|
],
|
|
),
|
|
|
|
// Content
|
|
SliverToBoxAdapter(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// Banner Image
|
|
_buildBannerImage(promotion),
|
|
|
|
// Promotion Header
|
|
_buildPromotionHeader(promotion),
|
|
|
|
// Program Content Section
|
|
_buildProgramContentSection(),
|
|
|
|
// Terms & Conditions Section
|
|
_buildTermsSection(),
|
|
|
|
// Contact Info Section
|
|
_buildContactSection(),
|
|
|
|
// Bottom padding for action bar
|
|
const SizedBox(height: 100),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
|
|
// Fixed Bottom Action Bar
|
|
Positioned(left: 0, right: 0, bottom: 0, child: _buildActionBar()),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Build banner image section
|
|
Widget _buildBannerImage(Promotion promotion) {
|
|
return CachedNetworkImage(
|
|
imageUrl: promotion.imageUrl,
|
|
width: double.infinity,
|
|
height: 200,
|
|
fit: BoxFit.cover,
|
|
placeholder: (context, url) => Container(
|
|
height: 200,
|
|
color: AppColors.grey100,
|
|
child: const Center(child: CircularProgressIndicator()),
|
|
),
|
|
errorWidget: (context, url, error) => Container(
|
|
height: 200,
|
|
color: AppColors.grey100,
|
|
child: const Center(
|
|
child: FaIcon(
|
|
FontAwesomeIcons.image,
|
|
size: 64,
|
|
color: AppColors.grey500,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Build promotion header with title and date
|
|
Widget _buildPromotionHeader(Promotion promotion) {
|
|
return Container(
|
|
padding: const EdgeInsets.fromLTRB(16, 24, 16, 16),
|
|
decoration: const BoxDecoration(
|
|
border: Border(bottom: BorderSide(color: Color(0xFFE2E8F0), width: 1)),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// Title
|
|
Text(
|
|
promotion.title,
|
|
style: const TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.w700,
|
|
color: Color(0xFF1E293B),
|
|
height: 1.3,
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
|
|
// Date Range and Status
|
|
Wrap(
|
|
spacing: 8,
|
|
crossAxisAlignment: WrapCrossAlignment.center,
|
|
children: [
|
|
// Clock icon and date
|
|
const FaIcon(
|
|
FontAwesomeIcons.clock,
|
|
size: 16,
|
|
color: Color(0xFFF59E0B), // warning color
|
|
),
|
|
Text(
|
|
_formatDateRange(promotion),
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w500,
|
|
color: Color(0xFFF59E0B),
|
|
),
|
|
),
|
|
|
|
// Status Badge
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: 12,
|
|
vertical: 4,
|
|
),
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF10B981), // success color
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
child: const Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
FaIcon(
|
|
FontAwesomeIcons.fire,
|
|
size: 14,
|
|
color: Colors.white,
|
|
),
|
|
SizedBox(width: 4),
|
|
Text(
|
|
'Đang diễn ra',
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Build program content section
|
|
Widget _buildProgramContentSection() {
|
|
return const PromotionSection(
|
|
title: 'Nội dung chương trình',
|
|
icon: FontAwesomeIcons.gift,
|
|
content: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
PromotionContentText(
|
|
'Chương trình khuyến mãi đặc biệt dành cho các công trình xây dựng với mức giảm giá hấp dẫn nhất trong năm.',
|
|
),
|
|
|
|
// Highlight Box
|
|
HighlightBox(
|
|
emoji: '🎉',
|
|
text: 'Giảm giá lên đến 30% cho tất cả sản phẩm gạch men cao cấp',
|
|
),
|
|
|
|
// Discount Details
|
|
PromotionContentText('Ưu đãi chi tiết:', isBold: true),
|
|
PromotionBulletList(
|
|
items: [
|
|
'Gạch men 60x60cm: Giảm 25% - 30%',
|
|
'Gạch men 80x80cm: Giảm 20% - 25%',
|
|
'Gạch men 120x60cm: Giảm 15% - 20%',
|
|
'Gạch granite 60x60cm: Giảm 20% - 25%',
|
|
'Gạch ốp tường: Giảm 15% - 20%',
|
|
],
|
|
),
|
|
|
|
SizedBox(height: 16),
|
|
|
|
// Additional Benefits
|
|
PromotionContentText('Ưu đãi bổ sung:', isBold: true),
|
|
PromotionBulletList(
|
|
items: [
|
|
'Miễn phí vận chuyển cho đơn hàng từ 500m²',
|
|
'Tặng keo dán gạch cho đơn hàng từ 200m²',
|
|
'Hỗ trợ thiết kế 3D miễn phí',
|
|
'Bảo hành sản phẩm lên đến 15 năm',
|
|
],
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Build terms and conditions section
|
|
Widget _buildTermsSection() {
|
|
return const PromotionSection(
|
|
title: 'Điều kiện áp dụng',
|
|
icon: FontAwesomeIcons.fileLines,
|
|
content: PromotionBulletList(
|
|
items: [
|
|
'Áp dụng cho tất cả khách hàng là thợ xây dựng đã đăng ký tài khoản',
|
|
'Đơn hàng tối thiểu: 50m² sản phẩm gạch men',
|
|
'Thanh toán tối thiểu 50% giá trị đơn hàng khi đặt',
|
|
'Không áp dụng đồng thời với các chương trình khuyến mãi khác',
|
|
'Giá đã bao gồm VAT, chưa bao gồm phí vận chuyển',
|
|
'Sản phẩm không áp dụng đổi trả sau khi đã cắt, gia công',
|
|
'Thời gian giao hàng: 3-7 ngày làm việc tùy theo khu vực',
|
|
'Khuyến mãi có thể kết thúc sớm nếu hết hàng',
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Build contact information section
|
|
Widget _buildContactSection() {
|
|
return const PromotionSection(
|
|
title: 'Thông tin liên hệ',
|
|
icon: FontAwesomeIcons.phone,
|
|
isLast: true,
|
|
content: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
ContactInfo(
|
|
label: 'Hotline',
|
|
value: '1900-xxxx (8:00 - 18:00 hàng ngày)',
|
|
),
|
|
ContactInfo(label: 'Email', value: 'promotion@company.com'),
|
|
ContactInfo(label: 'Zalo', value: '0123.456.789'),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Build fixed bottom action bar
|
|
Widget _buildActionBar() {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
border: const Border(
|
|
top: BorderSide(color: Color(0xFFE2E8F0), width: 1),
|
|
),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withValues(alpha: 0.1),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, -2),
|
|
),
|
|
],
|
|
),
|
|
padding: const EdgeInsets.all(16),
|
|
child: SafeArea(
|
|
top: false,
|
|
child: ElevatedButton(
|
|
onPressed: _handleViewProducts,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColors.primaryBlue,
|
|
foregroundColor: Colors.white,
|
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
elevation: 0,
|
|
),
|
|
child: const Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
FaIcon(FontAwesomeIcons.eye, size: 18),
|
|
SizedBox(width: 8),
|
|
Text(
|
|
'Xem sản phẩm áp dụng',
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Format date range for display
|
|
String _formatDateRange(Promotion promotion) {
|
|
final startDay = promotion.startDate.day.toString().padLeft(2, '0');
|
|
final startMonth = promotion.startDate.month.toString().padLeft(2, '0');
|
|
final startYear = promotion.startDate.year;
|
|
final endDay = promotion.endDate.day.toString().padLeft(2, '0');
|
|
final endMonth = promotion.endDate.month.toString().padLeft(2, '0');
|
|
final endYear = promotion.endDate.year;
|
|
|
|
return '$startDay/$startMonth/$startYear - $endDay/$endMonth/$endYear';
|
|
}
|
|
|
|
/// Handle share button press
|
|
void _handleShare() {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('Tính năng chia sẻ đang phát triển'),
|
|
duration: Duration(seconds: 2),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Handle bookmark button press
|
|
void _handleBookmark() {
|
|
setState(() {
|
|
_isBookmarked = !_isBookmarked;
|
|
});
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text(
|
|
_isBookmarked ? 'Đã lưu khuyến mãi' : 'Đã bỏ lưu khuyến mãi',
|
|
),
|
|
duration: const Duration(seconds: 2),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Handle view products button press
|
|
void _handleViewProducts() {
|
|
// Navigate to products page
|
|
context.push(RouteNames.products);
|
|
}
|
|
}
|