// // ProfileUpdateViewModel.swift // SodaLive // // Created by klaus on 2023/08/19. // import UIKit import Combine import Moya final class ProfileUpdateViewModel: ObservableObject { private let repository = UserRepository() private var subscription = Set() @Published var isLoading = false @Published var errorMessage = "" @Published var isShowPopup = false @Published var email = "" @Published var nickname = "" @Published var youtubeUrl = "" @Published var instagramUrl = "" @Published var websiteUrl = "" @Published var blogUrl = "" @Published var gender: Gender = .NONE @Published var introduce = "" @Published var currentPassword = "" @Published var newPassword = "" @Published var newPasswordConfirm = "" @Published var tags = [String]() @Published var insertTags = [String]() @Published var removeTags = [String]() var profileImage: UIImage? = nil { didSet { if let _ = profileImage { updateProfileImage() } } } var profileResponse: GetProfileResponse? var refresh: () -> Void = {} let placeholder = "소개글을 입력하세요" func getMyProfile() { isLoading = true repository.getMyProfile() .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.profileResponse = data self.email = data.email self.nickname = data.nickname self.youtubeUrl = data.youtubeUrl ?? "" self.instagramUrl = data.instagramUrl ?? "" self.blogUrl = data.blogUrl ?? "" self.websiteUrl = data.websiteUrl ?? "" self.introduce = data.introduce self.gender = data.gender self.tags.append(contentsOf: data.tags) UserDefaults.set(data.nickname, forKey: .nickname) } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true } } .store(in: &subscription) } func updateProfile() { if profileResponse!.nickname != nickname || profileResponse!.youtubeUrl != youtubeUrl || profileResponse!.instagramUrl != instagramUrl || profileResponse!.blogUrl != blogUrl || profileResponse!.websiteUrl != websiteUrl || profileResponse!.gender != gender || profileResponse!.introduce != introduce || !insertTags.isEmpty || !removeTags.isEmpty { let request = ProfileUpdateRequest( email: profileResponse!.email, nickname: profileResponse!.nickname != nickname ? nickname : nil, gender: profileResponse!.gender != gender ? gender : nil, introduce: profileResponse!.introduce != introduce && introduce.trimmingCharacters(in: .whitespacesAndNewlines) != placeholder ? introduce : nil, youtubeUrl: profileResponse!.youtubeUrl != youtubeUrl ? youtubeUrl : nil, instagramUrl: profileResponse!.instagramUrl != instagramUrl ? instagramUrl : nil, websiteUrl: profileResponse!.websiteUrl != websiteUrl ? websiteUrl : nil, blogUrl: profileResponse!.blogUrl != blogUrl ? blogUrl : nil, insertTags: !insertTags.isEmpty ? insertTags : nil, removeTags: !removeTags.isEmpty ? removeTags : nil ) isLoading = true repository.profileUpdate(request: request) .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 _ = decoded.data, decoded.success { self.refresh() self.errorMessage = "프로필이 변경되었습니다." self.isShowPopup = true DispatchQueue.main.asyncAfter(deadline: .now() + 1) { AppState.shared.back() } } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true } } .store(in: &subscription) } else { AppState.shared.back() } } func updatePassword() { if currentPassword.trimmingCharacters(in: .whitespaces).isEmpty { errorMessage = "현재 비밀번호를 입력하세요." isShowPopup = true return } if newPassword.trimmingCharacters(in: .whitespaces).isEmpty { errorMessage = "변경할 비밀번호를 입력하세요." isShowPopup = true return } if newPassword != newPasswordConfirm { errorMessage = "비밀번호가 일치하지 않습니다." isShowPopup = true return } if !validatePassword() { errorMessage = "영문, 숫자 포함 8자 이상의 비밀번호를 입력해 주세요." isShowPopup = true return } let request = ProfileUpdateRequest( email: UserDefaults.string(forKey: .email), password: currentPassword, modifyPassword: newPassword ) isLoading = true repository.profileUpdate(request: request) .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 _ = decoded.data, decoded.success { self.errorMessage = "비밀번호가 변경되었습니다." self.isShowPopup = true self.currentPassword = "" self.newPassword = "" self.newPasswordConfirm = "" DispatchQueue.main.asyncAfter(deadline: .now() + 1) { AppState.shared.back() } } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true } } .store(in: &subscription) } func removeTag(tag: String) { if let index = tags.firstIndex(of: tag) { tags.remove(at: index) } if (insertTags.contains(tag)) { if let index = insertTags.firstIndex(of: tag) { insertTags.remove(at: index) } } else { removeTags.append(tag) } } func addTag(tag: String) { tags.append(tag) if (removeTags.contains(tag)) { if let index = removeTags.firstIndex(of: tag) { removeTags.remove(at: index) } } else { insertTags.append(tag) } } private func updateProfileImage() { isLoading = false if let profileImage = profileImage, let imageData = profileImage.jpegData(compressionQuality: 0.8) { repository .profileImageUpdate(parameter: MultipartFormData( provider: .data(imageData), name: "image", fileName: "\(UUID().uuidString)_\(Date().timeIntervalSince1970 * 1000).jpg", mimeType: "image/*" )) .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 _ = decoded.data, decoded.success { self.refresh() self.getMyProfile() } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true } } .store(in: &subscription) } else { self.errorMessage = "프로필 이미지를 업데이트 하지 못했습니다.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true self.isLoading = false } } private func validatePassword() -> Bool { let passwordRegEx = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d$@!%*#?&]{8,}$" let predicate = NSPredicate(format:"SELF MATCHES %@", passwordRegEx) return predicate.evaluate(with: newPassword) } }