Skip to content

Conversation

@Rudy-009
Copy link
Contributor

@Rudy-009 Rudy-009 commented Jan 15, 2026

📌 Related Issue


📷 Screenshots

기능/화면 iPhone 11 Pro iPhone 16 Pro
UI MyReview iPhone 11 pro MyReview iPhone 17 pro

💬 To Reviewers

  • 리뷰어에게 전달하고 싶은 메시지를 남겨주세요.

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 사용자가 받은 후기를 만족도 지표 및 세부 정보와 함께 확인할 수 있는 새로운 후기 관리 화면 추가
    • 각 스포츠별 티어 진행 상황과 필요한 기술을 설명하는 새로운 티어 설명 화면 추가
  • UI/UX 개선

    • 새로운 아이콘 및 이미지 자산 추가
    • 초기 화면 네비게이션 개선
  • 기타

    • 내부 코드 정리 및 최적화

✏️ Tip: You can customize this high-level summary in your review settings.

@Rudy-009 Rudy-009 requested review from KuKaH and LJIN24 January 15, 2026 19:37
@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

받은 후기 UI 구현을 위한 뷰 컨트롤러, 셀, 칩 컴포넌트를 추가하고, 티어 설명 UI를 구성하며, SwiftUI 프리뷰 코드를 제거하고, 온보딩 뷰의 액션 프로퍼티 접근 제어를 변경합니다.

Changes

