Skip to content

Commit

Permalink
[refactor/#114] 뷰 관련 연결 리펙토링
Browse files Browse the repository at this point in the history
  • Loading branch information
kim-seonwoo committed Nov 25, 2024
1 parent 09e81d5 commit 7b53075
Show file tree
Hide file tree
Showing 11 changed files with 644 additions and 514 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// LoginUseCase.swift
// LoginFeature
//
// Created by Seonwoo Kim on 11/8/24.
// Copyright © 2024 HMH-iOS. All rights reserved.
//

import Foundation
import Combine

import Domain
import Core

public enum LoginResponseType {
case loginSuccess
case loginFailure
case onboardingNeeded
}

public protocol LoginUseCaseType {
func login(provider: OAuthProviderType) -> AnyPublisher<LoginResponseType, AuthError>
}

public final class LoginUseCase: LoginUseCaseType {

private let repository: AuthRepositoryType

public init(repository: AuthRepositoryType) {
self.repository = repository
}

public func login(provider: OAuthProviderType) -> AnyPublisher<LoginResponseType, Domain.AuthError> {
repository.authorize(provider)
.handleEvents(receiveOutput: { socialToken in
UserManager.shared.socialToken = socialToken
})
.flatMap { [weak self] _ -> AnyPublisher<LoginResponseType, AuthError> in
guard let self = self else {
return Fail(error: AuthError.appleAuthrizeError).eraseToAnyPublisher()
}

return self.repository.socialLogin(socialPlatform: provider.rawValue)
.map { _ in LoginResponseType.loginSuccess }
.catch { error -> AnyPublisher<LoginResponseType, AuthError> in
switch error {
case .unregisteredUser:
return Just(.onboardingNeeded)
.setFailureType(to: AuthError.self)
.eraseToAnyPublisher()
default:
return Just(.loginFailure)
.setFailureType(to: AuthError.self)
.eraseToAnyPublisher()
}
}
.eraseToAnyPublisher()
}
.eraseToAnyPublisher()
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// LoginUseCase.swift
// LoginFeature
//
// Created by Seonwoo Kim on 11/8/24.
// Copyright © 2024 HMH-iOS. All rights reserved.
//

import Foundation
import Combine

import Domain
import Core

public enum LoginResponseType {
case loginSuccess
case loginFailure
case onboardingNeeded
}

public protocol LoginUseCaseType {
func login(provider: OAuthProviderType) -> AnyPublisher<LoginResponseType, AuthError>
}

public final class LoginUseCase: LoginUseCaseType {

private let repository: AuthRepositoryType

public init(repository: AuthRepositoryType) {
self.repository = repository
}

public func login(provider: OAuthProviderType) -> AnyPublisher<LoginResponseType, Domain.AuthError> {
repository.authorize(provider)
.handleEvents(receiveOutput: { socialToken in
UserManager.shared.socialToken = socialToken
})
.flatMap { [weak self] _ -> AnyPublisher<LoginResponseType, AuthError> in
guard let self = self else {
return Fail(error: AuthError.appleAuthrizeError).eraseToAnyPublisher()
}

return self.repository.socialLogin(socialPlatform: provider.rawValue)
.map { _ in LoginResponseType.loginSuccess }
.catch { error -> AnyPublisher<LoginResponseType, AuthError> in
switch error {
case .unregisteredUser:
return Just(.onboardingNeeded)
.setFailureType(to: AuthError.self)
.eraseToAnyPublisher()
default:
return Just(.loginFailure)
.setFailureType(to: AuthError.self)
.eraseToAnyPublisher()
}
}
.eraseToAnyPublisher()
}
.eraseToAnyPublisher()
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,36 @@
//

import Foundation
import DSKit

struct SurveyButtonInfo: Identifiable {
let id = UUID()
var buttonTitle: String
var isSelected: Bool
}

extension SurveyButtonInfo {
static func initializeSurveyButtonItems() -> [[SurveyButtonInfo]] {
return [
[
SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.firstSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.secondSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.thirdSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.fourthSelect, isSelected: false),
],
[
SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.firstSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.secondSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.thirdSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.fourthSelect, isSelected: false),
],
[
SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.firstSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.secondSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.thirdSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.fourthSelect, isSelected: false),
]
]
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,9 @@ public final class OnboardingUseCase: OnboardingUseCaseType {
.map { auth -> Void in
// UserManager.shared.accessToken = auth.accessToken
// UserManager.shared.refreshToken = auth.refreshToken
print("Sign-up successful with user: \(auth)")
}
.mapError { error -> Error in
print("Sign-up failed with error: \(error)")

return error
}
.eraseToAnyPublisher()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,38 @@ import Core
import Domain
import DSKit

public final class OnboardingViewModel_Refactor : ObservableObject {
public final class OnboardingViewModel : ObservableObject {

private let useCase: OnboardingUseCaseType
private var cancelBag = CancelBag()

@Published private(set) var state = State(onboardingState: .timeSurveySelect, surveyButtonItems: [[]], isNextAvailable: false)
@Published private(set) var state = State(onboardingState: .timeSurveySelect, surveyButtonItems: [[]], isNextAvailable: false, surveyState: 0)
@Published
var selectedAppHour: String
@Published
var selectedAppMinute: String

var userName: String
var averageUseTime: String
var problems: [String]
var period: Int
var appGoalTime: Int

public init(useCase: OnboardingUseCaseType) {
self.useCase = useCase
self.state = State(
onboardingState: .timeSurveySelect,
surveyButtonItems: initializeSurveyButtonItems(),
isNextAvailable: false
surveyButtonItems: SurveyButtonInfo.initializeSurveyButtonItems(),
isNextAvailable: false,
surveyState: 0
)
self.userName = ""
self.averageUseTime = ""
self.problems = []
self.period = 0
self.selectedAppHour = ""
self.selectedAppMinute = ""
self.appGoalTime = 0
}

// MARK: Action
Expand All @@ -51,6 +61,7 @@ public final class OnboardingViewModel_Refactor : ObservableObject {
var onboardingState: OnboardingState
var surveyButtonItems: [[SurveyButtonInfo]]
var isNextAvailable: Bool
var surveyState: Int
}

func send(action: Action) {
Expand All @@ -67,65 +78,32 @@ public final class OnboardingViewModel_Refactor : ObservableObject {
func surveyButtonTap(index: Int) {
guard state.onboardingState.rawValue < state.surveyButtonItems.count else { return }

// 현재 상태에 해당하는 버튼 리스트 가져오기
let currentSurveyItems = state.surveyButtonItems[state.onboardingState.rawValue]

// index 유효성 검증
guard index >= 0 && index < currentSurveyItems.count else { return }

// 상태에 따라 다른 선택 로직 적용
switch state.onboardingState {
case .timeSurveySelect, .challangePeriodSelect, .goalTimeSelect:
// 단일 선택 상태
for i in 0..<currentSurveyItems.count {
state.surveyButtonItems[state.onboardingState.rawValue][i].isSelected = (i == index)
}
// 다음 버튼 활성화
state.isNextAvailable = true

onIsCompleted()

case .problemSurveySelect:
// 다중 선택 상태: 최대 두 개의 선택만 허용
let selectedCount = currentSurveyItems.filter { $0.isSelected }.count

if currentSurveyItems[index].isSelected {
// 이미 선택된 경우 해제
state.surveyButtonItems[state.onboardingState.rawValue][index].isSelected = false
} else if selectedCount < 2 {
// 선택 가능하면 활성화
state.surveyButtonItems[state.onboardingState.rawValue][index].isSelected = true
}

// 다음 버튼 활성화 여부 결정
state.isNextAvailable = state.surveyButtonItems[state.onboardingState.rawValue].contains { $0.isSelected }

default:
break
}
}

private func initializeSurveyButtonItems() -> [[SurveyButtonInfo]] {
return [
[
SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.firstSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.secondSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.thirdSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.fourthSelect, isSelected: false),
],
[
SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.firstSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.secondSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.thirdSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.fourthSelect, isSelected: false),
],
[
SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.firstSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.secondSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.thirdSelect, isSelected: false),
SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.fourthSelect, isSelected: false),
]
]
}


private func resetSelections(for state: OnboardingState) {
guard state.rawValue < self.state.surveyButtonItems.count else { return }
for i in 0..<self.state.surveyButtonItems[state.rawValue].count {
Expand Down Expand Up @@ -172,34 +150,43 @@ public final class OnboardingViewModel_Refactor : ObservableObject {
private func savePeriod() {
for index in 0..<4{
if state.surveyButtonItems[state.onboardingState.rawValue] [index].isSelected {
self.period = removeLastCharacterAndConvertToInt(from: state.surveyButtonItems[state.onboardingState.rawValue] [index].buttonTitle)
self.period = removeLastCharacterAndConvertToInt(from: state.surveyButtonItems[state.onboardingState.rawValue] [index].buttonTitle) ?? 0
}
}
addOnboardingState()
}

private func saveGoalTime() {

self.appGoalTime = convertToTotalMilliseconds(hour: selectedAppHour, minute: selectedAppMinute)
addOnboardingState()
}

private func savePermission() {
// screenViewModel.requestAuthorization()
// if screenViewModel.authorizationCenter.authorizationStatus == .approved {
// onboardingState += 1
// }
completOnboarding()
}

private func saveApp() {
// screenViewModel.requestAuthorization()
// if screenViewModel.authorizationCenter.authorizationStatus == .approved {
// onboardingState += 1
// }
private func convertToTotalMilliseconds(hour: String?, minute: String?) -> Int {
let hourInt = Int(hour ?? "") ?? 0
let minuteInt = Int(minute ?? "") ?? 0

let totalMinutes = hourInt * 60 + minuteInt
let totalMilliseconds = totalMinutes * 60 * 1000
return totalMilliseconds
}

private func addOnboardingState() {
state.onboardingState.rawValue += 1
guard let nextState = OnboardingState(rawValue: state.onboardingState.rawValue + 1) else { return }
state.onboardingState = nextState
if nextState.rawValue <= 2 {
state.surveyState = nextState.rawValue
}
}


private func removeLastCharacterAndConvertToInt(from string: String) -> Int? {
guard !string.isEmpty else {
return nil
Expand All @@ -218,16 +205,16 @@ public final class OnboardingViewModel_Refactor : ObservableObject {
case .problemSurveySelect, .challangePeriodSelect, .goalTimeSelect:
guard let previousState = OnboardingState(rawValue: state.onboardingState.rawValue - 1) else { return }
state.onboardingState = previousState
offIsCompleted()
case .appSelect:
guard let previousState = OnboardingState(rawValue: state.onboardingState.rawValue - 1) else { return }
state.onboardingState = previousState
state.surveyState = previousState.rawValue
resetSelections(for: previousState)
offIsCompleted()
default:
guard let previousState = OnboardingState(rawValue: state.onboardingState.rawValue - 1) else { return }
state.onboardingState = previousState
onIsCompleted()
}

print(state.onboardingState.rawValue)
}


Expand All @@ -240,12 +227,10 @@ public final class OnboardingViewModel_Refactor : ObservableObject {
}

private func completOnboarding() {
useCase.postSignUpData(socialPlatform: <#T##String#>, userName: <#T##String#>, averageUseTime: <#T##String#>, problems: <#T##[String]#>, period: <#T##Int#>)
useCase.postSignUpData(socialPlatform: "KAKAO", userName: "", averageUseTime: averageUseTime, problems: problems, period: period)
.sink(receiveCompletion: { _ in }) {
}
.store(in: cancelBag)
}


}

Loading

0 comments on commit 7b53075

Please sign in to comment.