Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WEAV-135] 프로필, 이상형 정보 입력 Intro 뷰 생성 #45

Merged
merged 4 commits into from
Nov 21, 2024

Conversation

jisu15-kim
Copy link
Member

@jisu15-kim jisu15-kim commented Nov 20, 2024

구현사항

  • 프로필 입력 Intro 뷰 생성
  • 이상형 정보 입력 Intro 뷰 생성
  • 애니메이션 이후 자동으로 다음 뷰로 넘어가도록 구현

스크린샷(선택)

프로필 입력 Intro 이상형 정보 Intro

Summary by CodeRabbit

  • 새로운 기능

    • 인증 정보 뷰에 로그아웃 버튼 추가 및 내비게이션 개선.
    • 프로필 소개 및 꿈의 파트너 소개 화면으로의 내비게이션 옵션 확장.
    • 사용자 등록 프로세스에 대한 새로운 뷰 및 상태 관리 모델 추가.
  • 버그 수정

    • 내비게이션 동작 및 툴팁 기능 개선.
  • 문서화

    • 새로운 JSON 파일을 통해 이미지 세트 정의 추가.

@jisu15-kim jisu15-kim added the Feature 기능 label Nov 20, 2024
@jisu15-kim jisu15-kim self-assigned this Nov 20, 2024
Copy link
Contributor

coderabbitai bot commented Nov 20, 2024

Walkthrough

이 풀 리퀘스트는 주로 AuthInfoView.swift, NavigationStack.swift, AppCoordinator.swift, PathTypes.swift 및 여러 SignUp 관련 파일에서의 변경 사항을 포함합니다. 주요 변경 사항으로는 AuthDebugInfoView에 로그아웃 버튼이 추가되고, PathType 열거형에 새로운 케이스가 추가되어 네비게이션 기능이 확장되었습니다. 또한, AppCoordinator 클래스에 로그아웃 메서드가 추가되었으며, 여러 새로운 모델 및 뷰 파일이 생성되었습니다.

Changes

파일 경로 변경 요약
Projects/App/Sources/Debug/AuthInfoView.swift AuthDebugInfoView에 로그아웃 버튼과 툴바 추가, copyToClipboard 메서드 추가.
Projects/App/Sources/Navigation/NavigationStack.swift PathType 열거형에 .profileIntro(let input).dreamPartnerIntro(let input) 케이스 추가.
Projects/Core/CommonKit/Sources/AppCoordinator.swift AppCoordinator 클래스에 logout() 메서드 추가.
Projects/Core/CommonKit/Sources/Path/PathTypes.swift PathTypeSignUpSubViewType 열거형에 새로운 케이스 추가 및 해시 메서드 수정.
Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/heart-with-arrow.imageset/Contents.json 하트-화살 이미지 세트 정의를 위한 새로운 JSON 파일 추가.
Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/magnifying-glass.imageset/Contents.json 확대경 아이콘을 위한 새로운 JSON 파일 추가.
Projects/Features/SignUp/Sources/AuthSignUp/AuthAgreement/AuthAgreementIntent.swift onTapNextButton 메서드 내에서 네비게이션 변경.
Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerAge/DreamPartnerAgeView.swift 네비게이션 설정 메서드 변경.
Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroIntent.swift DreamPartnerIntroIntent 클래스 추가 및 사용자 상호작용 관리.
Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroModel.swift DreamPartnerIntroModel 클래스 및 관련 프로토콜 추가.
Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroView.swift DreamPartnerIntroView 추가, MVI 아키텍처 사용.
Projects/Features/SignUp/Sources/ProfileInput/ProfileIntro/ProfileIntroIntent.swift ProfileIntroIntent 클래스 추가 및 사용자 상호작용 관리.
Projects/Features/SignUp/Sources/ProfileInput/ProfileIntro/ProfileIntroModel.swift ProfileIntroModel 클래스 및 관련 프로토콜 추가.
Projects/Features/SignUp/Sources/ProfileInput/ProfileIntro/ProfileIntroView.swift ProfileIntroView 추가, MVI 아키텍처 사용.

Possibly related PRs

Suggested labels

Design

"토끼가 말했어요,
새로운 버튼과 뷰가 생겼어요!
로그아웃도 간편하게,
사용자 여정이 즐거워요.
꿈의 파트너를 찾아,
함께 나아가요,
우리 모두의 행복을 위해!" 🐰✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (28)
Projects/Features/SignUp/Sources/ProfileInput/ProfileIntro/ProfileIntroIntent.swift (3)

36-44: 프로토콜 문서화 개선 필요

각 메서드의 목적과 사용법을 명확히 하기 위해 문서화가 필요합니다.

다음과 같이 문서화를 추가하는 것을 제안합니다:

 protocol Intentable {
-    // content
+    /// 다음 화면으로 전환하는 메서드
     func pushNextView() async
+    
+    /// 다음 버튼 탭 이벤트 처리 메서드
     func onTapNextButton()
     
-    // default
+    /// 뷰가 나타날 때 호출되는 메서드
     func onAppear()
+    
+    /// 비동기 작업을 처리하는 메서드
     func task() async
 }

60-65: 미구현된 메서드들의 용도 명시 필요

onAppear(), task(), onTapNextButton()가 비어있는 이유와 향후 구현 계획을 주석으로 명시해주세요.

특히 onTapNextButton()은 수동 네비게이션을 위해 필요할 수 있으므로, 구현 여부를 검토해주세요.

-    func onAppear() {}
+    /// 현재는 필요한 초기화 작업이 없음
+    func onAppear() {}
     
-    func task() async {}
+    /// 현재는 필요한 비동기 작업이 없음
+    func task() async {}
     
     // content
-    func onTapNextButton() {}
+    /// 자동 전환 외에 수동 전환이 필요한 경우를 위한 메서드
+    func onTapNextButton() {
+        Task {
+            await pushNextView()
+        }
+    }

14-14: MARK 주석 형식 수정 필요

