diff --git a/client/Projects/OpenList/OpenList.xcodeproj/project.pbxproj b/client/Projects/OpenList/OpenList.xcodeproj/project.pbxproj index 66cb8358..5d320b42 100644 --- a/client/Projects/OpenList/OpenList.xcodeproj/project.pbxproj +++ b/client/Projects/OpenList/OpenList.xcodeproj/project.pbxproj @@ -84,6 +84,13 @@ 5F93491E2B16DFF300282545 /* UICollectionView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F93491D2B16DFF300282545 /* UICollectionView+Extensions.swift */; }; 5F9349212B16E03400282545 /* PrivateDetailCheckListAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F93491F2B16E03400282545 /* PrivateDetailCheckListAction.swift */; }; 5F9349222B16E03400282545 /* PrivateDetailCheckListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9349202B16E03400282545 /* PrivateDetailCheckListRouter.swift */; }; + 5F9349242B17014700282545 /* FolderResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9349232B17014700282545 /* FolderResponseDTO.swift */; }; + 5F9349262B17016000282545 /* UserResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9349252B17016000282545 /* UserResponseDTO.swift */; }; + 5F9349282B17028100282545 /* FolderRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9349272B17028100282545 /* FolderRepository.swift */; }; + 5F93492A2B1702A000282545 /* CheckListFolderItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9349292B1702A000282545 /* CheckListFolderItem.swift */; }; + 5F93492C2B1702CF00282545 /* DefaultFolderRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F93492B2B1702CF00282545 /* DefaultFolderRepository.swift */; }; + 5F93492E2B1704D200282545 /* PrivateCheckListUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F93492D2B1704D200282545 /* PrivateCheckListUseCase.swift */; }; + 5F9349322B17129400282545 /* AccessTokenInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9349312B17129400282545 /* AccessTokenInterceptor.swift */; }; 5FA1F88E2AFF7DA400869079 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5FA1F88D2AFF7DA400869079 /* Assets.xcassets */; }; 5FA1F8912AFF7DA400869079 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5FA1F88F2AFF7DA400869079 /* LaunchScreen.storyboard */; }; 5FA1F8A62AFF7E6C00869079 /* AppComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FA1F8A52AFF7E6C00869079 /* AppComponent.swift */; }; @@ -233,6 +240,13 @@ 5F93491D2B16DFF300282545 /* UICollectionView+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UICollectionView+Extensions.swift"; sourceTree = ""; }; 5F93491F2B16E03400282545 /* PrivateDetailCheckListAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateDetailCheckListAction.swift; sourceTree = ""; }; 5F9349202B16E03400282545 /* PrivateDetailCheckListRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateDetailCheckListRouter.swift; sourceTree = ""; }; + 5F9349232B17014700282545 /* FolderResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderResponseDTO.swift; sourceTree = ""; }; + 5F9349252B17016000282545 /* UserResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserResponseDTO.swift; sourceTree = ""; }; + 5F9349272B17028100282545 /* FolderRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderRepository.swift; sourceTree = ""; }; + 5F9349292B1702A000282545 /* CheckListFolderItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckListFolderItem.swift; sourceTree = ""; }; + 5F93492B2B1702CF00282545 /* DefaultFolderRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultFolderRepository.swift; sourceTree = ""; }; + 5F93492D2B1704D200282545 /* PrivateCheckListUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateCheckListUseCase.swift; sourceTree = ""; }; + 5F9349312B17129400282545 /* AccessTokenInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessTokenInterceptor.swift; sourceTree = ""; }; 5FA1F8812AFF7DA200869079 /* OpenList.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OpenList.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5FA1F88D2AFF7DA400869079 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 5FA1F8902AFF7DA400869079 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -382,6 +396,7 @@ 78C2F0482B05C00800E4EC4E /* DefaultCheckListRepository.swift */, 78A4C7282B0F5F9300E07492 /* DefaultAuthRepository.swift */, 4DDC433D2B0F2A3D00859B28 /* DefaultCRDTRepository.swift */, + 5F93492B2B1702CF00282545 /* DefaultFolderRepository.swift */, ); path = Repositories; sourceTree = ""; @@ -458,6 +473,7 @@ 4D696CBA2B0F946100873B3B /* EditText.swift */, 4D8AEBD92B122AA400292AF3 /* CRDTRequestDTO.swift */, 4D8AEBDB2B122AAD00292AF3 /* CRDTResponseDTO.swift */, + 5F9349292B1702A000282545 /* CheckListFolderItem.swift */, ); path = Entites; sourceTree = ""; @@ -537,6 +553,8 @@ children = ( 78A4C7262B0F5E4300E07492 /* LoginResponseDTO.swift */, 5F70C84A2B05FE9100826B5D /* PrivateCheckListResponseDTO.swift */, + 5F9349232B17014700282545 /* FolderResponseDTO.swift */, + 5F9349252B17016000282545 /* UserResponseDTO.swift */, ); path = DTO; sourceTree = ""; @@ -640,6 +658,7 @@ 78F7476C2B126EB7003ED6DA /* KeyChain */, 4DCF10EE2B10EC3900C614B7 /* DataStructure */, 5FA1F8AE2AFF7FAD00869079 /* App */, + 5F9349312B17129400282545 /* AccessTokenInterceptor.swift */, ); path = Utils; sourceTree = ""; @@ -673,6 +692,7 @@ 78C2F0232B049AF100E4EC4E /* CheckListRepository.swift */, 78A4C72A2B0F5FB100E07492 /* AuthRepository.swift */, 4DDC43282B0F10EF00859B28 /* CRDTRepository.swift */, + 5F9349272B17028100282545 /* FolderRepository.swift */, ); path = Repositories; sourceTree = ""; @@ -685,6 +705,7 @@ 78A4C7242B0F5C6900E07492 /* AuthUseCase.swift */, 4DDC43252B0F0FAB00859B28 /* CRDTUseCase.swift */, 4DD97D9B2B14D3A600DF73BC /* DetailCheckListUseCase.swift */, + 5F93492D2B1704D200282545 /* PrivateCheckListUseCase.swift */, ); path = UseCases; sourceTree = ""; @@ -970,6 +991,7 @@ 4DDC433E2B0F2A3D00859B28 /* DefaultCRDTRepository.swift in Sources */, 5FA1F8B62AFF7FBB00869079 /* Dependency.swift in Sources */, 78A4C72B2B0F5FB100E07492 /* AuthRepository.swift in Sources */, + 5F93492C2B1702CF00282545 /* DefaultFolderRepository.swift in Sources */, 78C2F00F2B048B6C00E4EC4E /* TabBarViewController.swift in Sources */, 78C2F0222B049A8A00E4EC4E /* PersistenceUseCase.swift in Sources */, 4D8AEBDA2B122AA400292AF3 /* CRDTRequestDTO.swift in Sources */, @@ -984,10 +1006,12 @@ 5FA1F8B42AFF7FBB00869079 /* ViewControllable.swift in Sources */, 5F93490C2B16DF4D00282545 /* CheckListTopTabView.swift in Sources */, 5F8615E02B02249C00CF2686 /* ViewModelable.swift in Sources */, + 5F9349282B17028100282545 /* FolderRepository.swift in Sources */, 4DDC434B2B0F432900859B28 /* Device.swift in Sources */, 5FA1F8A92AFF7F6700869079 /* AppDelegate.swift in Sources */, 4D967CF12B05AF940032E0D7 /* CoreDataStorage.swift in Sources */, 78A4C7252B0F5C6900E07492 /* AuthUseCase.swift in Sources */, + 5F9349322B17129400282545 /* AccessTokenInterceptor.swift in Sources */, 5F93491E2B16DFF300282545 /* UICollectionView+Extensions.swift in Sources */, 5F9349162B16DF5500282545 /* CheckListFolderRouter.swift in Sources */, 4DD97D9C2B14D3A600DF73BC /* DetailCheckListUseCase.swift in Sources */, @@ -1007,6 +1031,7 @@ 78A4C71D2B0F2ED900E07492 /* LoginViewFactory.swift in Sources */, 5FA1F8E32AFF818E00869079 /* TabBarViewFactory.swift in Sources */, 78A4C71B2B0F2ED900E07492 /* LoginRouter.swift in Sources */, + 5F9349242B17014700282545 /* FolderResponseDTO.swift in Sources */, 4D3398082B023BE800963664 /* CheckListTableAction.swift in Sources */, 5F70C83D2B04C39F00826B5D /* CheckListItemTextField.swift in Sources */, 4D967CD42B050EA60032E0D7 /* UIFont+.swift in Sources */, @@ -1015,6 +1040,7 @@ 5F93491C2B16DFE300282545 /* CALayer+applySketchShadow.swift in Sources */, 78A4C7292B0F5F9300E07492 /* DefaultAuthRepository.swift in Sources */, 4DDC43322B0F16CC00859B28 /* WithDetailCheckListViewFactory.swift in Sources */, + 5F93492A2B1702A000282545 /* CheckListFolderItem.swift in Sources */, 4D967CF42B05AF9F0032E0D7 /* CoreDataStorage.xcdatamodeld in Sources */, 5F93490B2B16DF4D00282545 /* CheckListTabViewFactory.swift in Sources */, 5FA1F8D22AFF802900869079 /* RecommendTabRouter.swift in Sources */, @@ -1024,6 +1050,7 @@ 4DDC43292B0F10EF00859B28 /* CRDTRepository.swift in Sources */, 5FA1F8D12AFF802900869079 /* RecommendTabViewController.swift in Sources */, 5FCCA3C12B104ABF00496EB2 /* OpenListNavigationBar.swift in Sources */, + 5F93492E2B1704D200282545 /* PrivateCheckListUseCase.swift in Sources */, 5F70C8392B04BF7A00826B5D /* LocalCheckListItem.swift in Sources */, 5F9349022B16DF4600282545 /* SharedCheckListViewController.swift in Sources */, 5FA8466B2B10A08B00B90F85 /* UIDevice+safeAreaHeight.swift in Sources */, @@ -1046,6 +1073,7 @@ 5F9349192B16DF5500282545 /* CheckListFolderAction.swift in Sources */, 4DDC43422B0F2AC000859B28 /* CRDTStorage.swift in Sources */, 5F70C8402B04C6F000826B5D /* UITableView+Extensions.swift in Sources */, + 5F9349262B17016000282545 /* UserResponseDTO.swift in Sources */, 4D3398172B024FEE00963664 /* GaugeView.swift in Sources */, 78A4C71E2B0F2ED900E07492 /* LoginViewModel.swift in Sources */, 5FA1F8B32AFF7FBB00869079 /* Component.swift in Sources */, diff --git a/client/Projects/OpenList/OpenList/Data/DTO/FolderResponseDTO.swift b/client/Projects/OpenList/OpenList/Data/DTO/FolderResponseDTO.swift new file mode 100644 index 00000000..633403a8 --- /dev/null +++ b/client/Projects/OpenList/OpenList/Data/DTO/FolderResponseDTO.swift @@ -0,0 +1,24 @@ +// +// FolderResponseDTO.swift +// OpenList +// +// Created by 김영균 on 11/29/23. +// + +import Foundation + +struct FolderResponseDTO: Decodable { + let folderId: Int + let title: String + let user: UserResponseDTO + let createdAt: String + let updatedAt: String + + enum CodingKeys: String, CodingKey { + case folderId + case title + case user = "owner" + case createdAt + case updatedAt + } +} diff --git a/client/Projects/OpenList/OpenList/Data/DTO/UserResponseDTO.swift b/client/Projects/OpenList/OpenList/Data/DTO/UserResponseDTO.swift new file mode 100644 index 00000000..67df68c4 --- /dev/null +++ b/client/Projects/OpenList/OpenList/Data/DTO/UserResponseDTO.swift @@ -0,0 +1,20 @@ +// +// UserResponseDTO.swift +// OpenList +// +// Created by 김영균 on 11/29/23. +// + +import Foundation + +struct UserResponseDTO: Decodable { + let userId: Int + let email: String + let providerId: String + let provider: String + let fullName: String + let nickname: String + let profileImage: String + let createdAt: String + let updatedAt: String +} diff --git a/client/Projects/OpenList/OpenList/Data/Repositories/DefaultFolderRepository.swift b/client/Projects/OpenList/OpenList/Data/Repositories/DefaultFolderRepository.swift new file mode 100644 index 00000000..3cdf2410 --- /dev/null +++ b/client/Projects/OpenList/OpenList/Data/Repositories/DefaultFolderRepository.swift @@ -0,0 +1,36 @@ +// +// DefaultFolderRepository.swift +// OpenList +// +// Created by 김영균 on 11/29/23. +// + +import CustomNetwork +import Foundation + +final class DefaultFolderRepository { + private let session: CustomSession + + init(session: CustomSession = CustomSession(configuration: .default, interceptor: AccessTokenInterceptor())) { + self.session = session + } +} + +extension DefaultFolderRepository: FolderRepository { + enum Constant { + static let baseUrl = "https://openlist.kro.kr/folders" + } + + func fetchAllFolders() async throws -> [CheckListFolderItem] { + var builder = URLRequestBuilder(url: Constant.baseUrl) + builder.addHeader( + field: "Content-Type", + value: "application/json" + ) + let service = NetworkService(customSession: session, urlRequestBuilder: builder) + let data = try await service.getData() + let folderResponseDTO = try JSONDecoder().decode([FolderResponseDTO].self, from: data) + let folders = folderResponseDTO.map { CheckListFolderItem(folderId: $0.folderId, title: $0.title) } + return folders + } +} diff --git a/client/Projects/OpenList/OpenList/Domain/Entites/CheckListFolderItem.swift b/client/Projects/OpenList/OpenList/Domain/Entites/CheckListFolderItem.swift new file mode 100644 index 00000000..d6793773 --- /dev/null +++ b/client/Projects/OpenList/OpenList/Domain/Entites/CheckListFolderItem.swift @@ -0,0 +1,15 @@ +// +// CheckListFolderItem.swift +// OpenList +// +// Created by 김영균 on 11/29/23. +// + +import Foundation + +struct CheckListFolderItem: Hashable { + private var id: Int { folderId } + let folderId: Int + let title: String + var saveCount: Int = 0 +} diff --git a/client/Projects/OpenList/OpenList/Domain/Repositories/FolderRepository.swift b/client/Projects/OpenList/OpenList/Domain/Repositories/FolderRepository.swift new file mode 100644 index 00000000..8673bc9f --- /dev/null +++ b/client/Projects/OpenList/OpenList/Domain/Repositories/FolderRepository.swift @@ -0,0 +1,12 @@ +// +// FolderRepository.swift +// OpenList +// +// Created by 김영균 on 11/29/23. +// + +import Foundation + +protocol FolderRepository { + func fetchAllFolders() async throws -> [CheckListFolderItem] +} diff --git a/client/Projects/OpenList/OpenList/Domain/UseCases/PrivateCheckListUseCase.swift b/client/Projects/OpenList/OpenList/Domain/UseCases/PrivateCheckListUseCase.swift new file mode 100644 index 00000000..d468ab6f --- /dev/null +++ b/client/Projects/OpenList/OpenList/Domain/UseCases/PrivateCheckListUseCase.swift @@ -0,0 +1,31 @@ +// +// PrivateCheckListUseCase.swift +// OpenList +// +// Created by 김영균 on 11/29/23. +// + +import Foundation + +protocol PrivateCheckListUseCase { + func fetchAllFolders() async -> Result<[CheckListFolderItem], Error> +} + +final class DefaultPrivateCheckListUseCase { + private let folderRepository: FolderRepository + + init(folderRepository: FolderRepository) { + self.folderRepository = folderRepository + } +} + +extension DefaultPrivateCheckListUseCase: PrivateCheckListUseCase { + func fetchAllFolders() async -> Result<[CheckListFolderItem], Error> { + do { + let folders = try await folderRepository.fetchAllFolders() + return .success(folders) + } catch { + return .failure(error) + } + } +} diff --git a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderAction.swift b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderAction.swift index d0cb0f8b..d9d5fd63 100644 --- a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderAction.swift +++ b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderAction.swift @@ -7,6 +7,11 @@ import Combine -struct CheckListFolderInput { } +struct CheckListFolderInput { + let viewWillAppear: PassthroughSubject +} -enum CheckListFolderState { } +enum CheckListFolderState { + case folders([CheckListFolderItem]) + case error(Error) +} diff --git a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewController.swift b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewController.swift index e4475c9c..556d09ae 100644 --- a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewController.swift +++ b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewController.swift @@ -16,8 +16,10 @@ final class CheckListFolderViewController: UIViewController, ViewControllable { } // MARK: - Properties private let router: CheckListFolderRoutingLogic - private let viewModel: any ViewModelable + private let viewModel: any CheckListFolderViewModelable private var cancellables: Set = [] + // Event Properties + private var viewWillAppear: PassthroughSubject = .init() // MARK: - UI Components private let folderView: UICollectionView = .init(frame: .zero, collectionViewLayout: .init()) @@ -26,7 +28,7 @@ final class CheckListFolderViewController: UIViewController, ViewControllable { // MARK: - Initializers init( router: CheckListFolderRoutingLogic, - viewModel: some ViewModelable + viewModel: some CheckListFolderViewModelable ) { self.router = router self.viewModel = viewModel @@ -47,6 +49,11 @@ final class CheckListFolderViewController: UIViewController, ViewControllable { setViewHierarchies() setViewConstraints() } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + viewWillAppear.send() + } } // MARK: - Bind Methods @@ -54,11 +61,36 @@ extension CheckListFolderViewController: ViewBindable { typealias State = CheckListFolderState typealias OutputError = Error - func bind() {} + func bind() { + let input = CheckListFolderInput(viewWillAppear: viewWillAppear) + let state = viewModel.transform(input) + state + .receive(on: DispatchQueue.main) + .withUnretained(self) + .sink { (owner, state) in owner.render(state)} + .store(in: &cancellables) + } - func render(_ state: State) { } + func render(_ state: State) { + switch state { + case let .folders(folders): + reloadFolders(folders) + case let .error(error): + handleError(error) + } + } - func handleError(_ error: OutputError) { } + func handleError(_ error: OutputError) { + dump(error.localizedDescription) + } + + func reloadFolders(_ folders: [CheckListFolderItem]) { + guard var snapshot = folderViewDataSource?.snapshot() else { return } + let previousItems = snapshot.itemIdentifiers(inSection: .folder) + snapshot.deleteItems(previousItems) + snapshot.appendItems(folders) + folderViewDataSource?.apply(snapshot) + } } // MARK: - View Methods diff --git a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewFactory.swift b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewFactory.swift index 173a8093..4c82a01d 100644 --- a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewFactory.swift +++ b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewFactory.swift @@ -7,9 +7,15 @@ import Foundation -protocol CheckListFolderDependency: Dependency { } +protocol CheckListFolderDependency: Dependency { + var folderRepository: FolderRepository { get } +} -final class CheckListFolderComponent: Component { } +final class CheckListFolderComponent: Component { + fileprivate var privateCheckListUseCase: PrivateCheckListUseCase { + DefaultPrivateCheckListUseCase(folderRepository: parent.folderRepository) + } +} protocol CheckListFolderFactoryable: Factoryable { func make() -> ViewControllable @@ -21,8 +27,9 @@ final class CheckListFolderViewFactory: Factory, Chec } func make() -> ViewControllable { + let component = CheckListFolderComponent(parent: parent) let router = CheckListFolderRouter() - let viewModel = CheckListFolderViewModel() + let viewModel = CheckListFolderViewModel(privateCheckListUseCase: component.privateCheckListUseCase) let viewController = CheckListFolderViewController(router: router, viewModel: viewModel) router.viewController = viewController return viewController diff --git a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewModel.swift b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewModel.swift index b8072b03..5f2ed10a 100644 --- a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewModel.swift +++ b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/CheckListFolderViewModel.swift @@ -12,12 +12,37 @@ where Input == CheckListFolderInput, State == CheckListFolderState, Output == AnyPublisher { } -final class CheckListFolderViewModel { } +final class CheckListFolderViewModel { + private let privateCheckListUseCase: PrivateCheckListUseCase + + init(privateCheckListUseCase: PrivateCheckListUseCase) { + self.privateCheckListUseCase = privateCheckListUseCase + } +} extension CheckListFolderViewModel: CheckListFolderViewModelable { func transform(_ input: Input) -> Output { - return Publishers.MergeMany().eraseToAnyPublisher() + let viewWillAppear = viewWillAppear(input) + return Publishers.MergeMany(viewWillAppear).eraseToAnyPublisher() } } -private extension CheckListFolderViewModel { } +private extension CheckListFolderViewModel { + func viewWillAppear(_ input: Input) -> Output { + return input.viewWillAppear + .withUnretained(self) + .flatMap { owner, _ -> AnyPublisher, Never> in + return Future(asyncFunc: { await owner.privateCheckListUseCase.fetchAllFolders() }) + .eraseToAnyPublisher() + } + .map { result in + switch result { + case let .success(folders): + return .folders(folders) + case let .failure(error): + return .error(error) + } + } + .eraseToAnyPublisher() + } +} diff --git a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/View/CheckListFolderCell.swift b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/View/CheckListFolderCell.swift index 4f6e7a6f..9ffdef47 100644 --- a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/View/CheckListFolderCell.swift +++ b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListFolderScene/View/CheckListFolderCell.swift @@ -7,12 +7,6 @@ import UIKit -struct CheckListFolderItem: Hashable { - var id = UUID() - var categoryTitle: String - var saveCount: Int -} - final class CheckListFolderCell: UICollectionViewCell { // MARK: Properties private let titleLabel: UILabel = .init() @@ -37,7 +31,7 @@ final class CheckListFolderCell: UICollectionViewCell { // 폴더의 데이터를 넣는 메서드 func configure(with item: CheckListFolderItem) { - titleLabel.text = item.categoryTitle + titleLabel.text = item.title descriptionLabel.text = "\(item.saveCount)개 저장됨" } } diff --git a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListTabViewFactory.swift b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListTabViewFactory.swift index 4504d593..f0d30411 100644 --- a/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListTabViewFactory.swift +++ b/client/Projects/OpenList/OpenList/Scenes/TabbarScene/CheckListTabScene/CheckListTabViewFactory.swift @@ -25,6 +25,8 @@ final class CheckListTabComponent: var deepLinkSubject: PassthroughSubject { parent.deepLinkSubject } + var folderRepository: FolderRepository = DefaultFolderRepository() + fileprivate var checkListFolderFactoryable: CheckListFolderFactoryable { return CheckListFolderViewFactory(parent: self) } diff --git a/client/Projects/OpenList/OpenList/Utils/AccessTokenInterceptor.swift b/client/Projects/OpenList/OpenList/Utils/AccessTokenInterceptor.swift new file mode 100644 index 00000000..6f68c1e2 --- /dev/null +++ b/client/Projects/OpenList/OpenList/Utils/AccessTokenInterceptor.swift @@ -0,0 +1,21 @@ +// +// AccessTokenInterceptor.swift +// OpenList +// +// Created by 김영균 on 11/29/23. +// + +import CustomNetwork +import Foundation + +final class AccessTokenInterceptor: RequestInterceptor { + public func intercept(_ request: URLRequest) -> URLRequest { + var request = request + if let accessToken = KeyChain.shared.read(key: AuthKey.accessToken) { + request.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") + return request + } else { + return request + } + } +}