Skip to content

Commit

Permalink
Merge pull request #247 from Team-return/feature/(#204)-recruitment_f…
Browse files Browse the repository at this point in the history
…ilter

🔗 :: (#204) 모집의뢰서 필터 구현
  • Loading branch information
ray3238 committed Jun 12, 2024
2 parents cc0ea97 + 8ae10a2 commit 3a19767
Show file tree
Hide file tree
Showing 16 changed files with 591 additions and 13 deletions.
6 changes: 6 additions & 0 deletions Projects/Core/Sources/Steps/RecruitmentFilterStep.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import RxFlow

public enum RecruitmentFilterStep: Step {
case recruitmentFilterIsRequired
case popToRecruitment(jobCode: String?, techCode: [String]?)
}
1 change: 1 addition & 0 deletions Projects/Core/Sources/Steps/RecruitmentStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ import RxFlow
public enum RecruitmentStep: Step {
case recruitmentIsRequired
case recruitmentDetailIsRequired(recruitmentId: Int)
case recruitmentFilterIsRequired
case searchRecruitmentIsRequired
}
48 changes: 48 additions & 0 deletions Projects/Flow/Sources/Recruitment/RecruitmentFilterFlow.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import UIKit
import Presentation
import Swinject
import RxFlow
import Core

public final class RecruitmentFilterFlow: Flow {
public let container: Container
private let rootViewController: RecruitmentFilterViewController
public var root: Presentable {
return rootViewController
}

public init(container: Container) {
self.container = container
self.rootViewController = container.resolve(RecruitmentFilterViewController.self)!
}

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

switch step {
case .recruitmentFilterIsRequired:
return navigateToRecruitmentFilter()

case let .popToRecruitment(jobCode, techCode):
return popToRecruitment(jobCode: jobCode ?? "", techCode: techCode)
}
}
}

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

func popToRecruitment(jobCode: String, techCode: [String]?) -> FlowContributors {
let popView = self.rootViewController.navigationController?.viewControllers.first as? RecruitmentViewController
popView?.viewModel.jobCode = jobCode
popView?.viewModel.techCode = techCode
self.rootViewController.navigationController?.popViewController(animated: true)

return .none
}
}
18 changes: 18 additions & 0 deletions Projects/Flow/Sources/Recruitment/RecruitmentFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public final class RecruitmentFlow: Flow {
case let .recruitmentDetailIsRequired(id):
return navigateToRecruitmentDetail(recruitmentID: id)

case .recruitmentFilterIsRequired:
return navigateToRecruitmentFilter()

case .searchRecruitmentIsRequired:
return navigateToSearchRecruitment()
}
Expand Down Expand Up @@ -92,4 +95,19 @@ private extension RecruitmentFlow {
withNextStepper: OneStepper(withSingleStep: SearchRecruitmentStep.searchRecruitmentIsRequired)
))
}

func navigateToRecruitmentFilter() -> FlowContributors {
let recruitmentFilterFlow = RecruitmentFilterFlow(container: container)

Flows.use(recruitmentFilterFlow, when: .created) { (root) in
self.rootViewController.pushViewController(
root, animated: true
)
}

return .one(flowContributor: .contribute(
withNextPresentable: recruitmentFilterFlow,
withNextStepper: OneStepper(withSingleStep: RecruitmentFilterStep.recruitmentFilterIsRequired)
))
}
}
41 changes: 41 additions & 0 deletions Projects/Modules/DesignSystem/Sources/CheckBox/JobisCheckBox.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import UIKit
import RxSwift
import RxCocoa
import Then
import SnapKit