SwiftLint 규칙에 따라 MARK 주석 형식을 수정해주세요.

다음과 같이 수정을 제안합니다:

-//MARK: - Intent
+// MARK: - Intent

-//MARK: - Intentable
+// MARK: - Intentable

-//MARK: - Intentable
+// MARK: - Intentable

Also applies to: 34-34, 51-51

🧰 Tools
🪛 SwiftLint

[Warning] 14-14: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 14-14: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)

Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroIntent.swift (2)

34-49: 프로토콜 정의 위치 및 구조 개선 필요

이전 PR의 학습 내용을 참고하여, 프로토콜 정의를 클래스 extension 내부에 두는 것은 의도적인 설계로 보입니다. 하지만 다음 개선사항을 고려해주세요:

  1. 프로토콜 메서드들의 목적에 따른 그룹화가 필요합니다.
  2. "content"와 "default" 주석 대신 명확한 문서화 주석이 필요합니다.

다음과 같은 구조를 제안드립니다:

  protocol Intentable {
+     /// Navigation related methods
      func pushNextView() async
      func onTapNextButton()
      
+     /// Lifecycle related methods
      func onAppear()
      func task() async
  }
🧰 Tools
🪛 SwiftLint

[Warning] 34-34: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 34-34: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


14-14: MARK 주석 포맷 수정 필요

SwiftLint 경고에 따라 MARK 주석 포맷을 수정해주세요.

다음과 같이 수정이 필요합니다:

- //MARK: - Intent
+ // MARK: - Intent

- //MARK: - Intentable
+ // MARK: - Intentable

Also applies to: 34-34, 51-51

🧰 Tools
🪛 SwiftLint

[Warning] 14-14: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 14-14: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)

Projects/Features/SignUp/Sources/ProfileInput/AuthName/AuthNameInputIntent.swift (2)

Line range hint 64-69: 입력 유효성 검사 및 디버그 코드 개선 필요

  1. 다음 화면으로 이동하기 전에 이름 입력값의 유효성 검사가 필요합니다.
  2. 프로덕션 코드에 print 문이 남아있습니다.

다음과 같이 개선을 제안합니다:

 func onTapNextButton(state: AuthNameInputModel.Stateful) {
     Task {
         var payload = input.input
+        guard !state.inputText.isEmpty else { return }
         payload.name = state.inputText
-        print(state.inputText)
         await pushNextView(payload: payload)
     }
 }

네비게이션 흐름 변경이 불완전하게 적용되었습니다

코드베이스 분석 결과, .dreamPartnerAgeRange.dreamPartnerIntro 경로가 동시에 존재하며 일관성이 없습니다:

  • DreamPartnerIntroIntent.swift에서는 여전히 .dreamPartnerAgeRange로 네비게이션하고 있습니다
  • PathTypes.swift에 두 경로가 모두 정의되어 있어 혼선의 여지가 있습니다
  • NavigationStack.swift에도 두 경로가 모두 구현되어 있습니다
🔗 Analysis chain

Line range hint 70-74: 네비게이션 흐름 변경 검증 필요

네비게이션 흐름이 .dreamPartnerAgeRange에서 .dreamPartnerIntro로 변경되었습니다. 이는 의도된 변경으로 보이지만, 전체 회원가입 플로우에 미치는 영향을 확인해야 합니다.

다음 스크립트를 실행하여 관련된 네비게이션 변경사항을 확인하세요:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify navigation flow changes across the codebase

# Check for any remaining references to the old navigation path
rg "dreamPartnerAgeRange" 

# Check for consistent usage of the new navigation path
rg "dreamPartnerIntro"

Length of output: 1352

Projects/Features/SignUp/Sources/ProfileInput/ProfileIntro/ProfileIntroModel.swift (4)

13-40: 문서화 개선이 필요합니다.

각 프로토콜과 프로퍼티에 대한 문서화 주석을 추가하면 코드의 가독성과 유지보수성이 향상될 것 같습니다.

다음과 같이 문서화 주석을 추가해보세요:

