proxibuy_bussiness/lib/presentation/pages/home_page.dart

380 lines
13 KiB
Dart

import 'package:business_panel/core/config/app_colors.dart';
import 'package:business_panel/domain/entities/discount_entity.dart';
import 'package:business_panel/gen/assets.gen.dart';
import 'package:business_panel/presentation/home/bloc/home_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:slide_countdown/slide_countdown.dart';
import 'package:business_panel/presentation/pages/add_discount_page.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
super.initState();
context.read<HomeBloc>().add(FetchDiscounts());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildCustomAppBar(context),
body: BlocBuilder<HomeBloc, HomeState>(
builder: (context, state) {
if (state is HomeLoading) {
return const Center(child: CircularProgressIndicator());
}
if (state is HomeError) {
return Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text('خطا: ${state.message}', textAlign: TextAlign.center),
),
);
}
if (state is HomeLoaded) {
if (state.discounts.isEmpty) {
return _buildEmptyState();
}
return RefreshIndicator(
onRefresh: () async {
context.read<HomeBloc>().add(FetchDiscounts());
},
child: ListView.builder(
padding: const EdgeInsets.all(16),
// تعداد آیتم‌ها یکی بیشتر از تعداد تخفیف‌هاست تا دکمه هم جا شود
itemCount: state.discounts.length + 1,
itemBuilder: (context, index) {
// اگر ایندکس مربوط به آخرین آیتم بود، دکمه را نمایش بده
if (index == state.discounts.length) {
return _buildAddDiscountButton();
}
// در غیر این صورت، کارت تخفیف را نمایش بده
final discount = state.discounts[index];
return _buildDiscountCard(discount);
},
),
);
}
// حالت پیش‌فرض
return _buildEmptyState();
},
),
);
}
Widget _buildEmptyState() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(Assets.images.emptyHome, height: 200),
const SizedBox(height: 20),
const Text(
"هنوز تخفیفی ثبت نکرده‌اید",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: _buildAddDiscountButton(),
),
],
),
);
}
Widget _buildAddDiscountButton() {
return Padding(
padding: const EdgeInsets.only(top: 16.0),
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.confirm,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (_) => const AddDiscountPage()))
.then((_) {
// رفرش لیست بعد از بازگشت از صفحه افزودن
context.read<HomeBloc>().add(FetchDiscounts());
});
},
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.add, color: Colors.white),
SizedBox(width: 8),
Text(
"تعریف تخفیف جدید",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.normal,
color: Colors.white,
),
),
],
),
),
),
);
}
Widget _buildDiscountCard(DiscountEntity discount) {
final remaining = discount.endDate != null
? discount.endDate!.difference(DateTime.now())
: const Duration(seconds: -1);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
"تخفیف ${discount.type}",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
InkWell(
onTap: () {
// TODO: Implement edit functionality
},
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
SvgPicture.asset(Assets.icons.edit, width: 20, color: AppColors.active),
const SizedBox(width: 5),
const Text("ویرایش", style: TextStyle(color: AppColors.active)),
],
),
),
),
],
),
const Divider(height: 1),
const SizedBox(height: 10),
Card(
color: Colors.white,
elevation: 0,
margin: const EdgeInsets.only(bottom: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
side: BorderSide(color: Colors.grey.shade300, width: 1),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (discount.images.isNotEmpty && discount.images.first.isNotEmpty)
ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Image.network(
discount.images.first,
width: 100,
height: 100,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) => Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(15),
),
child: const Icon(Icons.image_not_supported, color: Colors.grey),
),
),
)
else
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(15),
),
child: const Icon(Icons.store, color: Colors.grey, size: 50),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
SvgPicture.asset(Assets.icons.shop, width: 18, color: Colors.grey.shade700),
const SizedBox(width: 10),
Expanded(
child: Text(
discount.shopName,
style: const TextStyle(fontSize: 16),
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 8),
Row(
children: [
SvgPicture.asset(Assets.icons.shoppingCart, width: 18, color: Colors.grey.shade700),
const SizedBox(width: 10),
Expanded(
child: Text(
discount.name,
style: TextStyle(fontSize: 15, color: Colors.grey.shade600),
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 12),
if (discount.endDate == null)
const Text(
'تاریخ نامعتبر',
style: TextStyle(color: Colors.orange, fontWeight: FontWeight.bold),
)
else if (remaining.isNegative)
const Text(
'منقضی شده',
style: TextStyle(color: AppColors.expiryReserve, fontWeight: FontWeight.bold),
)
else
Row(
children: [
SvgPicture.asset(Assets.icons.timerPause, width: 18, color: Colors.grey.shade700),
const SizedBox(width: 10),
Expanded(child: _buildCountdownTimer(remaining)),
],
),
],
),
),
],
),
),
),
],
);
}
Widget _buildCountdownTimer(Duration remaining) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Localizations.override(
context: context,
locale: const Locale('en'),
child: SlideCountdown(
duration: remaining,
slideDirection: SlideDirection.up,
separator: ':',
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
color: AppColors.countdown,
),
separatorStyle: const TextStyle(
fontSize: 15,
color: AppColors.countdown,
),
decoration: const BoxDecoration(color: Colors.transparent),
shouldShowDays: (d) => d.inDays > 0,
shouldShowHours: (d) => true,
shouldShowMinutes: (d) => true,
),
),
const SizedBox(height: 4),
_buildTimerLabels(remaining),
],
);
}
Widget _buildTimerLabels(Duration duration) {
const labelStyle = TextStyle(fontSize: 10, color: AppColors.selectedImg);
List<Widget> labels = [];
if (duration.inDays > 0) {
labels.add(const SizedBox(width: 30, child: Text("روز", style: labelStyle)));
}
if (duration.inHours > 0 || duration.inDays > 0) {
labels.add(const SizedBox(width: 35, child: Text("ساعت", style: labelStyle)));
}
labels.add(const SizedBox(width: 30, child: Text("دقیقه", style: labelStyle)));
labels.add(const SizedBox(width: 30, child: Text("ثانیه", style: labelStyle)));
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: labels.reversed.toList(),
);
}
PreferredSizeWidget _buildCustomAppBar(BuildContext context) {
return PreferredSize(
preferredSize: const Size.fromHeight(70.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.vertical(
bottom: Radius.circular(15),
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(Assets.icons.logoWithName),
Row(
children: [
IconButton(
onPressed: () {},
icon: SvgPicture.asset(
Assets.icons.discountShape,
color: Colors.black,
),
),
IconButton(
onPressed: () {},
icon: SvgPicture.asset(Assets.icons.scanBarcode),
),
],
),
],
),
),
),
),
);
}
}