From eb284c1545d1bd5b656ba8eb51106cee61f4e1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=8B?= =?UTF-8?q?=E1=85=B5=E1=86=AB?= Date: Fri, 8 Aug 2025 09:18:48 +0900 Subject: [PATCH 1/6] =?UTF-8?q?Fix:=20reissue=20role=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=ED=99=94=EB=A9=B4=20=EB=B6=84=EA=B8=B0=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/App/Sources/SceneDelegate.swift | 7 ++++--- .../Repository/UserDataRepository.swift | 20 ++++++++++--------- .../UserDataRepositoryProtocol.swift | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Projects/App/Sources/SceneDelegate.swift b/Projects/App/Sources/SceneDelegate.swift index da9a3199..3bb02afb 100644 --- a/Projects/App/Sources/SceneDelegate.swift +++ b/Projects/App/Sources/SceneDelegate.swift @@ -58,8 +58,9 @@ extension SceneDelegate: SplashViewDelegate { else { fatalError("onboardingRepository 의존성이 등록되지 않았습니다.") } Task { @MainActor in - let isLogined = await userDataRepository.reissueToken() - if isLogined { + let userState = await userDataRepository.reissueToken() + switch userState { + case .user: if onboardingRepository.isOnboardingDone() { window?.rootViewController = TabBarView() } else { @@ -70,7 +71,7 @@ extension SceneDelegate: SplashViewDelegate { let navigationController = UINavigationController(rootViewController: onboardingView) window?.rootViewController = navigationController } - } else { + case .guest, nil: let introView = IntroView() let navigationController = UINavigationController(rootViewController: introView) window?.rootViewController = navigationController diff --git a/Projects/DataSource/Sources/Repository/UserDataRepository.swift b/Projects/DataSource/Sources/Repository/UserDataRepository.swift index f71315cf..6dab123c 100644 --- a/Projects/DataSource/Sources/Repository/UserDataRepository.swift +++ b/Projects/DataSource/Sources/Repository/UserDataRepository.swift @@ -22,24 +22,26 @@ final class UserDataRepository: UserDataRepositoryProtocol { return user.nickname } - func reissueToken() async -> Bool { + func reissueToken() async -> UserState? { do { let refreshToken = try tokenManager.loadToken(tokenType: .refreshToken) let endpoint = AuthEndpoint.reissue(refreshToken: refreshToken) - guard let tokenResponse = try await networkService.request(endpoint: endpoint, type: TokenResponseDTO.self) - else { return false } + guard let loginResponse = try await networkService.request(endpoint: endpoint, type: LoginResponseDTO.self) + else { return nil } - try tokenManager.saveToken(token: tokenResponse.accessToken, tokenType: .accessToken) - try tokenManager.saveToken(token: tokenResponse.refreshToken, tokenType: .refreshToken) + try tokenManager.saveToken(token: loginResponse.accessToken, tokenType: .accessToken) + try tokenManager.saveToken(token: loginResponse.refreshToken, tokenType: .refreshToken) - BitnagilLogger.log(logType: .debug, message: "AccessToken Saved: \(tokenResponse.accessToken)") - BitnagilLogger.log(logType: .debug, message: "RefreshToken Saved: \(tokenResponse.refreshToken)") + BitnagilLogger.log(logType: .debug, message: "AccessToken Saved: \(loginResponse.accessToken)") + BitnagilLogger.log(logType: .debug, message: "RefreshToken Saved: \(loginResponse.refreshToken)") + BitnagilLogger.log(logType: .debug, message: "User State: \(loginResponse.userState)") - return true + let userState = UserState(rawValue: loginResponse.userState) + return userState } catch { BitnagilLogger.log(logType: .error, message: "\(error.localizedDescription)") - return false + return nil } } } diff --git a/Projects/Domain/Sources/Protocol/Repository/UserDataRepositoryProtocol.swift b/Projects/Domain/Sources/Protocol/Repository/UserDataRepositoryProtocol.swift index 3c5c5390..df73d2b0 100644 --- a/Projects/Domain/Sources/Protocol/Repository/UserDataRepositoryProtocol.swift +++ b/Projects/Domain/Sources/Protocol/Repository/UserDataRepositoryProtocol.swift @@ -12,5 +12,5 @@ public protocol UserDataRepositoryProtocol { func loadNickname() async throws -> String /// 토큰 재발급을 진행합니다. - func reissueToken() async -> Bool + func reissueToken() async -> UserState? } From 4c362668136fd18258d2c15791b1247d3c0c0c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=8B?= =?UTF-8?q?=E1=85=B5=E1=86=AB?= Date: Fri, 8 Aug 2025 15:26:15 +0900 Subject: [PATCH 2/6] =?UTF-8?q?Feat:=20Home=20Toast=20View=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Home/View/HomeView.swift | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Projects/Presentation/Sources/Home/View/HomeView.swift b/Projects/Presentation/Sources/Home/View/HomeView.swift index f79ea3a9..513559ae 100644 --- a/Projects/Presentation/Sources/Home/View/HomeView.swift +++ b/Projects/Presentation/Sources/Home/View/HomeView.swift @@ -54,12 +54,15 @@ final class HomeView: BaseViewController { static let deleteAlertViewWidth: CGFloat = 298 static let deleteAlertViewHeight: CGFloat = 214 static let toastMessageBottomSpacing: CGFloat = 19 + static let toastMessageWidth: CGFloat = 265 + static let toastMessageHeight: CGFloat = 44 } private let gradientLayer = CAGradientLayer() private let homeLabel = UILabel() private let informationButton = UIButton() private let emotionOrbView = UIImageView() + private let registerEmotionButtonActionIdentifier = UIAction.Identifier("goToEmotionRegisterView") private let registerEmotionButton = HomeRegisterEmotionButton() private let contentView = UIView() @@ -133,14 +136,15 @@ final class HomeView: BaseViewController { } }, for: .touchUpInside) - registerEmotionButton.addAction(UIAction { [weak self] _ in + let registerEmotionAction = UIAction(identifier: registerEmotionButtonActionIdentifier) { [weak self] _ in guard let emotionRegisterViewModel = DIContainer.shared.resolve(type: EmotionRegisterViewModel.self) else { fatalError("emotionRegisterViewModel 의존성이 등록되지 않았습니다.") } let emotionRegisterView = EmotionRegisterView(viewModel: emotionRegisterViewModel) emotionRegisterView.hidesBottomBarWhenPushed = true self?.navigationController?.pushViewController(emotionRegisterView, animated: true) - }, for: .touchUpInside) + } + registerEmotionButton.addAction(registerEmotionAction, for: .touchUpInside) contentView.backgroundColor = .white contentView.layer.cornerRadius = Layout.contentViewCornerRadius @@ -344,8 +348,8 @@ final class HomeView: BaseViewController { .sink { [weak self] fetchRoutineResult in if fetchRoutineResult { self?.viewModel.action(input: .refreshSelectedDateRoutine) - self?.hideIndicatorView() } + self?.hideIndicatorView() } .store(in: &cancellables) @@ -353,6 +357,7 @@ final class HomeView: BaseViewController { .receive(on: DispatchQueue.main) .sink { [weak self] routines in self?.updateRoutineView(routines: routines) + self?.hideIndicatorView() } .store(in: &cancellables) @@ -438,13 +443,16 @@ final class HomeView: BaseViewController { return } emotionOrbView.kf.setImage(with: emotionOrbImageUrl) - registerEmotionButton.isEnabled = false - - toastMessageView.showToast( - withCheckImage: true, - message: "선택한 감정 구슬이 이미 반영되었어요.", - width: 265, - height: 44) + registerEmotionButton.removeAction(identifiedBy: registerEmotionButtonActionIdentifier, for: .touchUpInside) + registerEmotionButton.addAction( + UIAction { [weak self] _ in + self?.toastMessageView.showToast( + withCheckImage: true, + message: "선택한 감정 구슬이 이미 반영되었어요.", + width: Layout.toastMessageWidth, + height: Layout.toastMessageHeight) + }, + for: .touchUpInside) } @objc private func handlePanGesture(_ gesture: UIPanGestureRecognizer) { From aa864c785af76c7b7d9ba2f587db2fa2baa3afe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=8B?= =?UTF-8?q?=E1=85=B5=E1=86=AB?= Date: Fri, 8 Aug 2025 15:26:31 +0900 Subject: [PATCH 3/6] =?UTF-8?q?Fix:=20=EA=B0=90=EC=A0=95=20=EA=B5=AC?= =?UTF-8?q?=EC=8A=AC=20=EB=93=B1=EB=A1=9D=20=ED=9B=84=20=EC=B6=94=EC=B2=9C?= =?UTF-8?q?=20=EB=A3=A8=ED=8B=B4=20=EB=93=B1=EB=A1=9D=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/ResultRecommendedRoutineView.swift | 20 +++++++++++++++---- .../ResultRecommendedRoutineViewModel.swift | 8 ++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Projects/Presentation/Sources/ResultRecommendedRoutine/View/ResultRecommendedRoutineView.swift b/Projects/Presentation/Sources/ResultRecommendedRoutine/View/ResultRecommendedRoutineView.swift index 2ca73675..e4df7126 100644 --- a/Projects/Presentation/Sources/ResultRecommendedRoutine/View/ResultRecommendedRoutineView.swift +++ b/Projects/Presentation/Sources/ResultRecommendedRoutine/View/ResultRecommendedRoutineView.swift @@ -261,6 +261,14 @@ final class ResultRecommendedRoutineView: BaseViewController + let selectedRoutineIdPublisher: AnyPublisher let selectedRecommendedRoutinePublisher: AnyPublisher, Never> let confirmButtonPublisher: AnyPublisher let registerRoutineResultPublisher: AnyPublisher @@ -32,6 +34,7 @@ final class ResultRecommendedRoutineViewModel: ViewModel { private(set) var output: Output private let resultRecommendedRoutinesSubject = CurrentValueSubject<[RecommendedRoutine], Never>([]) + private let selectedRoutinIdSubject = PassthroughSubject() private let selectedRecommendedRoutineSubject = CurrentValueSubject, Never>([]) private let confirmButtonSubject = PassthroughSubject() private let registerRoutineResultSubject = PassthroughSubject() @@ -42,6 +45,7 @@ final class ResultRecommendedRoutineViewModel: ViewModel { self.resultRecommendedRoutineUseCase = resultRecommendedRoutineUseCase output = Output( resultRecommendedRoutinesPublisher: resultRecommendedRoutinesSubject.eraseToAnyPublisher(), + selectedRoutineIdPublisher: selectedRoutinIdSubject.eraseToAnyPublisher(), selectedRecommendedRoutinePublisher: selectedRecommendedRoutineSubject.eraseToAnyPublisher(), confirmButtonPublisher: confirmButtonSubject.eraseToAnyPublisher(), registerRoutineResultPublisher: registerRoutineResultSubject.eraseToAnyPublisher() @@ -53,6 +57,10 @@ final class ResultRecommendedRoutineViewModel: ViewModel { case .fetchResultRecommendedRoutines: fetchResultRecommendedRoutines() + case .fetchSelectedRoutinId: + let routineId = selectedRecommendedRoutineSubject.value.first?.id + selectedRoutinIdSubject.send(routineId) + case .selectRecommendedRoutine(let routine): selectRecommendedRoutine(routine: routine) From 3b9bd732a82ce41ca71f8aadba53b84ff4f73d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=8B?= =?UTF-8?q?=E1=85=B5=E1=86=AB?= Date: Fri, 8 Aug 2025 15:27:11 +0900 Subject: [PATCH 4/6] =?UTF-8?q?Chore:=20=EB=B9=8C=EB=93=9C=20=EB=B2=84?= =?UTF-8?q?=EC=A0=84=20=EC=97=85=20(0.0.1=20->=200.0.3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SupportingFiles/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SupportingFiles/Info.plist b/SupportingFiles/Info.plist index bfed2c43..9a0ba43f 100644 --- a/SupportingFiles/Info.plist +++ b/SupportingFiles/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.0.1 + 0.0.3 CFBundleURLTypes From 9d710eb206926db34b1d226de3f9d191d0a467dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=8B?= =?UTF-8?q?=E1=85=B5=E1=86=AB?= Date: Fri, 8 Aug 2025 15:45:14 +0900 Subject: [PATCH 5/6] =?UTF-8?q?Refactor:=20=EC=98=A4=ED=83=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/ResultRecommendedRoutineView.swift | 2 +- .../ViewModel/ResultRecommendedRoutineViewModel.swift | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Projects/Presentation/Sources/ResultRecommendedRoutine/View/ResultRecommendedRoutineView.swift b/Projects/Presentation/Sources/ResultRecommendedRoutine/View/ResultRecommendedRoutineView.swift index e4df7126..a8960c73 100644 --- a/Projects/Presentation/Sources/ResultRecommendedRoutine/View/ResultRecommendedRoutineView.swift +++ b/Projects/Presentation/Sources/ResultRecommendedRoutine/View/ResultRecommendedRoutineView.swift @@ -360,7 +360,7 @@ final class ResultRecommendedRoutineView: BaseViewController([]) - private let selectedRoutinIdSubject = PassthroughSubject() + private let selectedRoutineIdSubject = PassthroughSubject() private let selectedRecommendedRoutineSubject = CurrentValueSubject, Never>([]) private let confirmButtonSubject = PassthroughSubject() private let registerRoutineResultSubject = PassthroughSubject() @@ -45,7 +45,7 @@ final class ResultRecommendedRoutineViewModel: ViewModel { self.resultRecommendedRoutineUseCase = resultRecommendedRoutineUseCase output = Output( resultRecommendedRoutinesPublisher: resultRecommendedRoutinesSubject.eraseToAnyPublisher(), - selectedRoutineIdPublisher: selectedRoutinIdSubject.eraseToAnyPublisher(), + selectedRoutineIdPublisher: selectedRoutineIdSubject.eraseToAnyPublisher(), selectedRecommendedRoutinePublisher: selectedRecommendedRoutineSubject.eraseToAnyPublisher(), confirmButtonPublisher: confirmButtonSubject.eraseToAnyPublisher(), registerRoutineResultPublisher: registerRoutineResultSubject.eraseToAnyPublisher() @@ -57,9 +57,9 @@ final class ResultRecommendedRoutineViewModel: ViewModel { case .fetchResultRecommendedRoutines: fetchResultRecommendedRoutines() - case .fetchSelectedRoutinId: + case .fetchSelectedRoutineId: let routineId = selectedRecommendedRoutineSubject.value.first?.id - selectedRoutinIdSubject.send(routineId) + selectedRoutineIdSubject.send(routineId) case .selectRecommendedRoutine(let routine): selectRecommendedRoutine(routine: routine) From 8bf4c2fee5353507fe6135a11d5c3bdbaa531aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=8B?= =?UTF-8?q?=E1=85=B5=E1=86=AB?= Date: Fri, 8 Aug 2025 15:49:48 +0900 Subject: [PATCH 6/6] =?UTF-8?q?Refactor:=20nil=EC=9D=BC=20=EB=95=8C?= =?UTF-8?q?=EC=97=90=EB=8F=84=20=EA=B0=90=EC=A0=95=20=EA=B5=AC=EC=8A=AC=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20action=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Home/View/HomeView.swift | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Projects/Presentation/Sources/Home/View/HomeView.swift b/Projects/Presentation/Sources/Home/View/HomeView.swift index 513559ae..79b02243 100644 --- a/Projects/Presentation/Sources/Home/View/HomeView.swift +++ b/Projects/Presentation/Sources/Home/View/HomeView.swift @@ -137,12 +137,7 @@ final class HomeView: BaseViewController { }, for: .touchUpInside) let registerEmotionAction = UIAction(identifier: registerEmotionButtonActionIdentifier) { [weak self] _ in - guard let emotionRegisterViewModel = DIContainer.shared.resolve(type: EmotionRegisterViewModel.self) else { - fatalError("emotionRegisterViewModel 의존성이 등록되지 않았습니다.") - } - let emotionRegisterView = EmotionRegisterView(viewModel: emotionRegisterViewModel) - emotionRegisterView.hidesBottomBarWhenPushed = true - self?.navigationController?.pushViewController(emotionRegisterView, animated: true) + self?.goToEmotionRegisterView() } registerEmotionButton.addAction(registerEmotionAction, for: .touchUpInside) @@ -439,6 +434,10 @@ final class HomeView: BaseViewController { guard let emotion, let emotionOrbImageUrl = emotion.emotionImageUrl else { + let registerEmotionAction = UIAction(identifier: registerEmotionButtonActionIdentifier) { [weak self] _ in + self?.goToEmotionRegisterView() + } + registerEmotionButton.addAction(registerEmotionAction, for: .touchUpInside) emotionOrbView.image = BitnagilGraphic.defaultEmotionGraphic return } @@ -569,6 +568,15 @@ final class HomeView: BaseViewController { loadingIndicatorView.stopAnimating() contentView.isUserInteractionEnabled = true } + + private func goToEmotionRegisterView() { + guard let emotionRegisterViewModel = DIContainer.shared.resolve(type: EmotionRegisterViewModel.self) else { + fatalError("emotionRegisterViewModel 의존성이 등록되지 않았습니다.") + } + let emotionRegisterView = EmotionRegisterView(viewModel: emotionRegisterViewModel) + emotionRegisterView.hidesBottomBarWhenPushed = true + navigationController?.pushViewController(emotionRegisterView, animated: true) + } } // MARK: RoutineViewDelegate