354 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
			
		
		
	
	
			354 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
//
 | 
						|
//  RouletteSettingsViewModel.swift
 | 
						|
//  SodaLive
 | 
						|
//
 | 
						|
//  Created by klaus on 2023/12/05.
 | 
						|
//
 | 
						|
 | 
						|
import Foundation
 | 
						|
import Combine
 | 
						|
 | 
						|
enum SelectedRoulette: Int {
 | 
						|
    case ROULETTE_1 = 0
 | 
						|
    case ROULETTE_2 = 1
 | 
						|
    case ROULETTE_3 = 2
 | 
						|
}
 | 
						|
 | 
						|
final class RouletteSettingsViewModel: ObservableObject {
 | 
						|
    private let repository = RouletteRepository()
 | 
						|
    private var subscription = Set<AnyCancellable>()
 | 
						|
    
 | 
						|
    @Published var isLoading = false
 | 
						|
    
 | 
						|
    @Published var errorMessage = ""
 | 
						|
    @Published var isShowErrorPopup = false
 | 
						|
    
 | 
						|
    @Published var canText = "" {
 | 
						|
        didSet {
 | 
						|
            can = Int(canText) ?? 0
 | 
						|
        }
 | 
						|
    }
 | 
						|
    @Published var isActive = false
 | 
						|
    @Published var options = [RouletteOption]()
 | 
						|
    
 | 
						|
    @Published var isShowPreview = false {
 | 
						|
        didSet {
 | 
						|
            if !isShowPreview {
 | 
						|
                previewData = nil
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    @Published var previewData: RoulettePreview? = nil
 | 
						|
    
 | 
						|
    @Published var selectedRoulette: SelectedRoulette? = nil
 | 
						|
    
 | 
						|
    var can = 0
 | 
						|
    private var rouletteId = 0
 | 
						|
    @Published var rouletteList = [GetNewRouletteResponse]()
 | 
						|
    
 | 
						|
    @Published var totalPercentage = Float(0)
 | 
						|
    
 | 
						|
    var availableActive: Bool = true
 | 
						|
    
 | 
						|
    func addOption() {
 | 
						|
        if (options.count >= 10) {
 | 
						|
            return
 | 
						|
        }
 | 
						|
        options.append(RouletteOption(title: "", percentage: ""))
 | 
						|
        calculateTotalPercentage()
 | 
						|
    }
 | 
						|
    
 | 
						|
    func deleteOption(index: Int) {
 | 
						|
        options.remove(at: index)
 | 
						|
        calculateTotalPercentage()
 | 
						|
    }
 | 
						|
    
 | 
						|
    func getAllRoulette(creatorId: Int) {
 | 
						|
        self.isLoading = true
 | 
						|
        repository.getAllRoulette(creatorId: creatorId)
 | 
						|
            .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<[GetNewRouletteResponse]>.self, from: responseData)
 | 
						|
                    
 | 
						|
                    if let data = decoded.data, decoded.success {
 | 
						|
                        rouletteList.removeAll()
 | 
						|
                        rouletteList.append(contentsOf: data)
 | 
						|
                        selectRoulette(selectedRoulette: .ROULETTE_1)
 | 
						|
                    } else {
 | 
						|
                        self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
 | 
						|
                        self.isShowErrorPopup = true
 | 
						|
                    }
 | 
						|
                } catch {
 | 
						|
                    self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
 | 
						|
                    self.isShowErrorPopup = true
 | 
						|
                }
 | 
						|
            }
 | 
						|
            .store(in: &subscription)
 | 
						|
    }
 | 
						|
    
 | 
						|
    func onClickPreview() {
 | 
						|
        isLoading = true
 | 
						|
        
 | 
						|
        var items = [RoulettePreviewItem]()
 | 
						|
        for option in options {
 | 
						|
            if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
 | 
						|
                isLoading = false
 | 
						|
                errorMessage = "옵션은 빈칸일 수 없습니다."
 | 
						|
                isShowErrorPopup = true
 | 
						|
                return
 | 
						|
            }
 | 
						|
            
 | 
						|
            items.append(RoulettePreviewItem(title: option.title, percent: "\(option.percentage)%"))
 | 
						|
        }
 | 
						|
        
