⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content

Conversation

@choijungp
Copy link
Contributor

@choijungp choijungp commented Nov 19, 2025

🌁 Background

제보 로딩 뷰와 제보 완료 뷰를 만들었어용 ~

📱 Screenshot

1. 제보 로딩 뷰

iPhone SE3 iPhone 13 mini iPhone 16 Pro
Simulator Screenshot - iPhone SE (3rd generation) - 2025-11-19 at 17 00 14 Simulator Screenshot - iPhone 13 mini - 2025-11-19 at 16 59 15 Simulator Screenshot - iPhone 16 Pro - 2025-11-19 at 16 58 25

2. 제보 완료 뷰

iPhone SE3 iPhone 13 mini iPhone 16 Pro
Simulator Screenshot - iPhone SE (3rd generation) - 2025-11-19 at 20 29 05 Simulator Screenshot - iPhone 13 mini - 2025-11-19 at 20 30 31 Simulator Screenshot - iPhone 16 Pro - 2025-11-19 at 20 32 28

※ ScrollView 입니다 !! 내리면 끝까지 보여유

👩‍💻 Contents

  • 제보 로딩 뷰 (ReportLoadingViewController)
  • 제보 완료 뷰 (ReportCompleteViewController)

📝 Review Note

1. ViewModel과 제보 등록 API 시점

제보 API를 쏘는 시점이 언제인지 결정하지 않았어서 일단 ViewModel 없이 만들었어유 !!!
제 개인적인 의견은 ReportLoadingViewController의 didAppear 시점에 제보 api를 쏘는게 맞다구 생각함 ... (근데 여기서 실패하면 어쩌죠 ??)

anyway 성공하면 약 1-2초 후에 ReportCompleteViewController로 이동하는 것으로 생각했는데
딩의 의견두 궁금함니다 !!!!

만약 생각이 일치한다면 api 연결할 때 ViewModel 생성해서 연결해놓겠심다 !!

📣 Related Issue

  • close #T3-200

Summary by CodeRabbit

릴리스 노트

  • New Features

    • 보고서 완료 화면 추가 (완료 아이콘, 타이틀, 요약 정보, 사진 표시)
    • 로딩 상태 화면 추가 (로딩 애니메이션 및 안내 텍스트)
  • Improvements

    • 디자인 시스템에 새로운 그래픽 및 아이콘 리소스 추가
    • 텍스트 정렬 옵션 추가
    • 보고서 상세 화면 레이아웃 스페이싱 개선

@choijungp choijungp requested a review from taipaise November 19, 2025 12:14
@choijungp choijungp self-assigned this Nov 19, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Walkthrough

새로운 이미지 에셋, 아이콘, 폰트 정렬 기능을 추가하고, 리포트 관련 두 개의 새로운 View Controller를 구현했습니다. ReportLoadingViewController는 로딩 화면을 표시하고 2초 후 ReportCompleteViewController로 전환합니다.

Changes

Cohort / File(s) Summary
이미지 에셋 카탈로그
Projects/Presentation/Resources/Images.xcassets/Graphic/loading_fomo_graphic.imageset/Contents.json, Projects/Presentation/Resources/Images.xcassets/Graphic/success_fomo_graphic.imageset/Contents.json, Projects/Presentation/Resources/Images.xcassets/Report/complete_icon.imageset/Contents.json, Projects/Presentation/Resources/Images.xcassets/Report/loading_icon.imageset/Contents.json
3가지 스케일(1x, 2x, 3x)에 대한 4개 새로운 이미지 에셋 카탈로그 매니페스트 추가
디자인 시스템 에셋 참조
Projects/Presentation/Sources/Common/DesignSystem/BitnagilGraphic.swift, Projects/Presentation/Sources/Common/DesignSystem/BitnagilIcon.swift
loadingFomoGraphic, successFomoGraphic, loadingIcon, completeIcon 4개 새로운 public 이미지/아이콘 상수 추가
폰트 정렬 기능
Projects/Presentation/Sources/Common/DesignSystem/Font/BitnagilFont.swift
attributedString 메서드에 alignment 파라미터 추가 (기본값: .left)
리포트 뷰 레이아웃 조정
Projects/Presentation/Sources/Report/View/ReportDetailViewController.swift
scrollView 및 contentStackView의 상하단 제약 조건을 명시적 레이아웃 상수로 리팩토링
새로운 리포트 뷰 컨트롤러
Projects/Presentation/Sources/Report/View/ReportLoadingViewController.swift, Projects/Presentation/Sources/Report/View/ReportCompleteViewController.swift
로딩 화면 표시 및 2초 후 완료 화면으로 전환하는 2개의 새로운 UIViewController 구현

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