+/// 프로필 소개 화면의 상태를 관리하는 모델
 final class ProfileIntroModel: ObservableObject {
     
     //MARK: Stateful
+    /// 프로필 소개 화면의 상태를 정의하는 프로토콜
     protocol Stateful {
+        /// 입력값의 유효성 검증 상태
         var isValidated: Bool { get }
         
+        /// 로딩 상태
         var isLoading: Bool { get }
         
+        /// 에러 뷰 표시 상태
         var showErrorView: ErrorModel? { get }
+        /// 에러 알림 표시 상태
         var showErrorAlert: ErrorModel? { get }
     }
🧰 Tools
🪛 SwiftLint

[Warning] 15-15: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 28-28: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 15-15: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 28-28: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


58-60: 유효성 검증 로직 강화가 필요합니다.

setValidation 메서드에 입력값 검증 로직이 없습니다. 잘못된 상태 변경을 방지하기 위해 검증 로직을 추가하는 것이 좋을 것 같습니다.

다음과 같이 개선해보세요:

 func setValidation(value: Bool) {
+    // 현재 상태와 동일한 경우 불필요한 상태 업데이트 방지
+    guard isValidated != value else { return }
     isValidated = value
 }

15-15: 코드 스타일 개선이 필요합니다.

SwiftLint 분석 결과에 따라 MARK 주석 형식을 수정해야 합니다.

다음과 같이 수정해주세요:

-    //MARK: Stateful
+    // MARK: - Stateful

-    //MARK: State Properties
+    // MARK: - State Properties

-//MARK: - Actionable
+// MARK: - Actionable

Also applies to: 28-28, 42-42

🧰 Tools
🪛 SwiftLint

[Warning] 15-15: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 15-15: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


1-12: 아키텍처 문서화가 필요합니다.

이 파일이 MVI 아키텍처 패턴을 따르고 있다는 것을 명시하는 파일 수준의 문서화가 있으면 좋을 것 같습니다.

파일 상단에 다음과 같은 문서화를 추가해보세요:

+/// ProfileIntroModel은 MVI 아키텍처의 Model 컴포넌트를 구현합니다.
+/// - State 관리: `Stateful` 프로토콜을 통해 뷰의 상태를 관리합니다.
+/// - Action 처리: `ProfileIntroModelActionable` 프로토콜을 통해 상태 변경 액션을 처리합니다.
+/// - Intent 연동: ProfileIntroIntent와 함께 작동하여 사용자 인터랙션을 처리합니다.
Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroModel.swift (3)

13-40: 프로토콜과 상태 관리가 잘 구현되어 있습니다.

상태 관리를 위한 구조가 명확하게 설계되어 있으며, SwiftUI의 ObservableObject를 적절히 활용하고 있습니다. 다만, 문서화를 추가하면 더 좋을 것 같습니다.

각 프로퍼티와 프로토콜에 대한 문서화를 추가하는 것을 제안드립니다:

+ /// 이상형 소개 화면의 상태를 관리하는 프로토콜
 protocol Stateful {
+    /// 유효성 검증 상태
     var isValidated: Bool { get }
     
+    /// 로딩 상태
     var isLoading: Bool { get }
     
+    /// 에러 표시 상태
     var showErrorView: ErrorModel? { get }
     var showErrorAlert: ErrorModel? { get }
 }
🧰 Tools
🪛 SwiftLint

[Warning] 15-15: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 28-28: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 15-15: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 28-28: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


42-78: 에러 처리 로직 개선이 필요합니다.

현재 구현은 깔끔하지만, 에러 처리를 좀 더 견고하게 만들 수 있습니다.

다음과 같은 개선사항을 제안드립니다:

 func showErrorView(error: ErrorModel) {
+    guard !isLoading else { return }
     showErrorView = error
 }
 
 func showErrorAlert(error: ErrorModel) {
+    guard !isLoading else { return }
     showErrorAlert = error
 }
 
 func resetError() {
+    guard showErrorView != nil || showErrorAlert != nil else { return }
     showErrorView = nil
     showErrorAlert = nil
 }
🧰 Tools
🪛 SwiftLint

[Warning] 42-42: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 42-42: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


15-15: MARK 주석 형식을 수정해주세요.

SwiftLint 분석 결과에 따라 MARK 주석 형식을 수정해야 합니다.

다음과 같이 수정해주세요:

-    //MARK: Stateful
+    // MARK: - Stateful

-    //MARK: State Properties
+    // MARK: - State Properties

-//MARK: - Actionable
+// MARK: - Actionable

Also applies to: 28-28, 42-42

🧰 Tools
🪛 SwiftLint

[Warning] 15-15: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 15-15: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)

Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerJobModel.swift (3)

14-29: 프로토콜 문서화 개선 및 MARK 포맷 수정 필요

프로토콜의 각 프로퍼티에 대한 문서화 주석을 추가하면 좋을 것 같습니다. 또한 MARK 주석 포맷을 수정해야 합니다.

다음과 같이 수정해주세요:

-    //MARK: Stateful
+    // MARK: - Stateful

그리고 각 프로퍼티에 대한 문서화를 추가해주세요:

/// 선택된 직업 배열
var selectedJobArray: [JobOccupation] { get }
/// 선택이 유효한지 여부
var isValidated: Bool { get }
🧰 Tools
🪛 SwiftLint

[Warning] 16-16: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 16-16: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


32-35: isValidated 프로퍼티 가독성 개선 제안

isValidated 프로퍼티의 의도를 더 명확하게 표현할 수 있습니다.

다음과 같이 수정하는 것을 제안합니다:

-    var isValidated: Bool {
-        selectedJobArray.isNotEmpty
-    }
+    var isValidated: Bool {
+        return !selectedJobArray.isEmpty
+    }

48-59: Actionable 프로토콜 문서화 필요

각 메서드의 용도와 매개변수에 대한 설명을 추가하면 좋을 것 같습니다.

다음과 같이 문서화를 추가해주세요:

/// 선택된 직업 배열을 설정합니다
/// - Parameter jobs: 설정할 직업 배열
func setSelectedJobArray(_ jobs: [JobOccupation])

/// 로딩 상태를 설정합니다
/// - Parameter status: 설정할 로딩 상태
func setLoading(status: Bool)
Projects/App/Sources/Navigation/NavigationStack.swift (1)

61-62: 이상형 정보 입력 인트로 화면 네비게이션이 기존 구조와 일관성있게 구현되었습니다.

DreamPartnerIntroView로의 네비게이션이 기존 패턴을 따르고 있으며, 이상형 정보 입력 플로우의 시작점으로 적절히 배치되었습니다.

다만, 사용자 경험 관점에서 한 가지 제안드립니다:

인트로 화면에서 다음 화면으로의 자동 전환 시 적절한 타이밍 조절이 필요할 수 있습니다. 사용자가 화면의 내용을 충분히 인지할 수 있는 시간이 보장되어야 합니다.

Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroView.swift (3)

17-23: 상태 관리 로직에 대한 문서화가 필요합니다.

MVIContainer와 상태 변수들의 목적과 사용법에 대한 주석을 추가하면 코드의 가독성과 유지보수성이 향상될 것 같습니다.

다음과 같은 형식의 문서화를 추가해보세요:

+/// MVI 아키텍처를 위한 컨테이너
 @StateObject var container: MVIContainer<DreamPartnerIntroIntent.Intentable, DreamPartnerIntroModel.Stateful>
    
+/// 아이콘 애니메이션을 위한 상태 변수
 @State var isShowIcon: Bool = false
+/// 텍스트 애니메이션을 위한 상태 변수
 @State var isShowText: Bool = false

25-37: 초기화 로직을 더 간단하게 개선할 수 있습니다.

현재 구현은 정상적으로 작동하지만, 타입 캐스팅을 줄이고 가독성을 개선할 수 있습니다.

