Files
sodalive-ios/SodaLive/Sources/MyPage/MyPageViewModel.swift
T

276 lines
10 KiB
Swift

//
// 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<AnyCancellable>()
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<MyPageResponse>.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<AuthResponse>.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<GetMemberInfoResponse>.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<NoticeItem>.self, from: responseData)
if let data = decoded.data, decoded.success {
self.latestNotice = data
}
} catch {
ERROR_LOG(error.localizedDescription)
}
}
.store(in: &subscription)
}
}