Skip to content
11 changes: 11 additions & 0 deletions Projects/Domain/Sources/Enums/DevelopmentType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,15 @@ public enum DevelopmentType: String, Codable {
return "iOS"
}
}

public init?(localizedString: String) {
switch localizedString {
case "์ „์ฒด", "All": self = .all
case "์„œ๋ฒ„", "Server": self = .server
case "์›น", "Web": self = .web
case "์•ˆ๋“œ๋กœ์ด๋“œ", "Android": self = .android
case "iOS": self = .ios
default: return nil
}
}
}
4 changes: 2 additions & 2 deletions Projects/Flow/Sources/MyPage/BugReport/BugReportFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ private extension BugReportFlow {
func navigateToBugReport() -> FlowContributors {
return .one(flowContributor: .contribute(
withNextPresentable: rootViewController,
withNextStepper: rootViewController.viewModel
withNextStepper: rootViewController.reactor
))
}

Expand All @@ -42,7 +42,7 @@ private extension BugReportFlow {
Flows.use(majorBottomSheetFlow, when: .created) { root in
let view = root as? MajorBottomSheetViewController
view?.dismiss = { majorType in
self.rootViewController.viewModel.majorType.accept(majorType)
self.rootViewController.reactor.action.onNext(.updateMajorType(majorType))
}
self.rootViewController.present(
root,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public final class InterestFieldCheckFlow: Flow {
return navigateToInterestFieldCheck()

case .popHomeFieldIsRequired:
return navigateToInterestField()
return popToMyPage()
}
}
}
Expand All @@ -37,7 +37,7 @@ private extension InterestFieldCheckFlow {
func navigateToInterestField() -> FlowContributors {
return .one(flowContributor: .contribute(
withNextPresentable: rootViewController,
withNextStepper: rootViewController.viewModel
withNextStepper: rootViewController.reactor
))
}

Expand All @@ -51,11 +51,12 @@ private extension InterestFieldCheckFlow {

return .one(flowContributor: .contribute(
withNextPresentable: interestFieldCheckViewController,
withNextStepper: interestFieldCheckViewController.viewModel
withNextStepper: interestFieldCheckViewController.reactor
))
}

// func navigateToHomeField() -> FlowContributors {
//
// }
func popToMyPage() -> FlowContributors {
rootViewController.navigationController?.popToRootViewController(animated: true)
return .none
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,31 @@ public final class InterestFieldFlow: Flow {
}

public func navigate(to step: Step) -> FlowContributors {
guard let step = step as? InterestFieldStep else { return .none }

switch step {
case .interestFieldIsRequired:
return navigateToInterestField()
case .interestFieldCheckIsRequired:
return navigateToInterestFieldCheck()
if let step = step as? InterestFieldStep {
switch step {
case .interestFieldIsRequired:
return navigateToInterestField()
case .interestFieldCheckIsRequired:
return navigateToInterestFieldCheck()
}
} else if let step = step as? InterestFieldCheckStep {
switch step {
case .popHomeFieldIsRequired:
return popToMyPage()
default:
return .none
}
}

return .none
}
}

private extension InterestFieldFlow {
func navigateToInterestField() -> FlowContributors {
return .one(flowContributor: .contribute(
withNextPresentable: rootViewController,
withNextStepper: rootViewController.viewModel
withNextStepper: rootViewController.reactor
))
}

Expand All @@ -43,7 +52,12 @@ private extension InterestFieldFlow {

return .one(flowContributor: .contribute(
withNextPresentable: interestFieldCheckViewController,
withNextStepper: interestFieldCheckViewController.viewModel
withNextStepper: interestFieldCheckViewController.reactor
))
}

func popToMyPage() -> FlowContributors {
rootViewController.navigationController?.popToRootViewController(animated: true)
return .none
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ private extension NotificationSettingFlow {
func navigateToNotificationSetting() -> FlowContributors {
return .one(flowContributor: .contribute(
withNextPresentable: rootViewController,
withNextStepper: rootViewController.viewModel
withNextStepper: rootViewController.reactor
))
}
}
110 changes: 110 additions & 0 deletions Projects/Presentation/Sources/BugReport/BugReportReactor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import ReactorKit
import RxSwift
import RxCocoa
import RxFlow
import Core
import Domain

public final class BugReportReactor: BaseReactor, Stepper {
public let steps = PublishRelay<Step>()
public let initialState: State
private let reportBugUseCase: ReportBugUseCase

public init(
reportBugUseCase: ReportBugUseCase
) {
self.initialState = .init()
self.reportBugUseCase = reportBugUseCase
}

public enum Action {
case updateTitle(String)
case updateContent(String)
case updateImageList([String])
case updateMajorType(String)
case majorViewDidTap
case bugReportButtonDidTap
}

public enum Mutation {
case setTitle(String)
case setContent(String)
case setImageList([String])
case setMajorType(String)
case setBugReportButtonIsEnabled(Bool)
case setBugReportCompleted
}

public struct State {
var title: String = ""
var content: String = ""
var imageList: [String] = []
var majorType: String = "์ „์ฒด"
var isBugReportButtonEnabled: Bool = false
var isBugReportCompleted: Bool = false
}
}

extension BugReportReactor {
public func mutate(action: Action) -> Observable<Mutation> {
switch action {
case let .updateTitle(title):
let isEnabled = !title.isEmpty && !currentState.content.isEmpty
return .concat([
.just(.setTitle(title)),
.just(.setBugReportButtonIsEnabled(isEnabled))
])

case let .updateContent(content):
let isEnabled = !currentState.title.isEmpty && !content.isEmpty
return .concat([
.just(.setContent(content)),
.just(.setBugReportButtonIsEnabled(isEnabled))
])

case let .updateImageList(imageList):
return .just(.setImageList(imageList))

case let .updateMajorType(majorType):
return .just(.setMajorType(majorType))

case .majorViewDidTap:
steps.accept(BugReportStep.majorBottomSheetIsRequired)
return .empty()

case .bugReportButtonDidTap:
return reportBugUseCase.execute(req: .init(
title: currentState.title,
content: currentState.content,
developmentArea: DevelopmentType(localizedString: currentState.majorType) ?? .all,
attachmentUrls: currentState.imageList
))
.asObservable()
.map { _ in Mutation.setBugReportCompleted }
}
}

public func reduce(state: State, mutation: Mutation) -> State {
var newState = state
switch mutation {
case let .setTitle(title):
newState.title = title

case let .setContent(content):
newState.content = content

case let .setImageList(imageList):
newState.imageList = imageList

case let .setMajorType(majorType):
newState.majorType = majorType

case let .setBugReportButtonIsEnabled(isEnabled):
newState.isBugReportButtonEnabled = isEnabled

case .setBugReportCompleted:
newState.isBugReportCompleted = true
}
return newState
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,9 @@ import Core
import DesignSystem
import PhotosUI

public final class BugReportViewController: BaseViewController<BugReportViewModel> {
private let bugReportButtonDidTap = PublishRelay<Void>()
private let bugReportImageList = BehaviorRelay<[String]>(value: [])
public final class BugReportViewController: BaseReactorViewController<BugReportReactor> {
var imageStringList: [String] = []
var imageList: [UIImage] = []
var titleBool: Bool = false
var contentBool: Bool = false

private let bugReportMajorView = BugReportMajorView()
private let bugReportTitleTextField = JobisTextField().then {
Expand Down Expand Up @@ -154,27 +150,41 @@ public final class BugReportViewController: BaseViewController<BugReportViewMode
}
}

public override func bind() {
let input = BugReportViewModel.Input(
title: bugReportTitleTextField.textField.rx.text.orEmpty.asDriver(),
content: bugReportContentTextView.textView.rx.text.orEmpty.asDriver(),
bugReportImageList: bugReportImageList,
majorViewDidTap: self.bugReportMajorView.majorViewDidTap,
bugReportButtonDidTap: self.bugReportButtonDidTap
)
public override func bindAction() {
bugReportTitleTextField.textField.rx.text.orEmpty
.map { BugReportReactor.Action.updateTitle($0) }
.bind(to: reactor.action)
.disposed(by: disposeBag)

let output = viewModel.transform(input)
bugReportContentTextView.textView.rx.text.orEmpty
.map { BugReportReactor.Action.updateContent($0) }
.bind(to: reactor.action)
.disposed(by: disposeBag)

output.bugReportButtonIsEnable.asObservable()
.bind { [weak self] isEnable in
self?.bugReportButton.isEnabled = isEnable
}
bugReportMajorView.majorViewDidTap
.map { BugReportReactor.Action.majorViewDidTap }
.bind(to: reactor.action)
.disposed(by: disposeBag)

output.majorType.asObservable()
.subscribe(onNext: {
self.bugReportMajorView.majorLabel.text = $0
bugReportButton.rx.tap
.do(onNext: { [weak self] in
guard let self = self else { return }
self.reactor.action.onNext(.updateImageList(self.imageStringList))
})
.map { BugReportReactor.Action.bugReportButtonDidTap }
.bind(to: reactor.action)
.disposed(by: disposeBag)
}

public override func bindState() {
reactor.state.map { $0.isBugReportButtonEnabled }
.distinctUntilChanged()
.bind(to: bugReportButton.rx.isEnabled)
.disposed(by: disposeBag)

reactor.state.map { $0.majorType }
.distinctUntilChanged()
.bind(to: bugReportMajorView.majorLabel.rx.text)
.disposed(by: disposeBag)
}

Expand All @@ -194,12 +204,12 @@ public final class BugReportViewController: BaseViewController<BugReportViewMode
})
.disposed(by: disposeBag)

bugReportButton.rx.tap.asObservable()
.subscribe(onNext: {
self.bugReportImageList.accept(self.imageStringList)
self.bugReportButtonDidTap.accept(())
self.showJobisToast(text: "๋ฒ„๊ทธ์ œ๋ณด๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.", inset: 70)
self.navigationController?.popViewController(animated: true)
reactor.state.map { $0.isBugReportCompleted }
.distinctUntilChanged()
.filter { $0 }
.bind(onNext: { [weak self] _ in
self?.showJobisToast(text: "๋ฒ„๊ทธ์ œ๋ณด๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.", inset: 70)
self?.navigationController?.popViewController(animated: true)
})
.disposed(by: disposeBag)
}
Expand Down
Loading