다음과 같이 개선해보세요:

 public init(_ input: SignUpFormDomain) {
-    let model = DreamPartnerIntroModel()
-    let intent = DreamPartnerIntroIntent(
-        model: model,
-        input: .init(input: input)
-    )
-    let container = MVIContainer(
-        intent: intent as DreamPartnerIntroIntent.Intentable,
-        model: model as DreamPartnerIntroModel.Stateful,
-        modelChangePublisher: model.objectWillChange
-    )
+    let model = DreamPartnerIntroModel()
+    let intent = DreamPartnerIntroIntent(model: model, input: .init(input: input))
+    let container = MVIContainer(intent: intent, model: model)
     self._container = StateObject(wrappedValue: container)
 }

90-94: 프리뷰 케이스를 다양화하면 좋을 것 같습니다.

현재는 기본 케이스만 프리뷰하고 있습니다. 다양한 상황에서의 UI를 확인할 수 있도록 프리뷰를 확장하면 좋을 것 같습니다.

다음과 같이 개선해보세요:

 #Preview {
-    NavigationView {
-        DreamPartnerIntroView(.mock)
+    Group {
+        NavigationView {
+            DreamPartnerIntroView(.mock)
+        }
+        .previewDisplayName("기본 상태")
+
+        NavigationView {
+            DreamPartnerIntroView(.mock)
+        }
+        .preferredColorScheme(.dark)
+        .previewDisplayName("다크 모드")
     }
 }
Projects/Core/CommonKit/Sources/AppCoordinator.swift (1)

126-131: 로그아웃 구현이 기본적으로 잘 되어있습니다만, 몇 가지 개선사항이 있습니다.

기본적인 토큰 제거와 상태 변경은 잘 구현되어 있습니다. 하지만 다음과 같은 개선사항을 제안드립니다:

  1. 다른 메서드들처럼 메인 스레드에서 상태를 변경하도록 수정
  2. 토큰 제거 실패에 대한 에러 처리 추가
  3. 로그아웃 이벤트 로깅 추가

다음과 같이 개선하는 것을 추천드립니다:

-    public func logout() {
-        TokenManager.accessToken = nil
-        TokenManager.refreshToken = nil
-        TokenManager.registerToken = nil
-        AuthState.change(.loggedOut)
+    public func logout() {
+        do {
+            // 토큰 제거
+            TokenManager.accessToken = nil
+            TokenManager.refreshToken = nil
+            TokenManager.registerToken = nil
+            
+            // 로그아웃 이벤트 로깅
+            print("👤 User logged out successfully")
+            
+            // 메인 스레드에서 상태 변경
+            DispatchQueue.main.async {
+                AuthState.change(.loggedOut)
+            }
+        } catch {
+            print("❌ Failed to logout: \(error)")
+        }
+    }
Projects/Features/SignUp/Sources/ProfileInput/AuthProfileAge/AuthProfileAgeInputView.swift (1)

Line range hint 1-150: 사용자 경험 개선을 위한 제안사항

다음과 같은 개선사항들을 고려해보시면 좋을 것 같습니다:

  1. 키보드가 나타날 때 자동으로 스크롤되어 입력 필드가 가려지지 않도록 처리
  2. 사용자가 잘못된 연도를 입력했을 때 즉각적인 피드백 제공
  3. 툴팁이 표시될 때 배경을 어둡게 처리하여 포커스 강조

다음과 같이 수정해보시는 건 어떨까요:

 public var body: some View {
     VStack {
         ProfileInputTemplatedView(
             currentPage: 2,
             maxPage: 5,
             subMessage: "좋은 \(state.targetGender.name)분 소개시켜 드릴께요!",
             mainMessage: "당신의 나이는 무엇인가요?"
         ) {
+            ScrollViewReader { proxy in
                 VStack {
                     HStack {
                         VerifyCodeInputView(
                             verifyCode: $container.model.birthYear,
                             errorMessage: $container.model.errorMessage,
                             verifyCodeMaxCount: 4,
                             boxHeight: 92,
                             textColor: .black,
                             borderWidth: 4,
                             borderColor: .white,
                             backColor: DesignCore.Colors.yellow50,
                             cornerRadius: 20,
                             focused: _isFocused
                         )
                         .padding(.horizontal, 6)
                         .onChange(of: state.birthYear) {
                             intent.onYearChanged(
                                 state.birthYear
                             )
+                            if !state.isValidYear {
+                                withAnimation {
+                                    proxy.scrollTo("yearInput", anchor: .center)
+                                }
+                            }
                         }
+                        .id("yearInput")
                     }
                 }
+            }
         }
+        .background(
+            Color.black.opacity(state.isShowToolTip ? 0.3 : 0)
+                .ignoresSafeArea()
+                .animation(.easeInOut, value: state.isShowToolTip)
+        )
     }
 }
Projects/App/Sources/Debug/AuthInfoView.swift (3)

158-165: 로그아웃 작업 시 확인 다이얼로그 추가 필요

사용자의 실수를 방지하기 위해 로그아웃 전에 확인 다이얼로그를 표시하는 것이 좋습니다.

다음과 같이 수정하는 것을 제안합니다:

 .toolbar {
     ToolbarItem(placement: .topBarTrailing) {
-        Button("로그아웃", role: .destructive) {
-            AppCoordinator.shared.logout()
-        }
+        Button("로그아웃", role: .destructive) {
+            showLogoutAlert = true
+        }
+        .alert("로그아웃", isPresented: $showLogoutAlert) {
+            Button("취소", role: .cancel) { }
+            Button("로그아웃", role: .destructive) {
+                AppCoordinator.shared.logout()
+            }
+        } message: {
+            Text("정말 로그아웃 하시겠습니까?")
+        }
     }
 }

Line range hint 1-165: 디버그 뷰의 보안 강화 필요

민감한 정보를 다루는 디버그 뷰에 대한 몇 가지 보안 개선사항을 제안드립니다:

  1. 토큰 값 표시 시 마스킹 처리
  2. 클립보드에 복사된 민감 정보의 자동 삭제 타이머 추가
  3. 디버그 뷰 접근 시 개발자 인증 추가

이러한 보안 기능을 구현하는데 도움이 필요하시다면 말씀해 주세요.


Line range hint 14-157: 데이터 관리 구조 개선 제안

현재 구조에 대한 개선 제안사항입니다:

  1. TableInfoModel을 별도 파일로 분리
  2. 각 섹션의 데이터 소스를 별도 타입으로 분리하여 관리
  3. AppCoordinator 의존성을 주입 방식으로 변경

이는 다음과 같은 이점이 있습니다:

  • 코드의 모듈성 향상
  • 테스트 용이성 증가
  • 유지보수성 개선

구체적인 리팩토링 방안이 필요하시다면 말씀해 주세요.

Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerAge/DreamPartnerAgeView.swift (2)

Line range hint 156-186: 연령 입력 유효성 검사 및 접근성 개선 필요

현재 구현에서 다음 사항들의 보완이 필요해 보입니다:

  • 상한/하한 나이 범위에 대한 유효성 검사 로직 추가
  • 선택 가능한 나이 범위에 대한 사용자 안내
  • VoiceOver 지원을 위한 접근성 레이블 추가

다음과 같은 개선사항을 제안드립니다:

func ageUpDownView(type: AgeUpDownType) -> some View {
    HStack(spacing: 8) {
        HStack {
            Text(type.imoji)
            Text("내 나이보다")
            Text(type.text)
            Text("로")
-       }
+       }.accessibilityElement(combinedLabel: true)
+        .accessibilityLabel("\(type == .up ? "상한" : "하한") 나이 설정")
        // ... 나머지 코드
    }
}

