// // LiveRoomCreateViewModel.swift // SodaLive // // Created by klaus on 2023/08/14. // import UIKit import Moya import Combine final class LiveRoomCreateViewModel: ObservableObject { enum TimeSettingMode: String { case NOW, RESERVATION } enum LiveRoomType: String, Codable { case OPEN, PRIVATE, SECRET } let prices = [0, 100, 300, 500, 1000, 2000] @Published var isLoading = false @Published var tags: [String] = [] @Published var title: String = "" @Published var content: String = "" { didSet { if content.count > 1000 { content = String(content.prefix(1000)) } } } @Published var coverImage: UIImage? = nil @Published var coverImageUrl: String? = nil @Published var numberOfPeople = "" @Published var timeSettingMode: TimeSettingMode = .NOW @Published var reservationDateString: String = Date().convertDateFormat(dateFormat: "yyyy.MM.dd") @Published var reservationTimeString: String = Date().convertDateFormat(dateFormat: "a hh : mm") @Published var roomType: LiveRoomType = .OPEN { didSet { if roomType == .SECRET { timeSettingMode = .NOW } if roomType != .PRIVATE { password = "" } } } @Published var password = "" { didSet { if password.count > 6 { password = String(password.prefix(6)) } } } @Published var isAdult = false @Published var priceString = "0" { didSet { if priceString.count > 5 { priceString = String(priceString.prefix(5)) } else { if let price = Int(priceString) { self.price = price } else { self.price = 0 } } } } @Published var price = 0 @Published var errorMessage = "" @Published var isShowPopup = false @Published var isShowGetRecentInfoButton = true private let repository = LiveRepository() private var subscription = Set() var reservationDate = Date() { willSet { reservationDateString = newValue.convertDateFormat(dateFormat: "yyyy.MM.dd") } } var reservationTime = Date() { willSet { reservationTimeString = newValue.convertDateFormat(dateFormat: "a hh : mm") } } var coverImagePath: String? = nil let placeholder = "라이브 공지를 입력하세요" func getRecentInfo() { isLoading = true repository.getRecentRoomInfo() .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 DispatchQueue.global(qos: .background).async { do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) if let data = decoded.data, decoded.success { DispatchQueue.main.async { self.title = data.title self.content = data.notice self.coverImageUrl = data.coverImageUrl self.coverImagePath = data.coverImagePath self.numberOfPeople = String(data.numberOfPeople) self.errorMessage = "최근데이터를 불러왔습니다." self.isShowPopup = true self.isShowGetRecentInfoButton = false } } else { DispatchQueue.main.async { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = "최근데이터를 불러오지 못했습니다.\n다시 시도해 주세요." } self.isShowPopup = true } } } catch { print(error) DispatchQueue.main.async { self.errorMessage = "최근데이터를 불러오지 못했습니다.\n다시 시도해 주세요." self.isShowPopup = true } } } } .store(in: &subscription) } func createRoom(onSuccess: @escaping (CreateLiveRoomResponse) -> Void) { if !isLoading && validate() { isLoading = true var request = CreateLiveRoomRequest( title: title, content: content.trimmingCharacters(in: .whitespacesAndNewlines) != placeholder ? content : "", coverImageUrl: coverImagePath, tags: tags, numberOfPeople: Int(numberOfPeople)!, isAdult: isAdult, price: price, type: roomType, password: (roomType == .PRIVATE && !password.trimmingCharacters(in: .whitespaces).isEmpty) ? password : nil ) if timeSettingMode == .RESERVATION && roomType != .SECRET { request.beginDateTimeString = "\(reservationDate.convertDateFormat(dateFormat: "yyyy-MM-dd")) \(reservationTime.convertDateFormat(dateFormat: "HH:mm"))" } var multipartData = [MultipartFormData]() let encoder = JSONEncoder() encoder.outputFormatting = .withoutEscapingSlashes let jsonData = try? encoder.encode(request) if let jsonData = jsonData { if let coverImage = coverImage, let imageData = coverImage.jpegData(compressionQuality: 0.8) { multipartData.append( MultipartFormData( provider: .data(imageData), name: "coverImage", fileName: "\(UUID().uuidString)_\(Date().timeIntervalSince1970 * 1000).jpg", mimeType: "image/*") ) } multipartData.append(MultipartFormData(provider: .data(jsonData), name: "request")) repository .createRoom(parameters: multipartData) .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: { 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 { onSuccess(data) } 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다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true self.isLoading = false } } } private func validate() -> Bool { if coverImage == nil && coverImagePath == nil { self.errorMessage = "커버이미지를 선택해주세요." self.isShowPopup = true return false } if title.trimmingCharacters(in: .whitespaces).isEmpty { self.errorMessage = "제목을 입력해 주세요." self.isShowPopup = true return false } let notice = content.trimmingCharacters(in: .whitespacesAndNewlines) != placeholder ? content : "" if notice.isEmpty && notice.count < 5 { self.errorMessage = "공지를 5자 이상 입력해주세요." self.isShowPopup = true return false } guard let numberOfPeople = Int(numberOfPeople), (numberOfPeople >= 3 && numberOfPeople <= 999) else { self.errorMessage = "인원을 3~999명 사이로 입력해주세요." self.isShowPopup = true return false } if roomType == .PRIVATE && (password.trimmingCharacters(in: .whitespaces).isEmpty || password.count != 6) { self.errorMessage = "방 입장 비밀번호 6자리를 입력해 주세요." self.isShowPopup = true return false } return true } }