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? } diff --git a/Projects/Presentation/Sources/Home/View/HomeView.swift b/Projects/Presentation/Sources/Home/View/HomeView.swift index f79ea3a9..79b02243 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,10 @@ final class HomeView: BaseViewController { } }, for: .touchUpInside) - registerEmotionButton.addAction(UIAction { [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) + let registerEmotionAction = UIAction(identifier: registerEmotionButtonActionIdentifier) { [weak self] _ in + self?.goToEmotionRegisterView() + } + registerEmotionButton.addAction(registerEmotionAction, for: .touchUpInside) contentView.backgroundColor = .white contentView.layer.cornerRadius = Layout.contentViewCornerRadius @@ -344,8 +343,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 +352,7 @@ final class HomeView: BaseViewController { .receive(on: DispatchQueue.main) .sink { [weak self] routines in self?.updateRoutineView(routines: routines) + self?.hideIndicatorView() } .store(in: &cancellables) @@ -434,17 +434,24 @@ 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 } 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) { @@ -561,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 diff --git a/Projects/Presentation/Sources/ResultRecommendedRoutine/View/ResultRecommendedRoutineView.swift b/Projects/Presentation/Sources/ResultRecommendedRoutine/View/ResultRecommendedRoutineView.swift index 2ca73675..a8960c73 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 selectedRoutineIdSubject = 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: selectedRoutineIdSubject.eraseToAnyPublisher(), selectedRecommendedRoutinePublisher: selectedRecommendedRoutineSubject.eraseToAnyPublisher(), confirmButtonPublisher: confirmButtonSubject.eraseToAnyPublisher(), registerRoutineResultPublisher: registerRoutineResultSubject.eraseToAnyPublisher() @@ -53,6 +57,10 @@ final class ResultRecommendedRoutineViewModel: ViewModel { case .fetchResultRecommendedRoutines: fetchResultRecommendedRoutines() + case .fetchSelectedRoutineId: + let routineId = selectedRecommendedRoutineSubject.value.first?.id + selectedRoutineIdSubject.send(routineId) + case .selectRecommendedRoutine(let routine): selectRecommendedRoutine(routine: routine) 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