import Foundation import Combine final class CreatorChannelHomeViewModel: ObservableObject { private let repository = CreatorChannelHomeRepository() private let userRepository = UserRepository() private var subscription = Set() @Published var isLoading = false @Published var response: CreatorChannelHomeResponse? @Published var hasLoaded = false @Published var selectedTab: CreatorChannelHomeTab = .home @Published var isApiFailedPlaceholderVisible = false @Published var errorMessage = "" @Published var isShowPopup = false func fetchHome(creatorId: Int) { isLoading = true isApiFailedPlaceholderVisible = false repository.getHome(creatorId: creatorId) .sink { [weak self] result in guard let self else { return } switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) self.applyApiFailedPlaceholderState() } } receiveValue: { [weak self] response in guard let self else { return } do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponse.self, from: response.data) if let data = decoded.data, decoded.success { self.response = data self.selectedTab = .home self.isApiFailedPlaceholderVisible = false } else { if let message = decoded.message { ERROR_LOG(message) } self.applyApiFailedPlaceholderState() } } catch { ERROR_LOG(error.localizedDescription) self.applyApiFailedPlaceholderState() } self.hasLoaded = true self.isLoading = false } .store(in: &subscription) } func follow(creatorId: Int, notify: Bool = true) { isLoading = true userRepository.creatorFollow(creatorId: creatorId, follow: true, notify: notify) .sink { [weak self] result in guard let self else { return } switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) self.isLoading = false } } receiveValue: { [weak self] response in guard let self else { return } do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: response.data) if decoded.success { self.updateCreatorFollowState(isFollow: true, isNotify: notify) } else { self.errorMessage = decoded.message ?? I18n.Common.commonError self.isShowPopup = true } } catch { ERROR_LOG(error.localizedDescription) self.errorMessage = I18n.Common.commonError self.isShowPopup = true } self.isLoading = false } .store(in: &subscription) } func unfollow(creatorId: Int) { isLoading = true userRepository.creatorUnFollow(creatorId: creatorId) .sink { [weak self] result in guard let self else { return } switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) self.isLoading = false } } receiveValue: { [weak self] response in guard let self else { return } do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: response.data) if decoded.success { self.updateCreatorFollowState(isFollow: false, isNotify: false) } else { self.errorMessage = decoded.message ?? I18n.Common.commonError self.isShowPopup = true } } catch { ERROR_LOG(error.localizedDescription) self.errorMessage = I18n.Common.commonError self.isShowPopup = true } self.isLoading = false } .store(in: &subscription) } private func applyApiFailedPlaceholderState() { response = nil isApiFailedPlaceholderVisible = true hasLoaded = true isLoading = false } private func updateCreatorFollowState(isFollow: Bool, isNotify: Bool) { response?.creator.isFollow = isFollow response?.creator.isNotify = isNotify } }