import 'dart:convert'; import 'package:hive_ce/hive.dart'; import 'package:worker/core/constants/storage_constants.dart'; import 'package:worker/core/database/models/enums.dart'; part 'user_model.g.dart'; /// User Model /// /// Hive CE model for caching user data locally. /// Maps to the 'users' table in the database. /// /// Type ID: 0 @HiveType(typeId: HiveTypeIds.userModel) class UserModel extends HiveObject { UserModel({ required this.userId, required this.phoneNumber, this.passwordHash, required this.fullName, this.email, required this.role, required this.status, required this.loyaltyTier, required this.totalPoints, this.companyInfo, this.cccd, this.attachments, this.address, this.avatarUrl, this.referralCode, this.referredBy, this.erpnextCustomerId, required this.createdAt, this.updatedAt, this.lastLoginAt, }); /// User ID (Primary Key) @HiveField(0) final String userId; /// Phone number (unique, used for login) @HiveField(1) final String phoneNumber; /// Password hash (stored encrypted) @HiveField(2) final String? passwordHash; /// Full name of the user @HiveField(3) final String fullName; /// Email address @HiveField(4) final String? email; /// User role (customer, distributor, admin, staff) @HiveField(5) final UserRole role; /// Account status (active, inactive, suspended, pending) @HiveField(6) final UserStatus status; /// Loyalty tier (bronze, silver, gold, platinum, diamond, titan) @HiveField(7) final LoyaltyTier loyaltyTier; /// Total accumulated loyalty points @HiveField(8) final int totalPoints; /// Company information (JSON encoded) /// Contains: company_name, tax_id, business_type, etc. @HiveField(9) final String? companyInfo; /// Citizen ID (CCCD/CMND) @HiveField(10) final String? cccd; /// Attachments (JSON encoded list) /// Contains: identity_card_images, business_license, etc. @HiveField(11) final String? attachments; /// Address @HiveField(12) final String? address; /// Avatar URL @HiveField(13) final String? avatarUrl; /// Referral code for this user @HiveField(14) final String? referralCode; /// ID of user who referred this user @HiveField(15) final String? referredBy; /// ERPNext customer ID for integration @HiveField(16) final String? erpnextCustomerId; /// Account creation timestamp @HiveField(17) final DateTime createdAt; /// Last update timestamp @HiveField(18) final DateTime? updatedAt; /// Last login timestamp @HiveField(19) final DateTime? lastLoginAt; // ========================================================================= // JSON SERIALIZATION // ========================================================================= /// Create UserModel from JSON factory UserModel.fromJson(Map json) { return UserModel( userId: json['user_id'] as String, phoneNumber: json['phone_number'] as String, passwordHash: json['password_hash'] as String?, fullName: json['full_name'] as String, email: json['email'] as String?, role: UserRole.values.firstWhere( (e) => e.name == (json['role'] as String), orElse: () => UserRole.customer, ), status: UserStatus.values.firstWhere( (e) => e.name == (json['status'] as String), orElse: () => UserStatus.pending, ), loyaltyTier: LoyaltyTier.values.firstWhere( (e) => e.name == (json['loyalty_tier'] as String), orElse: () => LoyaltyTier.bronze, ), totalPoints: json['total_points'] as int? ?? 0, companyInfo: json['company_info'] != null ? jsonEncode(json['company_info']) : null, cccd: json['cccd'] as String?, attachments: json['attachments'] != null ? jsonEncode(json['attachments']) : null, address: json['address'] as String?, avatarUrl: json['avatar_url'] as String?, referralCode: json['referral_code'] as String?, referredBy: json['referred_by'] as String?, erpnextCustomerId: json['erpnext_customer_id'] as String?, createdAt: DateTime.parse(json['created_at'] as String), updatedAt: json['updated_at'] != null ? DateTime.parse(json['updated_at'] as String) : null, lastLoginAt: json['last_login_at'] != null ? DateTime.parse(json['last_login_at'] as String) : null, ); } /// Convert UserModel to JSON Map toJson() { return { 'user_id': userId, 'phone_number': phoneNumber, 'password_hash': passwordHash, 'full_name': fullName, 'email': email, 'role': role.name, 'status': status.name, 'loyalty_tier': loyaltyTier.name, 'total_points': totalPoints, 'company_info': companyInfo != null ? jsonDecode(companyInfo!) : null, 'cccd': cccd, 'attachments': attachments != null ? jsonDecode(attachments!) : null, 'address': address, 'avatar_url': avatarUrl, 'referral_code': referralCode, 'referred_by': referredBy, 'erpnext_customer_id': erpnextCustomerId, 'created_at': createdAt.toIso8601String(), 'updated_at': updatedAt?.toIso8601String(), 'last_login_at': lastLoginAt?.toIso8601String(), }; } // ========================================================================= // HELPER METHODS // ========================================================================= /// Get company info as Map Map? get companyInfoMap { if (companyInfo == null) return null; try { return jsonDecode(companyInfo!) as Map; } catch (e) { return null; } } /// Get attachments as List List? get attachmentsList { if (attachments == null) return null; try { return jsonDecode(attachments!) as List; } catch (e) { return null; } } /// Check if user is active bool get isActive => status == UserStatus.active; /// Check if user is admin or staff bool get isStaff => role == UserRole.admin || role == UserRole.staff; /// Get user initials for avatar String get initials { final parts = fullName.trim().split(' '); if (parts.length >= 2) { return '${parts.first[0]}${parts.last[0]}'.toUpperCase(); } return fullName.isNotEmpty ? fullName[0].toUpperCase() : '?'; } // ========================================================================= // COPY WITH // ========================================================================= /// Create a copy with updated fields UserModel copyWith({ String? userId, String? phoneNumber, String? passwordHash, String? fullName, String? email, UserRole? role, UserStatus? status, LoyaltyTier? loyaltyTier, int? totalPoints, String? companyInfo, String? cccd, String? attachments, String? address, String? avatarUrl, String? referralCode, String? referredBy, String? erpnextCustomerId, DateTime? createdAt, DateTime? updatedAt, DateTime? lastLoginAt, }) { return UserModel( userId: userId ?? this.userId, phoneNumber: phoneNumber ?? this.phoneNumber, passwordHash: passwordHash ?? this.passwordHash, fullName: fullName ?? this.fullName, email: email ?? this.email, role: role ?? this.role, status: status ?? this.status, loyaltyTier: loyaltyTier ?? this.loyaltyTier, totalPoints: totalPoints ?? this.totalPoints, companyInfo: companyInfo ?? this.companyInfo, cccd: cccd ?? this.cccd, attachments: attachments ?? this.attachments, address: address ?? this.address, avatarUrl: avatarUrl ?? this.avatarUrl, referralCode: referralCode ?? this.referralCode, referredBy: referredBy ?? this.referredBy, erpnextCustomerId: erpnextCustomerId ?? this.erpnextCustomerId, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, lastLoginAt: lastLoginAt ?? this.lastLoginAt, ); } @override String toString() { return 'UserModel(userId: $userId, fullName: $fullName, role: $role, tier: $loyaltyTier, points: $totalPoints)'; } @override bool operator ==(Object other) { if (identical(this, other)) return true; return other is UserModel && other.userId == userId; } @override int get hashCode => userId.hashCode; }