Skip to content

Conversation

@doyeonk429
Copy link
Contributor

🚀 PR 개요

와인 검색 > 전체 리뷰 조회 화면 수정

💡 PR 유형

  • ✨ Feature (기능 추가)
  • 🐞 Bugfix (버그 수정)
  • 🔥 Hotfix (긴급 수정)
  • 🔧 Refactor (코드 리팩토링)
  • ⚙️ Chore (환경 설정)
  • 📝 Docs (문서 작성 및 수정)

✏️ 변경 사항 요약

  • 와인 검색 화면에서 더보기 버튼 노출 정책에 따라 UI 분기 처리
  • 전체 리뷰 화면에서 빈티지를 적용하여 API 호출
  • 와인 리뷰 셀 레이아웃 조정

🔗 관련 이슈

🧪 테스트 내역

  • 브라우저/기기에서 동작 확인
  • 엣지 케이스 테스트 완료
  • 기존 기능 영향 없음

🎨 스크린샷 또는 시연 영상 (선택)

Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-09-07.at.18.49.43.mp4

✅ PR 체크리스트

  • 커밋 메시지가 명확합니다
  • Merge 대상 Branch가 develop입니다
  • PR 제목이 컨벤션에 맞습니다
  • 관련 이슈 번호를 작성했습니다
  • 기능이 정상적으로 작동합니다
  • 불필요한 코드를 제거했습니다

💬 추가 설명 or 리뷰 포인트 (선택)

리뷰어가 중점적으로 봐야 할 부분이나 설명이 필요한 내용을 자유롭게 작성해주세요.

@doyeonk429 doyeonk429 self-assigned this Sep 7, 2025
@coderabbitai
Copy link

coderabbitai bot commented Sep 7, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • 리뷰 셀에 토글 콜백 추가로 외부 동작 연동 가능.
    • 리뷰 뷰에 더보기 버튼 표시/숨김 설정 옵션 추가.
    • 빈티지 기준 전체 리뷰 조회 지원 및 정렬 드롭다운 매핑 개선.
  • Bug Fixes

    • 리뷰 텍스트 줄수 기반 접기/펼치기 표시 안정화, 단일 줄 표시 보정.
    • 닉네임 라벨 압축 방지 및 버튼 제약 개선으로 레이아웃 깨짐 완화.
    • UI 업데이트를 메인 스레드에서 보장.
  • Refactor

    • 리뷰 UI 업데이트 경로 정리 및 중복 토글 제거.

Walkthrough

리뷰 셀에 onToggle 콜백과 라인 기반 잘림 판정(int)이 추가되고 레이아웃 제약이 완화되었습니다. ReviewView에 더보기 버튼 가시성 제어 API가 추가되었으며, EntireReviewViewController는 vintage를 모든 API 경로로 전달하도록 변경되었습니다. WineDetailViewController는 리뷰 UI 업데이트를 updateReviewView()로 일원화했습니다.

Changes

Cohort / File(s) Summary
Review cell: 토글·레이아웃·잘림 로직
DE/DE/Sources/Core/CommonUI/Cells/ReviewCollectionViewCell.swift
public var onToggle: (() -> Void)? 추가. toggleButtoncontentView에 추가하고 top 제약을 >=로 변경. 닉네임 레이블 vertical content hugging 조정. 잘림 판정 함수가 BoolInt로 변경되어 반환된 라인 수(>2)를 기준으로 토글 노출 및 제약 활성화 토글. shouldShowToggle == 1일 때 개행 추가 후 스타일 재적용.
Review view: 버튼 가시성 API
DE/DE/Sources/Core/CommonUI/View/ReviewView.swift
@MainActor로 UI 안전성 보장하고 public func configureButton(_ isHidden: Bool) 추가해 외부에서 moreBtn.isHidden 제어 가능. 기존 configure(_:)에 @mainactor 어트리뷰트 추가.
EntireReview: vintage 전달·정렬 매핑·로깅 위치 이동
DE/DE/Sources/Features/Search/ViewControllers/EntireReviewViewController.swift
초기 로드/드롭다운/페이지네이션 모든 경로에서 vintage(vintageYear)를 네트워크 호출로 전달하도록 변경. 드롭다운 선택 문자열을 내부 sortType으로 매핑하고, 화면 로깅 호출(logScreenView)을 viewDidAppear(_:)로 이동.
WineDetail: 리뷰 UI 갱신 일원화
DE/DE/Sources/Features/Search/ViewControllers/WineDetailViewController.swift
리뷰 버튼 상태를 reviewView.configureButton(reviewData.count != 3)로 설정하고, 서브뷰 직접 토글 및 DispatchQueue.main.async 호출 제거. 데이터 바인딩 흐름에서 updateReviewView()를 직접 호출하도록 통합.

