324 lines
11 KiB
Dart
324 lines
11 KiB
Dart
// lib/presentation/widgets/analytics_discount_card.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/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),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 15),
|
|
const Divider(height: 1),
|
|
const SizedBox(height: 20),
|
|
],
|
|
);
|
|
}
|
|
|
|
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),
|
|
_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)); // Defaulting to active
|
|
}
|
|
});
|
|
},
|
|
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(),
|
|
);
|
|
}
|
|
} |