This commit is contained in:
Phuoc Nguyen
2025-10-17 17:49:01 +07:00
parent 628c81ce13
commit 57bf73e4d1
23 changed files with 2655 additions and 87 deletions

View File

@@ -0,0 +1,184 @@
/// Data Model: Member Card
///
/// Data Transfer Object for member card information.
/// This model handles serialization/deserialization for:
/// - JSON (API responses)
/// - Hive (local database)
///
/// Extends the domain entity and adds data layer functionality.
library;
import 'package:hive_ce/hive.dart';
import 'package:worker/features/home/domain/entities/member_card.dart';
part 'member_card_model.g.dart';
/// Member Card Model
///
/// Used for:
/// - API JSON serialization/deserialization
/// - Hive local database storage
/// - Converting to/from domain entity
///
/// Hive Type ID: 10 (ensure this doesn't conflict with other models)
@HiveType(typeId: 10)
class MemberCardModel extends HiveObject {
/// Member ID
@HiveField(0)
final String memberId;
/// Member name
@HiveField(1)
final String name;
/// Member type (stored as string for serialization)
@HiveField(2)
final String memberType;
/// Membership tier (stored as string for serialization)
@HiveField(3)
final String tier;
/// Current points
@HiveField(4)
final int points;
/// Card expiration date (stored as ISO8601 string)
@HiveField(5)
final String validUntil;
/// QR code data
@HiveField(6)
final String qrData;
MemberCardModel({
required this.memberId,
required this.name,
required this.memberType,
required this.tier,
required this.points,
required this.validUntil,
required this.qrData,
});
/// From JSON constructor
factory MemberCardModel.fromJson(Map<String, dynamic> json) {
return MemberCardModel(
memberId: json['memberId'] as String,
name: json['name'] as String,
memberType: json['memberType'] as String,
tier: json['tier'] as String,
points: json['points'] as int,
validUntil: json['validUntil'] as String,
qrData: json['qrData'] as String,
);
}
/// To JSON method
Map<String, dynamic> toJson() {
return {
'memberId': memberId,
'name': name,
'memberType': memberType,
'tier': tier,
'points': points,
'validUntil': validUntil,
'qrData': qrData,
};
}
/// Convert to domain entity
MemberCard toEntity() {
return MemberCard(
memberId: memberId,
name: name,
memberType: _parseMemberType(memberType),
tier: _parseMemberTier(tier),
points: points,
validUntil: DateTime.parse(validUntil),
qrData: qrData,
);
}
/// Create from domain entity
factory MemberCardModel.fromEntity(MemberCard entity) {
return MemberCardModel(
memberId: entity.memberId,
name: entity.name,
memberType: entity.memberType.name,
tier: entity.tier.name,
points: entity.points,
validUntil: entity.validUntil.toIso8601String(),
qrData: entity.qrData,
);
}
/// Parse member type from string
static MemberType _parseMemberType(String type) {
return MemberType.values.firstWhere(
(e) => e.name.toLowerCase() == type.toLowerCase(),
orElse: () => MemberType.contractor, // Default fallback
);
}
/// Parse member tier from string
static MemberTier _parseMemberTier(String tier) {
return MemberTier.values.firstWhere(
(e) => e.name.toLowerCase() == tier.toLowerCase(),
orElse: () => MemberTier.gold, // Default fallback
);
}
/// Copy with method for creating modified copies
MemberCardModel copyWith({
String? memberId,
String? name,
String? memberType,
String? tier,
int? points,
String? validUntil,
String? qrData,
}) {
return MemberCardModel(
memberId: memberId ?? this.memberId,
name: name ?? this.name,
memberType: memberType ?? this.memberType,
tier: tier ?? this.tier,
points: points ?? this.points,
validUntil: validUntil ?? this.validUntil,
qrData: qrData ?? this.qrData,
);
}
@override
String toString() {
return 'MemberCardModel(memberId: $memberId, name: $name, memberType: $memberType, tier: $tier, points: $points)';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is MemberCardModel &&
other.memberId == memberId &&
other.name == name &&
other.memberType == memberType &&
other.tier == tier &&
other.points == points &&
other.validUntil == validUntil &&
other.qrData == qrData;
}
@override
int get hashCode {
return Object.hash(
memberId,
name,
memberType,
tier,
points,
validUntil,
qrData,
);
}
}

View File