Sequence Diagram(s)

sequenceDiagram
    participant U as 사용자
    participant Cell as ReviewCollectionViewCell
    participant VC as 부모 ViewController

    U->>Cell: 토글 버튼 탭
    Cell->>Cell: toggleButtonTapped()
    alt onToggle 존재
        Cell-->>VC: onToggle?()
    end
    VC->>VC: 레이아웃/데이터 갱신 처리
Loading
sequenceDiagram
    participant U as 사용자
    participant ER as EntireReviewViewController
    participant DD as Dropdown
    participant API as NetworkService

    U->>ER: 화면 진입
    ER->>API: fetchWineReviews(wineId, sortType, page=1, vintageYear?)
    API-->>ER: 리뷰 목록 응답

    U->>DD: 옵션 선택(정렬)
    DD-->>ER: onOptionSelected(option)
    ER->>API: fetchWineReviews(wineId, mappedSortType, page=1, vintageYear?)
    API-->>ER: 응답

    U->>ER: 스크롤 하단(페이징)
    ER->>API: fetchWineReviews(..., page+1, vintageYear?)
Loading
sequenceDiagram
    participant WDV as WineDetailViewController
    participant RV as ReviewView

    WDV->>WDV: 리뷰 데이터 준비
    WDV->>RV: configureButton(isHidden: reviewCount != 3)
    WDV->>WDV: updateReviewView()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • yeseonglee
  • dlguszoo

Poem

한 줄은 부드럽게, 셋은 펼쳐봐,
빈티지 싣고 호출해 웃음 짓네.
토글은 콜백으로 가볍게,
레이아웃은 여유 있게 숨을 쉬네.
작은 수정으로 UX가 반짝 ✨

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f36bc1a and c2015fd.

📒 Files selected for processing (1)
  • DE/DE/Sources/Core/CommonUI/View/ReviewView.swift (1 hunks)
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/issue-182

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

Caution

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

⚠️ Outside diff range comments (3)
DE/DE/Sources/Features/Search/ViewControllers/EntireReviewViewController.swift (1)

201-213: 셀 토글 클로저: 강한 순환 참조 + 재사용 시 인덱스 오류 + 2초 딜레이로 인한 UI 글리치

  • VC → CollectionView → Cell → onToggle(클로저) → VC로 강한 순환 가능.
  • indexPath 캡처는 재사용 후 잘못된 아이템 토글 가능.
  • 2초 지연은 스크롤/재사용 시 엉뚱한 셀에 라인 변경 적용 위험.

즉시 수정 권장.

-        cell.onToggle = {
-            self.expandedCells[indexPath.item].toggle()
-            
-            UIView.animate(withDuration: 0, animations: {
-                collectionView.performBatchUpdates(nil, completion: nil)
-            }) { _ in
-                // 텍스트를 약간 늦춰서 줄이기
-                DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
-                    cell.review.numberOfLines = self.expandedCells[indexPath.item] ? 0 : 2
-                }
-            }
-        }
+        cell.onToggle = { [weak self, weak collectionView, weak cell] in
+            guard
+                let self = self,
+                let collectionView = collectionView,
+                let cell = cell,
+                let currentIndexPath = collectionView.indexPath(for: cell)
+            else { return }
+            self.expandedCells[currentIndexPath.item].toggle()
+            collectionView.performBatchUpdates(nil) { _ in
+                cell.review.numberOfLines = self.expandedCells[currentIndexPath.item] ? 0 : 2
+            }
+        }

추가로, numberOfLines 토글은 셀 내부에서 처리하도록 일원화하면 VC 단 로직이 더 간결해집니다.

DE/DE/Sources/Features/Search/ViewControllers/WineDetailViewController.swift (1)

