diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index 6f4b7376..d4ed5b33 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -131,6 +131,8 @@ DAD5A3D8296C6D9600C8166B /* AdImageCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD5A3D7296C6D9600C8166B /* AdImageCollectionViewCell.swift */; }; DAD5A3DA296C6DA500C8166B /* TitleCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD5A3D9296C6DA500C8166B /* TitleCollectionViewCell.swift */; }; DAD5A3DC296C6DB800C8166B /* MapCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD5A3DB296C6DB800C8166B /* MapCollectionViewCell.swift */; }; + DAD5A3E2296D4C6500C8166B /* PickedMapListResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD5A3E1296D4C6500C8166B /* PickedMapListResponseDto.swift */; }; + DAD5A3E4296D526D00C8166B /* CourseDiscoveryRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD5A3E3296D526D00C8166B /* CourseDiscoveryRouter.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -152,9 +154,12 @@ CE0C23782966D6AF00B45063 /* ViewPager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPager.swift; sourceTree = ""; }; CE0D9FD229648DA300CEB5CD /* CustomAlertVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAlertVC.swift; sourceTree = ""; }; CE10063929680C5700FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; + CE10063B29680C6800FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CE10063C29680C7000FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CE10063D29680C8100FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CE10063E29680C8800FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; + CE10063F29680C9800FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; + CE10064129680CA700FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CE10064229680CAD00FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CE10064329680CB400FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CE10064429680CBC00FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; @@ -280,6 +285,8 @@ DAD5A3D7296C6D9600C8166B /* AdImageCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdImageCollectionViewCell.swift; sourceTree = ""; }; DAD5A3D9296C6DA500C8166B /* TitleCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleCollectionViewCell.swift; sourceTree = ""; }; DAD5A3DB296C6DB800C8166B /* MapCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapCollectionViewCell.swift; sourceTree = ""; }; + DAD5A3E1296D4C6500C8166B /* PickedMapListResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickedMapListResponseDto.swift; sourceTree = ""; }; + DAD5A3E3296D526D00C8166B /* CourseDiscoveryRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDiscoveryRouter.swift; sourceTree = ""; }; E837271A78E1C0A0C30789BF /* Pods-Runnect-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runnect-iOS.release.xcconfig"; path = "Target Support Files/Pods-Runnect-iOS/Pods-Runnect-iOS.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -406,7 +413,7 @@ CE10063529680C0F00FD31FB /* CourseDiscoveryDto */ = { isa = PBXGroup; children = ( - CE10063C29680C7000FD31FB /* .gitkeep */, + DAD5A3E0296D4C2A00C8166B /* ResponseDto */, ); path = CourseDiscoveryDto; sourceTree = ""; @@ -721,7 +728,7 @@ CE40BB28296808300030ABCA /* CourseDiscoveryRouter */ = { isa = PBXGroup; children = ( - CE10064229680CAD00FD31FB /* .gitkeep */, + DAD5A3E3296D526D00C8166B /* CourseDiscoveryRouter.swift */, ); path = CourseDiscoveryRouter; sourceTree = ""; @@ -1120,6 +1127,14 @@ path = VC; sourceTree = ""; }; + DAD5A3E0296D4C2A00C8166B /* ResponseDto */ = { + isa = PBXGroup; + children = ( + DAD5A3E1296D4C6500C8166B /* PickedMapListResponseDto.swift */, + ); + path = ResponseDto; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -1292,6 +1307,7 @@ CEEC6B3C2961C51A00D00E1E /* CourseStorageVC.swift in Sources */, CE4545C9295D7AF4003201E1 /* AppDelegate.swift in Sources */, CE6655C8295D849F00C64E12 /* StringLiterals.swift in Sources */, + DAD5A3E4296D526D00C8166B /* CourseDiscoveryRouter.swift in Sources */, CEEC6B3E2961C53700D00E1E /* CourseDiscoveryVC.swift in Sources */, CE6655E0295D87D200C64E12 /* UIDevice+.swift in Sources */, CE40BB242968068E0030ABCA /* Config.swift in Sources */, @@ -1312,6 +1328,7 @@ CE40BB1C2967E4910030ABCA /* RunningWaitingVC.swift in Sources */, CE6B63D6296731F9003F900F /* ScrapCourseListView.swift in Sources */, CE6655F8295D90CF00C64E12 /* adjusted+.swift in Sources */, + DAD5A3E2296D4C6500C8166B /* PickedMapListResponseDto.swift in Sources */, CE4545CB295D7AF4003201E1 /* SceneDelegate.swift in Sources */, CE591EA1296D5EB5000FCBB3 /* PrivateCourseResponseDto.swift in Sources */, A3BC2F3F2964706100198261 /* UploadedCourseInfoCVC.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDiscoveryDto/.gitkeep b/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDiscoveryDto/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDiscoveryDto/ResponseDto/PickedMapListResponseDto.swift b/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDiscoveryDto/ResponseDto/PickedMapListResponseDto.swift new file mode 100644 index 00000000..ed5b0f09 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDiscoveryDto/ResponseDto/PickedMapListResponseDto.swift @@ -0,0 +1,31 @@ +// +// CourseDiscoveryResponsDto.swift +// Runnect-iOS +// +// Created by YEONOO on 2023/01/10. +// + +import Foundation + +// MARK: - PickedMapListResponseDto + +struct PickedMapListResponseDto: Codable { + let publicCourses: [PublicCourse] +} + +// MARK: - PublicCourse + +struct PublicCourse: Codable { + let id, courseId: Int + let title: String + let image: String + let scarp: Bool + let departure: CourseDiscoveryDeparture +} + +// MARK: - CourseDiscoveryDeparture + +struct CourseDiscoveryDeparture: Codable { + let region: String + let city: String +} diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/CourseDiscoveryRouter/.gitkeep b/Runnect-iOS/Runnect-iOS/Network/Router/CourseDiscoveryRouter/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/CourseDiscoveryRouter/CourseDiscoveryRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/CourseDiscoveryRouter/CourseDiscoveryRouter.swift new file mode 100644 index 00000000..8d09ed2d --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Network/Router/CourseDiscoveryRouter/CourseDiscoveryRouter.swift @@ -0,0 +1,52 @@ +// +// pickedMapListRouter.swift +// Runnect-iOS +// +// Created by YEONOO on 2023/01/10. +// + +import Foundation + +import Moya + +enum pickedMapListRouter { + case getCourseData +} + +extension pickedMapListRouter: TargetType { + var baseURL: URL { + guard let url = URL(string: Config.baseURL) else { + fatalError("baseURL could not be configured") + } + + return url + } + + var path: String { + switch self { + case .getCourseData: + return "/public-course" + } + } + + var method: Moya.Method { + switch self { + case .getCourseData: + return .get + } + } + + var task: Moya.Task { + switch self { + case .getCourseData: + return .requestPlain + } + } + + var headers: [String: String]? { + switch self { + case .getCourseData: + return Config.headerWithDeviceId + } + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift index 9825c27a..a99b0c08 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift @@ -10,9 +10,17 @@ import UIKit import Then import SnapKit import Combine +import Moya final class CourseDiscoveryVC: UIViewController { - + // MARK: - Properties + + let pickedMapListProvider = MoyaProvider( + plugins: [NetworkLoggerPlugin(verbose: true)] + ) + + private var courseList = [PublicCourse]() + // MARK: - UIComponents private lazy var navibar = CustomNavigationBar(self, type: .title).setTitle("코스 발견") @@ -23,13 +31,13 @@ final class CourseDiscoveryVC: UIViewController { private let plusButton = UIButton(type: .system).then { $0.setImage(ImageLiterals.icPlus, for: .normal) } - + // MARK: - collectionview private lazy var mapCollectionView: UICollectionView = { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .vertical - + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) collectionView.backgroundColor = .clear collectionView.isScrollEnabled = true @@ -51,6 +59,7 @@ final class CourseDiscoveryVC: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.hideTabBar(wantsToHide: false) + self.getCourseData() } } @@ -58,6 +67,11 @@ final class CourseDiscoveryVC: UIViewController { extension CourseDiscoveryVC { + private func setData(courseList: [PublicCourse]) { + self.courseList = courseList + mapCollectionView.reloadData() + } + private func setDelegate() { mapCollectionView.delegate = self mapCollectionView.dataSource = self @@ -76,21 +90,22 @@ extension CourseDiscoveryVC { } } - - // MARK: - @objc Function - extension CourseDiscoveryVC { - @objc private func pushToSearchVC() { - let nextVC = CourseSearchVC() - self.navigationController?.pushViewController(nextVC, animated: true) - } - @objc private func pushToDiscoveryVC() { - let nextVC = MyCourseSelectVC() - self.navigationController?.pushViewController(nextVC, animated: true) - } +// MARK: - @objc Function + +extension CourseDiscoveryVC { + @objc private func pushToSearchVC() { + let nextVC = CourseSearchVC() + self.navigationController?.pushViewController(nextVC, animated: true) + } + @objc private func pushToDiscoveryVC() { + let nextVC = MyCourseSelectVC() + self.navigationController?.pushViewController(nextVC, animated: true) } +} + +// MARK: - UI & Layout - // MARK: - UI & Layout extension CourseDiscoveryVC { private func setNavigationBar() { view.addSubview(navibar) @@ -111,7 +126,7 @@ extension CourseDiscoveryVC { mapCollectionView.backgroundColor = .w1 view.addSubviews(plusButton, mapCollectionView) view.bringSubviewToFront(plusButton) - + mapCollectionView.snp.makeConstraints { $0.top.equalTo(self.navibar.snp.bottom) $0.leading.bottom.trailing.equalTo(view.safeAreaLayoutGuide) @@ -128,7 +143,7 @@ extension CourseDiscoveryVC { extension CourseDiscoveryVC: UICollectionViewDelegate, UICollectionViewDataSource { func numberOfSections(in collectionView: UICollectionView) -> Int { - 3 + return 3 } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { @@ -136,7 +151,7 @@ extension CourseDiscoveryVC: UICollectionViewDelegate, UICollectionViewDataSourc case 0, 1: return 1 case 2: - return 15 + return self.courseList.count default: return 0 } @@ -152,6 +167,9 @@ extension CourseDiscoveryVC: UICollectionViewDelegate, UICollectionViewDataSourc } else { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CourseListCVC.className, for: indexPath) as? CourseListCVC else { return UICollectionViewCell() } cell.setCellType(type: .all) + let model = self.courseList[indexPath.item] + let location = "\(model.departure.region) \(model.departure.city)" + cell.setData(imageURL: model.image, title: model.title, location: location, didLike: model.scarp) return cell } } @@ -208,3 +226,34 @@ extension CourseDiscoveryVC: UICollectionViewDelegateFlowLayout { } } } + +// MARK: - Network + +extension CourseDiscoveryVC { + private func getCourseData() { + LoadingIndicator.showLoading() + pickedMapListProvider.request(.getCourseData) { response in + LoadingIndicator.hideLoading() + switch response { + case .success(let result): + let status = result.statusCode + if 200..<300 ~= status { + do { + let responseDto = try result.map(BaseResponse.self) + guard let data = responseDto.data else { return } + self.setData(courseList: data.publicCourses) + } catch { + print(error.localizedDescription) + } + } + if status >= 400 { + print("400 error") + self.showNetworkFailureToast() + } + case .failure(let error): + print(error.localizedDescription) + self.showNetworkFailureToast() + } + } + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift index 1a29f45d..3e20bc09 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift @@ -58,6 +58,7 @@ extension PrivateCourseListView { func setData(courseList: [PrivateCourse]) { self.courseList = courseList self.courseListCollectionView.reloadData() + self.emptyView.isHidden = !courseList.isEmpty } private func setDelegate() {