From ec82e3b4c7f967454e20d550c15c30dd8cebee89 Mon Sep 17 00:00:00 2001 From: Choyoungjun Date: Wed, 25 Sep 2024 14:34:49 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=A7=A9=20::=20=EA=B2=A8=EC=9A=B8?= =?UTF-8?q?=EC=9D=B8=ED=84=B4=20=EB=B7=B0=20=ED=8D=BC=EB=B8=94=EB=A6=AC?= =?UTF-8?q?=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WinterInternViewController.swift | 109 +++++++++++++++++ .../WinterIntern/WinterInternViewModel.swift | 113 ++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 Projects/Presentation/Sources/WinterIntern/WinterInternViewController.swift create mode 100644 Projects/Presentation/Sources/WinterIntern/WinterInternViewModel.swift diff --git a/Projects/Presentation/Sources/WinterIntern/WinterInternViewController.swift b/Projects/Presentation/Sources/WinterIntern/WinterInternViewController.swift new file mode 100644 index 00000000..77861e70 --- /dev/null +++ b/Projects/Presentation/Sources/WinterIntern/WinterInternViewController.swift @@ -0,0 +1,109 @@ +import UIKit +import Domain +import RxSwift +import RxCocoa +import SnapKit +import Then +import Core +import DesignSystem + +public final class WinterInternViewController: BaseViewController { + public var viewWillappearWithTap: (() -> Void)? + public var isTabNavigation: Bool = true + private let bookmarkButtonDidClicked = PublishRelay() + private let pageCount = PublishRelay() + private let listEmptyView = ListEmptyView().then { + $0.setEmptyView(title: "아직 등록된 모집의뢰서가 없어요") + $0.isHidden = true + } + private let recruitmentTableView = UITableView().then { + $0.register( + RecruitmentTableViewCell.self, + forCellReuseIdentifier: RecruitmentTableViewCell.identifier + ) + $0.separatorStyle = .none + $0.rowHeight = 72 + $0.showsVerticalScrollIndicator = false + } + private let filterButton = UIButton().then { + $0.setImage(.jobisIcon(.filterIcon), for: .normal) + } + private let searchButton = UIButton().then { + $0.setImage(.jobisIcon(.searchIcon), for: .normal) + } + + public override func addView() { + self.view.addSubview(recruitmentTableView) + recruitmentTableView.addSubview(listEmptyView) + } + + public override func setLayout() { + recruitmentTableView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + listEmptyView.snp.makeConstraints { + $0.centerX.equalToSuperview() + $0.top.equalToSuperview().inset(80) + } + } + + public override func bind() { + let input = WinterInternVieModel.Input( + viewAppear: self.viewDidLoadPublisher, + bookMarkButtonDidTap: bookmarkButtonDidClicked, + pageChange: recruitmentTableView.rx.willDisplayCell + .filter { + $0.indexPath.row == self.recruitmentTableView.numberOfRows( + inSection: $0.indexPath.section + ) - 1 + }, + recruitmentTableViewDidTap: recruitmentTableView.rx + .modelSelected(RecruitmentEntity.self) + .asObservable() + .map { $0.recruitID } + .do(onNext: { _ in + self.isTabNavigation = false + }), + searchButtonDidTap: searchButton.rx.tap.asSignal(), + filterButtonDidTap: filterButton.rx.tap.asSignal() + ) + + let output = viewModel.transform(input) + + output.recruitmentData + .skip(1) + .do(onNext: { + self.listEmptyView.isHidden = !$0.isEmpty + }) + .bind( + to: recruitmentTableView.rx.items( + cellIdentifier: RecruitmentTableViewCell.identifier, + cellType: RecruitmentTableViewCell.self + )) { _, element, cell in + cell.adapt(model: element) + cell.bookmarkButtonDidTap = { + self.bookmarkButtonDidClicked.accept(cell.model!.recruitID) + } + } + .disposed(by: disposeBag) + } + + public override func configureViewController() { + viewWillAppearPublisher.asObservable() + .bind { + self.hideTabbar() + if self.isTabNavigation { + self.viewWillappearWithTap?() + } + } + .disposed(by: disposeBag) + } + + public override func configureNavigation() { + self.setSmallTitle(title: "체험형 현장실습") + navigationItem.rightBarButtonItems = [ + UIBarButtonItem(customView: searchButton), + UIBarButtonItem(customView: filterButton) + ] + } +} diff --git a/Projects/Presentation/Sources/WinterIntern/WinterInternViewModel.swift b/Projects/Presentation/Sources/WinterIntern/WinterInternViewModel.swift new file mode 100644 index 00000000..0685e507 --- /dev/null +++ b/Projects/Presentation/Sources/WinterIntern/WinterInternViewModel.swift @@ -0,0 +1,113 @@ +import UIKit +import RxSwift +import RxCocoa +import RxFlow +import Core +import Domain + +public final class WinterInternVieModel: BaseViewModel, Stepper { + public let steps = PublishRelay() + public var jobCode: String = "" + public var techCode: [String]? + public var recruitmentData = BehaviorRelay<[RecruitmentEntity]>(value: []) + private let disposeBag = DisposeBag() + private let fetchRecruitmentListUseCase: FetchRecruitmentListUseCase + private let bookmarkUseCase: BookmarkUseCase + private var pageCount: Int = 1 + + init( + fetchRecruitmentListUseCase: FetchRecruitmentListUseCase, + bookmarkUseCase: BookmarkUseCase + ) { + self.fetchRecruitmentListUseCase = fetchRecruitmentListUseCase + self.bookmarkUseCase = bookmarkUseCase + } + + public struct Input { + let viewAppear: PublishRelay + let bookMarkButtonDidTap: PublishRelay + var pageChange: Observable + let recruitmentTableViewDidTap: Observable + let searchButtonDidTap: Signal + let filterButtonDidTap: Signal + } + + public struct Output { + var recruitmentData = BehaviorRelay<[RecruitmentEntity]>(value: []) + } + + public func transform(_ input: Input) -> Output { + input.viewAppear.asObservable() + .flatMap { + self.pageCount = 1 + return self.fetchRecruitmentListUseCase.execute( + page: self.pageCount, + jobCode: self.jobCode, + techCode: self.techCode, + winterIntern: true + ) + } + .bind(onNext: { + self.recruitmentData.accept([]) + self.recruitmentData.accept(self.recruitmentData.value + $0) + self.pageCount = 1 + }) + .disposed(by: disposeBag) + + input.pageChange.asObservable() + .flatMap { _ in + self.pageCount += 1 + return self.fetchRecruitmentListUseCase.execute( + page: self.pageCount, + jobCode: self.jobCode, + techCode: self.techCode, + winterIntern: true + ) + .asObservable() + .take(while: { + !$0.isEmpty + }) + } + .bind { self.recruitmentData.accept(self.recruitmentData.value + $0) } + .disposed(by: disposeBag) + + input.bookMarkButtonDidTap.asObservable() + .do(onNext: { id in + var oldData = self.recruitmentData.value + oldData.enumerated().forEach { + if $0.element.recruitID == id { + oldData[$0.offset].bookmarked.toggle() + } + } + self.recruitmentData.accept(oldData) + }) + .flatMap { id in + self.bookmarkUseCase.execute(id: id) + } + .subscribe() + .disposed(by: disposeBag) + + input.recruitmentTableViewDidTap.asObservable() + .map { + RecruitmentStep.recruitmentDetailIsRequired( + recruitmentId: $0 + ) + } + .bind(to: steps) + .disposed(by: disposeBag) + + input.searchButtonDidTap.asObservable() + .map { + RecruitmentStep.searchRecruitmentIsRequired + } + .bind(to: steps) + .disposed(by: disposeBag) + + input.filterButtonDidTap.asObservable() + .map { _ in RecruitmentStep.recruitmentFilterIsRequired } + .bind(to: steps) + .disposed(by: disposeBag) + + return Output(recruitmentData: recruitmentData) + } +} From 848f52a9bc8ed69c91004adeba8c496826650c9c Mon Sep 17 00:00:00 2001 From: Choyoungjun Date: Wed, 25 Sep 2024 14:36:03 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=A7=A9=20::=20Flow=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/Core/Sources/Steps/HomeStep.swift | 1 + Projects/Flow/Sources/Home/HomeFlow.swift | 20 ++++ .../WinterIntern/WinterInternFlow.swift | 104 ++++++++++++++++++ .../Sources/Home/HomeViewController.swift | 6 +- .../Sources/Home/HomeViewModel.swift | 6 + 5 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 Projects/Flow/Sources/WinterIntern/WinterInternFlow.swift diff --git a/Projects/Core/Sources/Steps/HomeStep.swift b/Projects/Core/Sources/Steps/HomeStep.swift index 74012c0c..00012790 100644 --- a/Projects/Core/Sources/Steps/HomeStep.swift +++ b/Projects/Core/Sources/Steps/HomeStep.swift @@ -4,6 +4,7 @@ public enum HomeStep: Step { case homeIsRequired case alarmIsRequired case companyIsRequired + case winterInternIsRequired case easterEggIsRequired case rejectReasonIsRequired( recruitmentID: Int, diff --git a/Projects/Flow/Sources/Home/HomeFlow.swift b/Projects/Flow/Sources/Home/HomeFlow.swift index 9be291d6..c73a3680 100644 --- a/Projects/Flow/Sources/Home/HomeFlow.swift +++ b/Projects/Flow/Sources/Home/HomeFlow.swift @@ -28,6 +28,9 @@ public final class HomeFlow: Flow { case .companyIsRequired: return navigateToCompany() + case .winterInternIsRequired: + return navigateToWinterIntern() + case .easterEggIsRequired: return navigateToEasterEgg() @@ -108,6 +111,23 @@ private extension HomeFlow { )) } + func navigateToWinterIntern() -> FlowContributors { + let winterInternFlow = WinterInternFlow(container: container) + Flows.use(winterInternFlow, when: .created) { root in + self.rootViewController.pushViewController( + root, + animated: true + ) + } + + return .one(flowContributor: .contribute( + withNextPresentable: winterInternFlow, + withNextStepper: OneStepper( + withSingleStep: RecruitmentStep.recruitmentIsRequired + ) + )) + } + func navigateToRejectReason( _ recruitmentID: Int, _ applicationID: Int, diff --git a/Projects/Flow/Sources/WinterIntern/WinterInternFlow.swift b/Projects/Flow/Sources/WinterIntern/WinterInternFlow.swift new file mode 100644 index 00000000..017f32d2 --- /dev/null +++ b/Projects/Flow/Sources/WinterIntern/WinterInternFlow.swift @@ -0,0 +1,104 @@ +import UIKit +import Presentation +import Swinject +import RxFlow +import Core + +public final class WinterInternFlow: Flow { + public let container: Container + private let rootViewController: WinterInternViewController + public var root: Presentable { + return rootViewController + } + + public init(container: Container) { + self.container = container + self.rootViewController = container.resolve(WinterInternViewController.self)! + } + + public func navigate(to step: Step) -> FlowContributors { + guard let step = step as? RecruitmentStep else { return .none } + + switch step { + case .recruitmentIsRequired: + return navigateToRecruitment() + + case let .recruitmentDetailIsRequired(id): + return navigateToRecruitmentDetail(recruitmentID: id) + + case .recruitmentFilterIsRequired: + return navigateToRecruitmentFilter() + + case .searchRecruitmentIsRequired: + return navigateToSearchRecruitment() + } + } +} + +private extension WinterInternFlow { + func navigateToRecruitment() -> FlowContributors { + return .one(flowContributor: .contribute( + withNextPresentable: rootViewController, + withNextStepper: rootViewController.viewModel + )) + } + + func navigateToRecruitmentDetail(recruitmentID: Int) -> FlowContributors { + let recruitmentDetailFlow = RecruitmentDetailFlow(container: container) + + Flows.use(recruitmentDetailFlow, when: .created) { (root) in + let view = root as? RecruitmentDetailViewController + view?.viewModel.recruitmentID = recruitmentID + view?.isPopViewController = { id, bookmark in + let popView = self.rootViewController + var oldData = popView.viewModel.recruitmentData.value + oldData.enumerated().forEach { + if $0.element.recruitID == id { + oldData[$0.offset].bookmarked = bookmark + } + } + popView.viewModel.recruitmentData.accept(oldData) + popView.isTabNavigation = false + } + self.rootViewController.navigationController?.pushViewController( + view!, animated: true + ) + } + + return .one(flowContributor: .contribute( + withNextPresentable: recruitmentDetailFlow, + withNextStepper: OneStepper(withSingleStep: RecruitmentDetailStep.recruitmentDetailIsRequired) + )) + } + + func navigateToSearchRecruitment() -> FlowContributors { + let searchRecruitmentFlow = SearchRecruitmentFlow(container: container) + + Flows.use(searchRecruitmentFlow, when: .created) { (root) in + let view = root as? SearchRecruitmentViewController + self.rootViewController.navigationController?.pushViewController( + view!, animated: true + ) + } + + return .one(flowContributor: .contribute( + withNextPresentable: searchRecruitmentFlow, + withNextStepper: OneStepper(withSingleStep: SearchRecruitmentStep.searchRecruitmentIsRequired) + )) + } + + func navigateToRecruitmentFilter() -> FlowContributors { + let recruitmentFilterFlow = RecruitmentFilterFlow(container: container) + + Flows.use(recruitmentFilterFlow, when: .created) { (root) in + self.rootViewController.navigationController?.pushViewController( + root, animated: true + ) + } + + return .one(flowContributor: .contribute( + withNextPresentable: recruitmentFilterFlow, + withNextStepper: OneStepper(withSingleStep: RecruitmentFilterStep.recruitmentFilterIsRequired) + )) + } +} diff --git a/Projects/Presentation/Sources/Home/HomeViewController.swift b/Projects/Presentation/Sources/Home/HomeViewController.swift index 19d7adc8..0c7ae8d0 100644 --- a/Projects/Presentation/Sources/Home/HomeViewController.swift +++ b/Projects/Presentation/Sources/Home/HomeViewController.swift @@ -112,6 +112,7 @@ public final class HomeViewController: BaseViewController { navigateToAlarmButtonDidTap: navigateToAlarmButton.rx.tap.asSignal(), navigateToEasterEggDidTap: navigateToEasterEggDidTap, navigateToCompanyButtonDidTap: findCompanysCard.rx.tap.asSignal(), + navigateToWinterInternButtonDidTap: findWinterRecruitmentsCard.rx.tap.asSignal(), rejectButtonDidTap: rejectButtonDidTap, reApplyButtonDidTap: reApplyButtonDidTap, applicationStatusTableViewDidTap: applicationStatusTableView.rx @@ -196,11 +197,6 @@ public final class HomeViewController: BaseViewController { .bind { self.showTabbar() }.disposed(by: disposeBag) - - findWinterRecruitmentsCard.rx.tap.subscribe(onNext: { - print("findWinterRecruitment!!") - }) - .disposed(by: disposeBag) } public override func configureNavigation() { diff --git a/Projects/Presentation/Sources/Home/HomeViewModel.swift b/Projects/Presentation/Sources/Home/HomeViewModel.swift index 624358cc..b75d432f 100644 --- a/Projects/Presentation/Sources/Home/HomeViewModel.swift +++ b/Projects/Presentation/Sources/Home/HomeViewModel.swift @@ -30,6 +30,7 @@ public final class HomeViewModel: BaseViewModel, Stepper { let navigateToAlarmButtonDidTap: Signal let navigateToEasterEggDidTap: PublishRelay let navigateToCompanyButtonDidTap: Signal + let navigateToWinterInternButtonDidTap: Signal let rejectButtonDidTap: PublishRelay let reApplyButtonDidTap: PublishRelay let applicationStatusTableViewDidTap: Observable<(Int, ApplicationStatusType)> @@ -88,6 +89,11 @@ public final class HomeViewModel: BaseViewModel, Stepper { .bind(to: steps) .disposed(by: disposeBag) + input.navigateToWinterInternButtonDidTap.asObservable() + .map { _ in HomeStep.winterInternIsRequired } + .bind(to: steps) + .disposed(by: disposeBag) + input.viewAppear.asObservable() .flatMap { [self] in fetchBannerListUseCase.execute() From fc78a6cc0f56669d37cf915805af70a5d31c88c2 Mon Sep 17 00:00:00 2001 From: Choyoungjun Date: Wed, 25 Sep 2024 14:36:44 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=A7=A9=20::=20=EA=B2=A8=EC=9A=B8?= =?UTF-8?q?=EC=9D=B8=ED=84=B4=20=EB=A1=9C=EC=A7=81=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DataSource/API/RecruitmentsAPI.swift | 6 +++--- .../Remote/RemoteRecruitmentsDataSource.swift | 20 ++++++++++++++----- .../RecruitmentsRepositoryImpl.swift | 13 ++++++++++-- .../Repositories/RecruitmentsRepository.swift | 2 +- .../FetchRecruitmentListUseCase.swift | 14 +++++++++++-- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/Projects/Data/Sources/DataSource/API/RecruitmentsAPI.swift b/Projects/Data/Sources/DataSource/API/RecruitmentsAPI.swift index be948cda..2722107f 100644 --- a/Projects/Data/Sources/DataSource/API/RecruitmentsAPI.swift +++ b/Projects/Data/Sources/DataSource/API/RecruitmentsAPI.swift @@ -4,7 +4,7 @@ import AppNetwork enum RecruitmentsAPI { case fetchRecruitmentDetail(id: Int) - case fetchRecruitmentList(page: Int, jobCode: String?, techCode: [String]?, name: String?) + case fetchRecruitmentList(page: Int, jobCode: String?, techCode: [String]?, name: String?, winterIntern: Bool?) } extension RecruitmentsAPI: JobisAPI { @@ -33,13 +33,13 @@ extension RecruitmentsAPI: JobisAPI { var task: Moya.Task { switch self { - case let .fetchRecruitmentList(page, jobCode, techCode, name): + case let .fetchRecruitmentList(page, jobCode, techCode, name, winterIntern): return .requestParameters(parameters: [ "page": page, "job_code": jobCode ?? "", "tech_code": techCode?.joined(separator: ",") ?? "", "name": name ?? "", - "winter_intern": false + "winter_intern": winterIntern ?? false ], encoding: URLEncoding.queryString) default: diff --git a/Projects/Data/Sources/DataSource/Remote/RemoteRecruitmentsDataSource.swift b/Projects/Data/Sources/DataSource/Remote/RemoteRecruitmentsDataSource.swift index 59139a2d..fc9b41f6 100644 --- a/Projects/Data/Sources/DataSource/Remote/RemoteRecruitmentsDataSource.swift +++ b/Projects/Data/Sources/DataSource/Remote/RemoteRecruitmentsDataSource.swift @@ -4,7 +4,7 @@ import Domain protocol RemoteRecruitmentsDataSource { func fetchRecruitmentDetail(id: Int) -> Single func fetchRecruitmentList( - page: Int, jobCode: String?, techCode: [String]?, name: String? + page: Int, jobCode: String?, techCode: [String]?, name: String?, winterIntern: Bool? ) -> Single<[RecruitmentEntity]> } @@ -16,10 +16,20 @@ final class RemoteRecruitmentsDataSourceImpl: RemoteBaseDataSource Single<[RecruitmentEntity]> { - request(.fetchRecruitmentList(page: page, jobCode: jobCode, techCode: techCode, name: name)) - .map(RecruitmentListResponseDTO.self) - .map { $0.toDomain() } + request(.fetchRecruitmentList( + page: page, + jobCode: jobCode, + techCode: techCode, + name: name, + winterIntern: winterIntern + )) + .map(RecruitmentListResponseDTO.self) + .map { $0.toDomain() } } } diff --git a/Projects/Data/Sources/Repositories/RecruitmentsRepositoryImpl.swift b/Projects/Data/Sources/Repositories/RecruitmentsRepositoryImpl.swift index 0f7c5bcc..5ba11701 100644 --- a/Projects/Data/Sources/Repositories/RecruitmentsRepositoryImpl.swift +++ b/Projects/Data/Sources/Repositories/RecruitmentsRepositoryImpl.swift @@ -13,8 +13,17 @@ struct RecruitmentsRepositoryImpl: RecruitmentsRepository { } func fetchRecruitmentList( - page: Int, jobCode: String?, techCode: [String]?, name: String? + page: Int, + jobCode: String?, + techCode: [String]?, + name: String?, winterIntern: Bool? ) -> Single<[RecruitmentEntity]> { - remoteRecruitmentsDataSource.fetchRecruitmentList(page: page, jobCode: jobCode, techCode: techCode, name: name) + remoteRecruitmentsDataSource.fetchRecruitmentList( + page: page, + jobCode: jobCode, + techCode: techCode, + name: name, + winterIntern: winterIntern + ) } } diff --git a/Projects/Domain/Sources/Repositories/RecruitmentsRepository.swift b/Projects/Domain/Sources/Repositories/RecruitmentsRepository.swift index 9ea67e1f..097dba18 100644 --- a/Projects/Domain/Sources/Repositories/RecruitmentsRepository.swift +++ b/Projects/Domain/Sources/Repositories/RecruitmentsRepository.swift @@ -3,6 +3,6 @@ import RxSwift public protocol RecruitmentsRepository { func fetchRecruitmentDetail(id: Int) -> Single func fetchRecruitmentList( - page: Int, jobCode: String?, techCode: [String]?, name: String? + page: Int, jobCode: String?, techCode: [String]?, name: String?, winterIntern: Bool? ) -> Single<[RecruitmentEntity]> } diff --git a/Projects/Domain/Sources/UseCases/Recruitments/FetchRecruitmentListUseCase.swift b/Projects/Domain/Sources/UseCases/Recruitments/FetchRecruitmentListUseCase.swift index f9358d6f..318bf9e4 100644 --- a/Projects/Domain/Sources/UseCases/Recruitments/FetchRecruitmentListUseCase.swift +++ b/Projects/Domain/Sources/UseCases/Recruitments/FetchRecruitmentListUseCase.swift @@ -8,8 +8,18 @@ public struct FetchRecruitmentListUseCase { private let recruitmentsRepository: RecruitmentsRepository public func execute( - page: Int, jobCode: String? = nil, techCode: [String]? = nil, name: String? = nil + page: Int, + jobCode: String? = nil, + techCode: [String]? = nil, + name: String? = nil, + winterIntern: Bool? = nil ) -> Single<[RecruitmentEntity]> { - recruitmentsRepository.fetchRecruitmentList(page: page, jobCode: jobCode, techCode: techCode, name: name) + recruitmentsRepository.fetchRecruitmentList( + page: page, + jobCode: jobCode, + techCode: techCode, + name: name, + winterIntern: winterIntern + ) } } From 02c61a66e3cd9d515f3890aa24fefcfa4cc057dc Mon Sep 17 00:00:00 2001 From: Choyoungjun Date: Wed, 25 Sep 2024 14:37:27 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=A7=A9=20::=20=EA=B2=A8=EC=9A=B8?= =?UTF-8?q?=EC=9D=B8=ED=84=B4=20=EB=B7=B0=20=EC=9D=98=EC=A1=B4=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/DI/PresentationAssembly.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Projects/Presentation/Sources/DI/PresentationAssembly.swift b/Projects/Presentation/Sources/DI/PresentationAssembly.swift index 4a858f1b..d0fa1b0f 100644 --- a/Projects/Presentation/Sources/DI/PresentationAssembly.swift +++ b/Projects/Presentation/Sources/DI/PresentationAssembly.swift @@ -327,6 +327,18 @@ public final class PresentationAssembly: Assembly { MajorBottomSheetViewModel() } + container.register(WinterInternViewController.self) { resolver in + WinterInternViewController( + resolver.resolve(WinterInternVieModel.self)! + ) + } + container.register(WinterInternVieModel.self) { resolver in + WinterInternVieModel( + fetchRecruitmentListUseCase: resolver.resolve(FetchRecruitmentListUseCase.self)!, + bookmarkUseCase: resolver.resolve(BookmarkUseCase.self)! + ) + } + container.register(EasterEggViewController.self) { resolver in EasterEggViewController() }