490-497: 셀 토글 클로저의 강한 캡처

VC ↔ 셀 간 순환 참조 및 재사용 시 indexPath 불일치 위험. 약한 캡처와 현재 indexPath 조회로 보완하세요.

-        cell.onToggle = {
-            self.expandedCells[indexPath.item].toggle()
-            
-            UIView.animate(withDuration: 0, animations: {
-                collectionView.performBatchUpdates(nil, completion: nil)
-                self.updateScrollViewHeight()
-            })
-        }
+        cell.onToggle = { [weak self, weak collectionView, weak cell] in
+            guard
+                let self = self,
+                let collectionView = collectionView,
+                let cell = cell,
+                let currentIndexPath = collectionView.indexPath(for: cell)
+            else { return }
+            self.expandedCells[currentIndexPath.item].toggle()
+            collectionView.performBatchUpdates(nil) { _ in
+                self.updateScrollViewHeight()
+            }
+        }
DE/DE/Sources/Core/CommonUI/Cells/ReviewCollectionViewCell.swift (1)

89-95: toggleButton에 bottom 제약이 2개 설정되어 충돌합니다

  • Line 92: bottom = -10
  • Line 93-94: bottom = -12 (toggleBottomConstraint로 보관)

두 개의 동일 anchor(equal) 제약이 상충합니다. 하나만 남기세요. -12로 관리되는 보관 제약만 유지하는 수정을 제안합니다.

 toggleButton.snp.makeConstraints {
-    $0.top.greaterThanOrEqualTo(review.snp.bottom).offset(2)
+    $0.top.greaterThanOrEqualTo(review.snp.bottom).offset(2)
     $0.leading.equalTo(review.snp.leading)
-    $0.bottom.equalToSuperview().offset(-10)
-    self.toggleBottomConstraint = $0.bottom.equalToSuperview().offset(-12).constraint
+    self.toggleBottomConstraint = $0.bottom.equalToSuperview().offset(-12).constraint
 }
🧹 Nitpick comments (10)
DE/DE/Sources/Features/Search/ViewControllers/EntireReviewViewController.swift (4)

111-118: 드롭다운 클릭 로깅이 셋업 시점에 찍히는 문제

현재 setupDropdownAction() 진입 시점에 클릭 이벤트가 로깅됩니다. 실제 선택 시점으로 이동하세요.

적용 예시:

