// // MyPageViewModel.swift // SodaLive // // Created by klaus on 2023/08/10. // import Foundation import Combine final class MyPageViewModel: ObservableObject { private let repository = UserRepository() private let authRepository = AuthRepository() private let noticeRepository = NoticeRepository() private var subscription = Set() private var pendingAuthReceiptId: String? private var pendingAuthRequest: AuthVerifyRequest? private var pendingAuthSuccess: (() -> Void)? @Published var latestNotice: NoticeItem? = nil @Published var nickname: String = "" @Published var profileUrl: String = "" @Published var chargeCan: Int = 0 @Published var rewardCan: Int = 0 @Published var point: Int = 0 @Published var isAuth: Bool = false @Published var errorMessage = "" @Published var isShowPopup = false @Published var isLoading = false @Published var isShowAuthView = false @Published var isShowAuthContentSettings = false @Published var authIsAdultContentVisible = true { didSet { if !authIsAdultContentVisible { authContentType = .ALL } } } @Published var authContentType: ContentType = .ALL @Published private(set) var isSubmittingAuth = false func getMypage() { isLoading = true repository.getMypage() .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: {[unowned self] response in self.isLoading = false let responseData = response.data do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) if let data = decoded.data, decoded.success { self.nickname = data.nickname self.profileUrl = data.profileUrl self.chargeCan = data.chargeCan self.rewardCan = data.rewardCan self.point = data.point self.isAuth = data.isAuth } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = I18n.Common.commonError } self.isShowPopup = true } } catch { self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } .store(in: &subscription) } func authVerify(_ data: [String: Any], onSuccess: (() -> Void)? = nil) { guard Thread.isMainThread else { DispatchQueue.main.async { [weak self] in self?.authVerify(data, onSuccess: onSuccess) } return } guard pendingAuthReceiptId == nil, !isSubmittingAuth else { return } guard let payload = data["data"] as? [String: Any], let receiptId = payload["receipt_id"] as? String, !receiptId.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { errorMessage = I18n.Main.Auth.authenticationError isShowPopup = true return } pendingAuthReceiptId = receiptId pendingAuthSuccess = onSuccess authIsAdultContentVisible = true authContentType = .ALL } func presentAuthContentSettings() { guard Thread.isMainThread else { DispatchQueue.main.async { [weak self] in self?.presentAuthContentSettings() } return } guard pendingAuthReceiptId != nil, !isSubmittingAuth else { return } isShowAuthContentSettings = true } func confirmAuthContentSettings() { guard Thread.isMainThread else { DispatchQueue.main.async { [weak self] in self?.confirmAuthContentSettings() } return } guard let receiptId = pendingAuthReceiptId, !isSubmittingAuth else { return } pendingAuthRequest = AuthVerifyRequest( receiptId: receiptId, isAdultContentVisible: authIsAdultContentVisible, contentType: authIsAdultContentVisible ? authContentType : .ALL ) isSubmittingAuth = true isShowAuthContentSettings = false } func submitPendingAuthVerification() { guard Thread.isMainThread else { DispatchQueue.main.async { [weak self] in self?.submitPendingAuthVerification() } return } guard isSubmittingAuth, let request = pendingAuthRequest else { return } pendingAuthRequest = nil authRepository.authCertificate(request: request) .receive(on: DispatchQueue.main) .sink { [weak self] result in if case .failure = result { self?.handleAuthSubmissionFailure() } } receiveValue: { [weak self] response in guard let self = self else { return } guard (200..<300).contains(response.statusCode) else { self.handleAuthSubmissionFailure() return } do { let decoded = try JSONDecoder().decode(ApiResponse.self, from: response.data) guard decoded.success, decoded.data != nil else { self.handleAuthSubmissionFailure() return } if self.pendingAuthSuccess != nil { self.synchronizeAuthenticatedMember() } else { UserDefaults.set(request.isAdultContentVisible, forKey: .isAdultContentVisible) UserDefaults.set(request.contentType.rawValue, forKey: .contentPreference) self.restartAfterAuthVerification() } } catch { self.handleAuthSubmissionFailure() } } .store(in: &subscription) } private func handleAuthSubmissionFailure() { pendingAuthRequest = nil isSubmittingAuth = false errorMessage = I18n.MyPage.Auth.verificationErrorWithSupport isShowPopup = true isShowAuthContentSettings = true } private func synchronizeAuthenticatedMember() { repository.getMemberInfo() .receive(on: DispatchQueue.main) .sink { [weak self] result in if case .failure = result { self?.restartAfterAuthVerification() } } receiveValue: { [weak self] response in guard let self = self else { return } guard (200..<300).contains(response.statusCode) else { self.restartAfterAuthVerification() return } do { let decoded = try JSONDecoder().decode(ApiResponse.self, from: response.data) guard let data = decoded.data, decoded.success, data.isAuth else { self.restartAfterAuthVerification() return } UserDefaults.set(data.can, forKey: .can) UserDefaults.set(data.point, forKey: .point) UserDefaults.set(data.isAuth, forKey: .auth) UserDefaults.set(data.role.rawValue, forKey: .role) UserDefaults.set(data.auditionNotice ?? false, forKey: .isAuditionNotification) UserDefaults.set(data.countryCode, forKey: .countryCode) UserDefaults.set(data.isAdultContentVisible, forKey: .isAdultContentVisible) UserDefaults.set(data.isAdultContentVisible ? data.contentType : ContentType.ALL.rawValue, forKey: .contentPreference) self.isAuth = data.isAuth let onSuccess = self.pendingAuthSuccess self.clearPendingAuthVerification() onSuccess?() } catch { self.restartAfterAuthVerification() } } .store(in: &subscription) } private func clearPendingAuthVerification() { pendingAuthReceiptId = nil pendingAuthRequest = nil pendingAuthSuccess = nil isSubmittingAuth = false isShowAuthContentSettings = false } private func restartAfterAuthVerification() { clearPendingAuthVerification() AppState.shared.isRestartApp = true AppState.shared.setAppStep(step: .splash) } func getLatestNotice() { noticeRepository.getLatestNotice() .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: {[unowned self] response in self.isLoading = false let responseData = response.data do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) if let data = decoded.data, decoded.success { self.latestNotice = data } } catch { ERROR_LOG(error.localizedDescription) } } .store(in: &subscription) } }