Line range hint 193-211: BottomSheetPickerView 구현 개선 필요

피커 구현에서 다음 사항들을 검토해주세요:

  • 0-15 범위가 충분한지 검토 필요 (실제 나이 차이 범위가 더 클 수 있음)
  • "상관없어요" 옵션의 위치가 직관적인지 검토
  • 선택된 값에 대한 즉각적인 피드백 추가

더 넓은 범위를 지원하도록 수정을 제안드립니다:

Picker("숫자 선택", selection: $selectedValue) {
    Text("상관없어요")
        .tag(String?.none)
-   ForEach(0...15, id: \.self) { number in
+   ForEach(0...30, id: \.self) { number in
        Text("\(number)")
            .tag(String?(String(number)))
    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c20ec95 and 57cb1c6.

⛔ Files ignored due to path filters (6)
  • Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/heart-with-arrow.imageset/heart-with-arrow.png is excluded by !**/*.png
  • Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/heart-with-arrow.imageset/heart-with-arrow@2x.png is excluded by !**/*.png
  • Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/heart-with-arrow.imageset/heart-with-arrow@3x.png is excluded by !**/*.png
  • Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/magnifying-glass.imageset/magnifying-glass.png is excluded by !**/*.png
  • Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/magnifying-glass.imageset/magnifying-glass@2x.png is excluded by !**/*.png
  • Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/magnifying-glass.imageset/magnifying-glass@3x.png is excluded by !**/*.png
📒 Files selected for processing (18)
  • Projects/App/Sources/Debug/AuthInfoView.swift (1 hunks)
  • Projects/App/Sources/Navigation/NavigationStack.swift (2 hunks)
  • Projects/Core/CommonKit/Sources/AppCoordinator.swift (1 hunks)
  • Projects/Core/CommonKit/Sources/Path/PathTypes.swift (7 hunks)
  • Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/heart-with-arrow.imageset/Contents.json (1 hunks)
  • Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/magnifying-glass.imageset/Contents.json (1 hunks)
  • Projects/Features/SignUp/Sources/AuthSignUp/AuthAgreement/AuthAgreementIntent.swift (1 hunks)
  • Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerAge/DreamPartnerAgeView.swift (1 hunks)
  • Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroIntent.swift (1 hunks)
  • Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroModel.swift (1 hunks)
  • Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroView.swift (1 hunks)
  • Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerJobModel.swift (1 hunks)
  • Projects/Features/SignUp/Sources/ProfileInput/AuthName/AuthNameInputIntent.swift (1 hunks)
  • Projects/Features/SignUp/Sources/ProfileInput/AuthProfileAge/AuthProfileAgeInputView.swift (1 hunks)
  • Projects/Features/SignUp/Sources/ProfileInput/AuthProfileGenderInput/AuthProfileGenderInputView.swift (1 hunks)
  • Projects/Features/SignUp/Sources/ProfileInput/ProfileIntro/ProfileIntroIntent.swift (1 hunks)
  • Projects/Features/SignUp/Sources/ProfileInput/ProfileIntro/ProfileIntroModel.swift (1 hunks)
  • Projects/Features/SignUp/Sources/ProfileInput/ProfileIntro/ProfileIntroView.swift (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/heart-with-arrow.imageset/Contents.json
  • Projects/DesignSystem/DesignCore/Resources/Images/Images.xcassets/magnifying-glass.imageset/Contents.json
  • Projects/Features/SignUp/Sources/ProfileInput/AuthProfileGenderInput/AuthProfileGenderInputView.swift
🧰 Additional context used
📓 Learnings (1)
Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroIntent.swift (1)
Learnt from: jisu15-kim
PR: Student-Center/3days-ios#32
File: Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerAge/DreamPartnerAgeIntent.swift:28-42
Timestamp: 2024-11-12T13:22:13.201Z
Learning: 프로젝트에서 Intent 클래스의 `Intentable` 프로토콜을 정의할 때, 개발자가 의도적으로 클래스의 extension 내부에 프로토콜을 정의하는 경우가 있습니다.
🪛 SwiftLint
Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroIntent.swift

[Warning] 14-14: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 34-34: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 51-51: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 14-14: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 34-34: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 51-51: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)

Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroModel.swift

[Warning] 15-15: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 28-28: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 42-42: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 15-15: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 28-28: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 42-42: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)

Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerJobModel.swift

[Warning] 16-16: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 30-30: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 47-47: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 16-16: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 30-30: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 47-47: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)

Projects/Features/SignUp/Sources/ProfileInput/ProfileIntro/ProfileIntroIntent.swift

[Warning] 14-14: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 34-34: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 51-51: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 14-14: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 34-34: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 51-51: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)

