proxibuy_bussiness/lib/presentation/widgets/analytics_discount_card.dart

329 lines
11 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/discount_management/bloc/discount_management_bloc.dart';
import 'package:business_panel/presentation/pages/add_discount_page.dart';
import 'package:business_panel/presentation/pages/sales_analysis_page.dart';
import 'package:business_panel/presentation/widgets/delete_confirmation_dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:persian_datetime_picker/persian_datetime_picker.dart';
import 'package:slide_countdown/slide_countdown.dart';
class AnalyticsDiscountCard extends StatelessWidget {
final DiscountEntity discount;
const AnalyticsDiscountCard({super.key, required this.discount});
@override
Widget build(BuildContext context) {
final remaining = discount.endDate != null
? discount.endDate!.difference(DateTime.now())
: const Duration(seconds: -1);
final bool isExpired = remaining.isNegative;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!isExpired) _buildActionButtons(context),
const SizedBox(
height: 5,
),
Card(
color: Colors.white,
elevation: 0,
margin: const EdgeInsets.symmetric(vertical: 8),
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: [
_buildProductImage(),
const SizedBox(width: 16),
_buildCardDetails(context, remaining),
],
),
),
),
],
);
}
Widget _buildProductImage() {
return ClipRRect(
borderRadius: BorderRadius.circular(15),
child: (discount.images.isNotEmpty && discount.images.first.isNotEmpty)
? Image.network(
discount.images.first,
width: 100,
height: 100,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) =>
_buildImagePlaceholder(),
)
: _buildImagePlaceholder(),
);
}
Widget _buildImagePlaceholder() {
return 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),
);
}
Widget _buildCardDetails(BuildContext context, Duration remaining) {
return Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 5),
_buildInfoRow(
icon: Assets.icons.shoppingCart,
text: discount.name,
textColor: Colors.grey.shade600),
const SizedBox(height: 5),
if (discount.endDate == null)
_buildStatusText('تاریخ نامعتبر', Colors.orange)
else if (remaining.isNegative)
_buildExpiredDateRange()
else
_buildCountdownSection(remaining),
const SizedBox(height: 10),
InkWell(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => SalesAnalysisPage(discount: discount),
),
);
},
child: _buildInfoRow(
icon: Assets.icons.chart,
text: "آنالیز فروش",
textColor: AppColors.active,
isBold: true,
),
),
],
),
);
}
Widget _buildInfoRow(
{required String icon,
required String text,
Color? textColor,
bool isBold = false}) {
return Row(
children: [
SvgPicture.asset(icon, width: 18, color: Colors.grey.shade700),
const SizedBox(width: 10),
Expanded(
child: Text(
text,
style: TextStyle(
fontSize: 17,
color: textColor ?? Colors.black,
fontWeight: FontWeight.normal,
),
overflow: TextOverflow.ellipsis,
),
),
],
);
}
Widget _buildStatusText(String text, Color color) {
return Text(
text,
style: TextStyle(color: color, fontWeight: FontWeight.bold),
);
}
Widget _buildExpiredDateRange() {
final jalaliStart = Jalali.fromDateTime(discount.startDate!);
final jalaliEnd = Jalali.fromDateTime(discount.endDate!);
final formattedDateRange =
'${jalaliStart.day} ${jalaliStart.formatter.mN} تا ${jalaliEnd.day} ${jalaliEnd.formatter.mN} ${jalaliEnd.year}';
return Row(
children: [
SvgPicture.asset(Assets.icons.clunder,
width: 18, color: Colors.grey.shade700),
const SizedBox(width: 10),
Expanded(
child: Text(
formattedDateRange,
style: const TextStyle(
color: AppColors.secTitle,
fontWeight: FontWeight.normal,
fontSize: 14,
),
overflow: TextOverflow.ellipsis,
),
),
],
);
}
Widget _buildCountdownSection(Duration remaining) {
return Row(
children: [
SvgPicture.asset(Assets.icons.timerPause,
width: 18, color: Colors.grey.shade700),
const SizedBox(width: 5),
Expanded(child: _buildCountdownTimer(remaining)),
],
);
}
Widget _buildActionButtons(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(right: 8),
child: Row(
children: [
InkWell(
onTap: () => _showDeleteConfirmation(context),
borderRadius: BorderRadius.circular(8),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8.0),
decoration: BoxDecoration(
color: AppColors.backDelete,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColors.expiryReserve)),
child: Padding(
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(Assets.icons.trash,
width: 20, color: AppColors.expiryReserve),
const SizedBox(width: 5),
const Text("حذف",
style: TextStyle(
color: AppColors.expiryReserve,
fontWeight: FontWeight.bold)),
],
),
),
),
),
const SizedBox(width: 15),
InkWell(
onTap: () {
Navigator.of(context)
.push(
MaterialPageRoute(
builder: (_) => AddDiscountPage(discountId: discount.id),
),
)
.then((value) {
if (value == true) {
final bloc = context.read<DiscountManagementBloc>();
bloc.add(
FetchManagedDiscounts(status: 1));
}
});
},
borderRadius: BorderRadius.circular(8),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8.0),
decoration: BoxDecoration(
color: AppColors.backEdit,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColors.selectedImg)),
child: Padding(
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(Assets.icons.edit,
width: 20, color: AppColors.selectedImg),
const SizedBox(width: 5),
const Text("ویرایش",
style: TextStyle(
color: AppColors.selectedImg,
fontWeight: FontWeight.bold)),
],
),
),
),
),
],
),
);
}
void _showDeleteConfirmation(BuildContext context) {
showDeleteConfirmationDialog(
context,
title: 'حذف تخفیف',
content: 'با حذف این تخفیف، رزروهای احتمالی هم غیرفعال می‌شن و دیگه برای مشتری‌ها نمایش داده نمی‌شه.',
onConfirm: () {
context
.read<DiscountManagementBloc>()
.add(DeleteDiscount(discount.id));
},
);
}
Widget _buildCountdownTimer(Duration remaining) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Directionality(
textDirection: TextDirection.ltr,
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: 9, 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: 35, child: Text("دقیقه", style: labelStyle)));
labels
.add(const SizedBox(width: 35, child: Text(" ثانیه", style: labelStyle)));
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: labels.reversed.toList(),
);
}
}