Files
pos-system/apps/app-client-base-swift/AppClientBaseSwift/AppClientBaseSwift/Models/User.swift

199 lines
6.1 KiB
Swift

//
// User.swift
// AppClientBaseSwift
//
// User data model
// Model d liu ngưi dùng
//
import Foundation
// MARK: - User Model
// Model ngưi dùng
/// User entity representing authenticated user
/// Entity ngưi dùng đi din cho user đã xác thc
struct User: Codable, Identifiable, Equatable {
/// Unique user identifier
/// Đnh danh ngưi dùng duy nht
let id: String
/// User email address
/// Đa ch email ngưi dùng
let email: String
/// User display name
/// Tên hin th ngưi dùng
let name: String
/// User avatar URL
/// URL nh đi din ngưi dùng
let avatarUrl: String?
/// User phone number
/// S đin thoi ngưi dùng
let phoneNumber: String?
/// Whether email is verified
/// Email đã đưc xác minh chưa
let isEmailVerified: Bool
/// Account creation date
/// Ngày to tài khon
let createdAt: Date?
/// Last update date
/// Ngày cp nht cui
let updatedAt: Date?
// MARK: - CodingKeys
enum CodingKeys: String, CodingKey {
case id
case email
case name
case firstName
case lastName
case avatarUrl
case phoneNumber
case isEmailVerified = "emailConfirmed"
case createdAt
case updatedAt
}
// MARK: - Custom Decoding
/// Custom decoder to handle firstName + lastName from API
/// Custom decoder đ x lý firstName + lastName t API
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
email = try container.decode(String.self, forKey: .email)
// Handle name from either "name" field or "firstName" + "lastName"
// X lý name t field "name" hoc "firstName" + "lastName"
if let fullName = try? container.decode(String.self, forKey: .name), !fullName.isEmpty {
name = fullName
} else {
let firstName = try container.decodeIfPresent(String.self, forKey: .firstName) ?? ""
let lastName = try container.decodeIfPresent(String.self, forKey: .lastName) ?? ""
name = "\(firstName) \(lastName)".trimmingCharacters(in: .whitespaces)
}
avatarUrl = try container.decodeIfPresent(String.self, forKey: .avatarUrl)
phoneNumber = try container.decodeIfPresent(String.self, forKey: .phoneNumber)
isEmailVerified = try container.decodeIfPresent(Bool.self, forKey: .isEmailVerified) ?? false
createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt)
updatedAt = try container.decodeIfPresent(Date.self, forKey: .updatedAt)
}
// MARK: - Custom Encoding
/// Custom encoder for Encodable conformance
/// Custom encoder cho Encodable conformance
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(email, forKey: .email)
try container.encode(name, forKey: .name)
try container.encodeIfPresent(avatarUrl, forKey: .avatarUrl)
try container.encodeIfPresent(phoneNumber, forKey: .phoneNumber)
try container.encode(isEmailVerified, forKey: .isEmailVerified)
try container.encodeIfPresent(createdAt, forKey: .createdAt)
try container.encodeIfPresent(updatedAt, forKey: .updatedAt)
}
// MARK: - Standard Init
/// Standard initializer for creating User instances
/// Initializer chun đ to User instances
init(
id: String,
email: String,
name: String,
avatarUrl: String? = nil,
phoneNumber: String? = nil,
isEmailVerified: Bool = false,
createdAt: Date? = nil,
updatedAt: Date? = nil
) {
self.id = id
self.email = email
self.name = name
self.avatarUrl = avatarUrl
self.phoneNumber = phoneNumber
self.isEmailVerified = isEmailVerified
self.createdAt = createdAt
self.updatedAt = updatedAt
}
}
// MARK: - User Extensions
// Các extension ca User
extension User {
/// Get user initials for avatar placeholder
/// Ly ch cái đu tên cho placeholder avatar
var initials: String {
let components = name.split(separator: " ")
let firstInitial = components.first?.prefix(1) ?? ""
let lastInitial = components.count > 1 ? components.last?.prefix(1) ?? "" : ""
return "\(firstInitial)\(lastInitial)".uppercased()
}
/// Get display name (first name only)
/// Ly tên hin th (ch tên đu)
var firstName: String {
String(name.split(separator: " ").first ?? Substring(name))
}
/// Get masked email for privacy display
/// Ly email n đ hin th bo mt
var maskedEmail: String {
email.maskedEmail
}
/// Get masked phone for privacy display
/// Ly s đin thoi n đ hin th bo mt
var maskedPhone: String? {
phoneNumber?.maskedPhone
}
}
// MARK: - Mock Data
// D liu mu
#if DEBUG
extension User {
/// Sample user for previews and testing
/// Ngưi dùng mu cho preview và testing
static let sample = User(
id: "user_123456",
email: "john.doe@example.com",
name: "John Doe",
avatarUrl: "https://api.dicebear.com/7.x/avataaars/png?seed=john",
phoneNumber: "0912345678",
isEmailVerified: true,
createdAt: Date(),
updatedAt: Date()
)
/// Sample user without avatar
/// Ngưi dùng mu không có avatar
static let sampleNoAvatar = User(
id: "user_789012",
email: "jane.doe@example.com",
name: "Jane Doe",
avatarUrl: nil,
phoneNumber: nil,
isEmailVerified: false,
createdAt: Date(),
updatedAt: nil
)
}
#endif