특별히 주의가 필요한 부분:

  • ReportCompleteViewController.swift: 복잡한 UI 계층 구조와 동적 콘텐츠 생성 로직 검증 필요
  • ReportLoadingViewController.swift: 비동기 네비게이션 타이밍 및 메모리 누수 가능성(weak self 사용) 확인
  • BitnagilFont.swift: 정렬 파라미터 추가가 기존 호출부에 미치는 영향 검토

Poem

🐰 에셋 번들이 쏟아지고,
새 화면들 춤을 추네!
정렬 맞춰 로딩 시작,
완료 그래픽 반짝이며,
리포트도 우아하게 변신했네! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 주요 변경사항을 명확하게 설명하며, 제보 로딩 및 완료 화면 UI 구현이라는 핵심 변경사항을 정확하게 반영합니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/report-complete

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@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: 2

🧹 Nitpick comments (5)
Projects/Presentation/Sources/Report/View/ReportLoadingViewController.swift (1)

31-38: viewDidAppear 사용을 권장합니다.

viewWillAppear는 뷰가 나타날 때마다 호출되므로, 사용자가 뒤로 갔다가 다시 돌아오면 타이머가 중복 실행될 수 있습니다. API 연동 시점에 viewDidAppear로 변경하거나, 한 번만 실행되도록 플래그를 추가하는 것을 고려해보세요.

또한 navigationController가 nil일 수 있으므로 안전성을 위해 옵셔널 체이닝이나 가드문을 추가하는 것이 좋습니다.

예시:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { [weak self] in
        guard let self = self,
              let navigationController = self.navigationController else { return }
        let reportCompleteViewController = ReportCompleteViewController()
        navigationController.pushViewController(reportCompleteViewController, animated: true)
    }
}
Projects/Presentation/Sources/Report/View/ReportCompleteViewController.swift (4)

12-28: 레이아웃/콘텐츠 enum 설계는 좋지만, 네이밍 오타는 한 번 정리해 두면 좋겠습니다.

Layout / backgroudView 쪽에 오타가 있어 검색·자동완성 시 혼동이 올 수 있습니다. 기능 영향은 없지만, 초기에 정리해 두는 편이 유지보수에 유리해 보입니다.

예시:

-        static let subLableTopSpacing: CGFloat = 16
+        static let subLabelTopSpacing: CGFloat = 16
@@
-    private let backgroudView = UIView()
+    private let backgroundView = UIView()

아래 사용처들도 함께 변경해 주세요.