Cohort / File(s) 변경 사항
SwiftUI 프리뷰 제거
SMASHING/Global/Components/ComponentsTestViewController.swift, SMASHING/Presentation/MatchingManage/MatchingManageViewController.swift, SMASHING/Presentation/MatchingSearch/MatchingSearchViewController.swift, SMASHING/Presentation/Profile/ProfileViewController.swift, SMASHING/Presentation/ViewController.swift
SwiftUI import, @available 어노테이션, #Preview 블록 제거
후기 기본 컴포넌트
SMASHING/Presentation/Review/Cell/ReviewCollectionViewCell.swift, SMASHING/Presentation/Review/Cell/ReviewCountChip.swift, SMASHING/Presentation/Review/Cell/SatisfictionChip.swift
후기 표시용 셀 및 칩 컴포넌트 신규 작성 (프로필 이미지, 닉네임, 날짜, 콘텐츠, 카운트 표시)
후기 뷰 및 컨트롤러
SMASHING/Presentation/Review/MyReviewsView.swift, SMASHING/Presentation/Review/MyReviewsViewController.swift
받은 후기 표시 뷰 및 컨트롤러 신규 작성 (만족도, 빠른 후기, 후기 섹션)
티어 설명 UI
SMASHING/Presentation/TierExplanation/Cell/TierChipCell.swift, SMASHING/Presentation/TierExplanation/TierExplanationView.swift, SMASHING/Presentation/TierExplanation/TierExplanationViewController.swift
티어 칩, 설명 뷰, 컨트롤러 신규 작성 (tier 선택, 스킬 설명)
스킬 설명 셀
SMASHING/Presentation/Review/Cell/SkillExplanationCell.swift
스킬 설명 표시 컬렉션 뷰 셀 신규 작성
티어 및 리뷰 스코어 데이터 모델
SMASHING/Global/Enums/OreTier.swift, SMASHING/Global/Enums/ReviewScore.swift
OreTier 열거형 및 스포츠별 스킬 추가, ReviewScore에 displayText, imageLarge, imageSmall 프로퍼티 추가
UI 컴포넌트 확장
SMASHING/Global/Components/PaddingLabel.swift
패딩을 지원하는 UILabel 서브클래스 신규 작성
온보딩 뷰 액션 접근 제어 변경
SMASHING/Presentation/Onboarding/View/AreaSelectionView.swift, SMASHING/Presentation/Onboarding/View/GenderVIew.swift, SMASHING/Presentation/Onboarding/View/NicknameView.swift, SMASHING/Presentation/Onboarding/View/SportsSelectionView.swift, SMASHING/Presentation/Onboarding/View/TierSelectionView.swift
action 프로퍼티를 private에서 internal로 변경, configure 메서드 제거 또는 리팩토링
온보딩 초기화 및 MARK 추가
SMASHING/Presentation/Onboarding/Button/GenderButton.swift, SMASHING/Presentation/Onboarding/Button/SportsChip.swift, SMASHING/Presentation/Onboarding/Button/TierButton.swift, SMASHING/Presentation/Onboarding/View/OnboardView.swift
Setup Methods MARK 섹션 추가, nextAction 콜백 프로퍼티 추가
온보딩 뷰 컨트롤러 업데이트
SMASHING/Presentation/Onboarding/ViewController/AreaSelectionViewController.swift, SMASHING/Presentation/Onboarding/ViewController/GenderViewController.swift
configure(action:) 호출을 action 프로퍼티 접근으로 변경
네비게이션 및 셀 스타일 변경
SMASHING/Global/Coordinators/AppCoordinator.swift, SMASHING/Presentation/Home/Cell/MatchingCell.swift
초기 root VC를 MyReviewsViewController로 변경, 텍스트 색상 업데이트 (blue → muted, emphasis)
에셋 카탈로그
SMASHING/Global/Resource/Assets.xcassets/AppIcon.appiconset/Contents.json, SMASHING/Global/Resource/Colors.xcassets/Review/*
AppIcon 파일명 추가, 후기 관련 아이콘 에셋(thumbs_up, thumbs_down 등) 신규 추가

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 3
❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning PR 설명이 필수 섹션 중 'Work Description' 섹션이 누락되어 있으며, 구현된 기능에 대한 상세한 설명이 부족합니다. Work Description 섹션을 추가하여 구현한 기능과 핵심 내용을 요약해주세요. 예: 어떤 컴포넌트를 구현했는지, 동작 방식 등을 설명해주세요.
Out of Scope Changes check ⚠️ Warning PR에는 OreTier 열거형 추가, ReviewScore 속성 확장, TierExplanation 뷰 컨트롤러 구현 등 받은 후기 UI와 직접 관련되지 않은 변경사항들이 포함되어 있습니다. OreTier, TierExplanation 관련 변경사항이 issue #43의 범위에 포함되는지 확인하고, 필요시 별도의 PR로 분리하거나 설명을 추가해주세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목 '[feat] My Review UI 구현'은 변경 사항의 주요 내용인 My Review UI 구현을 명확하고 간결하게 요약합니다.
Linked Issues check ✅ Passed PR은 issue #43의 '받은 후기 UI 구현' 요구사항을 충족하며, 관련된 모든 UI 컴포넌트(MyReviewsView, ReviewCollectionViewCell, SatisfictionChip 등)가 구현되었습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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: 17

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
SMASHING/Presentation/Onboarding/View/NicknameView.swift (1)

56-64: checkButtonTapped 메서드에 수정이 필요합니다.

  1. 오타: Line 57의 주석에서 acrionaction이어야 합니다.
  2. 로직 오류: 성공 메시지와 실패 메시지가 순차적으로 모두 설정되고 있어, 마지막에 설정된 에러 메시지만 표시됩니다.

실제 중복 확인 API 연동 전 placeholder 코드로 보이지만, 조건 분기가 필요합니다.

🔧 제안하는 수정 사항
 `@objc` func checkButtonTapped() {
-    // acrion?()
-    // 성공한 경우
-    nicknameTextField.setMessage(message: "사용 가능한 닉네임입니다")
-    // + 키보드 해제
-    
-    // 실패한 경우
-    nicknameTextField.setError(message: "이미 존재하는 닉네임이에요")
+    // TODO: API 연동 후 조건에 따라 분기 처리 필요
+    action?()
+    
+    // 예시: 성공/실패 분기
+    // if isAvailable {
+    //     nicknameTextField.setMessage(message: "사용 가능한 닉네임입니다")
+    // } else {
+    //     nicknameTextField.setError(message: "이미 존재하는 닉네임이에요")
+    // }
 }
🤖 Fix all issues with AI agents
In `@SMASHING/Global/Components/PaddingLabel.swift`:
- Around line 14-19: The edgeInset property should trigger layout updates and
drawText should avoid recreating UIEdgeInsets; add a didSet on the edgeInset
variable to call invalidateIntrinsicContentSize() (and
setNeedsDisplay()/setNeedsLayout() if needed) so the layout refreshes when
edgeInset changes, and in the drawText(in:) method use the existing edgeInset
directly instead of creating a new UIEdgeInsets instance (referencing the
edgeInset property and the drawText(in:) override).

In `@SMASHING/Presentation/Onboarding/View/TierSelectionView.swift`:
- Around line 17-18: Remove the unused nextAction property from
TierSelectionView: delete the declaration "var nextAction: (() -> Void)?",
search for and remove any assignments or invocations of nextAction (including in
TierSelectionViewController or other callers), and ensure the view and
controller rely only on the existing action: ((Tier) -> Void)? property; then
run the build/tests to confirm no remaining references.

In
`@SMASHING/Presentation/Onboarding/ViewController/AreaSelectionViewController.swift`:
- Around line 26-28: The configure(action:) method in
AreaSelectionViewController does not assign the passed closure to the view, it
only reads areaSelectionView.action; fix by assigning the incoming action to the
view's action property (i.e., set areaSelectionView.action = action) inside
configure(action:), ensuring the view's callback is invoked when the address
button is tapped.

In `@SMASHING/Presentation/Onboarding/ViewController/GenderViewController.swift`:
- Around line 28-30: The configure(action: `@escaping` (Gender) -> Void) method
fails to assign the passed-in callback to the view, so selection events never
trigger; update the configure method in GenderViewController to set
genderView.action = action (or otherwise assign the incoming closure to the
view’s action property) so that selections call the provided callback, mirroring
the fix used in AreaSelectionViewController.

In `@SMASHING/Presentation/Review/Cell/ReviewCollectionViewCell.swift`:
- Line 101: 함수 시그니처 configure(_ review :TempReview) 에서 매개변수 타입 앞에 불필요한 공백이 있으니
수정하세요; 정확히는 configure(_ review : TempReview) 또는 Swift 스타일 가이드에 맞게 configure(_
review: TempReview)로 콜론 앞의 공백을 제거하여 함수 시그니처(메서드 이름 configure(_:))를 정리하면 됩니다.

In `@SMASHING/Presentation/Review/Cell/SatisfictionChip.swift`:
- Line 13: Rename the class SatisfictionChip to SatisfactionChip and update the
filename to SatisfactionChip.swift; change the class declaration (final class
SatisfictionChip: BaseUIView) to final class SatisfactionChip: BaseUIView and
update all references/usages (initializers, nib/storyboard identifiers, imports,
tests, and any factory or registration code) to the new symbol name so builds
and runtime lookups continue to work.

In `@SMASHING/Presentation/Review/MyReviewsView.swift`:
- Line 17: MyReviewsView declares an unused closure property backAction which
should be either removed or wired to the view's back button; locate the private
var backAction: (() -> Void)? in MyReviewsView and either delete the property
and any unused references, or hook it up by accepting it via initializer or a
setter and invoking it from the navigation/back button action (e.g., call
backAction?() inside the button's action or replace with a dedicated onBack()
method) so the property is actually used.

In `@SMASHING/Presentation/Review/MyReviewsViewController.swift`:
- Around line 58-71: In collectionView(_:cellForItemAt:) you’re adding width
constraints each reuse which causes conflicts; remove the
contentView.snp.makeConstraints call from cellForItemAt and instead set the
width constraint once inside ReviewCollectionViewCell (e.g., in
init/awakeFromNib) or compute the cell width in
UICollectionViewDelegateFlowLayout’s sizeForItemAt; also replace the current
dequeue call with the project’s type-safe dequeueReusableCell<T> extension to
simplify casting and use ReviewCollectionViewCell.reuseIdentifier and
mockReviews[indexPath.item] as the data source.

In `@SMASHING/Presentation/TierExplanation/Cell/TierChipCell.swift`:
- Around line 30-36: Initial UI sets layer.borderColor and label text color to
.Text.secondary while deselected() sets them to .Text.primary, causing
inconsistency; fix by making the initial state match deselected() — either
change the borderColor and label.textColor assignments in setUI() to
.Text.primary or call deselected() at the end of setUI() so the view starts in
the same state; update references in setUI(), deselected(), and the label
initialization to ensure label.textColor and layer.borderColor are consistent.

In `@SMASHING/Presentation/TierExplanation/TierExplanationView.swift`:
- Line 15: Update the MARK comment formatting in TierExplanationView.swift by
replacing occurrences of "//MARK:" with the correct SwiftLint-approved "//
MARK:" spacing; specifically fix the Properties marker ("// MARK: - Properties")
and the other MARK comments noted (near the "Properties" and the marker at the
end of the file around the view/section declarations, including the marker at
line ~102) so all markers follow "// MARK:". Ensure each corrected marker uses a
single space after // and before MARK.
- Around line 1-6: Update the file header comment to reflect the actual filename
and author info: replace the incorrect "File.swift" entry with
"TierExplanationView.swift" in the top-of-file comment block (the header above
the TierExplanationView declaration) and ensure any date/author lines remain
accurate; locate the header by finding the TierExplanationView type
(struct/class/UIView) to confirm you're editing the correct file.
- Around line 87-100: The collection view configuration in
tierExplanationCollectionView sets showsHorizontalScrollIndicator while the
layout.scrollDirection is .vertical; change the indicator property to
showsVerticalScrollIndicator on the UICollectionView instance to correctly
reflect vertical scrolling (locate the closure that creates
tierExplanationCollectionView and replace the showsHorizontalScrollIndicator
assignment with showsVerticalScrollIndicator).
- Around line 81-85: Rename the UILabel property recomandationLabel to
recommendationLabel and update every reference to it across the file/class
(e.g., any uses in TierExplanationView, constraints, and view setup code).
Ensure the declaration private let recomandationLabel = ... becomes private let
recommendationLabel = ... and update any property accesses, IBOutlets/usages,
and tests to the new identifier so the code compiles.
- Around line 17-24: navigationBar currently captures dismissAction's value at
init via dismissAction ?? {}, so later updates to dismissAction won't be used;
modify the navigationBar setup to invoke the latest dismissAction by providing a
closure that calls self?.dismissAction?() (e.g. setRightButton(image:
UIImage.icCloseLg, action: { [weak self] in self?.dismissAction?() })) or
alternatively implement dismissAction's didSet to call
navigationBar.setRightButton(...) with the new action; update references to
CustomNavigationBar.setRightButton and the dismissAction property accordingly.

In `@SMASHING/Presentation/TierExplanation/TierExplanationViewController.swift`:
- Around line 1-6: 헤더 주석의 파일명이 실제 파일명과 일치하지 않습니다; 업데이트할 때
TierExplanationViewController.swift 파일 상단의 comment(현재
"TierExplanationView.swift")를 실제 파일명인 "TierExplanationViewController.swift"로
바꾸고, 클래스/struct 선언인 TierExplanationViewController 및 관련 타입 이름과 일관되도록 파일 설명(작성자/날짜
등)이 필요하면 함께 갱신하세요.
- Around line 54-60: The collection count is hardcoded to use OreTier.diamond
and tableTennis; update numberOfItemsInSection (in function
collectionView(_:numberOfItemsInSection:)) so the else branch returns the
currently selected tier's skills for the currently selected sport instead of a
hardcoded value—use the view controller's selected oreTier and sports properties
(e.g., oreTier.skills(sports: sports)) or safely unwrap/guard them when
computing the count for
tierExplanationCollectionView/mainView.tierExplanationCollectionView.
- Around line 72-79: In cellForItemAt, remove the call that adds constraints to
the cell each dequeue (the block using cell.contentView.snp.makeConstraints)
because it causes duplicate constraints on reuse; instead either rely on
sizeForItemAt to provide the cell sizing or move a one-time constraint setup
into SkillExplanationCell (e.g., in its initializer/awakeFromNib or a setup
method with a guard like `didSetupConstraints`) so constraints are only added
once for SkillExplanationCell and not inside collectionView.dequeueReusableCell
in cellForItemAt.
🧹 Nitpick comments (15)
SMASHING/Global/Components/PaddingLabel.swift (2)

10-11: 사용하지 않는 import 제거를 권장합니다.

SnapKitThen이 import되어 있지만 이 파일에서 사용되지 않습니다.

♻️ 제안하는 수정
 import UIKit
-
-import SnapKit
-import Then

21-25: sizeThatFits(_:) 오버라이드 추가를 권장합니다.

intrinsicContentSize만 오버라이드하면 sizeToFit() 호출 시 패딩이 적용되지 않을 수 있습니다. 완전한 Auto Layout 지원을 위해 sizeThatFits(_:)도 오버라이드하는 것이 좋습니다.

♻️ 제안하는 수정
     override var intrinsicContentSize: CGSize {
         let size = super.intrinsicContentSize
         return CGSize(width: size.width + edgeInset.left + edgeInset.right,
                       height: size.height + edgeInset.top + edgeInset.bottom)
     }
+    
+    override func sizeThatFits(_ size: CGSize) -> CGSize {
+        let superSize = super.sizeThatFits(size)
+        return CGSize(width: superSize.width + edgeInset.left + edgeInset.right,
+                      height: superSize.height + edgeInset.top + edgeInset.bottom)
+    }
 }
SMASHING/Global/Resource/Assets.xcassets/AppIcon.appiconset/Contents.json (1)

4-4: 파일명 컨벤션 개선 권장

파일명에 공백이 포함되어 있습니다 ("logo-black 1.png", "logo-black 2.png", "logo-black 3.png"). 공백 대신 하이픈이나 언더스코어를 사용하는 것이 더 안전합니다 (예: "logo-black-1.png", "logo-black_1.png").

♻️ 권장하는 파일명 형식
-      "filename" : "logo-black 1.png",
+      "filename" : "logo-black-1.png",
-      "filename" : "logo-black 2.png",
+      "filename" : "logo-black-2.png",
-      "filename" : "logo-black 3.png",
+      "filename" : "logo-black-3.png",

Also applies to: 16-16, 28-28

SMASHING/Presentation/Onboarding/View/SportsSelectionView.swift (2)

17-17: 접근 제어자 변경은 적절하나, configure(action:) 메서드가 중복됩니다.

action 프로퍼티가 internal로 변경되어 외부에서 직접 할당이 가능해졌습니다. AI 요약에 따르면 다른 온보딩 뷰들(GenderView, NicknameView 등)은 configure(action:) 메서드를 제거하고 직접 할당 방식으로 전환했습니다. 일관성을 위해 이 파일에서도 해당 메서드 제거를 고려해주세요.

♻️ 제안된 수정
-    func configure(action: `@escaping` (Sports) -> Void) {
-        self.action = action
-    }

Also applies to: 59-61


77-79: Mirror 리플렉션 사용은 취약한 패턴입니다.

SportsChipsport 프로퍼티에 접근하기 위해 리플렉션을 사용하고 있습니다. 프로퍼티 이름이 변경되면 런타임에 조용히 실패할 수 있어 유지보수에 취약합니다. SportsChip에서 sport 프로퍼티를 직접 노출하는 것이 더 안전합니다.

♻️ 제안된 수정

SportsChip에 public 접근자 추가:

// SportsChip.swift
let sport: Sports // internal 또는 public으로 노출

그 후 getSport(from:) 메서드 간소화:

-    private func getSport(from chip: SportsChip) -> Sports? {
-        return Mirror(reflecting: chip).children.first(where: { $0.label == "sport" })?.value as? Sports
-    }
+    private func getSport(from chip: SportsChip) -> Sports {
+        return chip.sport
+    }

또는 메서드 자체를 제거하고 chipTapped에서 직접 접근:

     `@objc` private func chipTapped(_ sender: UITapGestureRecognizer) {
         guard let selectedChip = sender.view as? SportsChip else { return }
         
         chips.forEach { $0.isSelected = ($0 === selectedChip) }
         
-        if let sport = getSport(from: selectedChip) {
-            action?(sport)
-        }
+        action?(selectedChip.sport)
     }
SMASHING/Presentation/Review/Cell/SatisfictionChip.swift (1)

55-58: cornerRadius와 높이 불일치

contentStackView의 높이가 24이고 상하 inset이 10씩이므로 전체 높이는 44가 됩니다. 완전한 pill 모양을 위해서는 cornerRadius를 22 (44/2)로 설정해야 합니다.

♻️ 수정 제안
 private func setupAttributes() {
-    self.layer.cornerRadius = 20
+    self.layer.cornerRadius = 22
     self.imageView.image = review.imageSmall
 }

Also applies to: 65-70

SMASHING/Presentation/Review/Cell/ReviewCountChip.swift (3)

17-17: reviewTag 접근 제어 수준 검토

reviewTagvar로 외부에 노출되어 있습니다. 외부에서 직접 수정하는 것을 방지하려면 private(set)을 사용하는 것이 좋습니다.

♻️ 수정 제안
-    var reviewTag: ReviewTag?
+    private(set) var reviewTag: ReviewTag?

68-72: 텍스트에 공백 추가 방식 개선

displayText + " " 로 공백을 추가하는 것보다 UIStackViewspacing을 활용하는 것이 더 깔끔합니다. 이미 spacing = 8이 설정되어 있으므로 추가 공백은 불필요해 보입니다.

♻️ 수정 제안
 func configure(with reviewTag: ReviewTag, count: Int) {
     self.reviewTag = reviewTag
-    titleLabel.text = reviewTag.displayText + " "
+    titleLabel.text = reviewTag.displayText
     subLabel.text = "\(count)"
 }

49-53: cornerRadius와 높이 불일치 (SatisfictionChip과 동일)

SatisfictionChip과 마찬가지로 총 높이 44에 대해 cornerRadius가 20으로 설정되어 있습니다. 일관된 pill 모양을 위해 22로 수정을 고려해주세요.

Also applies to: 60-66

SMASHING/Presentation/Review/Cell/ReviewCollectionViewCell.swift (1)

46-54: prepareForReuse 구현 고려

UICollectionViewCell을 재사용할 때 이전 데이터가 잠시 보일 수 있습니다. prepareForReuse를 오버라이드하여 레이블과 이미지를 초기화하는 것을 권장합니다.

♻️ 추가 코드 제안
override func prepareForReuse() {
    super.prepareForReuse()
    profileImageView.image = nil
    nicknameLabel.text = nil
    dateLabel.text = nil
    contentLabel.text = nil
}
SMASHING/Presentation/Review/MyReviewsViewController.swift (1)

13-17: 임시 데이터 모델 위치 고려 필요

TempReview가 파일 스코프에 정의되어 있습니다. 임시 데이터 모델임을 명확히 하기 위해 별도의 Mock 폴더로 이동하거나, 추후 실제 데이터 모델로 교체될 것임을 주석으로 명시하는 것을 권장합니다.

SMASHING/Presentation/Review/MyReviewsView.swift (2)

97-100: Int.random 사용으로 인한 비결정적 UI

만족도 칩에 Int.random을 사용하면 앱 실행마다 다른 값이 표시됩니다. Mock 데이터라도 일관된 값을 사용하면 UI 테스트 및 스크린샷 비교가 용이합니다.

♻️ 고정 mock 값 사용 제안
-        [ReviewScore.best, .good, .bad].forEach { review in
-            let chip = SatisfictionChip(review: review, num: Int.random(in: 0...150))
-            satisfactionStackView.addArrangedSubview(chip)
-        }
+        let mockSatisfactionData: [(ReviewScore, Int)] = [(.best, 85), (.good, 42), (.bad, 3)]
+        mockSatisfactionData.forEach { (review, num) in
+            let chip = SatisfictionChip(review: review, num: num)
+            satisfactionStackView.addArrangedSubview(chip)
+        }

148-161: configure 메서드 개선 가능

현재 구현도 동작하지만, dictionary의 key를 순회하면서 다시 접근하는 방식은 약간 비효율적입니다.

♻️ 간결한 방식 제안
 func configure(_ data: [ReviewTag: Int]) {
-    for key in data.keys {
-        let count = data[key] ?? 0
-        switch key {
-        case .goodManner:
-            goodMannerCountChip.updateCount(count)
-        case .onTime:
-            onTimeCountChip.updateCount(count)
-        case .fairPlay:
-            fairPlayCountChip.updateCount(count)
-        case .fastResponse:
-            fastResponseCountChip.updateCount(count)
-        }
-    }
+    for (tag, count) in data {
+        switch tag {
+        case .goodManner:
+            goodMannerCountChip.updateCount(count)
+        case .onTime:
+            onTimeCountChip.updateCount(count)
+        case .fairPlay:
+            fairPlayCountChip.updateCount(count)
+        case .fastResponse:
+            fastResponseCountChip.updateCount(count)
+        }
+    }
 }
SMASHING/Global/Enums/OreTier.swift (1)

58-75: index 프로퍼티를 CaseIterable을 활용하여 단순화할 수 있습니다.

OreTier가 이미 CaseIterable을 준수하고 있으므로, 수동 switch 문 대신 allCases를 사용하면 유지보수가 더 용이합니다.

♻️ 제안된 리팩토링
 var index: Int {
-    switch self {
-    case .iron:
-        return 0
-    case .bronze:
-        return 1
-    case .silver:
-        return 2
-    case .gold:
-        return 3
-    case .platinum:
-        return 4
-    case .diamond:
-        return 5
-    case .challenger:
-        return 6
-    }
+    return Self.allCases.firstIndex(of: self) ?? 0
 }
SMASHING/Presentation/TierExplanation/TierExplanationViewController.swift (1)

14-17: sports 속성이 하드코딩되어 있어 다른 종목을 지원할 수 없습니다.

현재 sports.tableTennis로 고정되어 있습니다. 다양한 종목을 지원하려면 초기화 시 주입받거나 설정 메서드를 추가하는 것이 좋습니다.

♻️ 주입 방식 제안
 final class TierExplanationViewController: BaseViewController {
     
     private let mainView = TierExplanationView()
-    private var sports: Sports = .tableTennis
+    private let sports: Sports
     private var oreTier: OreTier = .bronze
+    
+    init(sports: Sports) {
+        self.sports = sports
+        super.init(nibName: nil, bundle: nil)
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73edb99 and 836a07d.

⛔ Files ignored due to path filters (9)
  • SMASHING/Global/Resource/Assets.xcassets/AppIcon.appiconset/logo-black 1.png is excluded by !**/*.png
  • SMASHING/Global/Resource/Assets.xcassets/AppIcon.appiconset/logo-black 2.png is excluded by !**/*.png
  • SMASHING/Global/Resource/Assets.xcassets/AppIcon.appiconset/logo-black 3.png is excluded by !**/*.png
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_down.imageset/ic_thumbs_down.pdf is excluded by !**/*.pdf
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_down_lg.imageset/ic_thumbs_down_lg.pdf is excluded by !**/*.pdf
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up.imageset/ic_thumbs_up.pdf is excluded by !**/*.pdf
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up_double.imageset/ic_thumbs_up_double.pdf is excluded by !**/*.pdf
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up_double_lg.imageset/ic_thumbs_up_double_lg.pdf is excluded by !**/*.pdf
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up_lg.imageset/ic_thumbs_up_lg.pdf is excluded by !**/*.pdf
📒 Files selected for processing (38)
  • SMASHING/Global/Components/ComponentsTestViewController.swift
  • SMASHING/Global/Components/PaddingLabel.swift
  • SMASHING/Global/Coordinators/AppCoordinator.swift
  • SMASHING/Global/Enums/OreTier.swift
  • SMASHING/Global/Enums/ReviewScore.swift
  • SMASHING/Global/Resource/Assets.xcassets/AppIcon.appiconset/Contents.json
  • SMASHING/Global/Resource/Colors.xcassets/Review/Contents.json
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_down.imageset/Contents.json
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_down_lg.imageset/Contents.json
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up.imageset/Contents.json
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up_double.imageset/Contents.json
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up_double_lg.imageset/Contents.json
  • SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up_lg.imageset/Contents.json
  • SMASHING/Presentation/Home/Cell/MatchingCell.swift
  • SMASHING/Presentation/MatchingManage/MatchingManageViewController.swift
  • SMASHING/Presentation/MatchingSearch/MatchingSearchViewController.swift
  • SMASHING/Presentation/Onboarding/Button/GenderButton.swift
  • SMASHING/Presentation/Onboarding/Button/SportsChip.swift
  • SMASHING/Presentation/Onboarding/Button/TierButton.swift
  • SMASHING/Presentation/Onboarding/View/AreaSelectionView.swift
  • SMASHING/Presentation/Onboarding/View/GenderVIew.swift
  • SMASHING/Presentation/Onboarding/View/NicknameView.swift
  • SMASHING/Presentation/Onboarding/View/OnboardView.swift
  • SMASHING/Presentation/Onboarding/View/SportsSelectionView.swift
  • SMASHING/Presentation/Onboarding/View/TierSelectionView.swift
  • SMASHING/Presentation/Onboarding/ViewController/AreaSelectionViewController.swift
  • SMASHING/Presentation/Onboarding/ViewController/GenderViewController.swift
  • SMASHING/Presentation/Profile/ProfileViewController.swift
  • SMASHING/Presentation/Review/Cell/ReviewCollectionViewCell.swift
  • SMASHING/Presentation/Review/Cell/ReviewCountChip.swift
  • SMASHING/Presentation/Review/Cell/SatisfictionChip.swift
  • SMASHING/Presentation/Review/Cell/SkillExplanationCell.swift
  • SMASHING/Presentation/Review/MyReviewsView.swift
  • SMASHING/Presentation/Review/MyReviewsViewController.swift
  • SMASHING/Presentation/TierExplanation/Cell/TierChipCell.swift
  • SMASHING/Presentation/TierExplanation/TierExplanationView.swift
  • SMASHING/Presentation/TierExplanation/TierExplanationViewController.swift
  • SMASHING/Presentation/ViewController.swift
