Files
pos-system/apps/app-client-base-swift/AppClientBaseSwift/AppClientBaseSwift/ViewModels/AuthViewModel.swift
Ho Ngoc Hai d1a7a791f9 feat(app-client-base-swift): Add iOS Swift client app with auth UI
- Add SplashView, AuthContainerView with Login/Register/ForgotPassword
- Add AuthViewModel with form validation
- Add HomeView, ProfileView, ExploreView screens
- Add APIService, AuthManager for networking
- Add multi-language support (en/vi)
- Add User model and extensions
2026-01-16 10:35:19 +07:00

281 lines
7.5 KiB
Swift

//
// AuthViewModel.swift
// AppClientBaseSwift
//
// ViewModel for authentication UI state management
// ViewModel qun lý state UI xác thc
//
import SwiftUI
import Combine
// MARK: - Auth Screen
// Màn hình Auth
/// Available auth screens
/// Các màn hình auth có sn
enum AuthScreen {
case login
case register
case forgotPassword
}
// MARK: - Auth View Model
// ViewModel Auth
/// ViewModel for authentication UI
/// ViewModel cho UI xác thc
@MainActor
final class AuthViewModel: ObservableObject {
// MARK: - Published Properties
/// Current auth screen
/// Màn hình auth hin ti
@Published var currentScreen: AuthScreen = .login
/// Login email
/// Email đăng nhp
@Published var loginEmail = ""
/// Login password
/// Mt khu đăng nhp
@Published var loginPassword = ""
/// Register name
/// Tên đăng ký
@Published var registerName = ""
/// Register email
/// Email đăng ký
@Published var registerEmail = ""
/// Register password
/// Mt khu đăng ký
@Published var registerPassword = ""
/// Register confirm password
/// Xác nhn mt khu đăng ký
@Published var registerConfirmPassword = ""
/// Forgot password email
/// Email quên mt khu
@Published var forgotEmail = ""
/// Is loading state
/// Trng thái đang ti
@Published var isLoading = false
/// Error message to display
/// Thông báo li hin th
@Published var errorMessage: String?
/// Success message to display
/// Thông báo thành công hin th
@Published var successMessage: String?
/// Agreed to terms
/// Đã đng ý điu khon
@Published var agreedToTerms = false
// MARK: - Validation
/// Validate login form
/// Kim tra form đăng nhp
var isLoginValid: Bool {
loginEmail.isValidEmail && !loginPassword.isEmpty
}
/// Validate register form
/// Kim tra form đăng ký
var isRegisterValid: Bool {
!registerName.trimmed.isEmpty &&
registerEmail.isValidEmail &&
registerPassword.isValidPassword &&
registerPassword == registerConfirmPassword &&
agreedToTerms
}
/// Validate forgot password form
/// Kim tra form quên mt khu
var isForgotPasswordValid: Bool {
forgotEmail.isValidEmail
}
/// Password strength (0-4)
/// Đ mnh mt khu (0-4)
var passwordStrength: Int {
var strength = 0
let password = registerPassword
if password.count >= 8 { strength += 1 }
if password.contains(where: { $0.isUppercase }) { strength += 1 }
if password.contains(where: { $0.isLowercase }) { strength += 1 }
if password.contains(where: { $0.isNumber }) { strength += 1 }
return strength
}
/// Password strength text
/// Text đ mnh mt khu
var passwordStrengthText: String {
switch passwordStrength {
case 0: return "Rất yếu"
case 1: return "Yếu"
case 2: return "Trung bình"
case 3: return "Mạnh"
case 4: return "Rất mạnh"
default: return ""
}
}
/// Password strength color
/// Màu đ mnh mt khu
var passwordStrengthColor: Color {
switch passwordStrength {
case 0: return .red
case 1: return .orange
case 2: return .yellow
case 3: return .green
case 4: return .blue
default: return .gray
}
}
// MARK: - Actions
// MARK: Mock Credentials (for testing)
// Thông tin mock đ test
private let mockEmail = "admin@goodgo.com"
private let mockPassword = "123456"
/// Perform login
/// Thc hin đăng nhp
func login() async {
guard isLoginValid else {
errorMessage = "Vui lòng nhập email và mật khẩu hợp lệ"
return
}
isLoading = true
errorMessage = nil
// Mock login for testing
// Đăng nhp mock đ test
if loginEmail.lowercased() == mockEmail && loginPassword == mockPassword {
// Simulate network delay
// Gi lp delay mng
try? await Task.sleep(nanoseconds: 1_000_000_000)
// Create mock user and authenticate
// To mock user và xác thc
let mockUser = User(
id: "admin-001",
email: mockEmail,
fullName: "Admin GoodGo",
avatarURL: nil,
phoneNumber: "+84901234567",
createdAt: Date(),
isEmailVerified: true,
isPhoneVerified: true
)
// Save mock tokens and user
// Lưu mock tokens và user
KeychainHelper.save(key: StorageKeys.accessToken, value: "mock_access_token_\(UUID().uuidString)")
KeychainHelper.save(key: StorageKeys.refreshToken, value: "mock_refresh_token_\(UUID().uuidString)")
if let userData = try? JSONEncoder().encode(mockUser) {
UserDefaults.standard.set(userData, forKey: StorageKeys.userData)
}
// Update auth state
// Cp nht trng thái auth
await MainActor.run {
AuthManager.shared.setAuthenticated(user: mockUser)
}
isLoading = false
return
}
// Real API login
// Đăng nhp API tht
do {
try await AuthManager.shared.login(email: loginEmail, password: loginPassword)
} catch {
errorMessage = "Đăng nhập thất bại: \(error.localizedDescription)"
}
isLoading = false
}
/// Perform registration
/// Thc hin đăng ký
func register() async {
guard isRegisterValid else {
errorMessage = "Vui lòng kiểm tra lại thông tin đăng ký"
return
}
isLoading = true
errorMessage = nil
do {
try await AuthManager.shared.register(
name: registerName,
email: registerEmail,
password: registerPassword
)
} catch {
errorMessage = "Đăng ký thất bại: \(error.localizedDescription)"
}
isLoading = false
}
/// Send forgot password email
/// Gi email quên mt khu
func forgotPassword() async {
guard isForgotPasswordValid else {
errorMessage = "Vui lòng nhập email hợp lệ"
return
}
isLoading = true
errorMessage = nil
// Simulate API call
// Gi lp gi API
try? await Task.sleep(nanoseconds: 1_500_000_000)
successMessage = "Đã gửi link đặt lại mật khẩu đến \(forgotEmail)"
isLoading = false
}
/// Navigate to screen
/// Điu hưng đến màn hình
func navigateTo(_ screen: AuthScreen) {
withAnimation(.easeInOut(duration: 0.3)) {
currentScreen = screen
errorMessage = nil
successMessage = nil
}
}
/// Clear all fields
/// Xóa tt c các field
func clearFields() {
loginEmail = ""
loginPassword = ""
registerName = ""
registerEmail = ""
registerPassword = ""
registerConfirmPassword = ""
forgotEmail = ""
agreedToTerms = false
errorMessage = nil
successMessage = nil
}
}