diff --git a/KkuMulKum.xcodeproj/project.pbxproj b/KkuMulKum.xcodeproj/project.pbxproj index bf720b61..5cd29853 100644 --- a/KkuMulKum.xcodeproj/project.pbxproj +++ b/KkuMulKum.xcodeproj/project.pbxproj @@ -111,6 +111,8 @@ DD3F9DD22C485753008E1FF7 /* UtilService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3F9DD12C485753008E1FF7 /* UtilService.swift */; }; DD3F9DD42C4858A3008E1FF7 /* UtilTargetType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3F9DD32C4858A3008E1FF7 /* UtilTargetType.swift */; }; DD3F9DD62C4988E2008E1FF7 /* RegisterMeetingsResponseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3F9DD52C4988E2008E1FF7 /* RegisterMeetingsResponseModel.swift */; }; + DD3F9DD82C49C25D008E1FF7 /* PagePromiseServiceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3F9DD72C49C25D008E1FF7 /* PagePromiseServiceType.swift */; }; + DD3F9DDA2C49F34D008E1FF7 /* ReadyStatusServiceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD86265D2C4606A300E4F980 /* ReadyStatusServiceType.swift */; }; DD41BEFA2C41D4160095A068 /* TardyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD41BEF92C41D4160095A068 /* TardyView.swift */; }; DD41BEFC2C41D54D0095A068 /* TardyPenaltyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD41BEFB2C41D54D0095A068 /* TardyPenaltyView.swift */; }; DD41BEFF2C41DAA40095A068 /* TardyEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD41BEFE2C41DAA40095A068 /* TardyEmptyView.swift */; }; @@ -135,7 +137,6 @@ DD8626672C4606A300E4F980 /* SetReadyInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8626592C4606A300E4F980 /* SetReadyInfoView.swift */; }; DD8626682C4606A300E4F980 /* ReadyStatusButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD86265A2C4606A300E4F980 /* ReadyStatusButton.swift */; }; DD8626692C4606A300E4F980 /* ReadyStatusProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD86265B2C4606A300E4F980 /* ReadyStatusProgressView.swift */; }; - DD86266A2C4606A300E4F980 /* MockReadyStatusService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD86265D2C4606A300E4F980 /* MockReadyStatusService.swift */; }; DD86266B2C4606A300E4F980 /* ReadyStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD86265F2C4606A300E4F980 /* ReadyStatusViewController.swift */; }; DD86266C2C4606A300E4F980 /* SetReadyInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8626602C4606A300E4F980 /* SetReadyInfoViewController.swift */; }; DD931B6E2C3DA27F00526452 /* ParticipantCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD931B6D2C3DA27F00526452 /* ParticipantCollectionViewCell.swift */; }; @@ -304,6 +305,7 @@ DD3F9DD12C485753008E1FF7 /* UtilService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtilService.swift; sourceTree = ""; }; DD3F9DD32C4858A3008E1FF7 /* UtilTargetType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtilTargetType.swift; sourceTree = ""; }; DD3F9DD52C4988E2008E1FF7 /* RegisterMeetingsResponseModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterMeetingsResponseModel.swift; sourceTree = ""; }; + DD3F9DD72C49C25D008E1FF7 /* PagePromiseServiceType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagePromiseServiceType.swift; sourceTree = ""; }; DD41BEF92C41D4160095A068 /* TardyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TardyView.swift; sourceTree = ""; }; DD41BEFB2C41D54D0095A068 /* TardyPenaltyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TardyPenaltyView.swift; sourceTree = ""; }; DD41BEFE2C41DAA40095A068 /* TardyEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TardyEmptyView.swift; sourceTree = ""; }; @@ -328,7 +330,7 @@ DD8626592C4606A300E4F980 /* SetReadyInfoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetReadyInfoView.swift; sourceTree = ""; }; DD86265A2C4606A300E4F980 /* ReadyStatusButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadyStatusButton.swift; sourceTree = ""; }; DD86265B2C4606A300E4F980 /* ReadyStatusProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadyStatusProgressView.swift; sourceTree = ""; }; - DD86265D2C4606A300E4F980 /* MockReadyStatusService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockReadyStatusService.swift; sourceTree = ""; }; + DD86265D2C4606A300E4F980 /* ReadyStatusServiceType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadyStatusServiceType.swift; sourceTree = ""; }; DD86265F2C4606A300E4F980 /* ReadyStatusViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadyStatusViewController.swift; sourceTree = ""; }; DD8626602C4606A300E4F980 /* SetReadyInfoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetReadyInfoViewController.swift; sourceTree = ""; }; DD931B6D2C3DA27F00526452 /* ParticipantCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipantCollectionViewCell.swift; sourceTree = ""; }; @@ -764,6 +766,7 @@ DD39768D2C41CA0700E2A4C4 /* PagePromise */ = { isa = PBXGroup; children = ( + DD3F9DD92C49CF05008E1FF7 /* Service */, DD39768E2C41CABE00E2A4C4 /* ViewController */, DD39768F2C41CAC700E2A4C4 /* ViewModel */, DD3976902C41CACF00E2A4C4 /* View */, @@ -855,6 +858,14 @@ path = ServiceType; sourceTree = ""; }; + DD3F9DD92C49CF05008E1FF7 /* Service */ = { + isa = PBXGroup; + children = ( + DD3F9DD72C49C25D008E1FF7 /* PagePromiseServiceType.swift */, + ); + path = Service; + sourceTree = ""; + }; DD41BEFD2C41D85F0095A068 /* View */ = { isa = PBXGroup; children = ( @@ -1036,7 +1047,7 @@ DD86265C2C4606A300E4F980 /* Service */ = { isa = PBXGroup; children = ( - DD86265D2C4606A300E4F980 /* MockReadyStatusService.swift */, + DD86265D2C4606A300E4F980 /* ReadyStatusServiceType.swift */, A39F2B202C499CE5008DA5F5 /* SetReadyStatusInfoServiceType.swift */, ); path = Service; @@ -1696,6 +1707,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DD3F9DDA2C49F34D008E1FF7 /* ReadyStatusServiceType.swift in Sources */, DDE7D2CC2C47F073005A921F /* PlaceModel.swift in Sources */, DEFBEBD12C46B33000437188 /* SelectCapsuleButton.swift in Sources */, DED5DBF22C34534A006ECE7E /* BaseCollectionReusableView.swift in Sources */, @@ -1766,6 +1778,7 @@ DD3F9DD02C48571A008E1FF7 /* MeetingListServiceType.swift in Sources */, A39F2B212C499CE5008DA5F5 /* SetReadyStatusInfoServiceType.swift in Sources */, DE6D4D132C3F14D80005584B /* MeetingMemberCell.swift in Sources */, + DD3F9DD82C49C25D008E1FF7 /* PagePromiseServiceType.swift in Sources */, DDAF1C932C3D6E3D008A37D3 /* PagePromiseViewController.swift in Sources */, 789D73BE2C47FE0F00C7077D /* AuthInterceptor.swift in Sources */, 789D73B32C47CC6D00C7077D /* LocalNotificationManager.swift in Sources */, @@ -1800,7 +1813,6 @@ DECB845E2C4442AF0022A003 /* FindPlaceView.swift in Sources */, DE6D4D0F2C3F14D80005584B /* MeetingInfoService.swift in Sources */, DD3F9DD62C4988E2008E1FF7 /* RegisterMeetingsResponseModel.swift in Sources */, - DDE7D2C32C470A58005A921F /* ProfileTargetType.swift in Sources */, DD3F9DCC2C485614008E1FF7 /* HomeServiceType.swift in Sources */, DD39768A2C41C2AD00E2A4C4 /* HomeViewController.swift in Sources */, DED5DBF42C34539A006ECE7E /* BaseTableViewCell.swift in Sources */, @@ -1851,9 +1863,7 @@ DE0137D32C43C5E50088C777 /* MyPageView.swift in Sources */, DE558C592C45954B008DAC4A /* SelectMemberViewController.swift in Sources */, DD4909962C440CDC003ED304 /* ArriveView.swift in Sources */, - DD86266A2C4606A300E4F980 /* MockReadyStatusService.swift in Sources */, 789196342C486F6B00FF8CDF /* KeychainAccessible.swift in Sources */, - DD86266A2C4606A300E4F980 /* MockReadyStatusService.swift in Sources */, DE254AB02C31195B00A4015E /* NSAttributedString+.swift in Sources */, DD43937B2C412F4500EC1799 /* CreateMeetingViewController.swift in Sources */, DD86266C2C4606A300E4F980 /* SetReadyInfoViewController.swift in Sources */, diff --git a/KkuMulKum/Application/SceneDelegate.swift b/KkuMulKum/Application/SceneDelegate.swift index 2af0dffc..bd9b87d7 100644 --- a/KkuMulKum/Application/SceneDelegate.swift +++ b/KkuMulKum/Application/SceneDelegate.swift @@ -36,7 +36,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { DispatchQueue.main.async { if success { print("Auto login successful, showing main screen") - self?.showLoginScreen() + self?.showMainScreen() } else { print("Auto login failed, showing login screen") self?.showLoginScreen() diff --git a/KkuMulKum/Network/DTO/Model/Promises/MyReadyStatusResponseModel.swift b/KkuMulKum/Network/DTO/Model/Promises/MyReadyStatusResponseModel.swift index da4a069e..bdeb6393 100644 --- a/KkuMulKum/Network/DTO/Model/Promises/MyReadyStatusResponseModel.swift +++ b/KkuMulKum/Network/DTO/Model/Promises/MyReadyStatusResponseModel.swift @@ -12,9 +12,9 @@ import Foundation struct MyReadyStatusModel: ResponseModelType { let promiseTime: String - let preparationTime: Int - let travelTime: Int - let preparationStartAt: String - let departureAt: String - let arrivalAt: String + let preparationTime: Int? + let travelTime: Int? + let preparationStartAt: String? + let departureAt: String? + let arrivalAt: String? } diff --git a/KkuMulKum/Network/DTO/Model/Promises/PromiseInfoResponseModel.swift b/KkuMulKum/Network/DTO/Model/Promises/PromiseInfoResponseModel.swift index 53554514..0f0b285d 100644 --- a/KkuMulKum/Network/DTO/Model/Promises/PromiseInfoResponseModel.swift +++ b/KkuMulKum/Network/DTO/Model/Promises/PromiseInfoResponseModel.swift @@ -12,10 +12,11 @@ import Foundation struct PromiseInfoModel: ResponseModelType { let promiseID: Int - let placeName, address, roadAddress, time, dressUpLevel, penalty: String + let promiseName, placeName, address, roadAddress, time, dressUpLevel, penalty: String enum CodingKeys: String, CodingKey { case promiseID = "promiseId" + case promiseName case placeName case address case roadAddress diff --git a/KkuMulKum/Source/AddPromise/ViewController/AddPromiseCompleteViewController.swift b/KkuMulKum/Source/AddPromise/ViewController/AddPromiseCompleteViewController.swift index 51edbcae..293662ff 100644 --- a/KkuMulKum/Source/AddPromise/ViewController/AddPromiseCompleteViewController.swift +++ b/KkuMulKum/Source/AddPromise/ViewController/AddPromiseCompleteViewController.swift @@ -69,7 +69,8 @@ final class AddPromiseCompleteViewController: BaseViewController { rootViewController.navigationController?.pushViewController( PagePromiseViewController( promiseViewModel: PagePromiseViewModel( - promiseID: self.promiseID + promiseID: self.promiseID, + service: PromiseService() ) ), animated: true diff --git a/KkuMulKum/Source/Home/ViewController/HomeViewController.swift b/KkuMulKum/Source/Home/ViewController/HomeViewController.swift index 97231eb7..7e707733 100644 --- a/KkuMulKum/Source/Home/ViewController/HomeViewController.swift +++ b/KkuMulKum/Source/Home/ViewController/HomeViewController.swift @@ -128,7 +128,8 @@ extension HomeViewController: UICollectionViewDelegateFlowLayout { ) { let pagePromiseViewController = PagePromiseViewController( promiseViewModel: PagePromiseViewModel( - promiseID: viewModel.upcomingPromiseList.value?.data?.promises[indexPath.item].promiseID ?? 0 + promiseID: viewModel.upcomingPromiseList.value?.data?.promises[indexPath.item].promiseID ?? 0, + service: PromiseService() ) ) @@ -390,7 +391,8 @@ private extension HomeViewController { func todayButtonDidTap(_ sender: UIButton) { let viewController = PagePromiseViewController( promiseViewModel: PagePromiseViewModel( - promiseID: viewModel.nearestPromise.value?.data?.promiseID ?? 0 + promiseID: viewModel.nearestPromise.value?.data?.promiseID ?? 0, + service: PromiseService() ) ) diff --git a/KkuMulKum/Source/MeetingInfo/ViewController/MeetingInfoViewController.swift b/KkuMulKum/Source/MeetingInfo/ViewController/MeetingInfoViewController.swift index 492d1ac9..2f16a191 100644 --- a/KkuMulKum/Source/MeetingInfo/ViewController/MeetingInfoViewController.swift +++ b/KkuMulKum/Source/MeetingInfo/ViewController/MeetingInfoViewController.swift @@ -75,7 +75,8 @@ extension MeetingInfoViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let pagePromiseViewController = PagePromiseViewController( promiseViewModel: PagePromiseViewModel( - promiseID: viewModel.meetingPromises[indexPath.item].promiseID + promiseID: viewModel.meetingPromises[indexPath.item].promiseID, + service: PromiseService() ) ) diff --git a/KkuMulKum/Source/Promise/PagePromise/Service/PagePromiseServiceType.swift b/KkuMulKum/Source/Promise/PagePromise/Service/PagePromiseServiceType.swift new file mode 100644 index 00000000..1b9ab2ee --- /dev/null +++ b/KkuMulKum/Source/Promise/PagePromise/Service/PagePromiseServiceType.swift @@ -0,0 +1,22 @@ +// +// PagePromiseServiceType.swift +// KkuMulKum +// +// Created by YOUJIM on 7/19/24. +// + +import Foundation + +protocol PagePromiseServiceType { + func fetchPromiseInfo(with promiseId: Int) async throws -> ResponseBodyDTO? +} + +extension PromiseService: PagePromiseServiceType { + func fetchPromiseInfo(with promiseId: Int) async throws -> ResponseBodyDTO? { + return try await request( + with: .fetchPromiseInfo( + promiseID: promiseId + ) + ) + } +} diff --git a/KkuMulKum/Source/Promise/PagePromise/ViewController/PagePromiseViewController.swift b/KkuMulKum/Source/Promise/PagePromise/ViewController/PagePromiseViewController.swift index f7e1f647..28647264 100644 --- a/KkuMulKum/Source/Promise/PagePromise/ViewController/PagePromiseViewController.swift +++ b/KkuMulKum/Source/Promise/PagePromise/ViewController/PagePromiseViewController.swift @@ -14,11 +14,16 @@ class PagePromiseViewController: BaseViewController { private let promiseViewModel: PagePromiseViewModel - // TODO: 서버 연결 시 데이터 바인딩 필요 private var promiseViewControllerList: [BaseViewController] = [] private let promiseInfoViewController: PromiseInfoViewController + + private let promiseInfoViewModel: PromiseInfoViewModel + private let readyStatusViewController: ReadyStatusViewController + + private let readyStatusViewModel: ReadyStatusViewModel + private let tardyViewController: TardyViewController private lazy var promiseSegmentedControl = PagePromiseSegmentedControl( @@ -30,53 +35,36 @@ class PagePromiseViewController: BaseViewController { navigationOrientation: .vertical ) - override func viewDidLoad() { - super.viewDidLoad() - - setupNavigationBarBackButton() - } - - // MARK: - LifeCycle - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - navigationController?.isNavigationBarHidden = false - - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - navigationController?.isNavigationBarHidden = true - } - - // MARK: Initialize + // MARK: Initializer init(promiseViewModel: PagePromiseViewModel) { self.promiseViewModel = promiseViewModel - // TODO: 네트워크 통신 필요 + promiseViewModel.fetchPromiseInfo(promiseID: promiseViewModel.promiseID) + + promiseInfoViewModel = PromiseInfoViewModel( + promiseID: promiseViewModel.promiseID, + promiseInfoService: PromiseService() + ) promiseInfoViewController = PromiseInfoViewController( - promiseInfoViewModel: PromiseInfoViewModel( - promiseInfoService: MockPromiseInfoService(), - promiseID: promiseViewModel.promiseID.value - ) + promiseInfoViewModel: promiseInfoViewModel + ) + + readyStatusViewModel = ReadyStatusViewModel( + readyStatusService: PromiseService(), + promiseID: promiseViewModel.promiseID ) readyStatusViewController = ReadyStatusViewController( - readyStatusViewModel: ReadyStatusViewModel( - readyStatusService: MockReadyStatusService(), - promiseID: promiseViewModel.promiseID.value - ) + readyStatusViewModel: readyStatusViewModel ) tardyViewController = TardyViewController( tardyViewModel: TardyViewModel( tardyService: MockTardyService(), - promiseID: promiseViewModel.promiseID.value + promiseID: promiseViewModel.promiseID ) ) @@ -94,6 +82,30 @@ class PagePromiseViewController: BaseViewController { } + // MARK: - LifeCycle + + override func viewDidLoad() { + super.viewDidLoad() + + setupNavigationBarBackButton() + setupBindings() + } + + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + navigationController?.isNavigationBarHidden = false + + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + navigationController?.isNavigationBarHidden = true + } + + // MARK: - Setup override func setupView() { @@ -148,7 +160,6 @@ class PagePromiseViewController: BaseViewController { } override func setupDelegate() { - promisePageViewController.delegate = self promisePageViewController.dataSource = self } } @@ -186,14 +197,6 @@ extension PagePromiseViewController { } - -// MARK: - UIPageViewControllerDelegate - -extension PagePromiseViewController: UIPageViewControllerDelegate { - -} - - // MARK: - UIPageViewControllerDataSource extension PagePromiseViewController: UIPageViewControllerDataSource { @@ -211,3 +214,16 @@ extension PagePromiseViewController: UIPageViewControllerDataSource { return nil } } + +private extension PagePromiseViewController { + func setupBindings() { + promiseViewModel.promiseInfo.bind { [weak self] model in + guard let model else { return } + DispatchQueue.main.async { + self?.setupNavigationBarTitle(with: model.promiseName) + self?.promiseInfoViewModel.promiseInfo.value = model + self?.readyStatusViewModel.promiseName.value = model.promiseName + } + } + } +} diff --git a/KkuMulKum/Source/Promise/PagePromise/ViewModel/PagePromiseViewModel.swift b/KkuMulKum/Source/Promise/PagePromise/ViewModel/PagePromiseViewModel.swift index 219f9b08..f4d31cb0 100644 --- a/KkuMulKum/Source/Promise/PagePromise/ViewModel/PagePromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/PagePromise/ViewModel/PagePromiseViewModel.swift @@ -12,16 +12,20 @@ class PagePromiseViewModel { // MARK: Property + + private let service: PagePromiseServiceType - var currentPage = ObservablePattern(0) - var promiseID: ObservablePattern + let promiseID: Int + let currentPage = ObservablePattern(0) + let promiseInfo = ObservablePattern(nil) let promiseName: String = "Test" // MARK: Initialize - init(promiseID: Int) { - self.promiseID = ObservablePattern(promiseID) + init(promiseID: Int, service: PagePromiseServiceType) { + self.service = service + self.promiseID = promiseID } } @@ -33,7 +37,19 @@ extension PagePromiseViewModel { currentPage.value = index } - func promiseIDDidChanged(id: Int) { - promiseID.value = id + func fetchPromiseInfo(promiseID: Int) { + Task { + do { + let result = try await service.fetchPromiseInfo(with: promiseID) + + guard let success = result?.success, + success == true + else { + return + } + + promiseInfo.value = result?.data + } + } } } diff --git a/KkuMulKum/Source/Promise/PromiseInfo/Cell/ParticipantCollectionViewCell.swift b/KkuMulKum/Source/Promise/PromiseInfo/Cell/ParticipantCollectionViewCell.swift index 95b4c364..028d03b0 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/Cell/ParticipantCollectionViewCell.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/Cell/ParticipantCollectionViewCell.swift @@ -12,7 +12,7 @@ import SnapKit class ParticipantCollectionViewCell: BaseCollectionViewCell { - // MARK: Property + // MARK: - Property let profileImageView: UIImageView = UIImageView().then { $0.backgroundColor = .gray1 diff --git a/KkuMulKum/Source/Promise/PromiseInfo/Service/PromiseInfoService.swift b/KkuMulKum/Source/Promise/PromiseInfo/Service/PromiseInfoService.swift index 50756154..001bc6cc 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/Service/PromiseInfoService.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/Service/PromiseInfoService.swift @@ -15,6 +15,7 @@ class MockPromiseInfoService: PromiseInfoServiceType { func getPromiseInfo(with promiseId: Int) -> ResponseBodyDTO? { let mockData = PromiseInfoModel( promiseID: 1, + promiseName: "dd", placeName: "홍대입구", address: "대현동 90-35", roadAddress: "서울 서대문구 이화여대1길 28", diff --git a/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift b/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift index 64fb7149..fbc90420 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift @@ -12,7 +12,7 @@ class PromiseInfoView: BaseView { // MARK: Property - private let participantNumberLabel: UILabel = UILabel().then { + let participantNumberLabel: UILabel = UILabel().then { $0.setText("약속 참여 인원 n명", style: .body01) $0.setHighlightText("n명", style: .body01, color: .maincolor) } @@ -57,7 +57,7 @@ class PromiseInfoView: BaseView { $0.setText("위치", style: .caption01, color: .maincolor) } - private let locationContentLabel: UILabel = UILabel().then { + let locationContentLabel: UILabel = UILabel().then { $0.setText("sss역 s번 출구", style: .body04, color: .gray7) } @@ -69,7 +69,7 @@ class PromiseInfoView: BaseView { $0.setText("약속시간", style: .caption01, color: .maincolor) } - private let timeContentLabel: UILabel = UILabel().then { + let timeContentLabel: UILabel = UILabel().then { $0.setText("mm월 dd일 hh:mm", style: .body04, color: .gray7) } @@ -81,7 +81,7 @@ class PromiseInfoView: BaseView { $0.setText("준비레벨", style: .caption01, color: .maincolor) } - private let readyLevelContentLabel: UILabel = UILabel().then { + let readyLevelContentLabel: UILabel = UILabel().then { $0.setText("LV n. sss", style: .body04, color: .gray7) } @@ -93,7 +93,7 @@ class PromiseInfoView: BaseView { $0.setText("벌칙", style: .caption01, color: .maincolor) } - private let penaltyLevelContentLabel: UILabel = UILabel().then { + let penaltyLevelContentLabel: UILabel = UILabel().then { $0.setText("ssss하기", style: .body04, color: .gray7) } diff --git a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift index 4607d923..f12ccc23 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift @@ -7,6 +7,8 @@ import UIKit +import Kingfisher + class PromiseInfoViewController: BaseViewController { @@ -15,9 +17,6 @@ class PromiseInfoViewController: BaseViewController { private let promiseInfoViewModel: PromiseInfoViewModel private let promiseInfoView: PromiseInfoView = PromiseInfoView() - - // MARK: - Setup - init(promiseInfoViewModel: PromiseInfoViewModel) { self.promiseInfoViewModel = promiseInfoViewModel @@ -28,19 +27,15 @@ class PromiseInfoViewController: BaseViewController { fatalError("init(coder:) has not been implemented") } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - // TODO: 서버 통신하고 데이터 바인딩 + override func loadView() { + view = promiseInfoView } - override func setupView() { - view.addSubview(promiseInfoView) - self.navigationController?.navigationBar.shadowImage = nil + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) - promiseInfoView.snp.makeConstraints { - $0.edges.equalToSuperview() - } + setupBinding() + promiseInfoViewModel.fetchPromiseParticipantList() } override func setupDelegate() { @@ -50,6 +45,57 @@ class PromiseInfoViewController: BaseViewController { } +// MARK: - Extension + +extension PromiseInfoViewController { + func setupBinding() { + promiseInfoViewModel.promiseInfo.bind(with: self) { owner, info in + owner.promiseInfoView.timeContentLabel.setText( + info?.time ?? "설정되지 않음", + style: .body04, + color: .gray7 + ) + + owner.promiseInfoView.readyLevelContentLabel.setText( + info?.dressUpLevel ?? "설정되지 않음", + style: .body04, + color: .gray7 + ) + + owner.promiseInfoView.locationContentLabel.setText( + info?.address ?? "설정되지 않음", + style: .body04, + color: .gray7 + ) + + owner.promiseInfoView.penaltyLevelContentLabel.setText( + info?.penalty ?? "설정되지 않음", + style: .body04, + color: .gray7 + ) + } + + promiseInfoViewModel.participantsInfo.bind(with: self) { + owner, + participantsInfo in + DispatchQueue.main.async { + owner.promiseInfoView.participantNumberLabel.setText( + "약속 참여 인원 \(participantsInfo?.count ?? 0)명", + style: .body01 + ) + owner.promiseInfoView.participantNumberLabel.setHighlightText( + "\(participantsInfo?.count ?? 0)명", + style: .body01, + color: .maincolor + ) + + owner.promiseInfoView.participantCollectionView.reloadData() + } + } + } +} + + // MARK: - UICollectionViewDataSource extension PromiseInfoViewController: UICollectionViewDataSource { @@ -57,8 +103,7 @@ extension PromiseInfoViewController: UICollectionViewDataSource { _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int { - // TODO: 데이터 바인딩 필요 - return 10 + return ((promiseInfoViewModel.participantsInfo.value?.count ?? 0) + 1) } } @@ -75,12 +120,27 @@ extension PromiseInfoViewController: UICollectionViewDelegateFlowLayout { for: indexPath) as? ParticipantCollectionViewCell else { return UICollectionViewCell() } - // TODO: 데이터 바인딩 필요 - if indexPath.row == 0 { cell.profileImageView.image = .imgEmptyCell cell.profileImageView.contentMode = .scaleAspectFill + cell.userNameLabel.isHidden = true + + return cell + } + + guard let info = promiseInfoViewModel.participantsInfo.value?[indexPath.row - 1] else { + return cell + } + + cell.userNameLabel.setText(info.name, style: .caption02, color: .gray6) + + guard let image = URL(string: info.profileImageURL ?? "") else { + cell.profileImageView.image = .imgProfile + + return cell } + + cell.profileImageView.kf.setImage(with: image) return cell } diff --git a/KkuMulKum/Source/Promise/PromiseInfo/ViewModel/PromiseInfoViewModel.swift b/KkuMulKum/Source/Promise/PromiseInfo/ViewModel/PromiseInfoViewModel.swift index 42034201..5808e3d7 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/ViewModel/PromiseInfoViewModel.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/ViewModel/PromiseInfoViewModel.swift @@ -8,11 +8,35 @@ import Foundation class PromiseInfoViewModel { - var promiseID: ObservablePattern - var promiseInfoService: PromiseInfoServiceType - init(promiseInfoService: PromiseInfoServiceType, promiseID: Int) { + let promiseID: Int + + let participantsInfo = ObservablePattern<[Participant]?>(nil) + let promiseInfo = ObservablePattern(nil) + + /// 굳이 서비스 하나 더 만들 필요 없을 것 같아서 같은 API 사용하는 ReadyStatusServiceType 가져옴 + private let promiseInfoService: ReadyStatusServiceType + + init(promiseID: Int, promiseInfoService: ReadyStatusServiceType) { + self.promiseID = promiseID self.promiseInfoService = promiseInfoService - self.promiseID = ObservablePattern(promiseID) + } +} + +extension PromiseInfoViewModel { + func fetchPromiseParticipantList() { + Task { + do { + let responseBody = try await promiseInfoService.fetchPromiseParticipantList(with: promiseID) + + guard let success = responseBody?.success, success == true else { + return + } + + participantsInfo.value = responseBody?.data?.participants + } catch { + print(">>>>> \(error.localizedDescription) : \(#function)") + } + } } } diff --git a/KkuMulKum/Source/Promise/ReadyStatus/Service/MockReadyStatusService.swift b/KkuMulKum/Source/Promise/ReadyStatus/Service/ReadyStatusServiceType.swift similarity index 63% rename from KkuMulKum/Source/Promise/ReadyStatus/Service/MockReadyStatusService.swift rename to KkuMulKum/Source/Promise/ReadyStatus/Service/ReadyStatusServiceType.swift index 79e016da..e7693a38 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/Service/MockReadyStatusService.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/Service/ReadyStatusServiceType.swift @@ -8,17 +8,30 @@ import Foundation protocol ReadyStatusServiceType { - func getMyPromiseStatus(with promiseID: Int) -> ResponseBodyDTO? - func patchMyReadyStatus(with myInfo: MyPromiseReadyInfoModel) - func getParticipantList(with promiseID: Int) -> ResponseBodyDTO? + func fetchMyReadyStatus(with promiseID: Int) async throws -> ResponseBodyDTO? + func fetchPromiseParticipantList(with promiseID: Int) async throws -> ResponseBodyDTO? } -final class MockReadyStatusService: ReadyStatusServiceType { - func patchMyReadyStatus(with myInfo: MyPromiseReadyInfoModel) { - +extension PromiseService: ReadyStatusServiceType { + func fetchMyReadyStatus(with promiseID: Int) async throws -> ResponseBodyDTO? { + return try await request( + with: .fetchMyReadyStatus( + promiseID: promiseID + ) + ) } - func getMyPromiseStatus(with promiseID: Int) -> ResponseBodyDTO? { + func fetchPromiseParticipantList(with promiseID: Int) async throws -> ResponseBodyDTO? { + return try await request( + with: .fetchPromiseParticipantList( + promiseID: promiseID + ) + ) + } +} + +final class MockReadyStatusService: ReadyStatusServiceType { + func fetchMyReadyStatus(with promiseID: Int) -> ResponseBodyDTO? { let mockData = MyReadyStatusModel( promiseTime: "", preparationTime: 300, @@ -35,7 +48,7 @@ final class MockReadyStatusService: ReadyStatusServiceType { ) } - func getParticipantList(with promiseID: Int) -> ResponseBodyDTO? { + func fetchPromiseParticipantList(with promiseID: Int) -> ResponseBodyDTO? { let mockData = PromiseParticipantListModel( participantCount: 3, participants: [ diff --git a/KkuMulKum/Source/Promise/ReadyStatus/View/OurReadyStatusCollectionViewCell.swift b/KkuMulKum/Source/Promise/ReadyStatus/View/OurReadyStatusCollectionViewCell.swift index 73ae6b7f..d0f7ee66 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/View/OurReadyStatusCollectionViewCell.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/View/OurReadyStatusCollectionViewCell.swift @@ -38,20 +38,19 @@ class OurReadyStatusCollectionViewCell: BaseCollectionViewCell { override func setupAutoLayout() { profileImageView.snp.makeConstraints { - $0.top.equalToSuperview().offset(14) - $0.bottom.equalToSuperview().inset(14) + $0.top.bottom.equalToSuperview().inset(14) $0.leading.equalToSuperview().offset(12) $0.height.equalTo(Screen.height(44)) $0.width.equalTo(profileImageView.snp.height) } nameLabel.snp.makeConstraints { - $0.centerY.equalToSuperview() + $0.centerY.equalTo(profileImageView) $0.leading.equalTo(profileImageView.snp.trailing).offset(13) } readyStatusButton.snp.makeConstraints { - $0.centerY.equalToSuperview() + $0.centerY.equalTo(profileImageView) $0.trailing.equalToSuperview().inset(12) $0.height.equalTo(Screen.height(28)) $0.width.equalTo(Screen.width(68)) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyPlanInfoView.swift b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyPlanInfoView.swift index 1eada867..06336de2 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyPlanInfoView.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyPlanInfoView.swift @@ -69,3 +69,7 @@ class ReadyPlanInfoView: BaseView { } } } + +extension ReadyPlanInfoView { + func configure() {} +} diff --git a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusButton.swift b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusButton.swift index 911de64b..f56c9041 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusButton.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusButton.swift @@ -7,7 +7,7 @@ import UIKit -enum ReadyStatus { +enum ReadyProgressStatus { case none case ready case move @@ -15,7 +15,7 @@ enum ReadyStatus { } class ReadyStatusButton: UIButton { - init(title: String, readyStatus: ReadyStatus) { + init(title: String, readyStatus: ReadyProgressStatus) { super.init(frame: .zero) setupButton(title, readyStatus) @@ -23,7 +23,7 @@ class ReadyStatusButton: UIButton { override init(frame: CGRect) { super.init(frame: frame) - } +} required init?(coder: NSCoder) { super.init(coder: coder) @@ -33,7 +33,7 @@ class ReadyStatusButton: UIButton { extension ReadyStatusButton { func setupButton( _ title: String, - _ readyStatus: ReadyStatus + _ readyStatus: ReadyProgressStatus ) { switch readyStatus { case .none: diff --git a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusView.swift b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusView.swift index d777b932..424e143e 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusView.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusView.swift @@ -60,8 +60,10 @@ class ReadyStatusView: BaseView { collectionViewLayout: UICollectionViewFlowLayout().then { $0.scrollDirection = .vertical $0.estimatedItemSize = .init(width: Screen.width(335), height: Screen.height(72)) + $0.minimumInteritemSpacing = 10 }).then { $0.backgroundColor = .clear + $0.isScrollEnabled = false $0.register( OurReadyStatusCollectionViewCell.self, forCellWithReuseIdentifier: OurReadyStatusCollectionViewCell.reuseIdentifier @@ -98,7 +100,8 @@ class ReadyStatusView: BaseView { } contentView.snp.makeConstraints { - $0.edges.width.height.equalToSuperview() + $0.edges.width.equalToSuperview() + $0.height.greaterThanOrEqualToSuperview() } baseStackView.snp.makeConstraints { diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index a29a4b85..78a267df 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -39,12 +39,8 @@ class ReadyStatusViewController: BaseViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - // TODO: 서버 통신해서 - readyStatusViewModel.isReadyInfoEntered.bind { [weak self] flag in - DispatchQueue.main.async { - self?.updateReadyInfoView(flag: flag) - } - } + readyStatusViewModel.fetchMyReadyStatus() + readyStatusViewModel.fetchPromiseParticipantList() } override func setupDelegate() { @@ -52,7 +48,6 @@ class ReadyStatusViewController: BaseViewController { } override func setupAction() { - // TODO: 각 함수에서 서버 통신 할 수 있도록 설정 rootView.myReadyStatusProgressView.readyStartButton.addTarget( self, action: #selector(readyStartButtonDidTapped), @@ -79,31 +74,33 @@ class ReadyStatusViewController: BaseViewController { @objc func readyStartButtonDidTapped() { // TODO: 늦었을 때 꾸물거릴 시간이 없어요 팝업 뜨도록 설정 - readyStatusViewModel.myReadyStatus.value = .ready + readyStatusViewModel.myReadyProgressStatus.value = .ready rootView.myReadyStatusProgressView.readyStartButton.isEnabled.toggle() } @objc func moveStartButtonDidTapped() { - // TODO: 늦었을 때 꾸물거릴 시간이 없어요 팝업 뜨도록 설정 - readyStatusViewModel.myReadyStatus.value = .move + readyStatusViewModel.myReadyProgressStatus.value = .move rootView.myReadyStatusProgressView.moveStartButton.isEnabled.toggle() } @objc func arrivalButtonDidTapped() { - readyStatusViewModel.myReadyStatus.value = .done + readyStatusViewModel.myReadyProgressStatus.value = .done rootView.myReadyStatusProgressView.arrivalButton.isEnabled.toggle() } - /// 눌렀을 때 준비 정보 입력하기 화면으로 넘어가도록 설정 @objc func enterReadyButtonDidTapped() { - // TODO: 유진이가 promiseID, promiseTime 를 전달하면 됩니다. + guard !readyStatusViewModel.promiseName.value.isEmpty else { return } + + guard let readyStatusInfo = readyStatusViewModel.myReadyStatus.value else { return } + let setReadyInfoViewController = SetReadyInfoViewController( viewModel: SetReadyInfoViewModel( - promiseID: 1, - promiseTime: "", + promiseID: readyStatusViewModel.promiseID, + promiseTime: readyStatusInfo.promiseTime, + promiseName: readyStatusViewModel.promiseName.value, service: PromiseService() ) ) @@ -166,26 +163,40 @@ extension ReadyStatusViewController: UICollectionViewDataSource { private extension ReadyStatusViewController { func setupBinding() { - readyStatusViewModel.isReadyInfoEntered.bind(with: self) { owner, status in + readyStatusViewModel.myReadyStatus.bind(with: self) { owner, model in DispatchQueue.main.async { - owner.readyStatusViewModel.isReadyInfoEntered.value = status - owner.updateReadyInfoView(flag: status) + guard let model else { + owner.updateReadyInfoView(flag: false) + return + } + + if model.preparationTime == nil { + owner.updateReadyInfoView(flag: false) + return + } + // TODO: 시간 계산 로직 필요.. + owner.updateReadyInfoView(flag: true) + owner.rootView.readyPlanInfoView.configure() } } - readyStatusViewModel.myReadyStatus.bind(with: self) { owner, status in + readyStatusViewModel.myReadyProgressStatus.bind(with: self) { owner, status in DispatchQueue.main.async { - owner.readyStatusViewModel.myReadyStatus.value = status owner.updateReadyStartButton(status: status) } } readyStatusViewModel.participantInfos.bind(with: self) { owner, participants in DispatchQueue.main.async { - owner.readyStatusViewModel.participantInfos.value = participants owner.rootView.ourReadyStatusCollectionView.reloadData() } } + + readyStatusViewModel.isLate.bind(with: self) { owner, status in + DispatchQueue.main.async { + self.updatePopUpImageView(isLate: !status) + } + } } /// flag에 따라 준비 정보 입력 버튼 표시 유무 변경 @@ -194,13 +205,13 @@ private extension ReadyStatusViewController { rootView.readyPlanInfoView.isHidden = !flag } - // TODO: 버튼 눌렀을 때 연결될 수 있도록 설정 /// 준비 시작이나 이동 시작 시간이 늦었을 때 팝업 표시 여부 변경 func updatePopUpImageView(isLate: Bool) { rootView.popUpImageView.isHidden = !isLate } - func updateReadyStartButton(status: ReadyStatus) { + func updateReadyStartButton(status: ReadyProgressStatus) { + /// 버튼 누를 때 서버 통신하게 설정 switch status { case .none: rootView.myReadyStatusProgressView.readyStartButton.setupButton( diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/ReadyStatusViewModel.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/ReadyStatusViewModel.swift index 0f2acbc8..f0e82c47 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/ReadyStatusViewModel.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/ReadyStatusViewModel.swift @@ -8,20 +8,33 @@ import Foundation class ReadyStatusViewModel { - // 서비스 객체 - var readyStatusService: ReadyStatusServiceType - // 서버 통신을 위한 promiseID - var promiseID: ObservablePattern + let promiseID: Int + + /// 단순히 값을 전달만 하기 위한 코드 + /// 준비 현황 입력하기 버튼을 눌렀을 때 + /// promiseName.value.isEmpty로 분기처리 1차 (실패 시 버튼 입력 안되게) + /// bind를 사용하라는 말이 아님 + let promiseName = ObservablePattern("") // 준비 정보가 입력되었는지 여부 - var isReadyInfoEntered = ObservablePattern(false) +// let isReadyInfoEntered = ObservablePattern(false) - // 현재 준비 상태 - var myReadyStatus = ObservablePattern(.none) + /// 나의 준비현황이 담긴 정보 + /// 설령 데이터가 없다하더라도 약속 시간은 담겨있음. + let myReadyStatus = ObservablePattern(nil) + + // 현재 준비 상태에 대한 버튼 처리 + let myReadyProgressStatus = ObservablePattern(.none) + + // 꾸물거림 여부 + let isLate = ObservablePattern(false) // 우리들의 준비 현황 스택 뷰에 들어갈 정보들 - var participantInfos = ObservablePattern<[Participant]>([]) + let participantInfos = ObservablePattern<[Participant]>([]) + + // 서비스 객체 + private let readyStatusService: ReadyStatusServiceType // 현재 시간 받아오기 위한 dateFormatter 구헌 private let dateFormatter = DateFormatter().then { @@ -33,7 +46,7 @@ class ReadyStatusViewModel { // 초기화 init(readyStatusService: ReadyStatusServiceType, promiseID: Int) { self.readyStatusService = readyStatusService - self.promiseID = ObservablePattern(promiseID) + self.promiseID = promiseID } // 우리들의 준비 현황 변동되었을 때 @@ -48,3 +61,41 @@ class ReadyStatusViewModel { return currentTimeString } } + +extension ReadyStatusViewModel { + func fetchMyReadyStatus() { + Task { + do { + let responseBody = try await readyStatusService.fetchMyReadyStatus(with: promiseID) + + guard let success = responseBody?.success, + success == true + else { + return + } + myReadyStatus.value = responseBody?.data + } catch { + print(">>>>> \(error.localizedDescription) : \(#function)") + } + } + } + + func fetchPromiseParticipantList() { + Task { + do { + let responseBody = try await readyStatusService.fetchPromiseParticipantList( + with: promiseID + ) + + guard let success = responseBody?.success, + success == true, + let participants = responseBody?.data?.participants + else { + participantInfos.value = [] + return + } + participantInfos.value = participants + } + } + } +} diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift index d1fb8bcd..bd4ce9b5 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift @@ -9,6 +9,7 @@ import Foundation final class SetReadyInfoViewModel { let promiseID: Int + let promiseName: String let promiseTime: String let isValid = ObservablePattern(false) @@ -29,9 +30,11 @@ final class SetReadyInfoViewModel { init( promiseID: Int, promiseTime: String, + promiseName: String, service: SetReadyStatusInfoServiceType ) { self.promiseID = promiseID + self.promiseName = promiseName self.promiseTime = promiseTime self.service = service } diff --git a/KkuMulKum/Source/Promise/Tardy/Service/TardyService.swift b/KkuMulKum/Source/Promise/Tardy/Service/TardyService.swift index 4021acdb..302bc85b 100644 --- a/KkuMulKum/Source/Promise/Tardy/Service/TardyService.swift +++ b/KkuMulKum/Source/Promise/Tardy/Service/TardyService.swift @@ -8,10 +8,57 @@ import Foundation protocol TardyServiceType { - func getPromiseTardyInfo(with promiseID: Int) -> ResponseBodyDTO? + func fetchTardyInfo(with promiseID: Int) async throws -> ResponseBodyDTO? + func updatePromiseCompletion(with promiseID: Int) async throws -> ResponseBodyDTO? +} + +extension PromiseService: TardyServiceType { + func fetchTardyInfo(with promiseID: Int) async throws -> ResponseBodyDTO? { + return try await request( + with: .fetchTardyInfo( + promiseID: promiseID + ) + ) + } + + func updatePromiseCompletion(with promiseID: Int) async throws -> ResponseBodyDTO? { + return try await request( + with: .updatePromiseCompletion( + promiseID: promiseID + ) + ) + } } final class MockTardyService: TardyServiceType { + func fetchTardyInfo(with promiseID: Int) -> ResponseBodyDTO? { + let mockData = TardyInfoModel( + penalty: "티라미수 케익 릴스", + isPastDue: true, + lateComers: [Comer( + participantId: 1, + name: "유짐이", + profileImageURL: "" + )] + ) + + return ResponseBodyDTO.init( + success: true, + data: mockData, + error: nil + ) + } + + func updatePromiseCompletion(with promiseID: Int) -> ResponseBodyDTO? { + let mockData = EmptyModel() + + return ResponseBodyDTO.init( + success: true, + data: mockData, + error: nil + ) + } + func getPromiseTardyInfo(with promiseID: Int) -> ResponseBodyDTO? { let mockData = TardyInfoModel( penalty: "티라미수 케익 릴스",