-        logButtonClick(screenName: screenName, buttonName: Tracking.ButtonEvent.dropdownBtnTapped, fileName: #file)
         
         entireReviewView.dropdownView.onOptionSelected = { [weak self] selectedOption in
             guard let self = self else { return }
+            self.logButtonClick(screenName: self.screenName,
+                                buttonName: Tracking.ButtonEvent.dropdownBtnTapped,
+                                fileName: #file)

117-125: 정렬 타입 하드코딩/공백 불일치 가능성

"최신 순" ↔ "최신순"처럼 UI 라벨과 API 파라미터가 혼재되어 있습니다. 맵으로 단일화하세요. 디폴트도 명시해 예외를 방지하세요.

-            if selectedOption == "최신 순" {
-                currentType = "최신순"
-            } else if selectedOption == "오래된 순" {
-                currentType = "오래된 순"
-            } else if selectedOption == "별점 높은 순" {
-                currentType = "별점 높은 순"
-            } else if selectedOption == "별점 낮은 순" {
-                currentType = "별점 낮은 순"
-            }
+            let sortMap: [String: String] = [
+                "최신 순": "최신순",
+                "오래된 순": "오래된 순",
+                "별점 높은 순": "별점 높은 순",
+                "별점 낮은 순": "별점 낮은 순"
+            ]
+            currentType = sortMap[selectedOption, default: "최신순"]

275-277: 중복 reloadData 호출

callEntireReviewAPI() 내부에서 이미 reloadData를 수행합니다. 아래 호출은 불필요합니다.

-                DispatchQueue.main.async {
-                    self.entireReviewView.reviewCollectionView.reloadData()
-                }
+                // 중복 호출 제거

261-270: 무한 스크롤에서 전체 화면 블로킹은 UX 저하

페이지네이션에는 테일 로더(footer spinner)나 셀 플래스홀더가 적합합니다. overlay는 입력을 막아 스크롤 흐름을 끊습니다.

DE/DE/Sources/Core/CommonUI/View/ReviewView.swift (1)

138-140: 버튼 가시성 제어 API 추가 OK

간단·명확합니다.

메서드 의도가 더 드러나도록 주석을 권장합니다.

-    public func configureButton(_ isHidden: Bool) {
+    /// "더보기" 버튼 노출 제어 (true = 숨김)
+    public func configureButton(_ isHidden: Bool) {
         moreBtn.isHidden = isHidden
     }
DE/DE/Sources/Core/CommonUI/Cells/ReviewCollectionViewCell.swift (5)

20-21: vertical hugging을 required로 올린 부분, 제약 충돌 가능성 점검

닉네임 라벨을 세로 방향 required로 고정하면, 동적 폰트/멀티라인 조합에서 score/date와의 제약 우선순위에 따라 경고가 날 수 있습니다. 증상이 있으면 .defaultHigh로 낮추거나, 인접 라벨의 compressionResistance를 조정하는 쪽을 고려해 주세요.


32-38: 토글 버튼 접근성/현지화 보완

  • 텍스트(“더보기/접기”) 하드코딩 → Localizable로 분리 권장.
  • 터치 타겟 44pt 확보 및 VoiceOver 레이블/힌트 지정 추천.

아래와 같이 최소 보완을 제안합니다.

 private let toggleButton = UIButton().then {
-    $0.setTitle("더보기", for: .normal)
+    $0.setTitle(NSLocalizedString("common.more", comment: "더보기"), for: .normal)
     $0.titleLabel?.font = UIFont.pretendard(.medium, size: 13)
     $0.setTitleColor(AppColor.gray70, for: .normal)
     $0.contentHorizontalAlignment = .left
     $0.isHidden = true
+    $0.contentEdgeInsets = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0) // 터치 타겟 확보
+    $0.accessibilityTraits = .button
 }

51-56: 토글 후 레이아웃 갱신 책임 범위 확인

셀 내부에서 numberOfLines만 바꾸면 셀 높이 변경이 컬렉션뷰에 반영되지 않을 수 있습니다. 외부(onToggle)에서 performBatchUpdates/reloadItems로 레이아웃을 갱신하고 있는지 확인해 주세요. 필요시 isExpanded 상태도 함께 전달하면 추적이 쉬워집니다.


112-122: 가독성/의도 명확화: lineCount 기반으로 분기하세요

변수명이 shouldShowToggle이지만 실제론 라인 수(Int)입니다. 가독성을 위해 lineCount와 showMore로 분리하면 조건이 즉시 읽힙니다. 동작은 동일합니다.

- let shouldShowToggle = isReviewTextTruncated()
- toggleButton.isHidden = !(shouldShowToggle > 2)
+ let lineCount = isReviewTextTruncated()
+ let showMore = lineCount > 2
+ toggleButton.isHidden = !showMore
@@
- if shouldShowToggle > 2 {
+ if showMore {
     toggleBottomConstraint?.activate()
     reviewBottomConstraint?.deactivate()
   } else {
     toggleBottomConstraint?.deactivate()
     reviewBottomConstraint?.activate()
   }

124-127: 1줄일 때 개행 추가하는 “텍스트 조작”은 제거 권장

실제 리뷰 내용을 임의로 변형하면 접근성/복사/분석 로직에서 부작용을 만들 수 있습니다. 레이아웃 문제라면 제약/인셋으로 해결하는 게 안전합니다. 아래처럼 해당 블록을 제거해도 의도한 레이아웃은 윗부분 분기(showMore=false일 때 reviewBottomConstraint 활성화)로 충족됩니다.

- if shouldShowToggle == 1 {
-     let reviewString = "\(model.contents)\n"
-     AppTextStyle.KR.body3.apply(to: review, text: reviewString, color: AppColor.gray90)
- }
+ // 1줄 케이스에서도 텍스트는 원본 그대로 표시합니다.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4134ded and f36bc1a.

📒 Files selected for processing (4)
  • DE/DE/Sources/Core/CommonUI/Cells/ReviewCollectionViewCell.swift (6 hunks)
  • DE/DE/Sources/Core/CommonUI/View/ReviewView.swift (1 hunks)
  • DE/DE/Sources/Features/Search/ViewControllers/EntireReviewViewController.swift (6 hunks)
  • DE/DE/Sources/Features/Search/ViewControllers/WineDetailViewController.swift (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: doyeonk429
PR: Drink-Easy/DE_iOS#0
File: :0-0
Timestamp: 2025-08-30T13:14:55.618Z
Learning: 사용자 doyeonk429는 한국어로 코드 리뷰를 받기를 선호합니다.
📚 Learning: 2025-09-02T12:53:54.084Z
Learnt from: doyeonk429
PR: Drink-Easy/DE_iOS#180
File: DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/RecordGraphViewController.swift:44-46
Timestamp: 2025-09-02T12:53:54.084Z
Learning: 사용자 doyeonk429는 와인 상세에서 테이스팅노트로 이동하는 플로우에서 빈티지가 무조건 설정되어 넘어간다고 설명했습니다. WineDetailViewController에서 goToTastingNote 메서드에서 vintage 가드 조건이 있어 빈티지 선택이 필수입니다.

Applied to files:

  • DE/DE/Sources/Features/Search/ViewControllers/WineDetailViewController.swift
  • DE/DE/Sources/Features/Search/ViewControllers/EntireReviewViewController.swift
🔇 Additional comments (11)
DE/DE/Sources/Features/Search/ViewControllers/EntireReviewViewController.swift (5)

47-52: 초기 로드에서 빈티지 파라미터 전파 OK

초기 API 호출에 vintage 반영이 일관적입니다.


61-64: 화면 로깅 위치 이전 OK

viewDidAppear로 이동해 정확한 노출 시점에 로깅됩니다.


130-136: 정렬 변경 시 빈티지 포함 재호출 OK

옵션 변경 시 vintage 동반 전파가 잘 되어 있습니다.


151-156: 네트워크 계층에 vintageYear 전달 OK

파라미터 체인이 명확합니다.


41-57: showColorBlockingView/hideBlockingView 페어 불일치 가능성 점검 필요

색상 블로킹 뷰와 일반 블로킹 뷰의 hide API가 동일 엔티티를 가리키는지 확인 부탁드립니다. 아니면 잔존 오버레이가 생길 수 있습니다.

다음 스크립트로 표시/해제 API 사용처를 점검해 주세요:

#!/bin/bash
rg -n --stats -C1 -S '\bshow(Color)?BlockingView\('
echo '----'
rg -n --stats -C1 -S '\bhide(Color)?BlockingView\('
DE/DE/Sources/Features/Search/ViewControllers/WineDetailViewController.swift (4)

223-231: 전체 리뷰 화면으로 빈티지 전달 OK

넘겨받은 vintage를 그대로 연결해 일관성 확보되었습니다.


310-311: '더보기' 노출 조건 재확인 필요

현재 count == 3일 때만 노출(그 외는 숨김)입니다. 사양이 “미리보기 개수(최대 3)만큼 내려오고, 3개면 더보기 노출”이라면 OK입니다. 전체 개수를 모르면 3 == hasMore의 휴리스틱이 맞는지 PM/백엔드와 재확인해 주세요.


409-413: 상세 API 호출에 vintageYear 전달 OK

빈티지 필터링 목표와 일치합니다.


406-423: 블로킹 뷰 API 페어 확인

여기도 showColorBlockingView → hideBlockingView 조합입니다. 앞선 코멘트와 함께 통일성/정상 해제 여부를 확인해 주세요.

DE/DE/Sources/Core/CommonUI/Cells/ReviewCollectionViewCell.swift (2)

15-16: onToggle 콜백 추가 적절합니다

셀 내부 토글 상태 변화에 대해 외부로 신호를 주는 방식이 간단하고 재사용성도 좋습니다. 현 시점에선 문제 없어 보입니다.


130-138: 레이블의 좌우 인셋이 실제로 어떻게 설정되어 있는지 확인하기 위해 아래 스크립트를 실행해주세요.

#!/bin/bash
FILE=$(fd ReviewCollectionViewCell.swift -t f)
echo "ReviewCollectionViewCell.swift 경로: $FILE"
rg -nC3 "review.snp.makeConstraints" "$FILE"

@doyeonk429
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Sep 11, 2025

✅ Actions performed

Full review triggered.

1 similar comment
@coderabbitai
Copy link

coderabbitai bot commented Sep 11, 2025

✅ Actions performed

Full review triggered.

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

Caution

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

⚠️ Outside diff range comments (1)
DE/DE/Sources/Core/CommonUI/Cells/ReviewCollectionViewCell.swift (1)

89-95: toggleButton에 bottom 제약 2개 설정됨(충돌 위험)

동일 뷰에 서로 다른 bottom 제약 두 개가 동시에 활성화됩니다. 하나만 유지하세요.

         toggleButton.snp.makeConstraints {
             $0.top.greaterThanOrEqualTo(review.snp.bottom).offset(2)
             $0.leading.equalTo(review.snp.leading)
-            $0.bottom.equalToSuperview().offset(-10)
             self.toggleBottomConstraint = $0.bottom.equalToSuperview().offset(-12).constraint
         }
🧹 Nitpick comments (9)
DE/DE/Sources/Core/CommonUI/View/ReviewView.swift (1)

137-140: 공개 API 네이밍 명확화 + 메인 스레드 보장 제안

뷰 외부에서 호출되는 공개 API는 의도가 드러나게 네이밍하고, UI 업데이트는 메인 스레드 보장이 안전합니다.

아래처럼 메서드명을 명확히 하고 MainActor로 보장하는 것을 제안합니다.

-    public func configureButton(_ isHidden: Bool) {
-        moreBtn.isHidden = isHidden
-    }
+    @MainActor
+    public func setMoreButtonHidden(_ hidden: Bool) {
+        moreBtn.isHidden = hidden
+    }

추가로 호출부 교체(동일 PR 내):

  • WineDetailViewController.updateReviewView():
-        reviewView.configureButton(reviewData.count != 3)
+        reviewView.setMoreButtonHidden(reviewData.count != 3)
DE/DE/Sources/Features/Search/ViewControllers/EntireReviewViewController.swift (4)

49-52: 초기 호출도 상태값(currentType) 사용

초기 로드 시에도 하드코딩 대신 currentType을 사용하면 소스 일관성이 좋아집니다.

-                    sortType: "최신순",
+                    sortType: currentType,

275-277: 중복 reloadData 제거

callEntireReviewAPI() 내부에서 이미 reload를 수행합니다. 여기서 한 번 더 호출하면 불필요한 레이아웃 패스가 발생합니다.

-                DispatchQueue.main.async {
-                    self.entireReviewView.reviewCollectionView.reloadData()
-                }
+                // 중복 reload 제거

45-59: Blocking View 토글의 메인 스레드 보장 확인

show/hideBlockingView가 UI 변경을 동반한다면 메인 스레드에서 호출되도록 보장하세요(내부에서 보장하지 않는 경우).

// 예: 보장이 없다면
await MainActor.run { self.view.hideBlockingView() }

Also applies to: 262-271


117-125: 정렬 문자열 분기 간소화 — 딕셔너리 매핑으로 교체하고 기본값을 '최신순'으로 통일

if-else 하드코딩은 오타 취약이므로 딕셔너리 매핑으로 단순화하세요. 레포에 이미 DE/DE/Sources/Features/Search/ViewControllers/EntireReviewViewController.swift 에서 sortType: "최신순"으로 호출되고 있으니 기본값도 "최신순"으로 맞춥니다 (WineService.fetchWineReviews 정의: DE/DE/Sources/Network/Wine/Service/WineService.swift).

-            if selectedOption == "최신 순" {
-                currentType = "최신순"
-            } else if selectedOption == "오래된 순" {
-                currentType = "오래된 순"
-            } else if selectedOption == "별점 높은 순" {
-                currentType = "별점 높은 순"
-            } else if selectedOption == "별점 낮은 순" {
-                currentType = "별점 낮은 순"
-            }
+            let map: [String: String] = [
+                "최신 순": "최신순",
+                "오래된 순": "오래된 순",
+                "별점 높은 순": "별점 높은 순",
+                "별점 낮은 순": "별점 낮은 순"
+            ]
+            currentType = map[selectedOption, default: "최신순"]
DE/DE/Sources/Features/Search/ViewControllers/WineDetailViewController.swift (2)

310-311: ‘더보기’ 노출 정책(count == 3) 적용 👍 + 메서드명 정합성

정책대로 count == 3 일 때만 노출되는 로직은 타당합니다. 상응하는 API 명도 위 제안(setMoreButtonHidden)으로 맞추면 가독성이 올라갑니다.

-        reviewView.configureButton(reviewData.count != 3)
+        reviewView.setMoreButtonHidden(reviewData.count != 3)

325-327: 고정 높이 계산 대신 실제 콘텐츠 높이 기반으로 전환 고려

현재 32 + count*100은 내용 줄수/토글에 따라 오차가 큽니다. 초기 바인딩 시점에 한 번 layoutIfNeeded 후 collectionViewContentSize.height로 세팅하는 접근을 권장합니다.

reviewView.reviewCollectionView.layoutIfNeeded()
let contentHeight = reviewView.reviewCollectionView.collectionViewLayout.collectionViewContentSize.height
reviewView.reviewCollectionView.snp.updateConstraints { $0.height.equalTo(max(contentHeight, 100)) }
DE/DE/Sources/Core/CommonUI/Cells/ReviewCollectionViewCell.swift (2)

97-114: 레이아웃 확정 전 폭 0 문제 방지

numberOfLines 계산 전에 layoutIfNeeded로 레이아웃을 확정하면 계산 안정성이 높아집니다. 또한 isHidden 표현을 단순화하세요.

         toggleButton.setTitle(isExpanded ? "접기" : "더보기", for: .normal)
-        let shouldShowToggle = isReviewTextTruncated()
-        toggleButton.isHidden = !(shouldShowToggle > 2)
+        contentView.layoutIfNeeded()
+        let shouldShowToggle = isReviewTextTruncated()
+        toggleButton.isHidden = (shouldShowToggle <= 2)

130-138: 라벨 너비 상수 정합성(인셋 17+17 = 34)

labelWidth는 좌우 인셋(17, 17)을 반영해 34를 사용하는 것이 수치 일관성에 맞습니다.

-        let labelWidth = contentView.frame.width - 30
+        let labelWidth = contentView.frame.width - 34
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4134ded and f36bc1a.

📒 Files selected for processing (4)
  • DE/DE/Sources/Core/CommonUI/Cells/ReviewCollectionViewCell.swift (6 hunks)
  • DE/DE/Sources/Core/CommonUI/View/ReviewView.swift (1 hunks)
  • DE/DE/Sources/Features/Search/ViewControllers/EntireReviewViewController.swift (6 hunks)
  • DE/DE/Sources/Features/Search/ViewControllers/WineDetailViewController.swift (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: doyeonk429
PR: Drink-Easy/DE_iOS#0
File: :0-0
Timestamp: 2025-08-30T13:14:55.618Z
Learning: 사용자 doyeonk429는 한국어로 코드 리뷰를 받기를 선호합니다.
📚 Learning: 2025-09-02T12:53:54.129Z
Learnt from: doyeonk429
PR: Drink-Easy/DE_iOS#180
File: DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/RecordGraphViewController.swift:44-46
Timestamp: 2025-09-02T12:53:54.129Z
Learning: 사용자 doyeonk429는 와인 상세에서 테이스팅노트로 이동하는 플로우에서 빈티지가 무조건 설정되어 넘어간다고 설명했습니다. WineDetailViewController에서 goToTastingNote 메서드에서 vintage 가드 조건이 있어 빈티지 선택이 필수입니다.

Applied to files:

  • DE/DE/Sources/Features/Search/ViewControllers/EntireReviewViewController.swift
  • DE/DE/Sources/Features/Search/ViewControllers/WineDetailViewController.swift
🔇 Additional comments (1)
DE/DE/Sources/Core/CommonUI/Cells/ReviewCollectionViewCell.swift (1)

17-21: 닉네임 라벨 hugging 우선순위 상향 👍

줄바꿈/압축 충돌 줄이는 데 도움 됩니다.

@doyeonk429 doyeonk429 merged commit 6e93cdc into develop Sep 12, 2025
1 check was pending
@doyeonk429 doyeonk429 deleted the feat/issue-182 branch September 12, 2025 01:12
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.

[Feat] 리뷰 조회 빈티지 필터링

2 participants