public final class JobisCheckBox: UIButton {
public var isCheck: Bool = false {
didSet { self.configureUI() }
}

private var fgColor: UIColor {
return isCheck ? .GrayScale.gray10: .GrayScale.gray50
}

private var bgColor: UIColor {
return isCheck ? .Primary.blue20: .GrayScale.gray30
}

public init() {
super.init(frame: .zero)
configureUI()
}

required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func configureUI() {
let image: UIImage? = .jobisIcon(.arrowDown)
.withTintColor(fgColor, renderingMode: .alwaysTemplate)
.resize(size: 28)

var config = UIButton.Configuration.plain()
config.image = image
config.imagePlacement = .all
self.configuration = config
self.layer.cornerRadius = 4
self.backgroundColor = bgColor
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import UIKit
import Then
import SnapKit
import RxSwift
import RxCocoa

public final class JobisSearchTextField: UIStackView {
private var disposeBag = DisposeBag()
private let searchImageView = UIImageView().then {
$0.image = .jobisIcon(.searchIcon)
}
private let searchTextField = UITextField()

public init() {
super.init(frame: .zero)
self.spacing = 4
self.axis = .horizontal
self.layoutMargins = .init(top: 12, left: 16, bottom: 12, right: 16)
self.isLayoutMarginsRelativeArrangement = true
self.backgroundColor = .GrayScale.gray30
self.layer.cornerRadius = 12
}

required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override public func layoutSubviews() {
addView()
setLayout()
}

public func setTextField(
placeholder: String
) {
self.searchTextField.placeholder = placeholder
}

private func addView() {
[
searchImageView,
searchTextField
].forEach(self.addArrangedSubview(_:))
}

private func setLayout() {
searchImageView.snp.makeConstraints {
$0.height.width.equalTo(24)
}
}
}
12 changes: 12 additions & 0 deletions Projects/Presentation/Sources/DI/PresentationAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,20 @@ public final class PresentationAssembly: Assembly {
)
}

container.register(RecruitmentFilterViewController.self) { resolver in
RecruitmentFilterViewController(
resolver.resolve(RecruitmentFilterViewModel.self)!
)
}
container.register(RecruitmentFilterViewModel.self) { resolver in
RecruitmentFilterViewModel(
fetchCodeListUseCase: resolver.resolve(FetchCodeListUseCase.self)!
)
}

container.register(EasterEggViewController.self) { resolver in
EasterEggViewController()
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ public final class RecruitmentViewController: BaseViewController<RecruitmentView
public var viewWillappearWithTap: (() -> Void)?
public var isTabNavigation: Bool = true
private let bookmarkButtonDidClicked = PublishRelay<Int>()
private let searchButtonDidTap = PublishRelay<Void>()
private let pageCount = PublishRelay<Int>()
private let listEmptyView = ListEmptyView().then {
$0.setEmptyView(title: "아직 등록된 모집의뢰서가 없어요")
Expand Down Expand Up @@ -65,7 +64,8 @@ public final class RecruitmentViewController: BaseViewController<RecruitmentView
.do(onNext: { _ in
self.isTabNavigation = false
}),
searchButtonDidTap: searchButtonDidTap
searchButtonDidTap: searchButton.rx.tap.asSignal(),
filterButtonDidTap: filterButton.rx.tap.asSignal()
)

let output = viewModel.transform(input)
Expand All @@ -89,12 +89,6 @@ public final class RecruitmentViewController: BaseViewController<RecruitmentView
}

public override func configureViewController() {
searchButton.rx.tap
.subscribe(onNext: { _ in
self.searchButtonDidTap.accept(())
})
.disposed(by: disposeBag)

viewWillAppearPublisher.asObservable()
.bind {
self.showTabbar()
Expand All @@ -115,8 +109,8 @@ public final class RecruitmentViewController: BaseViewController<RecruitmentView

public override func configureNavigation() {
navigationItem.rightBarButtonItems = [
UIBarButtonItem(customView: searchButton)
// UIBarButtonItem(customView: filterButton)
UIBarButtonItem(customView: searchButton),
UIBarButtonItem(customView: filterButton)
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import Domain

public final class RecruitmentViewModel: BaseViewModel, Stepper {
public let steps = PublishRelay<Step>()
public var jobCode: String = ""
public var techCode: [String]?
public var recruitmentData = BehaviorRelay<[RecruitmentEntity]>(value: [])
private let disposeBag = DisposeBag()
private let fetchRecruitmentListUseCase: FetchRecruitmentListUseCase
Expand All @@ -26,7 +28,8 @@ public final class RecruitmentViewModel: BaseViewModel, Stepper {
let bookMarkButtonDidTap: PublishRelay<Int>
var pageChange: Observable<WillDisplayCellEvent>
let recruitmentTableViewDidTap: Observable<Int>
let searchButtonDidTap: PublishRelay<Void>
let searchButtonDidTap: Signal<Void>
let filterButtonDidTap: Signal<Void>
}

public struct Output {
Expand All @@ -37,7 +40,11 @@ public final class RecruitmentViewModel: BaseViewModel, Stepper {
input.viewAppear.asObservable()
.flatMap {
self.pageCount = 1
return self.fetchRecruitmentListUseCase.execute(page: self.pageCount)
return self.fetchRecruitmentListUseCase.execute(
page: self.pageCount,
jobCode: self.jobCode,
techCode: self.techCode
)
}
.bind(onNext: {
self.recruitmentData.accept([])
Expand All @@ -49,7 +56,11 @@ public final class RecruitmentViewModel: BaseViewModel, Stepper {
input.pageChange.asObservable()
.flatMap { _ in
self.pageCount += 1
return self.fetchRecruitmentListUseCase.execute(page: self.pageCount)
return self.fetchRecruitmentListUseCase.execute(
page: self.pageCount,
jobCode: self.jobCode,
techCode: self.techCode
)
.asObservable()
.take(while: {
!$0.isEmpty
Expand Down Expand Up @@ -90,6 +101,11 @@ public final class RecruitmentViewModel: BaseViewModel, Stepper {
.bind(to: steps)
.disposed(by: disposeBag)

input.filterButtonDidTap.asObservable()
.map { _ in RecruitmentStep.recruitmentFilterIsRequired }
.bind(to: steps)
.disposed(by: disposeBag)

return Output(recruitmentData: recruitmentData)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import UIKit
import Domain
import DesignSystem
import SnapKit
import Then
import RxSwift
import RxCocoa

final class JobsCollectionViewCell: BaseCollectionViewCell<CodeEntity> {
static let identifier = "JobsCollectionViewCell"
public var isCheck: Bool = false {
didSet {
self.backgroundColor = isCheck ? .Primary.blue20 : .GrayScale.gray30
self.jobLabel.setJobisText(
model?.keyword ?? "",
font: .body,
color: isCheck ? .GrayScale.gray10 : .Primary.blue40
)
}
}
private var disposeBag = DisposeBag()
private let jobLabel = UILabel()

override func addView() {
self.contentView.addSubview(jobLabel)
}

override func setLayout() {
jobLabel.snp.makeConstraints {
$0.leading.trailing.equalToSuperview().inset(12)
$0.top.bottom.equalToSuperview().inset(4)
}
}

override func configureView() {
self.backgroundColor = .GrayScale.gray30
self.layer.cornerRadius = 16
}

override func adapt(model: CodeEntity) {
super.adapt(model: model)
jobLabel.setJobisText(model.keyword, font: .body, color: .Primary.blue40)
}
}
Loading

0 comments on commit 3a19767

Please sign in to comment.