💤 Files with no reviewable changes (5)
  • SMASHING/Presentation/MatchingManage/MatchingManageViewController.swift
  • SMASHING/Presentation/MatchingSearch/MatchingSearchViewController.swift
  • SMASHING/Presentation/ViewController.swift
  • SMASHING/Presentation/Profile/ProfileViewController.swift
  • SMASHING/Global/Components/ComponentsTestViewController.swift
🧰 Additional context used
🧬 Code graph analysis (4)
SMASHING/Presentation/TierExplanation/TierExplanationViewController.swift (6)
SMASHING/Presentation/TierExplanation/Cell/TierChipCell.swift (3)
  • configure (58-60)
  • selected (46-50)
  • deselected (52-56)
SMASHING/Presentation/Review/Cell/SkillExplanationCell.swift (1)
  • configure (60-63)
SMASHING/Presentation/TierExplanation/TierExplanationView.swift (1)
  • configure (151-155)
SMASHING/Global/Extensions/UIFont+.swift (1)
  • pretendard (21-24)
SMASHING/Global/Enums/OreTier.swift (1)
  • skills (17-26)
SMASHING/Global/Extensions/UICollectionView+.swift (1)
  • dequeueReusableCell (32-43)
SMASHING/Presentation/Review/Cell/ReviewCollectionViewCell.swift (2)
SMASHING/Global/Extensions/UIFont+.swift (1)
  • pretendard (21-24)