-        subLabel.snp.makeConstraints { make in
-            make.top.equalTo(completeLabel.snp.bottom).offset(Layout.subLableTopSpacing)
+        subLabel.snp.makeConstraints { make in
+            make.top.equalTo(completeLabel.snp.bottom).offset(Layout.subLabelTopSpacing)
@@
-        backgroudView.backgroundColor = BitnagilColor.gray98
+        backgroundView.backgroundColor = BitnagilColor.gray98
@@
-        backgroudView.addSubview(summaryStackView)
+        backgroundView.addSubview(summaryStackView)
@@
-        backgroudView.snp.makeConstraints { make in
+        backgroundView.snp.makeConstraints { make in

Also applies to: 30-51, 53-61


69-74: bind()는 사용되지 않고 있고, 더미 데이터 로딩 위치도 나중에 한 번 정리하는 게 좋겠습니다.

  • viewDidLoad에서 직접 fetchReport()를 호출하고 있고,
  • bind()에서도 다시 fetchReport()를 호출하지만, bind() 자체는 어디에서도 호출되지 않아 사실상 죽은 코드입니다.
  • 현재는 더미 데이터를 그려주는 용도라 문제는 없지만, ViewModel을 붙일 때 혼동을 줄이기 위해 지금부터 정리해 두면 좋겠습니다.

제안:

  1. 현재 단계
    • bind()는 삭제하고, viewDidLoadfetchReport()만 유지합니다.
-    private func bind() {
-        fetchReport()
-    }
  1. ViewModel 연결 시
    • fetchReport()의 더미 텍스트/사진 생성 로직은 ViewModel(or UseCase)로 옮기고,
    • 이 컨트롤러에서는 ViewModel output을 바인딩하는 메서드만 두는 방향이 깔끔해 보입니다.
    • TODO(// TODO: 추후 ViewModel로 옮기기)는 실제로 옮긴 시점에 제거해 주세요.

Also applies to: 174-176, 226-241


178-224: makeContentViewcontentLabel 초기화 패턴을 조금 정리하면 가독성이 좋아집니다.

현재는 임시 UILabel을 만들었다가 switch 안에서 다른 레이블로 계속 교체하고 있어, 실제로는 새 인스턴스가 사용되지 않습니다.

var contentLabel = UILabel()
contentLabel.text = " "
switch contentType {
case .title:
    contentLabel = titleLabel
...
}
contentView = contentLabel

아래처럼 let contentLabel + switch 패턴으로 변경하면 의도가 더 명확해 보입니다. 불필요한 " " 텍스트도 제거 가능합니다.

-        var contentView: UIView
-        if contentType == .photos {
-            contentView = photoStackView
-        } else {
-            var contentLabel = UILabel()
-            contentLabel.text = " "
-            switch contentType {
-            case .title:
-                contentLabel = titleLabel
-            case .category:
-                contentLabel = categoryLabel
-            case .location:
-                contentLabel = locationLabel
-            case .description:
-                contentLabel = descriptionLabel
-                contentLabel.numberOfLines = 0
-                contentTitleLabel.setContentHuggingPriority(.required, for: .horizontal)
-                descriptionLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
-            case .photos:
-                break
-            }
-            contentView = contentLabel
-        }
+        let contentView: UIView
+        if contentType == .photos {
+            contentView = photoStackView
+        } else {
+            let contentLabel: UILabel
+            switch contentType {
+            case .title:
+                contentLabel = titleLabel
+            case .category:
+                contentLabel = categoryLabel
+            case .location:
+                contentLabel = locationLabel
+            case .description:
+                contentLabel = descriptionLabel
+                contentLabel.numberOfLines = 0
+                contentTitleLabel.setContentHuggingPriority(.required, for: .horizontal)
+                descriptionLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
+            case .photos:
+                contentLabel = UILabel() // 이 case는 위 if에서 이미 처리되므로 도달하지 않음
+            }
+            contentView = contentLabel
+        }

(마지막 .photos case는 if contentType == .photos에서 이미 return되므로 실질적으로 도달하지 않지만, 컴파일러를 위해 최소 할당만 해 두는 식으로 정리할 수 있습니다.)


226-234: 제보 내용(descriptionLabel) 우측 정렬은 한 번 더 기획/디자인 확인이 필요해 보입니다.

descriptionLabel이 여러 줄 텍스트인데 아래처럼 .right 정렬로 설정되어 있습니다.

descriptionLabel.attributedText = BitnagilFont(style: .body1, weight: .medium)
    .attributedString(text: descriptionText, alignment: .right)

요약 카드 안에서 일반적으로는 본문 텍스트를 좌측 또는 자연 정렬로 두는 경우가 많아서, 다른 화면(예: ReportViewController의 입력 필드)과 비교했을 때도 UX적으로 다소 이질감이 있을 수 있습니다.

기획 방향이 좌측 정렬이라면 다음과 같이 조정하는 것이 좋겠습니다.

-        descriptionLabel.attributedText = BitnagilFont(style: .body1, weight: .medium)
-            .attributedString(text: descriptionText, alignment: .right)
+        descriptionLabel.attributedText = BitnagilFont(style: .body1, weight: .medium)
+            .attributedString(text: descriptionText, alignment: .left)

디자인 시안과 비교해서 정렬 방향만 한 번 더 확인 부탁드립니다.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f2486b3 and 9087750.

⛔ Files ignored due to path filters (12)
  • Projects/Presentation/Resources/Images.xcassets/Graphic/loading_fomo_graphic.imageset/loading_fomo_graphic.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/Graphic/loading_fomo_graphic.imageset/[email protected] is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/Graphic/loading_fomo_graphic.imageset/[email protected] is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/Graphic/success_fomo_graphic.imageset/success_fomo_graphic.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/Graphic/success_fomo_graphic.imageset/[email protected] is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/Graphic/success_fomo_graphic.imageset/[email protected] is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/Report/complete_icon.imageset/complete_icon.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/Report/complete_icon.imageset/[email protected] is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/Report/complete_icon.imageset/[email protected] is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/Report/loading_icon.imageset/loading_icon.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/Report/loading_icon.imageset/[email protected] is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/Report/loading_icon.imageset/[email protected] is excluded by !**/*.png
📒 Files selected for processing (10)
  • Projects/Presentation/Resources/Images.xcassets/Graphic/loading_fomo_graphic.imageset/Contents.json (1 hunks)
  • Projects/Presentation/Resources/Images.xcassets/Graphic/success_fomo_graphic.imageset/Contents.json (1 hunks)
  • Projects/Presentation/Resources/Images.xcassets/Report/complete_icon.imageset/Contents.json (1 hunks)
  • Projects/Presentation/Resources/Images.xcassets/Report/loading_icon.imageset/Contents.json (1 hunks)
  • Projects/Presentation/Sources/Common/DesignSystem/BitnagilGraphic.swift (2 hunks)
  • Projects/Presentation/Sources/Common/DesignSystem/BitnagilIcon.swift (1 hunks)
  • Projects/Presentation/Sources/Common/DesignSystem/Font/BitnagilFont.swift (1 hunks)
  • Projects/Presentation/Sources/Report/View/ReportCompleteViewController.swift (1 hunks)
  • Projects/Presentation/Sources/Report/View/ReportDetailViewController.swift (3 hunks)
  • Projects/Presentation/Sources/Report/View/ReportLoadingViewController.swift (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: choijungp
Repo: YAPP-Github/Bitnagil-iOS PR: 30
File: Projects/DataSource/Sources/NetworkService/Plugin/RefreshTokenPlugin.swift:42-43
Timestamp: 2025-07-30T03:56:18.617Z
Learning: choijungp는 현재 테스트 단계에서 RefreshTokenPlugin의 토큰 갱신 로직 디버깅을 위해 액세스 토큰과 리프레시 토큰의 실제 값을 로그에 기록하는 것을 선호함.
📚 Learning: 2025-08-17T13:30:29.342Z
Learnt from: taipaise
Repo: YAPP-Github/Bitnagil-iOS PR: 51
File: Projects/Presentation/Sources/Common/Component/RoutineCardView.swift:76-80
Timestamp: 2025-08-17T13:30:29.342Z
Learning: In SnapKit, even height constraints (intrinsic constraints) should be applied after adding the view to its superview hierarchy. While simple height constraints might work before adding to superview, it's not guaranteed and goes against best practices. The recommended approach is to call addArrangedSubview first, then apply constraints.

Applied to files:

  • Projects/Presentation/Sources/Report/View/ReportDetailViewController.swift
🧬 Code graph analysis (2)
Projects/Presentation/Sources/Report/View/ReportCompleteViewController.swift (3)
Projects/Presentation/Sources/Report/View/ReportLoadingViewController.swift (3)
  • viewDidLoad (25-29)
  • configureAttribute (40-54)
  • configureLayout (56-84)
Projects/Presentation/Sources/Common/DesignSystem/Font/BitnagilFont.swift (1)
  • attributedString (50-67)
Projects/Presentation/Sources/Report/View/ReportViewController.swift (1)
  • main (14-452)
Projects/Presentation/Sources/Report/View/ReportLoadingViewController.swift (2)
Projects/Presentation/Sources/Report/View/ReportCompleteViewController.swift (3)
  • viewDidLoad (69-74)
  • configureAttribute (76-106)
  • configureLayout (108-172)
Projects/Presentation/Sources/Common/DesignSystem/Font/BitnagilFont.swift (1)
  • attributedString (50-67)
🪛 SwiftLint (0.57.0)
Projects/Presentation/Sources/Report/View/ReportCompleteViewController.swift

[Warning] 226-226: TODOs should be resolved (추후 ViewModel로 옮기기)

(todo)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (15)
Projects/Presentation/Sources/Report/View/ReportDetailViewController.swift (4)

15-15: 매직 넘버를 상수로 추출한 것은 좋은 개선입니다.

코드 가독성과 유지보수성이 향상되었습니다.

Also applies to: 21-21


22-22: reportStatusViewTopSpacing 값 변경이 의도된 것인지 확인이 필요합니다.

AI 요약에 따르면 이 값이 74에서 20으로 크게 감소했습니다(73% 감소). 이는 상당히 큰 레이아웃 변경이므로 디자인 의도와 일치하는지 확인해 주세요.


102-103: scrollView의 bottom 제약 조건 변경을 확인해 주세요.

scrollView의 bottom이 이제 safeArea가 아닌 superview에 연결됩니다. 이는 scrollView가 하단 안전 영역(홈 인디케이터 영역 등) 아래까지 확장됨을 의미합니다. 의도된 변경이라면 문제없지만, 다음을 확인해 주세요:

  • 콘텐츠가 하단 안전 영역에 가려지지 않는지
  • contentInset이나 scrollIndicatorInsets 조정이 필요한지

131-131: 하드코딩된 값을 상수로 교체한 것은 좋은 개선입니다.

유지보수성이 향상되었습니다.

Projects/Presentation/Resources/Images.xcassets/Graphic/loading_fomo_graphic.imageset/Contents.json (1)

1-23: 에셋 카탈로그 구성이 올바릅니다.

표준 Xcode 에셋 카탈로그 형식으로 1x, 2x, 3x 이미지 variants가 올바르게 정의되어 있습니다.

Projects/Presentation/Sources/Common/DesignSystem/BitnagilIcon.swift (1)

84-85: 새로운 아이콘 추가가 적절합니다.

기존 패턴을 따라 loadingIconcompleteIcon이 올바르게 추가되었습니다.

Projects/Presentation/Resources/Images.xcassets/Graphic/success_fomo_graphic.imageset/Contents.json (1)

1-23: 에셋 카탈로그 구성이 올바릅니다.

표준 형식으로 success_fomo_graphic 이미지 에셋이 올바르게 정의되어 있습니다.

Projects/Presentation/Resources/Images.xcassets/Report/loading_icon.imageset/Contents.json (1)

1-23: 에셋 카탈로그 구성이 올바릅니다.

loading_icon 에셋이 표준 형식으로 올바르게 정의되어 있습니다.

Projects/Presentation/Resources/Images.xcassets/Report/complete_icon.imageset/Contents.json (1)

1-23: 에셋 카탈로그 구성이 올바릅니다.

complete_icon 에셋이 표준 형식으로 올바르게 정의되어 있습니다.

Projects/Presentation/Sources/Common/DesignSystem/BitnagilGraphic.swift (1)

61-63: 새로운 그래픽 에셋 추가가 적절합니다.

Report 섹션을 추가하고 loadingFomoGraphicsuccessFomoGraphic을 기존 패턴에 맞게 올바르게 정의했습니다.

Projects/Presentation/Sources/Report/View/ReportLoadingViewController.swift (2)

40-54: UI 구성이 잘 되어 있습니다.

레이아웃 상수 정의, 이미지 및 텍스트 설정이 깔끔하게 구현되었습니다. 디자인 시스템을 일관성 있게 활용하고 있습니다.


56-84: 레이아웃 구현이 적절합니다.

SnapKit을 사용한 Auto Layout 구성이 명확하고, safe area를 고려한 제약조건이 올바르게 설정되어 있습니다.

Projects/Presentation/Sources/Common/DesignSystem/Font/BitnagilFont.swift (1)

50-54: 텍스트 정렬 기능 추가가 좋습니다.

alignment 파라미터를 기본값과 함께 추가하여 기존 코드의 호환성을 유지하면서 텍스트 정렬 기능을 제공합니다. 새로운 제보 화면에서 중앙 정렬 텍스트를 구현하는 데 잘 활용되고 있습니다.

Projects/Presentation/Sources/Report/View/ReportCompleteViewController.swift (2)

76-106: 디자인 시스템과 일관된 attribute 설정이 잘 되어 있습니다.

폰트·컬러·라인 수 등 설정이 기존 ReportLoadingViewController와 톤이 맞고, 요약 섹션과 사진 스택뷰까지 역할이 명확하게 분리되어 있어 재사용성과 가독성이 좋습니다. 별다른 이슈는 없어 보입니다.


243-252: 사진 플레이스홀더 뷰 구성은 단순하고 이후 확장에도 좋아 보입니다.

고정 사이즈 + cornerRadius를 가진 뷰를 스택뷰에 얹는 구조라, 나중에 실제 썸네일 이미지를 입히거나 터치 이벤트를 추가하기에도 무난해 보입니다. 현재 형태로는 별다른 이슈는 없어 보입니다.

Comment on lines +67 to +68
private let confirmButton = PrimaryButton(buttonState: .default, buttonTitle: "확인")

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

확인 버튼에 액션이 없어 탭해도 아무 동작이 발생하지 않습니다.

confirmButton이 생성만 되고 .addAction / addTarget이 없어, 사용자 입장에서는 동작하지 않는 버튼처럼 보입니다. 제보 완료 후 이동 플로우(예: 이전 화면으로 pop, 루트로 이동 등)가 정해지는 대로 액션을 연결해 두는 것이 좋겠습니다.

예시:

     private func configureAttribute() {
         view.backgroundColor = .white
         scrollView.showsVerticalScrollIndicator = false
@@
-        photoStackView.axis = .horizontal
-        photoStackView.spacing = Layout.photoStackViewSpacing
+        photoStackView.axis = .horizontal
+        photoStackView.spacing = Layout.photoStackViewSpacing
+
+        confirmButton.addAction(
+            UIAction { [weak self] _ in
+                // TODO: 제보 완료 후 실제 플로우에 맞게 수정
+                self?.navigationController?.popViewController(animated: true)
+            },
+            for: .touchUpInside
+        )
     }

실제 요구사항(어디로 돌아가야 하는지)에 맞춰 동작만 조정해 주시면 될 것 같습니다.

Also applies to: 76-80, 167-171


🏁 Script executed:

#!/bin/bash
# Find and examine the ReportCompleteViewController.swift file
find . -type f -name "ReportCompleteViewController.swift" | head -20

Length of output: 78


🏁 Script executed:

#!/bin/bash
# Extract content around the specified lines (67-68, 76-80, 167-171)
if find . -type f -name "ReportCompleteViewController.swift" | head -1 | xargs grep -l "confirmButton"; then
  FILE=$(find . -type f -name "ReportCompleteViewController.swift" | head -1)
  echo "=== Lines 60-85 (around 67-68, 76-80) ==="
  sed -n '60,85p' "$FILE"
  echo ""
  echo "=== Lines 160-175 (around 167-171) ==="
  sed -n '160,175p' "$FILE"
  echo ""
  echo "=== Full file line count ==="
  wc -l "$FILE"
fi

Length of output: 1853


🏁 Script executed:

#!/bin/bash
# Search for all addAction and addTarget references to confirmButton
FILE=$(find . -type f -name "ReportCompleteViewController.swift" | head -1)
if [ -n "$FILE" ]; then
  echo "=== Searching for addAction/addTarget on confirmButton ==="
  grep -n -i "confirmButton.*addAction\|confirmButton.*addTarget\|addAction.*confirmButton\|addTarget.*confirmButton" "$FILE"
  echo ""
  echo "=== Total matches: $? (0 means found, 1 means not found) ==="
fi

Length of output: 119


🏁 Script executed:

#!/bin/bash
# Get the full content of the file to understand the context
FILE=$(find . -type f -name "ReportCompleteViewController.swift" | head -1)
if [ -n "$FILE" ]; then
  cat "$FILE"
fi

Length of output: 9290


confirmButton에 탭 액션이 없어 버튼이 동작하지 않습니다.

검증 결과, confirmButton은 68줄에서 생성되고 147줄에서 뷰 계층에 추가되지만, 파일 전체에서 .addAction() 또는 addTarget() 호출이 없습니다. 사용자가 버튼을 탭해도 아무 동작이 발생하지 않는 상태입니다.

configureAttribute() 메서드 또는 169줄의 bind() 메서드에 다음과 같이 액션을 추가하세요:

confirmButton.addAction(
    UIAction { [weak self] _ in
        // TODO: 제보 완료 후 실제 플로우에 맞게 수정
        self?.navigationController?.popViewController(animated: true)
    },
    for: .touchUpInside
)

실제 요구사항(이전 화면으로 pop, 루트로 이동 등)에 맞춰 동작을 조정하면 됩니다.

🤖 Prompt for AI Agents
In Projects/Presentation/Sources/Report/View/ReportCompleteViewController.swift
around lines 67–68, confirmButton is instantiated but never wired to a tap
handler so tapping does nothing; add a tap action in configureAttribute() or in
bind() that attaches a handler (use addAction with a UIAction capturing [weak
self] or addTarget(_:action:for:)) and invoke the appropriate navigation (e.g.
self?.navigationController?.popViewController(animated: true) or other
app-specific completion flow) to perform the required post-confirm behavior.

Comment on lines +108 to +172
private func configureLayout() {
let safeArea = view.safeAreaLayoutGuide

view.addSubview(scrollView)
scrollView.addSubview(contentView)

[completeImageView, completeLabel, subLabel, fomoImageView, backgroudView, confirmButton].forEach {
contentView.addSubview($0)
}

backgroudView.addSubview(summaryStackView)
summaryStackView.addArrangedSubview(summaryLabel)
ReportCompleteContent.allCases.forEach { reportCompleteContentType in
let contentStackView = makeContentView(contentType: reportCompleteContentType)
summaryStackView.addArrangedSubview(contentStackView)
}

scrollView.snp.makeConstraints { make in
make.edges.equalTo(safeArea)
}

contentView.snp.makeConstraints { make in
make.edges.equalTo(scrollView.contentLayoutGuide)
make.width.equalTo(scrollView.frameLayoutGuide)
}

completeImageView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(Layout.completeImageViewTopSpacing)
make.centerX.equalToSuperview()
make.size.equalTo(Layout.completeImageViewSize)
}

completeLabel.snp.makeConstraints { make in
make.top.equalTo(completeImageView.snp.bottom).offset(Layout.completeLabelTopSpacing)
make.centerX.equalToSuperview()
}

subLabel.snp.makeConstraints { make in
make.top.equalTo(completeLabel.snp.bottom).offset(Layout.subLableTopSpacing)
make.centerX.equalToSuperview()
}

fomoImageView.snp.makeConstraints { make in
make.top.equalTo(subLabel.snp.bottom).offset(Layout.fomoImageViewTopSpacing)
make.centerX.equalToSuperview()
}

backgroudView.snp.makeConstraints { make in
make.top.equalTo(fomoImageView).offset(Layout.backgroundViewTopSpacing)
make.horizontalEdges.equalToSuperview().inset(Layout.horizontalMargin)
make.bottom.equalTo(confirmButton.snp.top).offset(-Layout.backgroundViewBottomSpacing)
}

summaryStackView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(Layout.summaryStackViewTopSpacing)
make.horizontalEdges.equalToSuperview().inset(Layout.horizontalMargin)
make.bottom.equalToSuperview().offset(-Layout.summaryStackViewBottomSpacing)
}

confirmButton.snp.makeConstraints { make in
make.horizontalEdges.equalToSuperview().inset(Layout.horizontalMargin)
make.height.equalTo(Layout.confirmButtonHeight)
make.bottom.equalToSuperview().offset(-Layout.confirmButtonBottomSpacing)
}
}
Copy link

@coderabbitai coderabbitai bot Nov 19, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

backgroundView(backgroudView)의 top 제약이 FOMO 이미지의 top에 붙어 있어 의도보다 위에 붙을 수 있습니다.

지금은 다음과 같이 FOMO 이미지의 top 기준으로 오프셋을 주고 있습니다.

backgroudView.snp.makeConstraints { make in
    make.top.equalTo(fomoImageView).offset(Layout.backgroundViewTopSpacing)
    ...
}

디자인 상으로는 보통 FOMO 이미지의 하단에서부터 간격을 두는 게 자연스러워 보여, 아래처럼 fomoImageView.snp.bottom 기준으로 잡는 것이 맞아 보입니다.

-        backgroudView.snp.makeConstraints { make in
-            make.top.equalTo(fomoImageView).offset(Layout.backgroundViewTopSpacing)
+        backgroudView.snp.makeConstraints { make in
+            make.top.equalTo(fomoImageView.snp.bottom).offset(Layout.backgroundViewTopSpacing)
             make.horizontalEdges.equalToSuperview().inset(Layout.horizontalMargin)
             make.bottom.equalTo(confirmButton.snp.top).offset(-Layout.backgroundViewBottomSpacing)
         }

시뮬레이터에서 FOMO 이미지와 회색 배경 카드 사이 간격이 기획과 일치하는지 한 번만 더 확인 부탁드립니다.


제 도움이 필요합니다. 코드베이스를 검증하기 위해 몇 가지 확인이 필요합니다.


---

🏁 Script executed:

```shell
#!/bin/bash
# Examine the ReportCompleteViewController.swift file around the layout configuration
fd "ReportCompleteViewController.swift" --type f | head -1 | xargs -I {} sh -c '
  echo "=== File: {} ==="
  wc -l {}
  echo ""
  echo "=== Lines 100-180 (Layout context) ==="
  sed -n "100,180p" {}
  echo ""
  echo "=== Searching for Layout enum/constants ==="
  sed -n "1,300p" {} | grep -A 50 "enum Layout\|struct Layout"
'

Length of output: 5364


🏁 Script executed:

#!/bin/bash
# Search for Layout constants related to spacing and margins
rg "backgroundViewTopSpacing|backgroundViewBottomSpacing|fomoImageView" \
  --type swift -B 2 -A 2 | head -80

Length of output: 7055


🏁 Script executed:

#!/bin/bash
# Check if there are any design documents or comments about the layout
rg "FOMO|fomo|background.*spacing" --type swift -C 3 | head -100

Length of output: 10925



---

🏁 Script executed:

```shell
#!/bin/bash
# Check fomoImageView constraints and size
rg "fomoImageView.snp.makeConstraints" -A 5 --type swift

Length of output: 1370


fomoImageView의 하단이 아닌 상단에 제약이 연결되어 배경 뷰가 이미지와 겹칠 수 있습니다.

현재 코드는 FOMO 이미지의 상단(fomoImageView)을 기준으로 오프셋을 적용하고 있습니다. 하지만 fomoImageView는 이미지 뷰로서 실제 높이를 가지고 있기 때문에, 배경 뷰가 이미지와 겹치는 결과를 초래합니다.

// 현재 (문제)
backgroudView.snp.makeConstraints { make in
    make.top.equalTo(fomoImageView).offset(Layout.backgroundViewTopSpacing)
    ...
}

// 수정 필요
backgroudView.snp.makeConstraints { make in
    make.top.equalTo(fomoImageView.snp.bottom).offset(Layout.backgroundViewTopSpacing)
    ...
}

backgroundViewTopSpacing 값이 82pt(양수)인 점으로 보아 이미지 하단에서 간격을 두려는 의도가 명확하므로, fomoImageView.snp.bottom으로 수정하여 이미지 아래에 적절한 여백으로 배경 뷰를 배치해야 합니다.

🤖 Prompt for AI Agents
In Projects/Presentation/Sources/Report/View/ReportCompleteViewController.swift
around lines 108 to 172, the background view's top constraint is tied to the top
of fomoImageView which allows the background to overlap the image; change the
constraint to reference fomoImageView.snp.bottom with the same
Layout.backgroundViewTopSpacing so the background view is placed below the image
with the intended gap.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

겹치는것 댓츠 마이 의도

Copy link

Choose a reason for hiding this comment

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

@choijungp, 알겠습니다! 겹침이 의도된 디자인이라는 점 확인했습니다. 현재 레이아웃 구현이 올바르게 되어 있네요. 설명 감사합니다! 👍


✏️ Learnings added
Learnt from: choijungp
Repo: YAPP-Github/Bitnagil-iOS PR: 68
File: Projects/Presentation/Sources/Report/View/ReportCompleteViewController.swift:108-172
Timestamp: 2025-11-19T13:49:08.315Z
Learning: ReportCompleteViewController에서 backgroudView가 fomoImageView와 의도적으로 겹치도록 설계됨. 이를 위해 backgroudView의 top 제약을 fomoImageView.snp.top (또는 fomoImageView)을 기준으로 설정하여 오프셋을 적용함.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: choijungp
Repo: YAPP-Github/Bitnagil-iOS PR: 46
File: Projects/Presentation/Sources/Onboarding/View/OnboardingResultViewController.swift:139-144
Timestamp: 2025-08-13T10:59:57.531Z
Learning: OnboardingResultViewController에서 rectangleImageView가 resultGraphicView와 약간 겹치도록 의도된 레이아웃임. 겹침을 위해서는 inset 대신 offset에 음수 값을 사용하는 것이 더 의미상 적절함.

Learnt from: choijungp
Repo: YAPP-Github/Bitnagil-iOS PR: 19
File: Projects/Presentation/Sources/Login/View/TermsAgreementView.swift:44-46
Timestamp: 2025-07-16T09:09:13.869Z
Learning: BaseViewController의 viewDidLoad() 메서드에서 이미 configureAttribute(), configureLayout(), bind()를 호출하므로, 하위 클래스에서 super.viewDidLoad()를 호출하면 이 메서드들이 자동으로 호출된다. 따라서 하위 클래스에서 추가로 호출할 필요가 없다.

Learnt from: choijungp
Repo: YAPP-Github/Bitnagil-iOS PR: 19
File: Projects/Presentation/Sources/Login/View/TermsAgreementView.swift:44-46
Timestamp: 2025-07-16T09:09:13.869Z
Learning: BaseViewController의 viewDidLoad() 메서드에서 이미 configureAttribute(), configureLayout(), bind()를 호출하므로, 하위 클래스에서 super.viewDidLoad()를 호출하면 이 메서드들이 자동으로 호출된다. 따라서 하위 클래스에서 추가로 호출할 필요가 없다.

Learnt from: choijungp
Repo: YAPP-Github/Bitnagil-iOS PR: 30
File: Projects/DataSource/Sources/NetworkService/Plugin/RefreshTokenPlugin.swift:42-43
Timestamp: 2025-07-30T03:56:18.617Z
Learning: choijungp는 현재 테스트 단계에서 RefreshTokenPlugin의 토큰 갱신 로직 디버깅을 위해 액세스 토큰과 리프레시 토큰의 실제 값을 로그에 기록하는 것을 선호함.

Copy link
Collaborator

@taipaise taipaise left a comment

Choose a reason for hiding this comment

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

고생하셨습니다~! 평일에 최대한 빨리 뿌셔보겠습니다ㅏ

Copy link
Collaborator

Choose a reason for hiding this comment

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

아니 제 포모 키링 고리 부분 뿌러졌어요 ㅠ

Copy link
Contributor Author

Choose a reason for hiding this comment

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

쏘 샏 !!!!!!!!!!!!!!!

@taipaise
Copy link
Collaborator

  1. ViewModel과 제보 등록 API 시점
    제보 API를 쏘는 시점이 언제인지 결정하지 않았어서 일단 ViewModel 없이 만들었어유 !!!
    제 개인적인 의견은 ReportLoadingViewController의 didAppear 시점에 제보 api를 쏘는게 맞다구 생각함 ... (근데 여기서 실패하면 어쩌죠 ??)

저도 완벽하게 동의합니다요!!! 실패하면,, 플로우를 정해야할거 같은데 home으로 돌아가서 alert를 보여주거나, 사용자가 처음부터 다시 입력하는게 귀찮을 수 있으니 이전화면으로 돌아가는걸 고려해봐야할 것 같아요..!

@taipaise taipaise merged commit e7740ce into develop Nov 19, 2025
2 checks passed
@choijungp choijungp deleted the feat/report-complete branch November 20, 2025 06:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants