update info
This commit is contained in:
280
lib/features/account/data/models/user_info_model.dart
Normal file
280
lib/features/account/data/models/user_info_model.dart
Normal file
@@ -0,0 +1,280 @@
|
||||
/// User Info Model
|
||||
///
|
||||
/// Data model for user information from API.
|
||||
/// Handles JSON serialization and conversion to domain entity.
|
||||
library;
|
||||
|
||||
import 'package:worker/core/database/models/enums.dart';
|
||||
import 'package:worker/features/account/domain/entities/user_info.dart';
|
||||
|
||||
/// User Info Model
|
||||
///
|
||||
/// Maps API response from get_user_info endpoint to UserInfo entity.
|
||||
class UserInfoModel {
|
||||
const UserInfoModel({
|
||||
required this.userId,
|
||||
required this.fullName,
|
||||
this.email,
|
||||
this.phoneNumber,
|
||||
required this.role,
|
||||
required this.status,
|
||||
required this.loyaltyTier,
|
||||
this.totalPoints = 0,
|
||||
this.availablePoints = 0,
|
||||
this.expiringPoints = 0,
|
||||
this.avatarUrl,
|
||||
this.companyName,
|
||||
this.taxId,
|
||||
this.address,
|
||||
this.cccd,
|
||||
this.referralCode,
|
||||
this.erpnextCustomerId,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
});
|
||||
|
||||
final String userId;
|
||||
final String fullName;
|
||||
final String? email;
|
||||
final String? phoneNumber;
|
||||
final UserRole role;
|
||||
final UserStatus status;
|
||||
final LoyaltyTier loyaltyTier;
|
||||
final int totalPoints;
|
||||
final int availablePoints;
|
||||
final int expiringPoints;
|
||||
final String? avatarUrl;
|
||||
final String? companyName;
|
||||
final String? taxId;
|
||||
final String? address;
|
||||
final String? cccd;
|
||||
final String? referralCode;
|
||||
final String? erpnextCustomerId;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
|
||||
// =========================================================================
|
||||
// JSON SERIALIZATION
|
||||
// =========================================================================
|
||||
|
||||
/// Create UserInfoModel from API JSON response
|
||||
///
|
||||
/// Expected API response structure:
|
||||
/// ```json
|
||||
/// {
|
||||
/// "message": {
|
||||
/// "user_id": "...",
|
||||
/// "full_name": "...",
|
||||
/// "email": "...",
|
||||
/// "phone_number": "...",
|
||||
/// "role": "customer",
|
||||
/// "status": "active",
|
||||
/// "loyalty_tier": "gold",
|
||||
/// "total_points": 1000,
|
||||
/// "available_points": 800,
|
||||
/// "expiring_points": 200,
|
||||
/// "avatar_url": "...",
|
||||
/// "company_name": "...",
|
||||
/// "tax_id": "...",
|
||||
/// "address": "...",
|
||||
/// "cccd": "...",
|
||||
/// "referral_code": "...",
|
||||
/// "erpnext_customer_id": "...",
|
||||
/// "created_at": "...",
|
||||
/// "updated_at": "...",
|
||||
/// "last_login_at": "..."
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
factory UserInfoModel.fromJson(Map<String, dynamic> json) {
|
||||
// API response structure: { "message": { "success": true, "data": {...} } }
|
||||
final message = json['message'] as Map<String, dynamic>?;
|
||||
final data = message?['data'] as Map<String, dynamic>? ?? json;
|
||||
|
||||
return UserInfoModel(
|
||||
// Use email as userId since API doesn't provide user_id
|
||||
userId: data['email'] as String? ?? data['phone'] as String? ?? 'unknown',
|
||||
fullName: data['full_name'] as String? ?? '',
|
||||
email: data['email'] as String?,
|
||||
phoneNumber: data['phone'] as String?,
|
||||
// Default values for fields not in this API
|
||||
role: UserRole.customer, // Default to customer
|
||||
status: UserStatus.active, // Default to active
|
||||
loyaltyTier: LoyaltyTier.bronze, // Default to bronze
|
||||
totalPoints: 0,
|
||||
availablePoints: 0,
|
||||
expiringPoints: 0,
|
||||
avatarUrl: data['avatar'] as String?,
|
||||
companyName: data['company_name'] as String?,
|
||||
taxId: data['tax_code'] as String?,
|
||||
address: data['address'] as String?,
|
||||
cccd: data['id_card_front'] as String?, // Store front ID card
|
||||
referralCode: null,
|
||||
erpnextCustomerId: null,
|
||||
createdAt: _parseDateTime(data['date_of_birth'] as String?),
|
||||
updatedAt: _parseDateTime(data['date_of_birth'] as String?),
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert UserInfoModel to JSON
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'user_id': userId,
|
||||
'full_name': fullName,
|
||||
'email': email,
|
||||
'phone_number': phoneNumber,
|
||||
'role': role.name,
|
||||
'status': status.name,
|
||||
'loyalty_tier': loyaltyTier.name,
|
||||
'total_points': totalPoints,
|
||||
'available_points': availablePoints,
|
||||
'expiring_points': expiringPoints,
|
||||
'avatar_url': avatarUrl,
|
||||
'company_name': companyName,
|
||||
'tax_id': taxId,
|
||||
'address': address,
|
||||
'cccd': cccd,
|
||||
'referral_code': referralCode,
|
||||
'erpnext_customer_id': erpnextCustomerId,
|
||||
'created_at': createdAt?.toIso8601String(),
|
||||
'updated_at': updatedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// DOMAIN CONVERSION
|
||||
// =========================================================================
|
||||
|
||||
/// Convert to domain entity
|
||||
UserInfo toEntity() {
|
||||
final now = DateTime.now();
|
||||
return UserInfo(
|
||||
userId: userId,
|
||||
fullName: fullName,
|
||||
email: email,
|
||||
phoneNumber: phoneNumber,
|
||||
role: role,
|
||||
status: status,
|
||||
loyaltyTier: loyaltyTier,
|
||||
totalPoints: totalPoints,
|
||||
availablePoints: availablePoints,
|
||||
expiringPoints: expiringPoints,
|
||||
avatarUrl: avatarUrl,
|
||||
companyName: companyName,
|
||||
taxId: taxId,
|
||||
address: address,
|
||||
cccd: cccd,
|
||||
referralCode: referralCode,
|
||||
erpnextCustomerId: erpnextCustomerId,
|
||||
createdAt: createdAt ?? now,
|
||||
updatedAt: updatedAt ?? now,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create model from domain entity
|
||||
factory UserInfoModel.fromEntity(UserInfo entity) {
|
||||
return UserInfoModel(
|
||||
userId: entity.userId,
|
||||
fullName: entity.fullName,
|
||||
email: entity.email,
|
||||
phoneNumber: entity.phoneNumber,
|
||||
role: entity.role,
|
||||
status: entity.status,
|
||||
loyaltyTier: entity.loyaltyTier,
|
||||
totalPoints: entity.totalPoints,
|
||||
availablePoints: entity.availablePoints,
|
||||
expiringPoints: entity.expiringPoints,
|
||||
avatarUrl: entity.avatarUrl,
|
||||
companyName: entity.companyName,
|
||||
taxId: entity.taxId,
|
||||
address: entity.address,
|
||||
cccd: entity.cccd,
|
||||
referralCode: entity.referralCode,
|
||||
erpnextCustomerId: entity.erpnextCustomerId,
|
||||
createdAt: entity.createdAt,
|
||||
updatedAt: entity.updatedAt,
|
||||
);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// HELPER METHODS
|
||||
// =========================================================================
|
||||
|
||||
/// Parse user role from string
|
||||
static UserRole _parseUserRole(String? role) {
|
||||
if (role == null) return UserRole.customer;
|
||||
|
||||
return UserRole.values.firstWhere(
|
||||
(e) => e.name.toLowerCase() == role.toLowerCase(),
|
||||
orElse: () => UserRole.customer,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parse user status from string
|
||||
static UserStatus _parseUserStatus(String? status) {
|
||||
if (status == null) return UserStatus.pending;
|
||||
|
||||
// Handle ERPNext status values
|
||||
final normalizedStatus = status.toLowerCase();
|
||||
if (normalizedStatus == 'enabled' || normalizedStatus == 'active') {
|
||||
return UserStatus.active;
|
||||
}
|
||||
if (normalizedStatus == 'disabled' || normalizedStatus == 'inactive') {
|
||||
return UserStatus.suspended;
|
||||
}
|
||||
|
||||
return UserStatus.values.firstWhere(
|
||||
(e) => e.name.toLowerCase() == normalizedStatus,
|
||||
orElse: () => UserStatus.pending,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parse loyalty tier from string
|
||||
static LoyaltyTier _parseLoyaltyTier(String? tier) {
|
||||
if (tier == null) return LoyaltyTier.bronze;
|
||||
|
||||
return LoyaltyTier.values.firstWhere(
|
||||
(e) => e.name.toLowerCase() == tier.toLowerCase(),
|
||||
orElse: () => LoyaltyTier.bronze,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parse integer from dynamic value
|
||||
static int _parseInt(dynamic value) {
|
||||
if (value == null) return 0;
|
||||
if (value is int) return value;
|
||||
if (value is double) return value.toInt();
|
||||
if (value is String) return int.tryParse(value) ?? 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Parse DateTime from string
|
||||
static DateTime? _parseDateTime(String? dateString) {
|
||||
if (dateString == null || dateString.isEmpty) return null;
|
||||
try {
|
||||
return DateTime.parse(dateString);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// EQUALITY
|
||||
// =========================================================================
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is UserInfoModel && other.userId == userId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => userId.hashCode;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UserInfoModel(userId: $userId, fullName: $fullName, '
|
||||
'tier: $loyaltyTier, points: $totalPoints)';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user