SMASHING/Global/Extensions/UIView+.swift (1)
  • addSubviews (12-16)
SMASHING/Presentation/TierExplanation/Cell/TierChipCell.swift (2)
SMASHING/Presentation/Onboarding/View/TierSelectionView.swift (1)
  • configure (57-59)
SMASHING/Presentation/TierExplanation/TierExplanationView.swift (1)
  • configure (151-155)
SMASHING/Presentation/Review/MyReviewsViewController.swift (2)
SMASHING/Presentation/Review/MyReviewsView.swift (1)
  • configure (148-162)
SMASHING/Global/Extensions/UICollectionView+.swift (1)
  • dequeueReusableCell (32-43)
🪛 SwiftLint (0.57.0)
SMASHING/Presentation/TierExplanation/TierExplanationView.swift

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

(mark)


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

(mark)


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

(mark)

🔇 Additional comments (34)
SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up_double_lg.imageset/Contents.json (1)

1-12: LGTM!

에셋 카탈로그 설정이 올바르게 구성되어 있습니다. PDF 벡터 에셋에 "universal" idiom을 사용하여 자동 스케일링을 지원하며, 파일명이 imageset 폴더명과 일치합니다.

SMASHING/Presentation/Home/Cell/MatchingCell.swift (4)

30-35: 닉네임 텍스트 색상 변경 확인