Projects/Features/SignUp/Sources/ProfileInput/ProfileIntro/ProfileIntroModel.swift

[Warning] 15-15: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 28-28: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 42-42: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 15-15: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 28-28: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)


[Warning] 42-42: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)

🔇 Additional comments (11)
Projects/Features/SignUp/Sources/AuthSignUp/AuthAgreement/AuthAgreementIntent.swift (2)

56-56: 네비게이션 플로우 변경이 적절해 보입니다.

동의 화면에서 프로필 입력 인트로 화면으로의 전환이 PR의 목적과 잘 부합합니다.


56-56: 새로운 네비게이션 경로 검증이 필요합니다.

.profileIntro 케이스가 올바르게 구현되어 있는지 확인이 필요합니다.

✅ Verification successful

프로필 인트로 네비게이션 경로가 올바르게 구현되어 있습니다.

  • PathTypes.swiftprofileIntro 케이스가 정의되어 있고 필요한 입력값(SignUpFormDomain)을 받도록 구현되어 있습니다.
  • ProfileIntroView.swift 파일이 존재하며, NavigationStack.swift에서 해당 뷰로의 네비게이션이 적절히 처리되고 있습니다.
  • 네비게이션 스택에서 .profileIntro 케이스에 대한 라우팅이 ProfileIntroView로 올바르게 연결되어 있습니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of .profileIntro case and related views

# Check if ProfileIntro case exists in PathType
rg -A 5 "case profileIntro" 

# Check if ProfileIntroView exists
fd "ProfileIntroView" 

# Check coordinator handling of profileIntro
rg -A 5 "case .profileIntro"

Length of output: 2419

Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroIntent.swift (1)

51-66: ⚠️ Potential issue

프로토콜 구현부 개선 필요

구현부에서 다음 사항들을 검토해주세요:

  1. onTapNextButton()이 비어있는데, 이는 의도적인 것인지 확인이 필요합니다.
  2. pushNextView()가 실패할 경우에 대한 에러 처리가 없습니다.

onTapNextButton()의 구현이 필요한지 확인하기 위해 다음 스크립트를 실행합니다:

에러 처리를 위해 다음과 같은 수정을 제안드립니다:

  @MainActor
  func pushNextView() async {
+     do {
          AppCoordinator.shared.changeRootView(
              .signUp(.dreamPartnerAgeRange(input: input.input))
          )
+     } catch {
+         // TODO: 에러 처리 추가 필요
+         model?.handleError(error)
+     }
  }
🧰 Tools
🪛 SwiftLint

[Warning] 51-51: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 51-51: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)

Projects/App/Sources/Navigation/NavigationStack.swift (1)

43-44: 프로필 인트로 화면 네비게이션 추가가 적절히 구현되었습니다.

기존 네비게이션 패턴을 잘 따르고 있으며, 회원가입 플로우에 자연스럽게 통합되었습니다.

Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerIntro/DreamPartnerIntroView.swift (1)

9-13: 필요한 모듈들이 적절히 임포트되어 있습니다.

SwiftUI 기반 뷰 구현에 필요한 모든 의존성이 명확하게 정의되어 있습니다.

Projects/Core/CommonKit/Sources/Path/PathTypes.swift (3)

55-56: 디버그 프리뷰 타입이 적절히 추가되었습니다!

디버그 환경에서 새로운 화면을 미리보기 할 수 있도록 잘 구성되어 있습니다.


73-74: 화면 이름이 일관성 있게 추가되었습니다!

각 화면의 한글 이름이 기존 네이밍 패턴을 잘 따르고 있으며, 사용자가 이해하기 쉽게 작성되었습니다.

Also applies to: 83-86


97-97: 회원가입 플로우가 체계적으로 구성되었습니다!

프로필 입력과 이상형 정보 입력 플로우가 순차적으로 잘 구성되어 있습니다. 각 단계별로 SignUpFormDomain을 일관되게 사용하여 데이터 흐름이 명확합니다.

Also applies to: 106-109

Projects/Features/SignUp/Sources/ProfileInput/AuthProfileAge/AuthProfileAgeInputView.swift (2)

140-141: 네비게이션 처리 방식이 개선되었습니다.

기존의 showLeftBackButton 대신 setPopNavigation을 사용하여 일관된 네비게이션 흐름을 구현한 것이 좋습니다. AppCoordinator를 통한 중앙 집중식 네비게이션 관리는 앱의 일관성을 높여줄 것입니다.


Line range hint 20-41: SignUpFormDomain 의존성 검증 필요

현재 뷰는 SignUpFormDomain을 입력으로 받아 초기화되고 있습니다. 이 도메인 모델의 변경이 뷰에 영향을 줄 수 있으므로 의존성을 확인해야 합니다.

✅ Verification successful

Let's gather more information about the SignUpFormDomain model's structure and its usage in AuthProfileAgeInputView.


SignUpFormDomain 의존성 검증 완료

AuthProfileAgeInputView는 SignUpFormDomain을 안전하게 사용하고 있습니다:

  • 입력받은 나이 정보를 SignUpFormDomain의 profile.birthYear에만 저장
  • 다음 화면으로 이동 시 수정된 도메인 객체를 전달
  • 읽기 작업은 gender 정보 확인에만 제한적으로 사용
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# SignUpFormDomain 모델의 사용처와 의존성을 확인합니다.

# 모델 정의 검색
echo "Searching for SignUpFormDomain definition..."
rg -p "struct SignUpFormDomain" --type swift

# 모델 사용처 검색
echo "Searching for SignUpFormDomain usage..."
rg -p "SignUpFormDomain" --type swift

Length of output: 5692


Script:

