Files
worker/lib/features/home/domain/entities/promotion.dart
2025-11-07 11:52:06 +07:00

177 lines
4.3 KiB
Dart

/// Domain Entity: Promotion
///
/// Represents a promotional offer or campaign displayed on the home screen.
/// This entity contains all information needed to display promotion banners.
///
/// This is a pure domain entity with no external dependencies.
library;
/// Promotion status enum
enum PromotionStatus {
/// Currently active promotion
active,
/// Promotion starting in the future
upcoming,
/// Expired promotion
expired,
}
/// Promotion Entity
///
/// Contains all information needed to display a promotion:
/// - Basic info (title, description)
/// - Visual assets (image URL)
/// - Validity period
/// - Optional discount information
class Promotion {
/// Unique promotion ID
final String id;
/// Promotion title
final String title;
/// Detailed description
final String description;
/// Banner/cover image URL
final String imageUrl;
/// Promotion start date
final DateTime startDate;
/// Promotion end date
final DateTime endDate;
/// Optional discount percentage (e.g., 30 for 30%)
final int? discountPercentage;
/// Optional discount amount
final double? discountAmount;
/// Optional terms and conditions
final String? terms;
/// Optional link to detailed page
final String? detailsUrl;
/// Constructor
const Promotion({
required this.id,
required this.title,
required this.description,
required this.imageUrl,
required this.startDate,
required this.endDate,
this.discountPercentage,
this.discountAmount,
this.terms,
this.detailsUrl,
});
/// Get current promotion status
PromotionStatus get status {
final now = DateTime.now();
if (now.isBefore(startDate)) {
return PromotionStatus.upcoming;
} else if (now.isAfter(endDate)) {
return PromotionStatus.expired;
} else {
return PromotionStatus.active;
}
}
/// Check if promotion is currently active
bool get isActive => status == PromotionStatus.active;
/// Get days remaining until expiry (null if expired or upcoming)
int? get daysRemaining {
if (status != PromotionStatus.active) return null;
return endDate.difference(DateTime.now()).inDays;
}
/// Format discount display text
String? get discountText {
if (discountPercentage != null) {
return 'Giảm $discountPercentage%';
} else if (discountAmount != null) {
return 'Giảm ${discountAmount?.toStringAsFixed(0) ?? '0'}';
}
return null;
}
/// Copy with method for immutability
Promotion copyWith({
String? id,
String? title,
String? description,
String? imageUrl,
DateTime? startDate,
DateTime? endDate,
int? discountPercentage,
double? discountAmount,
String? terms,
String? detailsUrl,
}) {
return Promotion(
id: id ?? this.id,
title: title ?? this.title,
description: description ?? this.description,
imageUrl: imageUrl ?? this.imageUrl,
startDate: startDate ?? this.startDate,
endDate: endDate ?? this.endDate,
discountPercentage: discountPercentage ?? this.discountPercentage,
discountAmount: discountAmount ?? this.discountAmount,
terms: terms ?? this.terms,
detailsUrl: detailsUrl ?? this.detailsUrl,
);
}
/// Equality operator
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Promotion &&
other.id == id &&
other.title == title &&
other.description == description &&
other.imageUrl == imageUrl &&
other.startDate == startDate &&
other.endDate == endDate &&
other.discountPercentage == discountPercentage &&
other.discountAmount == discountAmount &&
other.terms == terms &&
other.detailsUrl == detailsUrl;
}
/// Hash code
@override
int get hashCode {
return Object.hash(
id,
title,
description,
imageUrl,
startDate,
endDate,
discountPercentage,
discountAmount,
terms,
detailsUrl,
);
}
/// String representation
@override
String toString() {
return 'Promotion(id: $id, title: $title, description: $description, '
'imageUrl: $imageUrl, startDate: $startDate, endDate: $endDate, '
'discountPercentage: $discountPercentage, discountAmount: $discountAmount, '
'terms: $terms, detailsUrl: $detailsUrl)';
}
}