myNickNamerivalNickName(Line 56)이 모두 .Text.muted로 일관되게 변경되어 디자인 통일성이 유지됩니다.


37-40: 포맷팅 변경 - 기능적 영향 없음

코드 포맷팅만 변경되었으며 기능적 영향은 없습니다.


53-58: 일관된 스타일 적용

myNickName과 동일하게 .Text.muted 색상이 적용되어 양측 닉네임의 시각적 일관성이 유지됩니다.


60-66: 버튼 텍스트 색상 변경 승인

.Text.emphasis로 변경하여 CTA 버튼의 시각적 강조가 개선되었습니다. .Button.backgroundPrimaryActive 배경색과의 대비가 접근성 기준(WCAG)을 충족하는지 확인해 주세요.

SMASHING/Global/Resource/Colors.xcassets/Review/Contents.json (1)

1-6: LGTM!

Review 에셋 카탈로그 폴더를 위한 표준 Xcode 메타데이터 파일입니다. 구조가 올바르게 작성되었습니다.

SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up_lg.imageset/Contents.json (1)

1-12: LGTM!

벡터 에셋을 위한 PDF 형식 사용은 다양한 화면 크기에서 선명한 렌더링을 보장하는 좋은 방식입니다. 에셋 카탈로그 구조가 올바릅니다.

SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_down.imageset/Contents.json (1)

1-12: LGTM!

표준 Xcode 에셋 카탈로그 메타데이터 구조를 따르고 있으며, 다른 리뷰 관련 아이콘 에셋들과 일관성 있게 작성되었습니다.

SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up.imageset/Contents.json (1)

1-12: LGTM!

ic_thumbs_up 에셋에 대한 올바른 메타데이터 구성입니다. 네이밍 컨벤션이 다른 thumbs 아이콘들과 일관성 있게 유지되고 있습니다.

SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_down_lg.imageset/Contents.json (1)

1-12: LGTM!

리뷰 기능을 위한 thumbs 아이콘 세트(up/down, 일반/대형)가 일관된 구조로 완성되었습니다. 모든 에셋 카탈로그 파일이 표준 형식을 따르고 있습니다.

SMASHING/Global/Resource/Colors.xcassets/Review/ic_thumbs_up_double.imageset/Contents.json (1)

1-12: LGTM! 애셋 카탈로그 구조가 올바릅니다.

Xcode 애셋 카탈로그의 표준 형식을 따르고 있으며, JSON 구조가 정확합니다. PDF 파일 참조를 통한 벡터 이미지 사용도 적절합니다.

SMASHING/Global/Resource/Assets.xcassets/AppIcon.appiconset/Contents.json (3)

1-38: PR 목적과 불일치하는 변경사항

이 PR은 "받은 후기 UI 구현"을 목적으로 하고 있으나, 이 파일은 앱 아이콘 에셋을 변경하고 있습니다. My Review UI 기능과 관련 없는 앱 아이콘 변경이 포함된 이유를 확인해주세요.


16-16: 다크 모드 아이콘 에셋 확인 필요

다크 모드(dark appearance)에 "logo-black 2.png"를 사용하고 있습니다. 일반적으로 다크 모드에서는 밝은 색상의 로고를 사용하는데, "logo-black"이라는 이름이 의도한 에셋이 맞는지 확인해주세요.


4-4: 모든 이미지 파일이 정상적으로 존재합니다

검증 결과, Contents.json에서 참조하는 세 개의 이미지 파일이 모두 에셋 카탈로그 디렉토리에 존재합니다:

  • logo-black 1.png (줄 4)
  • logo-black 2.png (줄 16)
  • logo-black 3.png (줄 28)

파일 경로와 파일명이 모두 정확하게 일치하므로, 해당 파일들이 빌드 시 정상적으로 참조될 것입니다.

Likely an incorrect or invalid review comment.

SMASHING/Presentation/Onboarding/Button/GenderButton.swift (1)

51-52: LGTM!

코드 구조화를 위한 MARK 주석 추가입니다. 다른 온보딩 버튼 컴포넌트(TierButton, SportsChip)와 일관된 패턴을 유지하고 있습니다.

SMASHING/Presentation/Onboarding/Button/TierButton.swift (1)

55-56: LGTM!

GenderButton과 동일하게 // MARK: - Setup Methods 주석을 추가하여 코드 구조를 일관되게 유지하고 있습니다.

SMASHING/Presentation/Onboarding/Button/SportsChip.swift (1)

51-52: LGTM!

