217 lines
5.2 KiB
Dart
217 lines
5.2 KiB
Dart
import 'package:hive/hive.dart';
|
|
|
|
part 'menu_model.g.dart';
|
|
|
|
@HiveType(typeId: 2)
|
|
class MenuModel extends HiveObject {
|
|
@HiveField(0)
|
|
String id;
|
|
|
|
@HiveField(1)
|
|
String name;
|
|
|
|
@HiveField(2)
|
|
String description;
|
|
|
|
@HiveField(3)
|
|
double price;
|
|
|
|
@HiveField(4)
|
|
String category;
|
|
|
|
@HiveField(5)
|
|
List<String> ingredients;
|
|
|
|
@HiveField(6)
|
|
List<String> allergens;
|
|
|
|
@HiveField(7)
|
|
String spiceLevel;
|
|
|
|
@HiveField(8)
|
|
bool isVegetarian;
|
|
|
|
@HiveField(9)
|
|
bool isVegan;
|
|
|
|
@HiveField(10)
|
|
bool isHalal;
|
|
|
|
@HiveField(11)
|
|
String? imageUrl;
|
|
|
|
@HiveField(12)
|
|
double rating;
|
|
|
|
@HiveField(13)
|
|
int reviewCount;
|
|
|
|
@HiveField(14)
|
|
bool isAvailable;
|
|
|
|
@HiveField(15)
|
|
DateTime createdAt;
|
|
|
|
@HiveField(16)
|
|
DateTime updatedAt;
|
|
|
|
MenuModel({
|
|
required this.id,
|
|
required this.name,
|
|
required this.description,
|
|
required this.price,
|
|
required this.category,
|
|
this.ingredients = const [],
|
|
this.allergens = const [],
|
|
this.spiceLevel = 'mild',
|
|
this.isVegetarian = false,
|
|
this.isVegan = false,
|
|
this.isHalal = true,
|
|
this.imageUrl,
|
|
this.rating = 0.0,
|
|
this.reviewCount = 0,
|
|
this.isAvailable = true,
|
|
required this.createdAt,
|
|
required this.updatedAt,
|
|
});
|
|
|
|
factory MenuModel.fromJson(Map<String, dynamic> json) {
|
|
return MenuModel(
|
|
id: json['id'] as String,
|
|
name: json['name'] as String,
|
|
description: json['description'] as String,
|
|
price: (json['price'] as num).toDouble(),
|
|
category: json['category'] as String,
|
|
ingredients: List<String>.from(json['ingredients'] ?? []),
|
|
allergens: List<String>.from(json['allergens'] ?? []),
|
|
spiceLevel: json['spiceLevel'] as String? ?? 'mild',
|
|
isVegetarian: json['isVegetarian'] as bool? ?? false,
|
|
isVegan: json['isVegan'] as bool? ?? false,
|
|
isHalal: json['isHalal'] as bool? ?? true,
|
|
imageUrl: json['imageUrl'] as String?,
|
|
rating: (json['rating'] as num?)?.toDouble() ?? 0.0,
|
|
reviewCount: json['reviewCount'] as int? ?? 0,
|
|
isAvailable: json['isAvailable'] as bool? ?? true,
|
|
createdAt: DateTime.parse(json['createdAt'] as String),
|
|
updatedAt: DateTime.parse(json['updatedAt'] as String),
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'id': id,
|
|
'name': name,
|
|
'description': description,
|
|
'price': price,
|
|
'category': category,
|
|
'ingredients': ingredients,
|
|
'allergens': allergens,
|
|
'spiceLevel': spiceLevel,
|
|
'isVegetarian': isVegetarian,
|
|
'isVegan': isVegan,
|
|
'isHalal': isHalal,
|
|
'imageUrl': imageUrl,
|
|
'rating': rating,
|
|
'reviewCount': reviewCount,
|
|
'isAvailable': isAvailable,
|
|
'createdAt': createdAt.toIso8601String(),
|
|
'updatedAt': updatedAt.toIso8601String(),
|
|
};
|
|
}
|
|
|
|
MenuModel copyWith({
|
|
String? id,
|
|
String? name,
|
|
String? description,
|
|
double? price,
|
|
String? category,
|
|
List<String>? ingredients,
|
|
List<String>? allergens,
|
|
String? spiceLevel,
|
|
bool? isVegetarian,
|
|
bool? isVegan,
|
|
bool? isHalal,
|
|
String? imageUrl,
|
|
double? rating,
|
|
int? reviewCount,
|
|
bool? isAvailable,
|
|
DateTime? createdAt,
|
|
DateTime? updatedAt,
|
|
}) {
|
|
return MenuModel(
|
|
id: id ?? this.id,
|
|
name: name ?? this.name,
|
|
description: description ?? this.description,
|
|
price: price ?? this.price,
|
|
category: category ?? this.category,
|
|
ingredients: ingredients ?? this.ingredients,
|
|
allergens: allergens ?? this.allergens,
|
|
spiceLevel: spiceLevel ?? this.spiceLevel,
|
|
isVegetarian: isVegetarian ?? this.isVegetarian,
|
|
isVegan: isVegan ?? this.isVegan,
|
|
isHalal: isHalal ?? this.isHalal,
|
|
imageUrl: imageUrl ?? this.imageUrl,
|
|
rating: rating ?? this.rating,
|
|
reviewCount: reviewCount ?? this.reviewCount,
|
|
isAvailable: isAvailable ?? this.isAvailable,
|
|
createdAt: createdAt ?? this.createdAt,
|
|
updatedAt: updatedAt ?? this.updatedAt,
|
|
);
|
|
}
|
|
|
|
String get formattedPrice {
|
|
return 'Rp ${price.toStringAsFixed(0).replaceAllMapped(
|
|
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
|
|
(Match m) => '${m[1]}.',
|
|
)}';
|
|
}
|
|
|
|
List<String> get dietaryTags {
|
|
List<String> tags = [];
|
|
if (isVegetarian) tags.add('Vegetarian');
|
|
if (isVegan) tags.add('Vegan');
|
|
if (isHalal) tags.add('Halal');
|
|
return tags;
|
|
}
|
|
|
|
String get spiceLevelEmoji {
|
|
switch (spiceLevel.toLowerCase()) {
|
|
case 'mild':
|
|
return '🌶️';
|
|
case 'medium':
|
|
return '🌶️🌶️';
|
|
case 'hot':
|
|
return '🌶️🌶️🌶️';
|
|
case 'very hot':
|
|
return '🌶️🌶️🌶️🌶️';
|
|
default:
|
|
return '';
|
|
}
|
|
}
|
|
|
|
bool hasAllergen(String allergen) {
|
|
return allergens.any((a) => a.toLowerCase() == allergen.toLowerCase());
|
|
}
|
|
|
|
bool isCompatibleWithPreferences(List<String> userAllergies, String dietaryRestriction) {
|
|
// Check allergies
|
|
for (String allergy in userAllergies) {
|
|
if (hasAllergen(allergy)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check dietary restrictions
|
|
switch (dietaryRestriction.toLowerCase()) {
|
|
case 'vegetarian':
|
|
return isVegetarian;
|
|
case 'vegan':
|
|
return isVegan;
|
|
case 'halal':
|
|
return isHalal;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
}
|