#!/bin/bash
# SignUpFormDomain 모델의 구조와 AuthProfileAgeInputView에서의 사용을 확인합니다.

# SignUpFormDomain 모델 구조 확인
echo "Checking SignUpFormDomain structure..."
cat "Projects/Model/Model/Sources/SignUp/Domain/SignUpFormDomain.swift"

# AuthProfileAgeInputView에서의 사용 확인
echo -e "\nChecking AuthProfileAgeInputView usage..."
cat "Projects/Features/SignUp/Sources/ProfileInput/AuthProfileAge/AuthProfileAgeInputView.swift"

# AuthProfileAgeInputIntent에서의 사용 확인
echo -e "\nChecking AuthProfileAgeInputIntent usage..."
cat "Projects/Features/SignUp/Sources/ProfileInput/AuthProfileAge/AuthProfileAgeInputIntent.swift"

Length of output: 12236

Projects/Features/SignUp/Sources/DreamPartnerInput/DreamPartnerAge/DreamPartnerAgeView.swift (1)

140-142: 뒤로 가기 버튼 제거에 대한 UX 검토 필요

뒤로 가기 버튼을 숨기는 것은 사용자의 네비게이션 경험에 영향을 줄 수 있습니다. 다음 사항들을 고려해주세요:

  • 사용자가 이전 화면으로 돌아가는 방법을 명확히 인지할 수 있는지
  • 프로필 입력 과정에서 실수로 잘못 입력했을 때의 수정 방법