세 개의 버튼 컴포넌트(GenderButton, TierButton, SportsChip) 모두 동일한 MARK 주석 패턴을 적용하여 코드베이스 전반의 일관성을 유지하고 있습니다.

SMASHING/Presentation/Onboarding/View/NicknameView.swift (1)

17-17: LGTM!

action 프로퍼티를 internal로 변경하여 외부에서 직접 설정할 수 있게 했습니다. 다른 온보딩 뷰 컴포넌트(AreaSelectionView, GenderView, SportsSelectionView 등)와 일관된 패턴입니다.

SMASHING/Presentation/Onboarding/View/OnboardView.swift (1)

15-18: LGTM!

nextAction 콜백을 선택적 프로퍼티로 노출하고, lazy var를 사용하여 self 캡처 문제를 올바르게 처리했습니다. 버튼 초기화 시점에 클로저 내에서 self를 안전하게 참조할 수 있습니다.

Also applies to: 46-48

SMASHING/Presentation/Onboarding/View/AreaSelectionView.swift (1)

19-19: LGTM!

action 프로퍼티를 internal로 변경하여 외부에서 직접 할당할 수 있도록 했습니다. configure(action:) 메서드 제거와 함께 일관된 패턴 변경입니다.

SMASHING/Presentation/Onboarding/View/GenderVIew.swift (1)

17-17: LGTM!

action 프로퍼티 가시성 변경이 다른 온보딩 뷰들과 일관된 패턴을 따릅니다.

SMASHING/Global/Enums/ReviewScore.swift (1)

8-9: LGTM! UIKit import 및 이미지 매핑 프로퍼티 추가

UIImage 타입 사용을 위한 import와 각 리뷰 점수에 대한 대형/소형 이미지 매핑이 잘 구현되었습니다. 기존 displayText 패턴과 일관성 있게 작성되었습니다.

Also applies to: 22-37

SMASHING/Presentation/Review/Cell/SatisfictionChip.swift (1)

39-49: LGTM! 초기화 로직

99 초과 시 "99+" 표시 로직과 초기화 흐름이 적절합니다.

SMASHING/Global/Coordinators/AppCoordinator.swift (1)

20-26: 개발용 변경사항 확인 필요

MyReviewsViewController를 루트로 설정한 것이 개발/테스트 목적인지 확인이 필요합니다. TabBarCoordinator가 주석 처리되어 있어 최종 병합 전에 원래 네비게이션 흐름으로 복원해야 할 수 있습니다.

PR 목적이 UI 구현 확인이라면 이해되지만, develop 브랜치에 병합 시 앱의 메인 진입점이 변경되므로 주의가 필요합니다.

SMASHING/Presentation/Review/Cell/ReviewCollectionViewCell.swift (2)

58-66: LGTM! UI 계층 구조

addSubviews 확장 메서드를 활용하여 뷰 계층 구조가 깔끔하게 설정되었습니다.


101-105: 프로필 이미지 설정은 필요 없습니다

TempReview 모델에는 프로필 이미지 관련 프로퍼티가 없으며, 오직 nickname, date, content 세 가지 String 프로퍼티만 있습니다. 따라서 configure 메서드에서 이미지를 설정할 데이터 자체가 존재하지 않습니다. 현재 profileImageViewsystemGray5 배경색으로 placeholder를 표시하는 구현은 적절합니다.

Likely an incorrect or invalid review comment.

SMASHING/Presentation/Review/MyReviewsViewController.swift (2)

23-25: 하드코딩된 mock 데이터 설정

mock 데이터가 하드코딩되어 있어 현재 UI 개발 단계에서는 적절합니다. 추후 실제 데이터 연동 시 이 부분을 교체해야 함을 인지하고 있으면 됩니다.


39-48: 뷰 설정 및 delegate 연결 구조 적절함

viewDidLoad에서 view 교체 및 delegate/dataSource 설정이 명확하게 분리되어 있습니다.

SMASHING/Presentation/Review/MyReviewsView.swift (2)

75-85: CollectionView 설정 적절함

estimatedItemSizeautomaticSize로 설정하여 self-sizing cell을 지원하고, cell 등록도 올바르게 되어 있습니다.


103-145: 레이아웃 구성 명확함

각 UI 컴포넌트의 constraints가 일관된 패턴으로 설정되어 있고, 간격 및 정렬이 적절합니다.

SMASHING/Global/Enums/OreTier.swift (2)

129-156: 테니스와 배드민턴의 일부 티어에서 동일한 스킬 설명이 반환됩니다.

tennisSkills()는 iron, silver, platinum만 개별 처리하고 나머지 티어(bronze, gold, diamond, challenger)는 default로 동일한 내용을 반환합니다. 의도된 설계인지 확인이 필요합니다.


158-185: 배드민턴 스킬도 일부 티어만 개별 정의되어 있습니다.

badmintonSkills()는 iron, gold, challenger만 개별 처리하며, 나머지 티어(bronze, silver, platinum, diamond)는 동일한 기본 스킬을 반환합니다. 향후 각 티어별 스킬 설명 추가가 필요할 수 있습니다.

SMASHING/Presentation/Review/Cell/SkillExplanationCell.swift (1)

13-64: LGTM!

셀 구현이 깔끔하고 프로젝트 패턴을 잘 따르고 있습니다. 레이아웃 구성과 configure(with:) 메서드가 적절하게 구현되어 있습니다.

SMASHING/Presentation/TierExplanation/Cell/TierChipCell.swift (1)

46-60: LGTM!

selected(), deselected(), configure(with:) 메서드가 명확하게 구현되어 있습니다. horizontalPadding 상수를 외부에서 참조할 수 있도록 static으로 선언한 것도 좋습니다.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +14 to +19
var edgeInset: UIEdgeInsets = .zero

