-
Notifications
You must be signed in to change notification settings - Fork 1
[Feat-T3-201] 제보 히스토리 화면 구현 (1차) #69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Walkthrough보고 이력 조회 기능을 추가하여 보고서 목록을 날짜별로 표시하고 진행 상태 및 카테고리로 필터링할 수 있도록 구현했습니다. 도메인 계층의 LocationEntity와 ReportEntity를 확장하고 새로운 UI 컴포넌트 및 ViewModel을 추가했습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant RLHViewController as ReportListHistoryViewController
participant RLHViewModel as ReportListHistoryViewModel
participant Domain as Domain Layer
User ->> RLHViewController: viewDidLoad
RLHViewController ->> RLHViewModel: action(.fetchReports)
RLHViewModel ->> Domain: 더미 데이터 로드
RLHViewModel -->> RLHViewController: reportsPublisher 업데이트
RLHViewController ->> RLHViewController: Table view snapshot 적용
User ->> RLHViewController: 진행 상태 필터 선택
RLHViewController ->> RLHViewModel: action(.filterProgress)
RLHViewModel ->> RLHViewModel: 선택 상태 토글
RLHViewModel -->> RLHViewController: progressPublisher 업데이트
RLHViewController ->> RLHViewController: Collection view snapshot 적용
User ->> RLHViewController: 카테고리 필터 선택
RLHViewController ->> RLHViewModel: action(.filterCategory)
RLHViewModel ->> RLHViewModel: 선택된 카테고리 변경
RLHViewModel -->> RLHViewController: selectedCategoryPublisher 업데이트
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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.
Example instruction:
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
🧹 Nitpick comments (8)
Projects/DataSource/Sources/Repository/LocationRepository.swift (1)
39-51: 좌표 nil 방어 로직 추가 방향 👍 / fallback 인자 전달 방식 소소한 개선 제안
fetchAddress(coordinate:)에서 위경도가 없는 경우 조기에nil을 반환하도록guard let을 추가한 것은, 잘못된 엔드포인트 호출을 막는다는 점에서 좋은 변경입니다.guard let longitude = coordinate.longitude, let latitude = coordinate.latitude else { return nil } let endpoint = LocationEndpoint.fetchAddress(longitude: longitude, latitude: latitude)추가로,
toLocationEntity호출 시 fallback 으로 현재는 옵셔널 프로퍼티(coordinate.longitude,coordinate.latitude)를 그대로 넘기고 있는데, 이 함수 시그니처가Double기반이라면 언랩된longitude,latitude를 넘기는 편이 타입/의도 면에서 더 자연스러울 수 있습니다. 시그니처가 이미Double?라면 현재 코드도 문제는 없습니다.Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift (1)
131-134: ReportListHistoryViewModel 등록 시 미사용 파라미터 정리 (SwiftLint 경고 대응)새 DI 등록 자체는 자연스러운데, 클로저 파라미터
container를 사용하지 않아 SwiftLint 의unused_closure_parameter경고가 발생하고 있습니다. 지금은 의존성이 없는 뷰모델이므로, 아래처럼 파라미터를_로 바꿔 주면 경고도 사라지고 의도도 더 명확해집니다.- DIContainer.shared - .register(type: ReportListHistoryViewModel.self) { container in - return ReportListHistoryViewModel() - } + DIContainer.shared + .register(type: ReportListHistoryViewModel.self) { _ in + ReportListHistoryViewModel() + }나중에 ReportListHistoryViewModel 에 의존성이 추가되면 그때
_를 실제 이름으로 되돌리고container.resolve를 사용하시면 될 것 같습니다.Projects/Presentation/Sources/Report/View/Component/ReportProgressCollectionViewCell.swift (1)
56-69: 셀 구성 로직이 잘 구현되었습니다.진행 상태와 카운트를 조건부로 표시하는 로직이 명확하며, 선택 상태에 따른 스타일 변경도 적절합니다.
선택적 개선사항: Line 59의
item.count != 0를item.count > 0로 변경하면 의도가 더 명확해질 수 있습니다(음수 방지).Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift (5)
12-30: 레이아웃 상수 네이밍 및 safe area 하단 제약 확인 필요
Layout.cetegoryButtonHeight오타는 기능에는 문제 없지만, 추후 유지보수성을 위해categoryButtonHeight등으로 정리하는 게 좋습니다.historyTableView의 bottom 제약이safeAreaLayoutGuide가 아니라superview에 바로 붙어 있어서, 홈 인디케이터 영역과 겹칠 수 있습니다. 의도라면 괜찮지만, 다른 화면들과 일관성 있게safeArea기준으로 맞출지 한 번 확인 부탁드립니다.Also applies to: 92-103, 124-134
55-69: 카테고리 UI 및 선택/상세 선택 바인딩이 아직 미완성 상태로 보임
categoryButton에 대한addTarget이 없어 현재는 탭해도 아무 동작을 하지 않습니다.categoryPublisher구독 클로저(라인 140142)와174)가 비어 있어, 실제 카테고리 선택 UI 표시 및 제보 상세 화면 진입 로직이 아직 구현되지 않은 상태입니다.selectedReportPublisher구독 클로저(라인 172- PR 설명에 “내일 추가 작업 예정”이라고 되어 있으니, 후속 커밋에서:
categoryButton탭 → 카테고리 선택 UI 표시 (filterCategory액션 호출)selectedReportPublisher→ 상세 화면 push/present
를 연결해 주면 흐름이 완성될 것 같습니다.Also applies to: 137-155, 170-175
71-135: 카테고리 버튼 오버레이 레이아웃은 의도대로인지 재확인 권장
categoryLabel/categoryButtonImage/categoryButton이historyTableView.top을 기준으로 오버레이처럼 떠 있는 구조입니다. 스크롤 시 섹션 헤더와 겹치거나, 첫 섹션 셀과 시각적으로 부딪힐 수 있습니다.- 의도된 디자인(“테이블 상단에 고정된 필터 행”)이라면 괜찮지만, 다른 화면에서 유사한 UI 가
tableHeaderView로 올라가는 패턴이라면 구조를 맞출지도 검토해 보셔도 좋겠습니다.
240-247: 디버그용print(items)는 제거 권장
applyProgressSnapshot내print(items)(라인 244)는 디버그 로그로 보이며, 나중에 실제 API 연동 시 콘솔 노이즈가 될 수 있습니다.- UI 검증이 끝나면 제거해 주세요.
265-273: 컬렉션 셀 선택 시 snapshot 인덱스 접근 방식 개선 제안
- 현재 구현:
let snapshot = progressDataSource?.snapshot() let item = snapshot.itemIdentifiers[indexPath.item] as? ReportProgressItem
itemIdentifiers의 요소 타입이 이미ReportProgressItem이라as? ReportProgressItem캐스트는 항상 성공하는 불필요한 연산입니다.snapshot 기반 인덱스 접근은 이론상 diffable snapshot 과 컬렉션 뷰의 인덱스가 어긋날 여지가 있습니다.
좀 더 안전하고 간결하게는
itemIdentifier(for:)를 직접 사용하는 것이 좋습니다.예시:
guard let item = progressDataSource?.itemIdentifier(for: indexPath) else { return } viewModel.action(input: .filterProgress(progress: item.progress))
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
Projects/DataSource/Sources/Repository/LocationRepository.swift(1 hunks)Projects/Domain/Sources/Entity/Enum/ReportProgress.swift(1 hunks)Projects/Domain/Sources/Entity/LocationEntity.swift(1 hunks)Projects/Domain/Sources/Entity/ReportEntity.swift(1 hunks)Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift(1 hunks)Projects/Presentation/Sources/Report/Model/PhotoItem.swift(1 hunks)Projects/Presentation/Sources/Report/Model/ReportHistoryItem.swift(1 hunks)Projects/Presentation/Sources/Report/Model/ReportProgressItem.swift(1 hunks)Projects/Presentation/Sources/Report/View/Component/ReportCategoryTableViewCell.swift(1 hunks)Projects/Presentation/Sources/Report/View/Component/ReportHistoryCategoryCollectionViewCell.swift(1 hunks)Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableHeaderView.swift(1 hunks)Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swift(1 hunks)Projects/Presentation/Sources/Report/View/Component/ReportPhotoCollectionViewCell.swift(1 hunks)Projects/Presentation/Sources/Report/View/Component/ReportProgressCollectionViewCell.swift(1 hunks)Projects/Presentation/Sources/Report/View/ReportHistoryListViewController.swift(1 hunks)Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift(1 hunks)Projects/Presentation/Sources/Report/View/ReportViewController.swift(1 hunks)Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-19T13:49:08.315Z
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)을 기준으로 설정하여 오프셋을 적용함.
Applied to files:
Projects/Presentation/Sources/Report/View/ReportHistoryListViewController.swiftProjects/Presentation/Sources/Report/View/ReportListHistoryViewController.swiftProjects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swift
🧬 Code graph analysis (8)
Projects/Presentation/Sources/Report/View/ReportHistoryListViewController.swift (2)
Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift (3)
configureAttribute(55-69)configureLayout(71-135)bind(137-176)Projects/Presentation/Sources/Common/Extension/UIViewController+.swift (1)
configureCustomNavigationBar(19-29)
Projects/Presentation/Sources/Report/View/ReportViewController.swift (1)
Projects/Presentation/Sources/Report/View/Component/ReportPhotoCollectionViewCell.swift (1)
configure(85-88)
Projects/Presentation/Sources/Report/View/Component/ReportPhotoCollectionViewCell.swift (3)
Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableHeaderView.swift (1)
configure(62-68)Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swift (1)
configure(182-201)Projects/Presentation/Sources/Report/View/Component/ReportProgressCollectionViewCell.swift (1)
configure(56-69)
Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift (1)
Projects/Shared/Sources/DIContainer/DIContainer.swift (1)
register(14-16)
Projects/Presentation/Sources/Report/View/Component/ReportProgressCollectionViewCell.swift (1)
Projects/Presentation/Sources/Report/View/Component/ReportHistoryCategoryCollectionViewCell.swift (3)
configureAttribute(32-40)configureLayout(42-54)configure(56-73)
Projects/Presentation/Sources/Report/View/Component/ReportHistoryCategoryCollectionViewCell.swift (1)
Projects/Presentation/Sources/Report/View/Component/ReportProgressCollectionViewCell.swift (3)
configureAttribute(32-40)configureLayout(42-54)configure(56-69)
Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift (6)
Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift (3)
action(54-65)fetchReports(103-105)filterProgress(83-97)Projects/Presentation/Sources/Common/Extension/UIViewController+.swift (1)
configureCustomNavigationBar(19-29)Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableHeaderView.swift (1)
configure(62-68)Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swift (1)
configure(182-201)Projects/Presentation/Sources/Report/View/Component/ReportProgressCollectionViewCell.swift (1)
configure(56-69)Projects/Presentation/Sources/Common/DesignSystem/BitnagilIcon.swift (1)
chevronIcon(49-51)
Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableHeaderView.swift (2)
Projects/Presentation/Sources/Report/View/Component/ReportCategoryTableViewCell.swift (1)
configureAttribute(45-55)Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swift (2)
configureAttribute(53-78)configure(182-201)
🪛 SwiftLint (0.57.0)
Projects/Presentation/Sources/Report/View/ReportHistoryListViewController.swift
[Warning] 110-110: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 117-117: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 124-124: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 131-131: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 138-138: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 145-145: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift
[Warning] 132-132: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
⏰ 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 (12)
Projects/Domain/Sources/Entity/LocationEntity.swift (1)
9-15: 위경도 옵셔널 변경 방향 적절
longitude,latitude를Double?로 바꾼 덕분에 좌표가 없는 위치도 표현할 수 있어 도메인 유연성이 좋아졌습니다. 아래처럼 Repository 에서도nil가드가 들어가 있어 일관성도 맞습니다.
LocationRepository.fetchAddress(coordinate:)에서guard let으로 언랩 후 사용추가로, 다른 사용처에서 강제 언랩(
!) 이 남아 있지 않은지만 한 번만 확인해 주시면 충분할 것 같습니다.Projects/Presentation/Sources/Report/View/Component/ReportHistoryCategoryCollectionViewCell.swift (1)
12-73: 카테고리 셀 구성 깔끔하고 기존 패턴과 일관레이아웃/폰트/코너 라운딩 설정이 기존
ReportProgressCollectionViewCell과 잘 맞고,count가 있을 때만 공백을 붙여 표현하는 부분도 명확합니다. 선택 상태에 따른 배경/텍스트 컬러 토글도 직관적이라 재사용성과 가독성이 좋습니다.현재 형태 그대로 사용하셔도 무방해 보입니다.
Projects/Presentation/Sources/Report/Model/PhotoItem.swift (1)
10-17: PhotoItem 가시성 축소로 프레젠테이션 모듈 캡슐화 개선
PhotoItem을public→ 모듈 내부용으로 줄이고, 프로퍼티/이니셜라이저도 동일하게 internal 로 맞춘 것은 Presentation 모듈의 API 표면을 줄인다는 점에서 좋은 방향입니다.Hashable유지로 diffable datasource 등에서도 그대로 활용 가능해 보입니다.외부 모듈에서 직접
PhotoItem을 참조하지 않는 구조라면 현재 변경은 문제 없이 적절해 보입니다.Projects/Presentation/Sources/Report/View/Component/ReportCategoryTableViewCell.swift (1)
108-115: 아이콘 매핑 개선이 적절합니다.각 리포트 타입에 대한 아이콘 매핑이 더 명확하고 의미있는 아이콘으로 업데이트되었습니다.
Projects/Presentation/Sources/Report/View/Component/ReportPhotoCollectionViewCell.swift (1)
85-88: 메서드 시그니처 개선이 좋습니다.
configure(with:)형태로 변경하여 Swift API 디자인 가이드라인과 일관성을 유지하고 있으며, 다른 셀 컴포넌트들과의 일관성도 확보되었습니다.Projects/Presentation/Sources/Report/View/ReportViewController.swift (1)
373-377: 셀 구성 호출이 올바르게 업데이트되었습니다.
ReportPhotoCollectionViewCell의 새로운 메서드 시그니처와 일치하도록 정확하게 업데이트되었습니다.Projects/Presentation/Sources/Report/Model/ReportProgressItem.swift (1)
11-16: 모델 정의가 적절합니다.선택 상태를 추적하기 위한
isSelected를var로, 나머지 불변 속성들을let으로 선언하여 적절한 가변성 설계를 유지하고 있습니다.Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swift (2)
182-201: 히스토리 아이템 구성 로직이 잘 구현되었습니다.옵셔널 처리와 이미지 로딩이 적절하게 구현되어 있으며, Kingfisher를 사용한 이미지 로딩도 올바릅니다.
204-230: ReportProgress 확장이 적절합니다.Domain 타입에 대한 Presentation 레이어의 확장을 통해 UI 관련 색상을 제공하는 것은 이 아키텍처에서 수용 가능한 패턴입니다. 각 진행 상태별로 적절한 색상이 매핑되어 있습니다.
Projects/Presentation/Sources/Report/View/ReportHistoryListViewController.swift (1)
41-43: configureAttribute 구현이 불완전합니다.
configureAttribute()메서드가categoryButton.backgroundColor설정만 포함하고 있습니다. 파일의 다른 유사한 뷰 컨트롤러(ReportListHistoryViewController.swift)를 보면, 이 메서드에서 폰트, 색상, 컬렉션뷰/테이블뷰 설정 등 더 많은 속성 구성이 필요합니다.PR 설명에 언급된 대로 추가 작업이 예정되어 있으므로, 다음 구성들을 추가해주세요:
- categoryLabel, categoryButtonImage 스타일 설정
- progressCollectionView 레이아웃 및 데이터소스 구성
- historyTableView 스타일 및 데이터소스 구성
- view.backgroundColor 설정
완전한 구현 예시가 필요하시면 도움을 드릴 수 있습니다.
⛔ Skipped due to learnings
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()를 호출하면 이 메서드들이 자동으로 호출된다. 따라서 하위 클래스에서 추가로 호출할 필요가 없다.Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift (1)
178-213: Diffable Data Source + Compositional Layout 사용 구조는 전체적으로 깔끔함
UICollectionViewDiffableDataSource와UITableViewDiffableDataSource를 각각 분리해서 구성하고, 레이아웃/등록/델리게이트 설정을configure*메서드로 나눈 구조가 읽기 쉽고 확장하기 좋아 보입니다.- 프로그레스 컬렉션의
estimated폭, interItemSpacing, continuous 스크롤 조합도 태그형 필터 UI에 적절해 보입니다.Also applies to: 215-238
Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift (1)
12-26: Input/Output 구조 및 Combine 기반 설계는 전체적으로 좋음
Input/Output으로 입출력을 명확히 분리하고, 내부는CurrentValueSubject/PassthroughSubject로 감추는 패턴이 깔끔합니다.ReportProgress.allCases→ReportProgressItem초기화,ReportType.allCases초기 세팅도 명확해서 이후 실제 API 연동 시 교체하기 쉬울 것 같습니다.Also applies to: 28-52
| static var dummyData: [ReportHistoryItem] { | ||
| let types = ReportType.allCases | ||
| let progresses = ReportProgress.allCases.filter { $0 != .entire } | ||
|
|
||
| func makeItem( | ||
| id: Int, | ||
| title: String, | ||
| date: String, | ||
| location: String, | ||
| typeIndex: Int, | ||
| progressIndex: Int | ||
| ) -> ReportHistoryItem { | ||
| let type = types[typeIndex % types.count] | ||
| let progress = progresses[progressIndex % progresses.count] | ||
|
|
||
| return ReportHistoryItem( | ||
| id: id, | ||
| title: title, | ||
| thumbnailUrl: "https://picsum.photos/200", | ||
| date: date, | ||
| type: type, | ||
| progress: progress, | ||
| location: location | ||
| ) | ||
| } | ||
|
|
||
| return [ | ||
| makeItem( | ||
| id: 1, | ||
| title: "횡단보도 앞 가로등 불이 꺼져 있어요", | ||
| date: "2025-11-19월", | ||
| location: "서울시 강남구 삼성동", | ||
| typeIndex: 0, | ||
| progressIndex: 0 | ||
| ), | ||
| makeItem( | ||
| id: 2, | ||
| title: "지하철 역사 계단 난간이 파손되었어요", | ||
| date: "2025-11-19월", | ||
| location: "서울시 송파구 잠실동", | ||
| typeIndex: 1, | ||
| progressIndex: 1 | ||
| ), | ||
|
|
||
| // 다른 날짜 | ||
| makeItem( | ||
| id: 3, | ||
| title: "공원 놀이터 바닥이 파여 있어 위험해요", | ||
| date: "2025-11-18월", | ||
| location: "서울시 마포구 상암동", | ||
| typeIndex: 2, | ||
| progressIndex: 2 | ||
| ), | ||
| makeItem( | ||
| id: 4, | ||
| title: "버스 정류장 안내판 조명이 나갔습니다", | ||
| date: "2025-11-18월", | ||
| location: "서울시 서초구 서초동", | ||
| typeIndex: 3, | ||
| progressIndex: 0 | ||
| ), | ||
|
|
||
| makeItem( | ||
| id: 5, | ||
| title: "자전거 도로에 불법 주차된 차량이 있어요", | ||
| date: "2025-11-17월", | ||
| location: "서울시 노원구 공릉동", | ||
| typeIndex: 1, | ||
| progressIndex: 1 | ||
| ), | ||
| makeItem( | ||
| id: 6, | ||
| title: "보도블럭이 들떠서 걸려 넘어질 위험이 있어요", | ||
| date: "2025-11-16월", | ||
| location: "서울시 종로구 종로1가", | ||
| typeIndex: 0, | ||
| progressIndex: 2 | ||
| ), | ||
|
|
||
| makeItem( | ||
| id: 7, | ||
| title: "교차로 신호등이 고장난 것 같습니다", | ||
| date: "2025-11-16월", | ||
| location: "서울시 동작구 사당동", | ||
| typeIndex: 2, | ||
| progressIndex: 0 | ||
| ), | ||
| makeItem( | ||
| id: 8, | ||
| title: "지하차도에 물이 고여 있어요", | ||
| date: "2025-11-15월", | ||
| location: "서울시 영등포구 영등포동", | ||
| typeIndex: 3, | ||
| progressIndex: 1 | ||
| ) | ||
| ] | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
더미 데이터의 날짜 형식을 확인해주세요.
더미 데이터의 모든 날짜가 "월"(월요일) 요일 접미사를 가지고 있습니다. 예를 들어 2025-11-19, 2025-11-18, 2025-11-17 등 서로 다른 날짜임에도 모두 "월"로 표시되어 있어 실제 요일과 일치하지 않을 수 있습니다. UI 검증을 위해 다양한 요일 표현(월, 화, 수 등)을 사용하는 것이 좋겠습니다.
참고: PR 설명에 언급된 대로, UI 완성 시 이 더미 데이터는 제거 예정입니다.
날짜별로 올바른 요일을 계산하는 헬퍼 함수를 생성하는 것이 도움이 될까요?
🤖 Prompt for AI Agents
In Projects/Presentation/Sources/Report/Model/ReportHistoryItem.swift around
lines 21 to 117, the dummy items use hard-coded weekday suffixes ("월") that may
not match the actual weekday for each date; replace these hard-coded weekday
strings by computing the correct weekday from the date value: add a small helper
that parses the date string (use the same format used elsewhere, e.g.
"yyyy-MM-dd"), computes the calendar weekday, maps it to the Korean weekday
symbols ("일","월","화","수","목","금","토"), and returns a formatted date string like
"2025-11-19월"; update the dummyData builder to call this helper for each item
(or store correctly formatted date strings) and make the helper resilient to
parse failures by falling back to the original string or a safe default.
Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableHeaderView.swift
Show resolved
Hide resolved
Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swift
Show resolved
Hide resolved
| categoryButton.snp.makeConstraints { make in | ||
| make.centerY.equalTo(categoryButtonImage) | ||
|
|
||
| make.trailing | ||
| .equalToSuperview() | ||
| .offset(-Layout.horizontalSpacing) | ||
|
|
||
| make.height.equalTo(Layout.cetegoryButtonHeight) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
categoryButton의 레이아웃 제약이 불완전합니다.
categoryButton의 제약 조건이 불완전합니다. leading 또는 width 제약이 없어 버튼의 가로 크기가 결정되지 않습니다. ReportListHistoryViewController.swift의 구현을 참고하면, leading을 categoryLabel.snp.leading에 연결해야 합니다.
다음과 같이 수정해주세요:
categoryButton.snp.makeConstraints { make in
make.centerY.equalTo(categoryButtonImage)
+
+ make.leading.equalTo(categoryLabel.snp.leading)
make.trailing
.equalToSuperview()
.offset(-Layout.horizontalSpacing)
make.height.equalTo(Layout.cetegoryButtonHeight)
}📝 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.
| categoryButton.snp.makeConstraints { make in | |
| make.centerY.equalTo(categoryButtonImage) | |
| make.trailing | |
| .equalToSuperview() | |
| .offset(-Layout.horizontalSpacing) | |
| make.height.equalTo(Layout.cetegoryButtonHeight) | |
| } | |
| categoryButton.snp.makeConstraints { make in | |
| make.centerY.equalTo(categoryButtonImage) | |
| make.leading.equalTo(categoryLabel.snp.leading) | |
| make.trailing | |
| .equalToSuperview() | |
| .offset(-Layout.horizontalSpacing) | |
| make.height.equalTo(Layout.cetegoryButtonHeight) | |
| } |
🤖 Prompt for AI Agents
In
Projects/Presentation/Sources/Report/View/ReportHistoryListViewController.swift
around lines 96 to 104, the categoryButton constraints are incomplete because
its horizontal size is not defined; add a leading constraint to align
categoryButton.leading to categoryLabel.snp.leading (or alternatively add an
explicit width) so the button’s horizontal size is resolved, keeping the
existing centerY, trailing, and height constraints.
| override func bind() { | ||
| viewModel.output.categoryPublisher | ||
| .receive(on: DispatchQueue.main) | ||
| .sink(receiveValue: { reportTypes in | ||
|
|
||
| }) | ||
| .store(in: &cancellables) | ||
|
|
||
| viewModel.output.selectedCategoryPublisher | ||
| .receive(on: DispatchQueue.main) | ||
| .sink(receiveValue: { selectedCategory in | ||
|
|
||
| }) | ||
| .store(in: &cancellables) | ||
|
|
||
| viewModel.output.progressPublisher | ||
| .receive(on: DispatchQueue.main) | ||
| .sink(receiveValue: { progresses in | ||
|
|
||
| }) | ||
| .store(in: &cancellables) | ||
|
|
||
| viewModel.output.selectedProgressPublisher | ||
| .receive(on: DispatchQueue.main) | ||
| .sink(receiveValue: { selectedProgress in | ||
|
|
||
| }) | ||
| .store(in: &cancellables) | ||
|
|
||
| viewModel.output.reportsPublisher | ||
| .receive(on: DispatchQueue.main) | ||
| .sink(receiveValue: { reports in | ||
|
|
||
| }) | ||
| .store(in: &cancellables) | ||
|
|
||
| viewModel.output.selectedReportPublisher | ||
| .receive(on: DispatchQueue.main) | ||
| .sink(receiveValue: { selectedReport in | ||
|
|
||
| }) | ||
| .store(in: &cancellables) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Publisher 바인딩 구현이 필요합니다.
모든 publisher의 sink 핸들러가 비어있어 데이터 바인딩이 작동하지 않습니다. PR 설명에 추가 작업이 예정되어 있다고 언급되어 있으므로, 다음 구현들이 필요합니다:
categoryPublisher(line 110): 카테고리 목록 데이터 처리selectedCategoryPublisher(line 117): 선택된 카테고리로 UI 업데이트progressPublisher(line 124): 진행 상태 컬렉션뷰에 스냅샷 적용selectedProgressPublisher(line 131): 선택된 진행 상태 처리reportsPublisher(line 138): 리포트 목록을 테이블뷰에 스냅샷 적용selectedReportPublisher(line 145): 선택된 리포트 상세 화면으로 이동
참고로, 유사한 파일인 ReportListHistoryViewController.swift에 일부 구현이 있으니 참고하시기 바랍니다.
추가로, SwiftLint가 플래그한 대로 사용하지 않는 클로저 파라미터들을 _로 대체해주세요 (lines 110, 117, 124, 131, 138, 145).
전체 바인딩 구현을 생성해드릴까요?
🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 110-110: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 117-117: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 124-124: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 131-131: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 138-138: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 145-145: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
🤖 Prompt for AI Agents
In
Projects/Presentation/Sources/Report/View/ReportHistoryListViewController.swift
around lines 107 to 149, the Combine sink closures are empty and unused closure
parameters should be replaced with `_`; implement each publisher binding as
follows: subscribe to categoryPublisher and update the categories data source
and reload the category UI (use `_` for unused params if any), subscribe to
selectedCategoryPublisher and update selection state in the UI (e.g., highlight
or select the corresponding category cell), subscribe to progressPublisher and
apply a snapshot to the progress collection view data source, subscribe to
selectedProgressPublisher and update selected progress state in the UI,
subscribe to reportsPublisher and apply a snapshot to the table view data source
for reports, and subscribe to selectedReportPublisher and navigate/present the
report detail view for the selected report; ensure all UI updates are performed
on the main thread, store cancellables, and replace unused closure params with
`_` to satisfy SwiftLint.
| private func applyHistorySnapshot(reports: [ReportHistoryItem]) { | ||
| let reportsDictionary = Dictionary(grouping: reports) { $0.date ?? "" } | ||
| let sortedDates = reportsDictionary.keys.sorted(by: >) | ||
|
|
||
| var snapshot = NSDiffableDataSourceSnapshot<String, ReportHistoryItem>() | ||
|
|
||
| for dateKey in sortedDates { | ||
| snapshot.appendSections([dateKey]) | ||
| if let items = reportsDictionary[dateKey] { | ||
| snapshot.appendItems(items, toSection: dateKey) | ||
| } | ||
| } | ||
|
|
||
| historyDataSource?.apply(snapshot, animatingDifferences: true) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
nil/빈 날짜에 대한 헤더 처리 시 크래시 가능성
applyHistorySnapshot에서Dictionary(grouping: reports) { $0.date ?? "" }로 그룹핑하고, 키가 빈 문자열("")일 수도 있는 상태로 섹션을 만듭니다.ReportHistoryTableHeaderView.configure(with:)(다른 파일)에서는dateString.removeLast()를 호출하는데, 빈 문자열이 들어가면 런타임 크래시가 발생합니다.ReportHistoryItem.date가 항상 non-nil/non-empty 라는 도메인 보장이 없다면:- 날짜가 없는 아이템은 섹션에서 제외하거나,
"날짜 미상"등의 안전한 기본 문자열을 사용하고, header 쪽에서 빈 문자열 처리 가드를 추가하는 것이 좋겠습니다.
예시 수정 방향(컨셉):
let reportsDictionary = Dictionary(grouping: reports.compactMap { $0.date == nil ? nil : $0 }) { $0.date! }또는 date 가 없으면 별도의 섹션 키(예: "날짜 없음")를 사용하도록 처리.
Also applies to: 278-291
🏁 Script executed:
#!/bin/bash
# Search for ReportHistoryTableHeaderView file and configure method
fd -e swift -x grep -l "ReportHistoryTableHeaderView" {} \;Length of output: 170
🏁 Script executed:
#!/bin/bash
# Search for removeLast() usage in the codebase, particularly in header view
rg -n "removeLast" --type=swift -B3 -A3Length of output: 842
🏁 Script executed:
#!/bin/bash
# Search for the configure method that handles date strings
rg -n "configure.*date" --type=swift -iLength of output: 2366
🏁 Script executed:
#!/bin/bash
# Look at the specific lines mentioned in the review
cat "Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift" | head -300 | tail -80Length of output: 3428
🏁 Script executed:
#!/bin/bash
# Find ReportHistoryTableHeaderView file
fd -e swift "ReportHistoryTableHeaderView"Length of output: 86
🏁 Script executed:
#!/bin/bash
# Search for where applyHistorySnapshot calls configure or appendSections
rg -n "appendSections\|configure" "Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift" -A2 -B2Length of output: 0
🏁 Script executed:
#!/bin/bash
# Look for ReportHistoryTableHeaderView and check its configure method
fd -e swift -x grep -H "configure.*with" {} \; | grep -i historyLength of output: 987
🏁 Script executed:
#!/bin/bash
# Broader search for ReportHistoryTableHeaderView in the entire project
rg -n "ReportHistoryTableHeaderView" --type=swiftLength of output: 759
🏁 Script executed:
#!/bin/bash
# Check for any file containing "TableHeaderView"
fd -e swift -x grep -l "TableHeaderView" {} \;Length of output: 170
🏁 Script executed:
#!/bin/bash
# Search for removeLast specifically with context to see if it's guarded
rg -n "removeLast\(\)" --type=swift -B5 -A2Length of output: 904
🏁 Script executed:
#!/bin/bash
# Look for the header view class definition and configure method
rg -n "class.*ReportHistoryTableHeaderView\|func configure" --type=swift -A10Length of output: 0
🏁 Script executed:
#!/bin/bash
# Check the actual implementation files in the Report directory
find "Projects/Presentation/Sources/Report" -name "*.swift" -type f | head -20Length of output: 1529
🏁 Script executed:
#!/bin/bash
# Get list of all Swift files in Report View directory
ls -la "Projects/Presentation/Sources/Report/View/" 2>/dev/null || find "Projects/Presentation/Sources/Report" -type f -name "*.swift" | head -30Length of output: 768
🏁 Script executed:
#!/bin/bash
# Search for where snapshot sections are created and look for date handling
rg -n "appendSections\|dateKey\|date \?\?" --type=swift -C3Length of output: 0
🏁 Script executed:
#!/bin/bash
# Look for ReportHistoryItem and its date property definition
rg -n "ReportHistoryItem\|\.date" --type=swift | head -50Length of output: 0
🏁 Script executed:
#!/bin/bash
# Check if there are any guards related to empty string checks before configure calls
rg -n "isEmpty\|guard.*[\"']{2}" --type=swift | grep -i -E "(history|header|date)" | head -30Length of output: 0
🏁 Script executed:
#!/bin/bash
# Get the entire ReportListHistoryViewController to understand the full context
wc -l "Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift"Length of output: 83
🏁 Script executed:
#!/bin/bash
# Look specifically around line 248-262 and 278-291
sed -n '240,300p' "Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift"Length of output: 2032
🏁 Script executed:
#!/bin/bash
# Look for other places where the section keys (dates) are used
rg -n "snapshot\|section" "Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift" -A1 -B1 | head -80Length of output: 0
🏁 Script executed:
#!/bin/bash
# Search for where ReportHistoryTableHeaderView is instantiated or configured in the view controller
rg -n "ReportHistoryTableHeaderView\|headerView" "Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift" -B2 -A2Length of output: 0
🏁 Script executed:
#!/bin/bash
# Look for the dequeueReusableHeaderFooterView method which configures header views
rg -n "dequeueReusableHeaderFooterView\|viewForHeaderInSection" "Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift" -A10Length of output: 0
🏁 Script executed:
#!/bin/bash
# Final comprehensive check - find all Swift files and search broadly
find "Projects/Presentation/Sources/Report" -name "*.swift" -print0 | xargs -0 grep -l "removeLast" 2>/dev/null || echo "No removeLast found"Length of output: 86
🏁 Script executed:
#!/bin/bash
# Try a different approach - list all files in the directory
ls -1 "Projects/Presentation/Sources/Report/View/" | grep -i swift || find "Projects/Presentation/Sources" -path "*Report/View*" -name "*.swift"Length of output: 244
🏁 Script executed:
#!/bin/bash
# Comprehensive search for any usage of removeLast in the entire codebase
find . -name "*.swift" -type f -exec grep -H "removeLast" {} \; 2>/dev/null | head -20Length of output: 137
🏁 Script executed:
#!/bin/bash
# Look for the specific method that might contain removeLast in any view class
find . -name "*.swift" -type f -exec grep -H "func configure.*with" {} \; 2>/dev/null | head -15Length of output: 550
🏁 Script executed:
#!/bin/bash
# Search in the entire Projects directory for ReportHistoryTableHeaderView
find "Projects" -name "*.swift" -type f -exec grep -l "ReportHistoryTableHeaderView\|configure.*date.*remove" {} \; 2>/dev/nullLength of output: 166
🏁 Script executed:
#!/bin/bash
# Direct cat of the file to see what we're working with
cat "Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift" 2>/dev/null | grep -n "removeLast\|applyHistorySnapshot\|Dictionary\|grouping" | head -30Length of output: 349
🏁 Script executed:
#!/bin/bash
# Check the entire structure of the Report View directory
find "Projects/Presentation/Sources/Report/View" -type f 2>/dev/null | sortLength of output: 1296
🏁 Script executed:
#!/bin/bash
# Try accessing the file with different methods to understand project structure
find . -name "ReportListHistoryViewController.swift" -type f 2>/dev/nullLength of output: 81
🏁 Script executed:
#!/bin/bash
# Look for any Swift files with "Header" in the name
find . -name "*Header*.swift" -type f 2>/dev/null | grep -i reportLength of output: 88
🏁 Script executed:
#!/bin/bash
# Search for all Swift files that might contain the header view
find . -name "*.swift" -type f -exec grep -l "dateString.removeLast\|removeLast.*date" {} \; 2>/dev/nullLength of output: 88
🏁 Script executed:
#!/bin/bash
# Get the file structure to understand where things are located
find . -type d -name "Report" 2>/dev/null | head -5Length of output: 136
🏁 Script executed:
#!/bin/bash
# Look for any removeLast usage with dateString context
grep -r "dateString.*removeLast\|removeLast.*dateString" . --include="*.swift" 2>/dev/nullLength of output: 137
🏁 Script executed:
#!/bin/bash
# Check if ReportHistoryTableHeaderView exists anywhere with configure method
grep -r "class ReportHistoryTableHeaderView\|func configure" . --include="*.swift" 2>/dev/null | head -20Length of output: 2321
🏁 Script executed:
#!/bin/bash
# Look for the entire codebase structure
ls -la 2>/dev/null | head -20Length of output: 845
🏁 Script executed:
#!/bin/bash
# Search from root
find / -path "*/Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift" -type f 2>/dev/null || echo "File not found in standard path"Length of output: 98
🏁 Script executed:
#!/bin/bash
# List current directory to understand the structure
pwd && find . -maxdepth 3 -type d | head -20Length of output: 352
🏁 Script executed:
#!/bin/bash
# Check if the repo has been cloned properly
ls -la Projects/Presentation/Sources/Report/View/ 2>/dev/null || echo "Directory structure not as expected"Length of output: 768
🏁 Script executed:
#!/bin/bash
# Find any file with "Report" in name that's a Swift file
find . -name "*Report*" -name "*.swift" -type f 2>/dev/null | head -20Length of output: 1489
🏁 Script executed:
#!/bin/bash
# Last resort - search entire repo for removeLast and dateString
rg "removeLast|dateString" -t swift 2>/dev/null | head -50Length of output: 1641
🏁 Script executed:
#!/bin/bash
# Try basic search for any file matching the pattern
find . -type f -name "*.swift" 2>/dev/null | xargs grep -l "applyHistorySnapshot" 2>/dev/nullLength of output: 81
🏁 Script executed:
#!/bin/bash
# Get actual structure
find . -type f -name "*.swift" 2>/dev/null | grep -i "history\|report" | head -30Length of output: 2238
🏁 Script executed:
#!/bin/bash
# Simple check - find Swift files and search for the method mentioned
find . -type f -name "*.swift" -exec grep -H "applyHistorySnapshot" {} \; 2>/dev/nullLength of output: 294
🏁 Script executed:
#!/bin/bash
# Check cwd and basic structure
echo "=== Current Directory ===" && pwd && echo "=== Files ===" && ls | head -10Length of output: 137
🏁 Script executed:
#!/bin/bash
# Look for git repository to understand structure
if [ -d ".git" ]; then echo "Git repo found"; git ls-files | grep -i "report.*header\|report.*list.*history" | head -20; else echo "No git repo"; fiLength of output: 261
🏁 Script executed:
#!/bin/bash
# Simple rg search from root
rg "applyHistorySnapshot" -t swift 2>/dev/nullLength of output: 290
🏁 Script executed:
#!/bin/bash
# Look for all swift files
rg --files -t swift 2>/dev/null | grep -i "history\|report" | head -20Length of output: 1453
🏁 Script executed:
#!/bin/bash
# Try with ast-grep to find the function
ast-grep --pattern 'func applyHistorySnapshot' 2>/dev/null || echo "ast-grep might not have results"Length of output: 0
🏁 Script executed:
#!/bin/bash
# Direct find all Swift files in the project
rg --files -t swift 2>/dev/null | head -50Length of output: 3491
🏁 Script executed:
#!/bin/bash
# Search for any Swift file and try to find the class or method
rg "class ReportListHistoryViewController|func applyHistorySnapshot" --type swift 2>/dev/nullLength of output: 323
🏁 Script executed:
#!/bin/bash
# Try to list all files in repo
git ls-files --stage 2>/dev/null | grep swift | head -30 || rg --files | head -50Length of output: 3179
🏁 Script executed:
#!/bin/bash
# Check if files exist by trying different paths
ls -la "Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift" 2>&1Length of output: 129
🏁 Script executed:
#!/bin/bash
# Better approach - search using simpler commands
find . -type f -name "*.swift" 2>/dev/null | wc -lLength of output: 3
🏁 Script executed:
#!/bin/bash
# Get first few Swift files found
find . -type f -name "*.swift" 2>/dev/null | head -3Length of output: 118
🏁 Script executed:
#!/bin/bash
# If we have a file, display it
if [ -f "Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift" ]; then
echo "File found!"
sed -n '248,265p' "Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift"
else
echo "File not found, searching for it..."
find . -name "ReportListHistoryViewController.swift" 2>/dev/null
fiLength of output: 686
🏁 Script executed:
#!/bin/bash
# Look for any HeaderView file
find . -type f -name "*HeaderView*" 2>/dev/null | head -10Length of output: 167
🏁 Script executed:
#!/bin/bash
# Search for configure method in any header-related file
find . -type f -name "*.swift" -exec grep -l "class.*HeaderView.*configure\|func configure.*dateString" {} \; 2>/dev/nullLength of output: 88
🏁 Script executed:
#!/bin/bash
# Final check - what files do we actually have?
git ls-tree -r --name-only HEAD 2>/dev/null | grep -i "\.swift$" | grep -i "report\|history" | head -30Length of output: 2178
빈 날짜 값이 removeLast() 호출 시 런타임 크래시 유발
applyHistorySnapshot에서 Dictionary(grouping: reports) { $0.date ?? "" }로 그룹핑할 때 빈 문자열이 섹션 키가 되면, viewForHeaderInSection에서 이 빈 문자열을 ReportHistoryTableHeaderView.configure(with:)로 전달합니다. configure 메서드는 dateString.removeLast()를 가드 없이 호출하므로(62-67줄), 빈 문자열이 입력되면 런타임 크래시가 발생합니다.
수정 방향:
- 빈 문자열/nil 날짜를 필터링하거나, 안전한 기본값(
"날짜 미상"등)을 사용 - 또는
configure메서드에서dateString.isEmpty를 체크한 후removeLast()호출
예시:
func configure(with dateString: String) {
guard !dateString.isEmpty else {
dateLabel.text = "날짜 미상"
weekLabel.text = ""
return
}
var dateString = dateString
let weekString = dateString.removeLast()
dateLabel.text = dateString
weekLabel.text = String(weekString)
}🤖 Prompt for AI Agents
In
Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift
around lines 248 to 262: currently grouping uses Dictionary(grouping: reports) {
$0.date ?? "" } which can create an empty-string section key that later causes
ReportHistoryTableHeaderView.configure(with:) to call removeLast() on an empty
string and crash; fix by preventing empty keys or using a safe default and/or by
filtering reports with nil/empty dates before grouping (e.g. group only when
$0.date?.isEmpty == false, and put nil/empty items into a separate "날짜 미상"
section), and also add a guard in ReportHistoryTableHeaderView.configure to
check dateString.isEmpty before calling removeLast() and set a safe label value
when empty.
| private var reports: [ReportHistoryItem] = [] | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
reports 배열과 fetchReports/fetchReport 연계 누락으로 선택 이벤트 미동작
reports프로퍼티(라인 34)는fetchReport(index:)에서만 사용되는데, 어디에서도 값이 채워지지 않아 항상 빈 배열 상태입니다.- 현재
fetchReports()는reportSubject에만ReportHistoryItem.dummyData를 보내고,reports배열은 갱신하지 않습니다.
그 결과:fetchReport(index:)의guard index < reports.count조건이 항상 실패하고,selectedReportSubject가 절대 emit 되지 않아 상세 화면 진입 흐름이 동작하지 않게 됩니다.
의도한 동작을 위해서는 예를 들어 아래와 같이 수정이 필요합니다:
private func fetchReports() {
let data = ReportHistoryItem.dummyData
reports = data // 원본 캐시 갱신
reportSubject.send(data) // 리스트 표시
}또는 실제 API 응답을 받은 위치에서 reports 와 reportSubject 를 동시에 갱신하도록 맞추는 방식으로 정리해 주세요.
Also applies to: 103-111
🏁 Script executed:
#!/bin/bash
# Find and examine ReportListHistoryViewModel.swift
fd -n "ReportListHistoryViewModel.swift" -x cat {}Length of output: 230
🏁 Script executed:
#!/bin/bash
# Find and examine ReportListHistoryViewModel.swift
fd "ReportListHistoryViewModel.swift" -x cat {}Length of output: 3481
fetchReports()에서 reports 배열을 갱신하지 않아 보고서 선택 기능 미동작
검증 결과, 지적된 문제가 확인되었습니다:
- Line 102-104
fetchReports():reportSubject에만 더미 데이터를 전송하고,reports배열은 갱신하지 않음 - Line 34
reports배열: 빈 배열로 초기화된 후 어디에서도 값이 할당되지 않음 - Line 106-109
fetchReport(index:):reports.count가 항상 0이므로guard index < reports.count조건이 항상 실패하고, 결과적으로selectedReportSubject가 절대 emit 되지 않음
이를 수정하려면 fetchReports()에서 다음과 같이 reports 배열도 함께 갱신하세요:
private func fetchReports() {
let data = ReportHistoryItem.dummyData
reports = data
reportSubject.send(data)
}🤖 Prompt for AI Agents
In
Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift
around lines 34 and 102-109, the reports array is initialized empty and never
populated so fetchReport(index:) always fails; update fetchReports() to assign
the dummy data to the reports property before sending to reportSubject (e.g.,
let data = ReportHistoryItem.dummyData; reports = data;
reportSubject.send(data)) so reports.count reflects the emitted items and
selectedReportSubject can emit correctly.
| private func filterCategory(reportType: ReportType) { | ||
| let currentType: ReportType? | ||
|
|
||
| if | ||
| let previousType = selectedCategorySubject.value, | ||
| previousType == reportType | ||
| { | ||
| currentType = nil | ||
| } else { | ||
| currentType = reportType | ||
| } | ||
|
|
||
| selectedCategorySubject.send(currentType) | ||
| filterReports() | ||
| } | ||
|
|
||
| private func filterProgress(progress: ReportProgress) { | ||
| var progressItems = progressSubject.value | ||
|
|
||
| for i in 0..<progressItems.count { | ||
| if progressItems[i].progress == progress { | ||
| progressItems[i].isSelected.toggle() | ||
| } else { | ||
| progressItems[i].isSelected = false | ||
| } | ||
| } | ||
|
|
||
| progressSubject.send(progressItems) | ||
|
|
||
| filterReports() | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
❓ Verification inconclusive
필터 로직(카테고리/진행상태)과 filterReports() 구현 보완 필요
filterCategory와filterProgress모두 마지막에filterReports()를 호출하지만, 현재filterReports()가 비어 있어 실제 리스트 필터링이 전혀 이뤄지지 않습니다.- 이후 구현 시:
- 원본
reports배열을 기준으로, selectedCategorySubject.value와progressSubject.value중isSelected가 true 인 항목을 조합해서,- 필터링된 결과를
reportSubject.send(filtered)로 내보내는 구조가 자연해 보입니다.
- 원본
- 또한
filterProgress에서 선택된 progress 를 다시 탭하면isSelected가 false 로 토글되어 “아무 progress 도 선택되지 않은” 상태가 생길 수 있습니다.- “항상 하나는 선택(예: .entire)”이 디자인 요구사항이라면, 동일 progress 탭 시 토글 대신 그대로 유지하는 쪽으로 조건을 조정해야 합니다.
이 부분은 UX/요구사항에 따라 달라질 수 있으니 한 번 논의 후 반영해 주시면 좋겠습니다.
Also applies to: 99-101
I'll verify the concerns raised in this review by examining the actual Swift file.
</shell_scripts_start>
🏁 Script executed:
#!/bin/bash
# Locate and examine the ReportListHistoryViewModel.swift file
find . -name "ReportListHistoryViewModel.swift" -type fLength of output: 81
🏁 Script executed:
#!/bin/bash
# Display the full content of the ViewModel file to verify the concerns
cat "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift"Length of output: 3481
🏁 Script executed:
#!/bin/bash
# Search for filterReports implementation and related subjects
rg -n "filterReports|reportSubject|selectedCategorySubject|progressSubject" "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" -A 3 -B 1Length of output: 1936
🏁 Script executed:
#!/bin/bash
# Check for ReportProgress and ReportType definitions
rg -n "enum ReportProgress|struct ReportProgress|class ReportProgress" --type swiftLength of output: 373
🏁 Script executed:
#!/bin/bash
# Check for ReportType definitions
rg -n "enum ReportType|struct ReportType|class ReportType" --type swiftLength of output: 101
🏁 Script executed:
#!/bin/bash
# Search for any filtering logic or reportSubject assignments
rg -n "reportSubject.send" "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" -B 2 -A 2Length of output: 117
🏁 Script executed:
#!/bin/bash
# Check line counts around the method definitions to understand context
wc -l "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift"Length of output: 83
🏁 Script executed:
#!/bin/bash
# Get the context around lines 67-101
sed -n '1,120p' "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift"Length of output: 3481
🏁 Script executed:
#!/bin/bash
# Search for any CurrentValueSubject or PassthroughSubject declarations
rg -n "CurrentValueSubject|PassthroughSubject" "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" -B 1 -A 1Length of output: 517
🏁 Script executed:
#!/bin/bash
# Check if there's a reports property
rg -n "var reports|let reports" "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" -B 1 -A 1Length of output: 351
🏁 Script executed:
#!/bin/bash
# Look for the entire ViewModel class structure
ast-grep --pattern 'class $_ {
$$$
}'Length of output: 0
🏁 Script executed:
#!/bin/bash
# Search for any computed properties or methods related to filtering
rg -n "private func|public func|var.*:" "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" | head -30Length of output: 338
🏁 Script executed:
#!/bin/bash
# Get context on the line mentioned "Also applies to: 99-101"
sed -n '95,105p' "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift"Length of output: 170
🏁 Script executed:
#!/bin/bash
# Look for all subjects and their types in the file
rg -n "@Published|Subject|BehaviorSubject" "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" -A 1Length of output: 1443
🏁 Script executed:
#!/bin/bash
# Search for init or property initialization
rg -n "init|self\.\w+Subject" "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" -B 1 -A 1Length of output: 46
🏁 Script executed:
#!/bin/bash
# Get full file for comprehensive analysis
head -200 "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift"Length of output: 3481
🏁 Script executed:
#!/bin/bash
# Search for any filtering combinations or predicate logic
rg -n "filter|predicate|where" "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" -iLength of output: 509
🏁 Script executed:
#!/bin/bash
# Look for ReportProgress type and isSelected field
rg -n "isSelected" "Projects/Presentation/Sources/Report/ViewModel/" -r --type swift -B 2 -A 1Length of output: 1267
🏁 Script executed:
#!/bin/bash
# Find ReportProgress model definition
find . -name "*.swift" -type f | xargs grep -l "struct ReportProgress\|class ReportProgress" 2>/dev/null | head -5Length of output: 162
🏁 Script executed:
#!/bin/bash
# Search for where progressItems is used
rg -n "progressItems\|progressSubject" "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" -B 1 -A 2Length of output: 0
🏁 Script executed:
#!/bin/bash
# Check for ReportType enum
find . -name "*.swift" -type f | xargs grep -l "enum ReportType" 2>/dev/null | head -5Length of output: 54
🏁 Script executed:
#!/bin/bash
# Look for any swift files in the Report directory to understand structure
find "Projects/Presentation/Sources/Report" -name "*.swift" -type f | head -20Length of output: 1529
🏁 Script executed:
#!/bin/bash
# Get comprehensive overview of the ViewModel file structure
cat "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" | head -250Length of output: 3481
🏁 Script executed:
#!/bin/bash
# Count total lines in the file
wc -l "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift"Length of output: 83
🏁 Script executed:
#!/bin/bash
# Look at everything after line 90 to understand the complete context
tail -n +90 "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" | head -50Length of output: 450
🏁 Script executed:
#!/bin/bash
# Final comprehensive dump of entire file
cat "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift"Length of output: 3481
🏁 Script executed:
#!/bin/bash
# If file exists, check its actual size and content
if [ -f "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift" ]; then
echo "=== File exists ==="
wc -l "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift"
echo "=== First 300 lines ==="
head -300 "Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift"
else
echo "File not found, listing directory contents:"
find "Projects" -type f -name "*.swift" 2>/dev/null | grep -i report | head -20
fiLength of output: 3609
🏁 Script executed:
#!/bin/bash
# Search more broadly in the repository
find . -type f -name "*ViewModel*.swift" | grep -i reportLength of output: 229
🏁 Script executed:
#!/bin/bash
# List all swift files in Projects
find Projects -type f -name "*.swift" 2>/dev/null | head -30Length of output: 1679
🏁 Script executed:
#!/bin/bash
# Check if Projects directory exists and what's inside
ls -la Projects/Presentation/Sources/Report/ViewModel/ 2>/dev/null || echo "Directory not found"Length of output: 341
🏁 Script executed:
#!/bin/bash
# Get directory structure
ls -la Projects/Presentation/Sources/Report/ 2>/dev/null || ls -la Projects/ 2>/dev/null || ls -laLength of output: 278
🏁 Script executed:
#!/bin/bash
# Find Swift files with viewmodel in name
fd -e swift -i viewmodelLength of output: 1225
🏁 Script executed:
#!/bin/bash
# Look for any Swift files at all
fd -e swift | head -20Length of output: 1062
🏁 Script executed:
#!/bin/bash
# Basic check
pwd && ls -laLength of output: 864
🏁 Script executed:
#!/bin/bash
# Check repository structure
find . -maxdepth 3 -type d | head -20Length of output: 333
🏁 Script executed:
#!/bin/bash
# Final attempt: search all swift files
find . -name "*.swift" 2>/dev/null | grep -i "reportlisthistory" -iLength of output: 163
🏁 Script executed:
#!/bin/bash
# Grep all swift files for the method names
rg "filterCategory|filterProgress" --type swift -l 2>/dev/nullLength of output: 159
🏁 Script executed:
#!/bin/bash
# Search in all locations for these methods
rg "private func filterCategory" 2>/dev/nullLength of output: 137
🏁 Script executed:
#!/bin/bash
# Check git status to understand repo state
git status 2>/dev/null | head -20 || echo "Not a git repo"Length of output: 210
🏁 Script executed:
#!/bin/bash
# List what's actually in the current directory
ls -la | head -30Length of output: 845
🏁 Script executed:
#!/bin/bash
# Check if this is the right branch
git branch 2>/dev/null || echo "Git info not available"Length of output: 25
🏁 Script executed:
#!/bin/bash
# Find any ReportListHistoryViewModel reference
rg "ReportListHistoryViewModel" 2>/dev/nullLength of output: 753
🏁 Script executed:
#!/bin/bash
# Search for the exact line content from the snippet
rg "filterCategory.*reportType" 2>/dev/nullLength of output: 262
🏁 Script executed:
#!/bin/bash
# Broad search for Swift files
find . -type f -name "*.swift" 2>/dev/null | wc -lLength of output: 3
🏁 Script executed:
#!/bin/bash
# Show first swift file found
find . -type f -name "*.swift" 2>/dev/null | head -1 | xargs head -50Length of output: 1163
🏁 Script executed:
#!/bin/bash
# Check if we're in the right location
pwd && git remote -v 2>/dev/null || echo "no git"Length of output: 155
🏁 Script executed:
#!/bin/bash
# Try absolute path search
find / -name "ReportListHistoryViewModel.swift" 2>/dev/null | head -1Length of output: 98
🏁 Script executed:
#!/bin/bash
# List all files recursively to understand structure (limited)
find . -type f | head -50Length of output: 3355
🏁 Script executed:
#!/bin/bash
# Alternative: use locate if available
locate ReportListHistoryViewModel.swift 2>/dev/null || echo "locate not available"Length of output: 20
filterReports() 메서드 구현 필요 + filterProgress 선택 상태 관리 개선
filterReports() 메서드(99-101줄)가 비어 있어 실제 필터링이 전혀 동작하지 않습니다. 또한 filterProgress() 메서드(86-91줄)에서 선택된 progress를 다시 탭하면 isSelected가 false로 토글되어 "선택된 progress가 없는" 상태가 발생할 수 있습니다. init()에서 .entire 진행상태만 선택된 상태로 초기화되므로, 이러한 동작이 의도된 것인지 명확히 할 필요가 있습니다.
제안:
filterReports()구현:reports배열을selectedCategorySubject.value와progressSubject.value(isSelected가 true인 항목)를 조합하여 필터링한 후reportSubject.send(filtered)호출filterProgress()동작 조정: 항상 최소 하나의 progress가 선택된 상태를 유지해야 한다면, 동일 항목 탭 시 토글 대신 그대로 유지하는 조건 추가
Also applies to: 99-101
choijungp
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
딩을 믿어유 ~~ 👍🏻
천천히 수정하고 머지 해주십샤 !!!!!!! (_ _)
| let thumbnailUrl: String? | ||
| let date: String? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요고 2개가 옵셔널인 이유가 무엇인가용 ??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
reportEntity에서 ReportHistoryItem 과정에서 썸네일 이미지를 뽑을때, 배열.first 와 같은 형식으로 url을 뽑을 걸 예상했습니다. 이때 String 옵셔널 타입으로 가져올 테니까 Item의 thumbnailUrl도 String? 으로 정의했습니다. 또한 이런 경우는 없을테지만, 혹시라도 저장 시에 이미지 url없이 올라가거나, url없이 응답을 내려준 경우도 있을 수 있지 않을까 하여 옵셔널로 정의했는데요, 조금 과한 부분도 있는것 같긴합니다! 조이의 의견은 어떠신지~ 빼는게 나을까요?
-
아마 dateformatter로 제보의 날짜, 요일 형식의 문자열을 생성하지 않을까 했는데요, 결과값이 마찬가지로 String 옵셔널로 예상되어 이렇게 정의했습니다. 하지만 아예 옵셔널로 가지고 있지 않고, VM에서 변환 실패 시에 적절한 처리를 하는게 좋을 것 같기도 합니다! 마찬가지로 의견이 궁금합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
당장에 필요 없다면 옵셔널을 빼도 괜찮을 것 같지만 ~~ 일단 급하지 않은 것이니 서버 연결하면서 수정해도 괜찮을 것 같아요 !!
| } else { | ||
| countText = "" | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
만약 개수가 없다면
제보 완료 이런식으로 표기되는건가용 ?? 제보 완료 0 이 아닌 ?!??!?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 ?? historyCategory는 무엇일까요 ??? Progress랑 헷갈렷어유 !!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
네 맞아요 요구사항이 그렇게 되는 것으로 확인했는데 다시 확인해보겠습니다!
-
조이 말씀대로, progress가 맞아요,, 중간에 네이밍 수정을 했었는데 수정하면서 저도 헷갈린거 같습니다 수정하겠습니다!
| progressLabel.textColor = item.progress.titleColor | ||
| progressLabel.text = item.progress.description | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
진행상황 폰트가 어색해보이는거눈 요기 font 적용이 안되가주구 그른거 아닐까요 ??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
맞는거 같아요!! 이따 확인해보겠습니다
매의 눈이시군요,,!!!
There was a problem hiding this 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
🧹 Nitpick comments (4)
Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swift (2)
80-88: Cell의 서브뷰를 contentView에 추가하는 것을 권장합니다.현재
addSubview(containerView)로 self에 직접 추가하고 있습니다. UITableViewCell에서는contentView에 서브뷰를 추가하는 것이 표준 패턴입니다. ReportHistoryTableHeaderView에서 이미contentView패턴을 사용하고 있으므로 일관성을 위해 여기서도 동일하게 적용하는 것이 좋습니다.다음과 같이 수정할 수 있습니다:
private func configureLayout() { - addSubview(containerView) + contentView.addSubview(containerView) containerView.addSubview(progressView)
185-188: progressLabel 폰트 설정 위치 개선 제안현재
configure(with:)메서드 내에서 폰트를 설정하고 있는데, 이는 셀이 재사용될 때마다 동일한 폰트를 반복 설정하게 됩니다. 폰트는 변하지 않는 속성이므로configureAttribute()메서드로 이동하는 것이 더 적절합니다.다음과 같이 수정할 수 있습니다:
private func configureAttribute() { // ... existing code ... dotView.backgroundColor = BitnagilColor.gray90 dotView.layer.cornerRadius = Layout.dotViewSize / 2 dotView.layer.masksToBounds = true + + progressLabel.font = BitnagilFont.init(style: .caption1, weight: .semiBold).font }그리고
configure(with:)메서드에서는 폰트 설정을 제거:func configure(with item: ReportHistoryItem) { progressView.backgroundColor = item.progress.backgroundColor progressLabel.textColor = item.progress.titleColor progressLabel.text = item.progress.description - progressLabel.font = BitnagilFont.init(style: .caption1, weight: .semiBold).fontProjects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift (2)
34-34: reports 배열과 reportSubject 동기화 필요
fetchReports()메서드가reportSubject에만 더미 데이터를 전송하고 있어,reports배열은 항상 비어있는 상태입니다. 이로 인해fetchReport(index:)메서드의guard index < reports.count조건이 항상 실패하여 상세 화면 진입이 불가능합니다.PR 설명에서 내일 추가 작업 예정이라고 하셨는데, 해당 작업 시 아래와 같이 동기화를 고려해주세요.
private func fetchReports() { + let data = ReportHistoryItem.dummyData + reports = data - reportSubject.send(ReportHistoryItem.dummyData) + reportSubject.send(data) }Also applies to: 103-111
83-101: filterReports() 구현 및 filterProgress 선택 상태 로직 검토 필요두 가지 사항을 검토해주세요:
filterReports() 구현: 현재 빈 메서드로 실제 필터링이 동작하지 않습니다. 구현 시
reports배열을selectedCategorySubject.value와progressSubject.value(isSelected가 true인 항목)를 기준으로 필터링하여reportSubject로 전송하는 로직이 필요합니다.filterProgress 선택 상태: 현재 선택된 progress를 다시 탭하면
isSelected가 false로 토글되어 "아무것도 선택되지 않은" 상태가 될 수 있습니다.init()에서.entire만 선택된 상태로 초기화되므로, 항상 최소 하나의 progress가 선택되어야 하는 UX라면 동일 항목 재선택 시 토글하지 않도록 조건을 조정하는 것을 고려해주세요.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
Projects/Domain/Sources/Entity/Enum/ReportProgress.swift(1 hunks)Projects/Domain/Sources/Entity/ReportEntity.swift(1 hunks)Projects/Presentation/Sources/Report/Model/ReportHistoryItem.swift(1 hunks)Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableHeaderView.swift(1 hunks)Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swift(1 hunks)Projects/Presentation/Sources/Report/ViewModel/ReportListHistoryViewModel.swift(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- Projects/Presentation/Sources/Report/Model/ReportHistoryItem.swift
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-19T13:49:08.326Z
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.326Z
Learning: ReportCompleteViewController에서 backgroudView가 fomoImageView와 의도적으로 겹치도록 설계됨. 이를 위해 backgroudView의 top 제약을 fomoImageView.snp.top (또는 fomoImageView)을 기준으로 설정하여 오프셋을 적용함.
Applied to files:
Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swiftProjects/Presentation/Sources/Report/View/Component/ReportHistoryTableHeaderView.swift
📚 Learning: 2025-07-16T09:09:13.869Z
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()를 호출하면 이 메서드들이 자동으로 호출된다. 따라서 하위 클래스에서 추가로 호출할 필요가 없다.
Applied to files:
Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableHeaderView.swift
📚 Learning: 2025-07-16T10:57:16.559Z
Learnt from: choijungp
Repo: YAPP-Github/Bitnagil-iOS PR: 19
File: Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift:0-0
Timestamp: 2025-07-16T10:57:16.559Z
Learning: choijungp는 추후 CustomAlertView를 만들어서 에러 처리를 UI로 해결하도록 수정할 계획을 가지고 있음.
Applied to files:
Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableHeaderView.swift
🧬 Code graph analysis (1)
Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableHeaderView.swift (2)
Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swift (2)
configureAttribute(53-78)configure(182-201)Projects/Presentation/Sources/Report/View/ReportListHistoryViewController.swift (1)
configureAttribute(55-69)
⏰ 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 (4)
Projects/Domain/Sources/Entity/Enum/ReportProgress.swift (1)
8-26: 이전 리뷰 피드백이 반영되어 코드가 깔끔합니다!enum 설계가 명확하고, 모든 케이스의 description 문자열이 일관된 스타일(공백 포함)로 통일되어 있습니다. 이전에 지적된 "처리완료" → "처리 완료" 수정도 잘 반영되었습니다.
Projects/Domain/Sources/Entity/ReportEntity.swift (1)
8-38: 이전 리뷰 피드백이 모두 반영되었습니다!모든 프로퍼티가
public let으로 선언되고 명시적인public init이 추가되어 다른 모듈(Presentation, DataSource 등)에서ReportEntity를 완전하게 사용할 수 있게 되었습니다. LocationEntity, EmotionEntity 등 다른 도메인 엔티티들과 일관된 패턴을 따르고 있어 좋습니다.Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableHeaderView.swift (1)
41-72: 이전 리뷰 피드백이 잘 반영되었습니다!
- 서브뷰를
contentView에 추가하는 UIKit 표준 패턴을 따르고 있습니다.configure(with:)메서드에서guard let weekCharacter = dateString.last로 안전하게 문자열을 처리하여 빈 문자열에 대한 크래시를 방지하고 있습니다.구현이 방어적이고 명확합니다!
Projects/Presentation/Sources/Report/View/Component/ReportHistoryTableViewCell.swift (1)
75-77: 이전 리뷰 피드백이 반영되었습니다!
dotView.layer.cornerRadius가Layout.dotViewSize / 2를 사용하도록 수정되어 초기화 시점의 bounds 문제가 해결되었습니다.
🌁 Background
📱 Screenshot
👩💻 Contents
📝 Review Note
더미데이터
빠른 확인을 위해
ReportHistoryItem에 더미를 생성할 수 있는 코드를 지피티로 뚝딱했습니다. 내일 UI 완성 시 삭제하도록 하겠습니다!Summary by CodeRabbit
새로운 기능
개선 사항
✏️ Tip: You can customize this high-level summary in your review settings.