 | 
						|
        previewData = RoulettePreview(id: 0, can: self.can, items: items)
 | 
						|
        isLoading = false
 | 
						|
        isShowPreview = true
 | 
						|
    }
 | 
						|
    
 | 
						|
    func createOrUpdateRoulette(onSuccess: @escaping (Bool, String) -> Void) {
 | 
						|
        if !isLoading {
 | 
						|
            isLoading = true
 | 
						|
            
 | 
						|
            if validationOptions() {
 | 
						|
                if rouletteId > 0 {
 | 
						|
                    updateRoulette(onSuccess: onSuccess)
 | 
						|
                } else {
 | 
						|
                    createRoulette(onSuccess: onSuccess)
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    private func validationOptions() -> Bool {
 | 
						|
        var totalPercentage = Float(0)
 | 
						|
        
 | 
						|
        for option in options {
 | 
						|
            if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
 | 
						|
                isLoading = false
 | 
						|
                errorMessage = "옵션은 빈칸일 수 없습니다."
 | 
						|
                isShowErrorPopup = true
 | 
						|
                return false
 | 
						|
            }
 | 
						|
            
 | 
						|
            if let percentage = Float(option.percentage) {
 | 
						|
                totalPercentage += percentage
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        if totalPercentage > Float(100.1) || totalPercentage <= Float(99.99) {
 | 
						|
            isLoading = false
 | 
						|
            errorMessage = "확률이 100%가 아닙니다"
 | 
						|
            isShowErrorPopup = true
 | 
						|
            return false
 | 
						|
        }
 | 
						|
        
 | 
						|
        return true
 | 
						|
    }
 | 
						|
    
 | 
						|
    private func createRoulette(onSuccess: @escaping (Bool, String) -> Void) {
 | 
						|
        var items = [RouletteItem]()
 | 
						|
        for option in options {
 | 
						|
            if let percentage = Float(option.percentage) {
 | 
						|
                items.append(RouletteItem(title: option.title, percentage: percentage))
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        let selectedRouletteTitle: String
 | 
						|
        let successMessage: String
 | 
						|
        
 | 
						|
        switch (self.selectedRoulette) {
 | 
						|
        case .ROULETTE_2:
 | 
						|
            selectedRouletteTitle = "룰렛 2"
 | 
						|
            
 | 
						|
        case .ROULETTE_3:
 | 
						|
            selectedRouletteTitle = "룰렛 3"
 | 
						|
        
 | 
						|
        default:
 | 
						|
            selectedRouletteTitle = "룰렛 1"
 | 
						|
        }
 | 
						|
        
 | 
						|
        if availableActive {
 | 
						|
            if isActive {
 | 
						|
                successMessage = "\(selectedRouletteTitle)로 설정하였습니다."
 | 
						|
            } else {
 | 
						|
                successMessage = "\(selectedRouletteTitle)을 설정했습니다."
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            successMessage = "\(selectedRouletteTitle)을 생성했습니다."
 | 
						|
        }
 | 
						|
        
 | 
						|
        let request = CreateRouletteRequest(can: can, isActive: isActive, items: items)
 | 
						|
        repository.createRoulette(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(ApiResponseWithoutData.self, from: responseData)
 | 
						|
                    
 | 
						|
                    if decoded.success {
 | 
						|
                        onSuccess(isActive, successMessage)
 | 
						|
                    } else {
 | 
						|
                        self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
 | 
						|
                        self.isShowErrorPopup = true
 | 
						|
                    }
 | 
						|
                } catch {
 | 
						|
                    self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
 | 
						|
                    self.isShowErrorPopup = true
 | 
						|
                }
 | 
						|
            }
 | 
						|
            .store(in: &subscription)
 | 
						|
    }
 | 
						|
    
 | 
						|
    private func updateRoulette(onSuccess: @escaping (Bool, String) -> Void) {
 | 
						|
        var items = [RouletteItem]()
 | 
						|
        for option in options {
 | 
						|
            if let percentage = Float(option.percentage) {
 | 
						|
                items.append(RouletteItem(title: option.title, percentage: percentage))
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        let selectedRoulette = rouletteList[selectedRoulette!.rawValue]
 | 
						|
        if selectedRoulette.isActive == isActive && selectedRoulette.can == can && selectedRoulette.items == items {
 | 
						|
            self.errorMessage = "변동사항이 없습니다."
 | 
						|
            self.isShowErrorPopup = true
 | 
						|
            self.isLoading = false
 | 
						|
            return
 | 
						|
        }
 | 
						|
        
 | 
						|
        let selectedRouletteTitle: String
 | 
						|
        let successMessage: String
 | 
						|
        
 | 
						|
        switch (self.selectedRoulette) {
 | 
						|
        case .ROULETTE_2:
 | 
						|
            selectedRouletteTitle = "룰렛 2"
 | 
						|
            
 | 
						|
        case .ROULETTE_3:
 | 
						|
            selectedRouletteTitle = "룰렛 3"
 | 
						|
        
 | 
						|
        default:
 | 
						|
            selectedRouletteTitle = "룰렛 1"
 | 
						|
        }
 | 
						|
        
 | 
						|
        if availableActive {
 | 
						|
            if isActive {
 | 
						|
                successMessage = "\(selectedRouletteTitle)을 활성화 했습니다."
 | 
						|
            } else {
 | 
						|
                successMessage = "\(selectedRouletteTitle)을 비활성화 했습니다."
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            successMessage = "\(selectedRouletteTitle)을 변경했습니다."
 | 
						|
        }
 | 
						|
        
 | 
						|
        let request = UpdateRouletteRequest(id: rouletteId, can: can, isActive: isActive, items: items)
 | 
						|
        repository.updateRoulette(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(ApiResponseWithoutData.self, from: responseData)
 | 
						|
                    
 | 
						|
                    if decoded.success {
 | 
						|
                        onSuccess(isActive, successMessage)
 | 
						|
                    } else {
 | 
						|
                        self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
 | 
						|
                        self.isShowErrorPopup = true
 | 
						|
                    }
 | 
						|
                } catch {
 | 
						|
                    self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
 | 
						|
                    self.isShowErrorPopup = true
 | 
						|
                }
 | 
						|
            }
 | 
						|
            .store(in: &subscription)
 | 
						|
    }
 | 
						|
    
 | 
						|
    func selectRoulette(selectedRoulette: SelectedRoulette) {
 | 
						|
        if rouletteList.isEmpty && (selectedRoulette == .ROULETTE_2 || selectedRoulette == .ROULETTE_3) {
 | 
						|
            errorMessage = "룰렛 1을 먼저 설정하세요"
 | 
						|
            isShowErrorPopup = true
 | 
						|
            return
 | 
						|
        }
 | 
						|
        
 | 
						|
        if rouletteList.count == 1 && selectedRoulette == .ROULETTE_3 {
 | 
						|
            errorMessage = "룰렛 1과 룰렛 2를 먼저 설정하세요"
 | 
						|
            isShowErrorPopup = true
 | 
						|
            return
 | 
						|
        }
 | 
						|
        
 | 
						|
        if self.selectedRoulette != selectedRoulette {
 | 
						|
            self.selectedRoulette = selectedRoulette
 | 
						|
            
 | 
						|
            if rouletteList.count > selectedRoulette.rawValue {
 | 
						|
                let roulette = rouletteList[selectedRoulette.rawValue]
 | 
						|
                if roulette.can > 0 {
 | 
						|
                    self.canText = String(roulette.can)
 | 
						|
                } else {
 | 
						|
                    self.canText = ""
 | 
						|
                }
 | 
						|
                
 | 
						|
                self.rouletteId = roulette.id
 | 
						|
                self.isActive = roulette.isActive
 | 
						|
                let options = roulette.items.map {
 | 
						|
                    RouletteOption(title: $0.title, percentage: String($0.percentage))
 | 
						|
                }
 | 
						|
                
 | 
						|
                self.options.removeAll()
 | 
						|
                self.options.append(contentsOf: options)
 | 
						|
            } else {
 | 
						|
                self.canText = ""
 | 
						|
                self.isActive = false
 | 
						|
                self.rouletteId = 0
 | 
						|
                
 | 
						|
                options.removeAll()
 | 
						|
                self.addOption()
 | 
						|
                self.addOption()
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        calculateTotalPercentage()
 | 
						|
    }
 | 
						|
    
 | 
						|
    func calculateTotalPercentage() {
 | 
						|
        let totalPercent = options.map {
 | 
						|
            let percentage = Float($0.percentage)
 | 
						|
            
 | 
						|
            if let percentage = percentage {
 | 
						|
                return percentage
 | 
						|
            } else {
 | 
						|
                return Float(0)
 | 
						|
            }
 | 
						|
        }.reduce(0, +)
 | 
						|
        
 | 
						|
        self.totalPercentage = totalPercent
 | 
						|
    }
 | 
						|
}
 |