- 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
281 lines
7.5 KiB
Swift
281 lines
7.5 KiB
Swift
//
|
|
// AuthViewModel.swift
|
|
// AppClientBaseSwift
|
|
//
|
|
// ViewModel for authentication UI state management
|
|
// ViewModel quản lý state UI xác thực
|
|
//
|
|
|
|
import SwiftUI
|
|
import Combine
|
|
|
|
// MARK: - Auth Screen
|
|
// Màn hình Auth
|
|
|
|
/// Available auth screens
|
|
/// Các màn hình auth có sẵn
|
|
enum AuthScreen {
|
|
case login
|
|
case register
|
|
case forgotPassword
|
|
}
|
|
|
|
// MARK: - Auth View Model
|
|
// ViewModel Auth
|
|
|
|
/// ViewModel for authentication UI
|
|
/// ViewModel cho UI xác thực
|
|
@MainActor
|
|
final class AuthViewModel: ObservableObject {
|
|
|
|
// MARK: - Published Properties
|
|
|
|
/// Current auth screen
|
|
/// Màn hình auth hiện tại
|
|
@Published var currentScreen: AuthScreen = .login
|
|
|
|
/// Login email
|
|
/// Email đăng nhập
|
|
@Published var loginEmail = ""
|
|
|
|
/// Login password
|
|
/// Mật khẩu đăng nhập
|
|
@Published var loginPassword = ""
|
|
|
|
/// Register name
|
|
/// Tên đăng ký
|
|
@Published var registerName = ""
|
|
|
|
/// Register email
|
|
/// Email đăng ký
|
|
@Published var registerEmail = ""
|
|
|
|
/// Register password
|
|
/// Mật khẩu đăng ký
|
|
@Published var registerPassword = ""
|
|
|
|
/// Register confirm password
|
|
/// Xác nhận mật khẩu đăng ký
|
|
@Published var registerConfirmPassword = ""
|
|
|
|
/// Forgot password email
|
|
/// Email quên mật khẩu
|
|
@Published var forgotEmail = ""
|
|
|
|
/// Is loading state
|
|
/// Trạng thái đang tải
|
|
@Published var isLoading = false
|
|
|
|
/// Error message to display
|
|
/// Thông báo lỗi hiển thị
|
|
@Published var errorMessage: String?
|
|
|
|
/// Success message to display
|
|
/// Thông báo thành công hiển thị
|
|
@Published var successMessage: String?
|
|
|
|
/// Agreed to terms
|
|
/// Đã đồng ý điều khoản
|
|
@Published var agreedToTerms = false
|
|
|
|
// MARK: - Validation
|
|
|
|
/// Validate login form
|
|
/// Kiểm tra form đăng nhập
|
|
var isLoginValid: Bool {
|
|
loginEmail.isValidEmail && !loginPassword.isEmpty
|
|
}
|
|
|
|
/// Validate register form
|
|
/// Kiểm tra form đăng ký
|
|
var isRegisterValid: Bool {
|
|
!registerName.trimmed.isEmpty &&
|
|
registerEmail.isValidEmail &&
|
|
registerPassword.isValidPassword &&
|
|
registerPassword == registerConfirmPassword &&
|
|
agreedToTerms
|
|
}
|
|
|
|
/// Validate forgot password form
|
|
/// Kiểm tra form quên mật khẩu
|
|
var isForgotPasswordValid: Bool {
|
|
forgotEmail.isValidEmail
|
|
}
|
|
|
|
/// Password strength (0-4)
|
|
/// Độ mạnh mật khẩu (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 độ mạnh mật khẩu
|
|
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 độ mạnh mật khẩu
|
|
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
|
|
/// Thực hiện đăng nhập
|
|
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 nhập mock để test
|
|
if loginEmail.lowercased() == mockEmail && loginPassword == mockPassword {
|
|
// Simulate network delay
|
|
// Giả lập delay mạng
|
|
try? await Task.sleep(nanoseconds: 1_000_000_000)
|
|
|
|
// Create mock user and authenticate
|
|
// Tạo mock user và xác thực
|
|
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
|
|
// Cập nhật trạng thái auth
|
|
await MainActor.run {
|
|
AuthManager.shared.setAuthenticated(user: mockUser)
|
|
}
|
|
|
|
isLoading = false
|
|
return
|
|
}
|
|
|
|
// Real API login
|
|
// Đăng nhập API thật
|
|
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
|
|
/// Thực hiện đă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
|
|
/// Gửi email quên mật khẩu
|
|
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ả lập gọi 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
|
|
/// Điều 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 tất cả các field
|
|
func clearFields() {
|
|
loginEmail = ""
|
|
loginPassword = ""
|
|
registerName = ""
|
|
registerEmail = ""
|
|
registerPassword = ""
|
|
registerConfirmPassword = ""
|
|
forgotEmail = ""
|
|
agreedToTerms = false
|
|
errorMessage = nil
|
|
successMessage = nil
|
|
}
|
|
}
|