/// Domain Entity: UserInfo /// /// Represents complete user information fetched from the API. /// This is a plain Dart class matching the app's entity pattern. library; import 'package:worker/core/database/models/enums.dart'; /// UserInfo Entity /// /// Contains all user account information including: /// - Personal details (name, email, phone, CCCD) /// - Role and status /// - Loyalty program data (tier, points) /// - Company information /// - ERPNext integration data class UserInfo { /// Unique user identifier (name field from ERPNext) final String userId; /// Full name final String fullName; /// Email address final String? email; /// Phone number final String? phoneNumber; /// User role final UserRole role; /// Account status final UserStatus status; /// Current loyalty tier final LoyaltyTier loyaltyTier; /// Total loyalty points earned (lifetime) final int totalPoints; /// Available points for redemption final int availablePoints; /// Points expiring soon final int expiringPoints; /// Avatar image URL final String? avatarUrl; /// Company name final String? companyName; /// Tax identification number final String? taxId; /// Address final String? address; /// CCCD/ID card number final String? cccd; /// Referral code final String? referralCode; /// ERPNext customer ID final String? erpnextCustomerId; /// Account creation timestamp final DateTime createdAt; /// Last update timestamp final DateTime updatedAt; const UserInfo({ required this.userId, required this.fullName, this.email, this.phoneNumber, required this.role, required this.status, required this.loyaltyTier, required this.totalPoints, required this.availablePoints, required this.expiringPoints, this.avatarUrl, this.companyName, this.taxId, this.address, this.cccd, this.referralCode, this.erpnextCustomerId, required this.createdAt, required this.updatedAt, }); /// Check if user is active bool get isActive => status == UserStatus.active; /// Check if user is pending approval bool get isPending => status == UserStatus.pending; /// Check if user has company info bool get hasCompanyInfo => companyName != null && companyName!.isNotEmpty; /// Get user initials for avatar fallback String get initials { final nameParts = fullName.trim().split(' '); if (nameParts.isEmpty) return '?'; if (nameParts.length == 1) { return nameParts[0].substring(0, 1).toUpperCase(); } // First letter of first name + first letter of last name return '${nameParts.first.substring(0, 1)}${nameParts.last.substring(0, 1)}' .toUpperCase(); } /// Get tier display name String get tierDisplayName { switch (loyaltyTier) { case LoyaltyTier.titan: return 'Titan'; case LoyaltyTier.diamond: return 'Diamond'; case LoyaltyTier.platinum: return 'Platinum'; case LoyaltyTier.gold: return 'Gold'; case LoyaltyTier.silver: return 'Silver'; case LoyaltyTier.bronze: return 'Bronze'; } } /// Copy with method for immutability UserInfo copyWith({ String? userId, String? fullName, String? email, String? phoneNumber, UserRole? role, UserStatus? status, LoyaltyTier? loyaltyTier, int? totalPoints, int? availablePoints, int? expiringPoints, String? avatarUrl, String? companyName, String? taxId, String? address, String? cccd, String? referralCode, String? erpnextCustomerId, DateTime? createdAt, DateTime? updatedAt, }) { return UserInfo( userId: userId ?? this.userId, fullName: fullName ?? this.fullName, email: email ?? this.email, phoneNumber: phoneNumber ?? this.phoneNumber, role: role ?? this.role, status: status ?? this.status, loyaltyTier: loyaltyTier ?? this.loyaltyTier, totalPoints: totalPoints ?? this.totalPoints, availablePoints: availablePoints ?? this.availablePoints, expiringPoints: expiringPoints ?? this.expiringPoints, avatarUrl: avatarUrl ?? this.avatarUrl, companyName: companyName ?? this.companyName, taxId: taxId ?? this.taxId, address: address ?? this.address, cccd: cccd ?? this.cccd, referralCode: referralCode ?? this.referralCode, erpnextCustomerId: erpnextCustomerId ?? this.erpnextCustomerId, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, ); } @override bool operator ==(Object other) { if (identical(this, other)) return true; return other is UserInfo && other.userId == userId && other.fullName == fullName && other.email == email && other.phoneNumber == phoneNumber && other.role == role && other.status == status && other.loyaltyTier == loyaltyTier && other.totalPoints == totalPoints && other.availablePoints == availablePoints && other.expiringPoints == expiringPoints && other.avatarUrl == avatarUrl && other.companyName == companyName && other.taxId == taxId && other.address == address && other.cccd == cccd && other.referralCode == referralCode && other.erpnextCustomerId == erpnextCustomerId; } @override int get hashCode { return Object.hash( userId, fullName, email, phoneNumber, role, status, loyaltyTier, totalPoints, availablePoints, expiringPoints, avatarUrl, companyName, taxId, address, cccd, referralCode, erpnextCustomerId, ); } @override String toString() { return 'UserInfo(userId: $userId, fullName: $fullName, ' 'role: $role, status: $status, loyaltyTier: $loyaltyTier, ' 'totalPoints: $totalPoints, availablePoints: $availablePoints)'; } }