@@ -0,0 +1,59 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'member_card_model.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class MemberCardModelAdapter extends TypeAdapter<MemberCardModel> {
@override
final typeId = 10;
@override
MemberCardModel read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return MemberCardModel(
memberId: fields[0] as String,
name: fields[1] as String,
memberType: fields[2] as String,
tier: fields[3] as String,
points: (fields[4] as num).toInt(),
validUntil: fields[5] as String,
qrData: fields[6] as String,
);
}
@override
void write(BinaryWriter writer, MemberCardModel obj) {
writer
..writeByte(7)
..writeByte(0)
..write(obj.memberId)
..writeByte(1)
..write(obj.name)
..writeByte(2)
..write(obj.memberType)
..writeByte(3)
..write(obj.tier)
..writeByte(4)
..write(obj.points)
..writeByte(5)
..write(obj.validUntil)
..writeByte(6)
..write(obj.qrData);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is MemberCardModelAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@@ -0,0 +1,207 @@
/// Data Model: Promotion
///
/// Data Transfer Object for promotion information.
/// This model handles serialization/deserialization for:
/// - JSON (API responses)
/// - Hive (local database)
///
/// Extends the domain entity and adds data layer functionality.
library;
import 'package:hive_ce/hive.dart';
import 'package:worker/features/home/domain/entities/promotion.dart';
part 'promotion_model.g.dart';
/// Promotion Model
///
/// Used for:
/// - API JSON serialization/deserialization
/// - Hive local database storage
/// - Converting to/from domain entity
///
/// Hive Type ID: 11 (ensure this doesn't conflict with other models)
@HiveType(typeId: 11)
class PromotionModel extends HiveObject {
/// Promotion ID
@HiveField(0)
final String id;
/// Promotion title
@HiveField(1)
final String title;
/// Description
@HiveField(2)
final String description;
/// Image URL
@HiveField(3)
final String imageUrl;
/// Start date (ISO8601 string)
@HiveField(4)
final String startDate;
/// End date (ISO8601 string)
@HiveField(5)
final String endDate;
/// Discount percentage (nullable)
@HiveField(6)
final int? discountPercentage;
/// Discount amount (nullable)
@HiveField(7)
final double? discountAmount;
/// Terms and conditions (nullable)
@HiveField(8)
final String? terms;
/// Details URL (nullable)
@HiveField(9)
final String? detailsUrl;
PromotionModel({
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,
});
/// From JSON constructor
factory PromotionModel.fromJson(Map<String, dynamic> json) {
return PromotionModel(
id: json['id'] as String,
title: json['title'] as String,
description: json['description'] as String,
imageUrl: json['imageUrl'] as String,
startDate: json['startDate'] as String,
endDate: json['endDate'] as String,
discountPercentage: json['discountPercentage'] as int?,
discountAmount: json['discountAmount'] as double?,
terms: json['terms'] as String?,
detailsUrl: json['detailsUrl'] as String?,
);
}
/// To JSON method
Map<String, dynamic> toJson() {
return {
'id': id,
'title': title,
'description': description,
'imageUrl': imageUrl,
'startDate': startDate,
'endDate': endDate,
'discountPercentage': discountPercentage,
'discountAmount': discountAmount,
'terms': terms,
'detailsUrl': detailsUrl,
};
}
/// Convert to domain entity
Promotion toEntity() {
return Promotion(
id: id,
title: title,
description: description,
imageUrl: imageUrl,
startDate: DateTime.parse(startDate),
endDate: DateTime.parse(endDate),
discountPercentage: discountPercentage,
discountAmount: discountAmount,
terms: terms,
detailsUrl: detailsUrl,
);
}
/// Create from domain entity
factory PromotionModel.fromEntity(Promotion entity) {
return PromotionModel(
id: entity.id,
title: entity.title,
description: entity.description,
imageUrl: entity.imageUrl,
startDate: entity.startDate.toIso8601String(),
endDate: entity.endDate.toIso8601String(),
discountPercentage: entity.discountPercentage,
discountAmount: entity.discountAmount,
terms: entity.terms,
detailsUrl: entity.detailsUrl,
);
}
/// Copy with method for creating modified copies
PromotionModel copyWith({
String? id,
String? title,
String? description,
String? imageUrl,
String? startDate,
String? endDate,
int? discountPercentage,
double? discountAmount,
String? terms,
String? detailsUrl,
}) {
return PromotionModel(
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,
);
}
@override
String toString() {
return 'PromotionModel(id: $id, title: $title, startDate: $startDate, endDate: $endDate)';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is PromotionModel &&
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;
}
@override
int get hashCode {
return Object.hash(
id,
title,
description,
imageUrl,
startDate,
endDate,
discountPercentage,
discountAmount,
terms,
detailsUrl,
);
}
}

View File

@@ -0,0 +1,68 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'promotion_model.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class PromotionModelAdapter extends TypeAdapter<PromotionModel> {
@override
final typeId = 11;
@override
PromotionModel read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return PromotionModel(
id: fields[0] as String,
title: fields[1] as String,
description: fields[2] as String,
imageUrl: fields[3] as String,
startDate: fields[4] as String,
endDate: fields[5] as String,
discountPercentage: (fields[6] as num?)?.toInt(),
discountAmount: (fields[7] as num?)?.toDouble(),
terms: fields[8] as String?,
detailsUrl: fields[9] as String?,
);
}
@override
void write(BinaryWriter writer, PromotionModel obj) {
writer
..writeByte(10)
..writeByte(0)
..write(obj.id)
..writeByte(1)
..write(obj.title)
..writeByte(2)
..write(obj.description)
..writeByte(3)
..write(obj.imageUrl)
..writeByte(4)
..write(obj.startDate)
..writeByte(5)
..write(obj.endDate)
..writeByte(6)
..write(obj.discountPercentage)
..writeByte(7)
..write(obj.discountAmount)
..writeByte(8)
..write(obj.terms)
..writeByte(9)
..write(obj.detailsUrl);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is PromotionModelAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}