override func drawText(in rect: CGRect) {
let insets = UIEdgeInsets(top: edgeInset.top, left: edgeInset.left, bottom: edgeInset.bottom, right: edgeInset.right)
super.drawText(in: rect.inset(by: insets))
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

edgeInset 변경 시 레이아웃 갱신 및 중복 코드 제거가 필요합니다.

  1. edgeInset이 변경될 때 invalidateIntrinsicContentSize()를 호출하지 않으면 레이아웃이 자동으로 갱신되지 않습니다.
  2. Line 17에서 edgeInset을 다시 UIEdgeInsets로 생성하는 것은 불필요합니다.
🔧 제안하는 수정
 final class PaddingLabel: UILabel {
-    var edgeInset: UIEdgeInsets = .zero
+    var edgeInset: UIEdgeInsets = .zero {
+        didSet {
+            invalidateIntrinsicContentSize()
+        }
+    }
     
     override func drawText(in rect: CGRect) {
-        let insets = UIEdgeInsets(top: edgeInset.top, left: edgeInset.left, bottom: edgeInset.bottom, right: edgeInset.right)
-        super.drawText(in: rect.inset(by: insets))
+        super.drawText(in: rect.inset(by: edgeInset))
     }
🤖 Prompt for AI Agents
In `@SMASHING/Global/Components/PaddingLabel.swift` around lines 14 - 19, The
edgeInset property should trigger layout updates and drawText should avoid
recreating UIEdgeInsets; add a didSet on the edgeInset variable to call
invalidateIntrinsicContentSize() (and setNeedsDisplay()/setNeedsLayout() if
needed) so the layout refreshes when edgeInset changes, and in the drawText(in:)
method use the existing edgeInset directly instead of creating a new
UIEdgeInsets instance (referencing the edgeInset property and the drawText(in:)
override).

Comment on lines +17 to +18
var action: ((Tier) -> Void)?
var nextAction: (() -> Void)?
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for all usages of nextAction in the codebase
rg -n "nextAction" --type swift

Repository: TEAM-SMASHING/SMASHING-iOS

Length of output: 347


🏁 Script executed:

# Get context around the target file and verify the line numbers
cat -n SMASHING/Presentation/Onboarding/View/TierSelectionView.swift | head -70

Repository: TEAM-SMASHING/SMASHING-iOS

Length of output: 2314


🏁 Script executed:

# Check other onboarding view files for similar patterns with action properties
fd "View\.swift$" SMASHING/Presentation/Onboarding/View/ -type f

Repository: TEAM-SMASHING/SMASHING-iOS

Length of output: 240


🏁 Script executed:

# Search for where TierSelectionView is used and how nextAction is assigned
rg -n "TierSelectionView" --type-list | head -20

Repository: TEAM-SMASHING/SMASHING-iOS

Length of output: 459


🏁 Script executed:

# Search for TierSelectionView usage and nextAction assignment
rg -A5 -B5 "TierSelectionView" --type swift | grep -A5 -B5 "nextAction"

Repository: TEAM-SMASHING/SMASHING-iOS

Length of output: 589


🏁 Script executed:

# Find other onboarding view files to verify the pattern
fd . SMASHING/Presentation/Onboarding/View/ --type f -name "*.swift"

Repository: TEAM-SMASHING/SMASHING-iOS

Length of output: 300


🏁 Script executed:

# Find files that import or use TierSelectionView
rg "TierSelectionView" --type swift

Repository: TEAM-SMASHING/SMASHING-iOS

Length of output: 929


🏁 Script executed:

# List all files in the Onboarding directory
find SMASHING/Presentation/Onboarding -type f -name "*.swift"

Repository: TEAM-SMASHING/SMASHING-iOS

Length of output: 1457


🏁 Script executed:

# Read TierSelectionViewController to see how it uses TierSelectionView and nextAction
cat -n SMASHING/Presentation/Onboarding/ViewController/TierSelectionViewController.swift

Repository: TEAM-SMASHING/SMASHING-iOS

Length of output: 851


🏁 Script executed:

# Read OnboardView to understand the nextAction usage pattern
cat -n SMASHING/Presentation/Onboarding/View/OnboardView.swift

Repository: TEAM-SMASHING/SMASHING-iOS

Length of output: 3648


nextAction 프로퍼티를 제거하세요.

nextAction은 선언되었지만 TierSelectionView 내에서 사용되지 않으며, TierSelectionViewController에서도 설정되거나 호출되지 않습니다. OnboardingView의 패턴과 달리 TierSelectionView는 자체 "다음" 버튼이 없고 nextAction을 호출할 필요가 없습니다. 이 프로퍼티는 제거하는 것이 좋습니다.

🤖 Prompt for AI Agents
In `@SMASHING/Presentation/Onboarding/View/TierSelectionView.swift` around lines
17 - 18, Remove the unused nextAction property from TierSelectionView: delete
the declaration "var nextAction: (() -> Void)?", search for and remove any
assignments or invocations of nextAction (including in
TierSelectionViewController or other callers), and ensure the view and
controller rely only on the existing action: ((Tier) -> Void)? property; then
run the build/tests to confirm no remaining references.

Comment on lines 26 to 28
func configure(action: @escaping () -> Void) {
areaSelectionView.configure(action: action)
areaSelectionView.action
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

액션 콜백이 할당되지 않았습니다.

configure 메서드에서 전달받은 actionareaSelectionView.action에 할당하지 않고 있습니다. 현재 코드는 프로퍼티를 읽기만 하고 아무 동작도 하지 않습니다. 주소 버튼을 탭해도 콜백이 실행되지 않습니다.

🐛 수정 제안
 func configure(action: `@escaping` () -> Void) {
-    areaSelectionView.action
+    areaSelectionView.action = action
 }
📝 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 configure(action: @escaping () -> Void) {
areaSelectionView.configure(action: action)
areaSelectionView.action
}
func configure(action: `@escaping` () -> Void) {
areaSelectionView.action = action
}
🤖 Prompt for AI Agents
In
`@SMASHING/Presentation/Onboarding/ViewController/AreaSelectionViewController.swift`
around lines 26 - 28, The configure(action:) method in
AreaSelectionViewController does not assign the passed closure to the view, it
only reads areaSelectionView.action; fix by assigning the incoming action to the
view's action property (i.e., set areaSelectionView.action = action) inside
configure(action:), ensuring the view's callback is invoked when the address
button is tapped.

Comment on lines 28 to 30
func configure(action: @escaping (Gender) -> Void) {
genderView.configure(action: action)
genderView.action
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

액션 콜백이 할당되지 않았습니다.

AreaSelectionViewController와 동일한 문제입니다. configure 메서드에서 전달받은 actiongenderView.action에 할당하지 않고 있습니다. 성별 선택 시 콜백이 실행되지 않습니다.

🐛 수정 제안
 func configure(action: `@escaping` (Gender) -> Void) {
-    genderView.action
+    genderView.action = action
 }
🤖 Prompt for AI Agents
In `@SMASHING/Presentation/Onboarding/ViewController/GenderViewController.swift`
around lines 28 - 30, The configure(action: `@escaping` (Gender) -> Void) method
fails to assign the passed-in callback to the view, so selection events never
trigger; update the configure method in GenderViewController to set
genderView.action = action (or otherwise assign the incoming closure to the
view’s action property) so that selections call the provided callback, mirroring
the fix used in AreaSelectionViewController.


// MARK: - Data Binding

func configure(_ review :TempReview) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

함수 시그니처 포맷팅 수정

콜론 앞에 불필요한 공백이 있습니다.

✏️ 수정 제안
-    func configure(_ review :TempReview) {
+    func configure(_ review: TempReview) {
📝 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 configure(_ review :TempReview) {
func configure(_ review: TempReview) {
🤖 Prompt for AI Agents
In `@SMASHING/Presentation/Review/Cell/ReviewCollectionViewCell.swift` at line
101, 함수 시그니처 configure(_ review :TempReview) 에서 매개변수 타입 앞에 불필요한 공백이 있으니 수정하세요;
정확히는 configure(_ review : TempReview) 또는 Swift 스타일 가이드에 맞게 configure(_ review:
TempReview)로 콜론 앞의 공백을 제거하여 함수 시그니처(메서드 이름 configure(_:))를 정리하면 됩니다.

Comment on lines +81 to +85
private let recomandationLabel = UILabel().then {
$0.text = "승급을 위해 아래의 기술들을 연마해보세요"
$0.font = .pretendard(.textMdSb)
$0.textColor = .Text.primary
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

오타: recomandationLabelrecommendationLabel

변수명에 오타가 있습니다. recomandationrecommendation

🔧 수정 제안
-    private let recomandationLabel = UILabel().then {
+    private let recommendationLabel = UILabel().then {

관련된 모든 참조도 함께 수정해야 합니다.

🤖 Prompt for AI Agents
In `@SMASHING/Presentation/TierExplanation/TierExplanationView.swift` around lines
81 - 85, Rename the UILabel property recomandationLabel to recommendationLabel
and update every reference to it across the file/class (e.g., any uses in
TierExplanationView, constraints, and view setup code). Ensure the declaration
private let recomandationLabel = ... becomes private let recommendationLabel =
... and update any property accesses, IBOutlets/usages, and tests to the new
identifier so the code compiles.

Comment on lines +87 to +100
let tierExplanationCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
layout.minimumLineSpacing = 12

let collection = UICollectionView(frame: .zero, collectionViewLayout: layout)
collection.showsHorizontalScrollIndicator = false
collection.backgroundColor = .clear
collection
.register(SkillExplanationCell.self, forCellWithReuseIdentifier: SkillExplanationCell.reuseIdentifier)

return collection
}()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

세로 스크롤 컬렉션뷰에서 showsHorizontalScrollIndicator가 설정되어 있습니다.

scrollDirection.vertical인 컬렉션뷰에서는 showsVerticalScrollIndicator를 설정하는 것이 적절합니다.

🔧 수정 제안
         let collection = UICollectionView(frame: .zero, collectionViewLayout: layout)
-        collection.showsHorizontalScrollIndicator = false
+        collection.showsVerticalScrollIndicator = false
         collection.backgroundColor = .clear
📝 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
let tierExplanationCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
layout.minimumLineSpacing = 12
let collection = UICollectionView(frame: .zero, collectionViewLayout: layout)
collection.showsHorizontalScrollIndicator = false
collection.backgroundColor = .clear
collection
.register(SkillExplanationCell.self, forCellWithReuseIdentifier: SkillExplanationCell.reuseIdentifier)
return collection
}()
let tierExplanationCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
layout.minimumLineSpacing = 12
let collection = UICollectionView(frame: .zero, collectionViewLayout: layout)
collection.showsVerticalScrollIndicator = false
collection.backgroundColor = .clear
collection
.register(SkillExplanationCell.self, forCellWithReuseIdentifier: SkillExplanationCell.reuseIdentifier)
return collection
}()
🤖 Prompt for AI Agents
In `@SMASHING/Presentation/TierExplanation/TierExplanationView.swift` around lines
87 - 100, The collection view configuration in tierExplanationCollectionView
sets showsHorizontalScrollIndicator while the layout.scrollDirection is
.vertical; change the indicator property to showsVerticalScrollIndicator on the
UICollectionView instance to correctly reflect vertical scrolling (locate the
closure that creates tierExplanationCollectionView and replace the
showsHorizontalScrollIndicator assignment with showsVerticalScrollIndicator).

Comment on lines +1 to +6
//
// TierExplanationView.swift
// SMASHING
//
// Created by 이승준 on 1/14/26.
//
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

파일 헤더 주석이 실제 파일명과 일치하지 않습니다.

파일명은 TierExplanationViewController.swift이지만 헤더에는 TierExplanationView.swift로 되어 있습니다.

🔧 수정 제안
 //
-//  TierExplanationView.swift
+//  TierExplanationViewController.swift
 //  SMASHING
 //
📝 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
//
// TierExplanationView.swift
// SMASHING
//
// Created by 이승준 on 1/14/26.
//
//
// TierExplanationViewController.swift
// SMASHING
//
// Created by 이승준 on 1/14/26.
//
🤖 Prompt for AI Agents
In `@SMASHING/Presentation/TierExplanation/TierExplanationViewController.swift`
around lines 1 - 6, 헤더 주석의 파일명이 실제 파일명과 일치하지 않습니다; 업데이트할 때
TierExplanationViewController.swift 파일 상단의 comment(현재
"TierExplanationView.swift")를 실제 파일명인 "TierExplanationViewController.swift"로
바꾸고, 클래스/struct 선언인 TierExplanationViewController 및 관련 타입 이름과 일관되도록 파일 설명(작성자/날짜
등)이 필요하면 함께 갱신하세요.

Comment on lines +54 to +60
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == mainView.tierCollectionView {
return OreTier.allCases.count
} else {
return OreTier.diamond.skills(sports: .tableTennis).count
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

numberOfItemsInSection에서 하드코딩된 값으로 인해 버그가 발생합니다.

tierExplanationCollectionView의 아이템 수가 OreTier.diamond.skills(sports: .tableTennis).count로 하드코딩되어 있습니다. 현재 선택된 oreTiersports를 사용해야 합니다.

🐛 버그 수정 제안
 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
     if collectionView == mainView.tierCollectionView {
         return OreTier.allCases.count
     } else {
-        return OreTier.diamond.skills(sports: .tableTennis).count
+        return oreTier.skills(sports: sports).count
     }
 }
📝 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 collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == mainView.tierCollectionView {
return OreTier.allCases.count
} else {
return OreTier.diamond.skills(sports: .tableTennis).count
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == mainView.tierCollectionView {
return OreTier.allCases.count
} else {
return oreTier.skills(sports: sports).count
}
}
🤖 Prompt for AI Agents
In `@SMASHING/Presentation/TierExplanation/TierExplanationViewController.swift`
around lines 54 - 60, The collection count is hardcoded to use OreTier.diamond
and tableTennis; update numberOfItemsInSection (in function
collectionView(_:numberOfItemsInSection:)) so the else branch returns the
currently selected tier's skills for the currently selected sport instead of a
hardcoded value—use the view controller's selected oreTier and sports properties
(e.g., oreTier.skills(sports: sports)) or safely unwrap/guard them when
computing the count for
tierExplanationCollectionView/mainView.tierExplanationCollectionView.

Comment on lines +72 to +79
} else {
let cell = collectionView.dequeueReusableCell(SkillExplanationCell.self, for: indexPath)
cell.contentView.snp.makeConstraints {
$0.width.equalTo(collectionView.frame.width)
}
cell.configure(with: oreTier.skills(sports: sports)[indexPath.row])
return cell
}
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

cellForItemAt에서 제약조건을 추가하면 셀 재사용 시 문제가 발생합니다.

makeConstraints가 셀이 dequeue될 때마다 호출되어 제약조건이 중복 추가됩니다. 이미 sizeForItemAt에서 크기를 지정하고 있으므로 이 제약조건은 불필요합니다.

🐛 수정 제안
         } else {
             let cell = collectionView.dequeueReusableCell(SkillExplanationCell.self, for: indexPath)
-            cell.contentView.snp.makeConstraints {
-                $0.width.equalTo(collectionView.frame.width)
-            }
             cell.configure(with: oreTier.skills(sports: sports)[indexPath.row])
             return cell
         }
📝 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
} else {
let cell = collectionView.dequeueReusableCell(SkillExplanationCell.self, for: indexPath)
cell.contentView.snp.makeConstraints {
$0.width.equalTo(collectionView.frame.width)
}
cell.configure(with: oreTier.skills(sports: sports)[indexPath.row])
return cell
}
} else {
let cell = collectionView.dequeueReusableCell(SkillExplanationCell.self, for: indexPath)
cell.configure(with: oreTier.skills(sports: sports)[indexPath.row])
return cell
}
🤖 Prompt for AI Agents
In `@SMASHING/Presentation/TierExplanation/TierExplanationViewController.swift`
around lines 72 - 79, In cellForItemAt, remove the call that adds constraints to
the cell each dequeue (the block using cell.contentView.snp.makeConstraints)
because it causes duplicate constraints on reuse; instead either rely on
sizeForItemAt to provide the cell sizing or move a one-time constraint setup
into SkillExplanationCell (e.g., in its initializer/awakeFromNib or a setup
method with a guard like `didSetupConstraints`) so constraints are only added
once for SkillExplanationCell and not inside collectionView.dequeueReusableCell
in cellForItemAt.

Copy link
Contributor

@LJIN24 LJIN24 left a comment

Choose a reason for hiding this comment

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

GOOD

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 받은 후기 UI 구현

3 participants