192 lines
5.9 KiB
Dart
192 lines
5.9 KiB
Dart
import 'package:equatable/equatable.dart';
|
|
import 'package:proxibuy/data/models/comment_model.dart';
|
|
import 'package:proxibuy/data/models/working_hours.dart';
|
|
|
|
class ShopData {
|
|
final String id;
|
|
final String name;
|
|
final String category;
|
|
final String address;
|
|
final double latitude;
|
|
final double longitude;
|
|
final List<String> properties;
|
|
|
|
const ShopData({
|
|
required this.id,
|
|
required this.name,
|
|
required this.category,
|
|
required this.address,
|
|
required this.latitude,
|
|
required this.longitude,
|
|
required this.properties,
|
|
});
|
|
|
|
factory ShopData.fromJson(Map<String, dynamic> json) {
|
|
return ShopData(
|
|
id: json['_id'] ?? '',
|
|
name: json['Name'] ?? 'نام فروشگاه نامشخص',
|
|
category: json['Category'] ?? 'بدون دستهبندی',
|
|
address: json['Address'] ?? 'آدرس نامشخص',
|
|
latitude: (json['Map']?['coordinates']?[1] as num?)?.toDouble() ?? 0.0,
|
|
longitude: (json['Map']?['coordinates']?[0] as num?)?.toDouble() ?? 0.0,
|
|
properties: List<String>.from(json['Property'] ?? []),
|
|
);
|
|
}
|
|
}
|
|
|
|
class OfferModel extends Equatable {
|
|
final String id;
|
|
final String storeName;
|
|
final String title;
|
|
final String discount;
|
|
final List<String> imageUrls;
|
|
final String category;
|
|
final int distanceInMeters;
|
|
final DateTime expiryTime;
|
|
final String address;
|
|
final List<WorkingHours> workingHours;
|
|
final String discountType;
|
|
final bool isOpen;
|
|
final double rating;
|
|
final int ratingCount;
|
|
final double latitude;
|
|
final double longitude;
|
|
final double originalPrice;
|
|
final double finalPrice;
|
|
final List<String> features;
|
|
final String discountInfo;
|
|
final List<CommentModel> comments;
|
|
|
|
const OfferModel({
|
|
required this.id,
|
|
required this.storeName,
|
|
required this.title,
|
|
required this.discount,
|
|
required this.imageUrls,
|
|
required this.category,
|
|
required this.distanceInMeters,
|
|
required this.expiryTime,
|
|
required this.address,
|
|
required this.workingHours,
|
|
required this.discountType,
|
|
required this.isOpen,
|
|
required this.rating,
|
|
required this.ratingCount,
|
|
required this.latitude,
|
|
required this.longitude,
|
|
required this.originalPrice,
|
|
required this.finalPrice,
|
|
this.features = const [],
|
|
required this.discountInfo,
|
|
this.comments = const [],
|
|
});
|
|
|
|
factory OfferModel.fromJson(Map<String, dynamic> json) {
|
|
final shopDataJson = json['shopData'] as Map<String, dynamic>? ?? {};
|
|
final shopData = ShopData.fromJson(shopDataJson);
|
|
|
|
final now = DateTime.now();
|
|
bool checkIsOpen = false;
|
|
try {
|
|
final startTimeString = json['StartTime'] as String?;
|
|
final endTimeString = json['EndTime'] as String?;
|
|
if (startTimeString != null && endTimeString != null) {
|
|
final startTimeParts = startTimeString.split(':');
|
|
final endTimeParts = endTimeString.split(':');
|
|
final startHour = int.parse(startTimeParts[0]);
|
|
final startMinute = int.parse(startTimeParts[1]);
|
|
final endHour = int.parse(endTimeParts[0]);
|
|
final endMinute = int.parse(endTimeParts[1]);
|
|
|
|
final startTime = DateTime(now.year, now.month, now.day, startHour, startMinute);
|
|
final endTime = DateTime(now.year, now.month, now.day, endHour, endMinute);
|
|
|
|
checkIsOpen = now.isAfter(startTime) && now.isBefore(endTime);
|
|
}
|
|
} catch(e) {
|
|
checkIsOpen = false;
|
|
}
|
|
|
|
final originalPriceValue = (json['Price'] as num?)?.toDouble() ?? 0.0;
|
|
final finalPriceValue = (json['NPrice'] as num?)?.toDouble() ?? 0.0;
|
|
|
|
final distanceFromServer = (json['distance'] as num?)?.round() ?? (json['Distance'] as num?)?.round() ?? 0;
|
|
|
|
List<String> images = [];
|
|
if (json['imageData'] is List) {
|
|
images = (json['imageData'] as List<dynamic>)
|
|
.map((imageData) => imageData['Url']?.toString() ?? '')
|
|
.where((url) => url.isNotEmpty)
|
|
.toList();
|
|
} else if (json['Images'] is List) {
|
|
images = (json['Images'] as List<dynamic>)
|
|
.map((imageData) => (imageData is Map) ? imageData['Url']?.toString() ?? '' : '')
|
|
.where((url) => url.isNotEmpty)
|
|
.toList();
|
|
}
|
|
|
|
final typeData = json['typeData'] ?? json['Type'];
|
|
final discountTypeName = (typeData is Map) ? typeData['Name']?.toString() : typeData?.toString();
|
|
|
|
return OfferModel(
|
|
id: json['ID'] ?? '',
|
|
title: json['Name'] ?? 'بدون عنوان',
|
|
discount: json['Description'] ?? '',
|
|
imageUrls: images,
|
|
category: json['categoryData']?['Name']?.toString() ?? '',
|
|
expiryTime: DateTime.tryParse(json['EndDate'] ?? '') ?? DateTime.now().add(const Duration(days: 1)),
|
|
discountType: discountTypeName ?? '',
|
|
originalPrice: originalPriceValue,
|
|
finalPrice: finalPriceValue,
|
|
storeName: shopData.name,
|
|
address: shopData.address,
|
|
latitude: shopData.latitude,
|
|
longitude: shopData.longitude,
|
|
features: shopData.properties,
|
|
distanceInMeters: distanceFromServer,
|
|
isOpen: checkIsOpen,
|
|
workingHours: [],
|
|
rating: 0.0,
|
|
ratingCount: 0,
|
|
comments: [],
|
|
discountInfo: json['Description'] ?? 'توضیحات موجود نیست',
|
|
);
|
|
}
|
|
|
|
String get coverImageUrl =>
|
|
imageUrls.isNotEmpty ? imageUrls.first : 'https://via.placeholder.com/400x200.png?text=No+Image';
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
id,
|
|
storeName,
|
|
title,
|
|
discount,
|
|
imageUrls,
|
|
category,
|
|
distanceInMeters,
|
|
expiryTime,
|
|
address,
|
|
workingHours,
|
|
discountType,
|
|
isOpen,
|
|
rating,
|
|
ratingCount,
|
|
latitude,
|
|
longitude,
|
|
originalPrice,
|
|
finalPrice,
|
|
features,
|
|
discountInfo,
|
|
comments,
|
|
];
|
|
|
|
String get distanceAsString {
|
|
if (distanceInMeters < 1000) {
|
|
return "$distanceInMeters متر";
|
|
} else {
|
|
final distanceInKm = (distanceInMeters / 1000).toStringAsFixed(1);
|
|
return "$distanceInKm کیلومتر";
|
|
}
|
|
}
|
|
} |