Comment on lines +27 to +31
Task {
try? await Task.sleep(for: .milliseconds(2500))
await pushNextView()
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Task 생명주기 관리 및 에러 처리 개선 필요

초기화 시 시작되는 Task에 대해 다음 사항들을 고려해주세요:

  1. Task 취소 처리가 없어 메모리 누수가 발생할 수 있습니다.
  2. 하드코딩된 2.5초 지연은 사용자 경험에 일관성이 없을 수 있습니다.
  3. Task.sleep의 에러 처리가 무시되고 있습니다.

다음과 같이 개선을 제안합니다:

 class ProfileIntroIntent {
     private weak var model: ProfileIntroModelActionable?
     private let input: DataModel
+    private var transitionTask: Task<Void, Never>?
 
     // MARK: Life cycle
     init(
         model: ProfileIntroModelActionable,
         input: DataModel
     ) {
         self.input = input
         self.model = model
         
-        Task {
-            try? await Task.sleep(for: .milliseconds(2500))
-            await pushNextView()
-        }
+        startTransitionTimer()
+    }
+    
+    private func startTransitionTimer() {
+        transitionTask = Task {
+            do {
+                try await Task.sleep(for: .milliseconds(2500))
+                if !Task.isCancelled {
+                    await pushNextView()
+                }
+            } catch {
+                print("Transition timer interrupted: \(error)")
+            }
+        }
+    }
+    
+    deinit {
+        transitionTask?.cancel()
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Task {
try? await Task.sleep(for: .milliseconds(2500))
await pushNextView()
}
}
class ProfileIntroIntent {
private weak var model: ProfileIntroModelActionable?
private let input: DataModel
private var transitionTask: Task<Void, Never>?
// MARK: Life cycle
init(
model: ProfileIntroModelActionable,
input: DataModel
) {
self.input = input
self.model = model
startTransitionTimer()
}
private func startTransitionTimer() {
transitionTask = Task {
do {
try await Task.sleep(for: .milliseconds(2500))
if !Task.isCancelled {
await pushNextView()
}
} catch {
print("Transition timer interrupted: \(error)")
}
}
}
deinit {
transitionTask?.cancel()
}
}

Comment on lines +14 to +32
//MARK: - Intent
class DreamPartnerIntroIntent {
private weak var model: DreamPartnerIntroModelActionable?
private let input: DataModel

// MARK: Life cycle
init(
model: DreamPartnerIntroModelActionable,
input: DataModel
) {
self.input = input
self.model = model

Task {
try? await Task.sleep(for: .milliseconds(2500))
await pushNextView()
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

초기화 시 자동 전환 로직 검토 필요

Task 내에서 sleep을 사용하여 지연된 화면 전환을 구현하고 있습니다. 다음 사항들을 고려해주세요:

  1. 사용자가 화면을 벗어나거나 앱이 백그라운드로 전환될 때 Task가 적절히 취소되어야 합니다.
  2. 화면 전환 시간(2.5초)을 상수로 분리하는 것이 좋습니다.
  3. Task.sleep 대신 더 안전한 방법을 고려해볼 수 있습니다.

다음과 같이 수정하는 것을 제안드립니다:

+ private let transitionDelay: Double = 2.5
+ private var transitionTask: Task<Void, Error>?

  init(
      model: DreamPartnerIntroModelActionable,
      input: DataModel
  ) {
      self.input = input
      self.model = model
      
-     Task {
+     transitionTask = Task {
          try? await Task.sleep(for: .milliseconds(2500))
          await pushNextView()
      }
  }

+ deinit {
+     transitionTask?.cancel()
+ }

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 SwiftLint

[Warning] 14-14: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 14-14: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'

(mark)

Comment on lines 73 to 82
func showErrorView(error: ErrorModel) {
showErrorView = error
}
func showErrorAlert(error: ErrorModel) {
showErrorAlert = error
}
func resetError() {
showErrorView = nil
showErrorAlert = nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

에러 처리 메서드의 스레드 안전성 개선 필요

에러 상태를 변경하는 메서드들이 메인 스레드에서 실행되도록 보장하면 좋을 것 같습니다.

다음과 같이 수정하는 것을 제안합니다:

     func showErrorView(error: ErrorModel) {
-        showErrorView = error
+        DispatchQueue.main.async {
+            self.showErrorView = error
+        }
     }
     func showErrorAlert(error: ErrorModel) {
-        showErrorAlert = error
+        DispatchQueue.main.async {
+            self.showErrorAlert = error
+        }
     }
     func resetError() {
-        showErrorView = nil
-        showErrorAlert = nil
+        DispatchQueue.main.async {
+            self.showErrorView = nil
+            self.showErrorAlert = nil
+        }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func showErrorView(error: ErrorModel) {
showErrorView = error
}
func showErrorAlert(error: ErrorModel) {
showErrorAlert = error
}
func resetError() {
showErrorView = nil
showErrorAlert = nil
}
func showErrorView(error: ErrorModel) {
DispatchQueue.main.async {
self.showErrorView = error
}
}
func showErrorAlert(error: ErrorModel) {
DispatchQueue.main.async {
self.showErrorAlert = error
}
}
func resetError() {
DispatchQueue.main.async {
self.showErrorView = nil
self.showErrorAlert = nil
}
}

Comment on lines +44 to +51
colors: [
.init(hex: 0xF3DDE5).opacity(0.0),
.init(hex: 0xF3DDE5)
],
startPoint: .top,
endPoint: .bottom
)
.frame(height: Device.height * 0.5)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

상수값들의 분리가 필요합니다.

하드코딩된 색상값과 크기값들을 상수로 분리하면 유지보수성이 향상될 것 같습니다.

다음과 같이 개선해보세요:

+private enum Constants {
+    static let gradientStartColor = Color(hex: 0xF3DDE5)
+    static let gradientHeight: CGFloat = Device.height * 0.5
+}

 LinearGradient(
     colors: [
-        .init(hex: 0xF3DDE5).opacity(0.0),
-        .init(hex: 0xF3DDE5)
+        Constants.gradientStartColor.opacity(0.0),
+        Constants.gradientStartColor
     ],
     startPoint: .top,
     endPoint: .bottom
 )
-.frame(height: Device.height * 0.5)
+.frame(height: Constants.gradientHeight)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
colors: [
.init(hex: 0xF3DDE5).opacity(0.0),
.init(hex: 0xF3DDE5)
],
startPoint: .top,
endPoint: .bottom
)
.frame(height: Device.height * 0.5)
private enum Constants {
static let gradientStartColor = Color(hex: 0xF3DDE5)
static let gradientHeight: CGFloat = Device.height * 0.5
}
LinearGradient(
colors: [
Constants.gradientStartColor.opacity(0.0),
Constants.gradientStartColor
],
startPoint: .top,
endPoint: .bottom
)
.frame(height: Constants.gradientHeight)

Comment on lines +77 to +83
.task {
await intent.task()
try? await Task.sleep(for: .milliseconds(250))
isShowIcon = true
try? await Task.sleep(for: .milliseconds(150))
isShowText = true
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Task.sleep 사용에 대한 개선이 필요합니다.

애니메이션 타이밍을 위해 Task.sleep을 사용하는 것은 다음과 같은 문제가 있습니다:

  1. 사용자 경험에 일관성이 없을 수 있습니다
  2. 디바이스 성능에 따라 다르게 동작할 수 있습니다
  3. 테스트하기 어려운 구조입니다

애니메이션 로직을 다음과 같이 개선하는 것을 추천드립니다:

-.task {
-    await intent.task()
-    try? await Task.sleep(for: .milliseconds(250))
-    isShowIcon = true
-    try? await Task.sleep(for: .milliseconds(150))
-    isShowText = true
-}
+.task {
+    await intent.task()
+    withAnimation(.easeInOut(duration: 0.25)) {
+        isShowIcon = true
+    }
+    withAnimation(.easeInOut(duration: 0.15).delay(0.25)) {
+        isShowText = true
+    }
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.task {
await intent.task()
try? await Task.sleep(for: .milliseconds(250))
isShowIcon = true
try? await Task.sleep(for: .milliseconds(150))
isShowText = true
}
.task {
await intent.task()
withAnimation(.easeInOut(duration: 0.25)) {
isShowIcon = true
}
withAnimation(.easeInOut(duration: 0.15).delay(0.25)) {
isShowText = true
}
}

Comment on lines +117 to +118
case .profileIntro:
hasher.combine(-1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

해시 값 할당 방식의 개선이 필요합니다.

현재 인트로 화면들에 대해 음수 값(-1, -2)을 사용하고 있는데, 이는 기존의 양수 시퀀스 패턴과 일치하지 않습니다. 유지보수성을 높이기 위해 일관된 번호 체계를 사용하는 것이 좋습니다.

다음과 같이 수정하는 것을 제안드립니다:

case .profileIntro:
-    hasher.combine(-1)
+    hasher.combine(13)
case .dreamPartnerIntro:
-    hasher.combine(-2)
+    hasher.combine(14)

Also applies to: 140-141

Comment on lines +68 to +69
.animation(.easeInOut, value: isShowIcon)
.animation(.easeInOut, value: isShowText)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

.animation Modifier의 사용 방법 업데이트 필요

iOS 15부터 .animation(_:value:) Modifier는 폐기되었습니다. 대신 상태 변화 시 withAnimation 블록을 사용해 애니메이션을 적용해 주세요.

코드 수정 제안:

-                .animation(.easeInOut, value: isShowIcon)
-                .animation(.easeInOut, value: isShowText)

상태 변경 시 withAnimation 사용:

withAnimation(.easeInOut) {
    isShowIcon = true
}

Comment on lines +77 to +83
.task {
await intent.task()
try? await Task.sleep(for: .milliseconds(250))
isShowIcon = true
try? await Task.sleep(for: .milliseconds(150))
isShowText = true
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Task.sleep(for:)의 호환성 확인 필요

Task.sleep(for:) 메소드는 iOS 16 이상에서만 지원됩니다. 최소 지원 버전이 iOS 15 이하라면 Task.sleep(nanoseconds:)를 사용하는 것이 좋습니다.

코드 수정 제안:

-            try? await Task.sleep(for: .milliseconds(250))
+            try? await Task.sleep(nanoseconds: UInt64(250_000_000))

Committable suggestion skipped: line range outside the PR's diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature 기능
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant