-
Notifications
You must be signed in to change notification settings - Fork 1
[Feat-T3-203] 제보 히스토리 API 연동 #72
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보고서 목록 조회 기능을 추가하며, 새로운 데이터 모델과 엔드포인트를 도입하고, 의존성 주입을 통해 뷰 계층을 업데이트하여 보고서 선택 처리를 구현합니다. Changes
Sequence DiagramsequenceDiagram
participant VC as ReportHistoryViewController
participant VM as ReportHistoryViewModel
participant Repo as ReportRepository
participant Endpoint as ReportEndpoint
participant API as API Server
Note over VC,API: 보고서 목록 조회 흐름
VC->>VM: 초기화 (reportRepository 주입)
VM->>Repo: fetchReports()
Repo->>Endpoint: fetchReports 요청
Endpoint->>API: GET /reports
API-->>Endpoint: ReportDictonaryDTO 응답
Endpoint-->>Repo: 응답 반환
Repo->>Repo: reportInfos 순회<br/>각 ReportDTO를<br/>toReportEntity(date:)로 변환
Repo-->>VM: [ReportEntity] 반환
VM->>VM: ReportHistoryItem으로 매핑<br/>reportSubject 발행
VM-->>VC: reports 데이터 업데이트
Note over VC,VM: 보고서 행 선택 흐름
VC->>VC: tableView(_:didSelectRowAt:) 호출
VC->>VC: 스냅샷에서 선택 항목 조회
VC->>VC: DIContainer에서 ReportDetailViewModel 해결
VC->>VC: ReportDetailViewController 생성 및 푸시
VC->>VC: 행 선택 해제
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 특히 다음 부분은 검토 시 주의 깊게 확인이 필요합니다:
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 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: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Projects/Presentation/Sources/Report/ViewModel/ReportHistoryViewModel.swift (1)
87-101: 진행 상태 필터링 로직 오류를 수정하세요.
filterProgress메서드가selectedProgressSubject를 업데이트하지 않아서,filterReports()의 Line 108-110에서 진행 상태 필터링이 작동하지 않습니다.다음과 같이 수정하세요:
private func filterProgress(progress: ReportProgress) { var progressItems = progressSubject.value + var selectedProgress: ReportProgress? = nil for i in 0..<progressItems.count { if progressItems[i].progress == progress { progressItems[i].isSelected.toggle() + if progressItems[i].isSelected { + selectedProgress = progress + } } else { progressItems[i].isSelected = false } } progressSubject.send(progressItems) + selectedProgressSubject.send(selectedProgress) filterReports() }
🧹 Nitpick comments (3)
Projects/DataSource/Sources/DTO/ReportDTO.swift (1)
39-53: 코드 중복을 제거하여 유지보수성을 개선하세요.새로 추가된
toReportEntity(date:)메서드가 기존toReportEntity()메서드와 거의 동일한 로직을 포함하고 있습니다. 날짜 소스만 다를 뿐 나머지 매핑 로직이 완전히 중복됩니다.다음과 같이 리팩토링하여 중복을 제거할 수 있습니다:
func toReportEntity() throws -> ReportEntity { - guard let reportId else { throw NetworkError.decodingError } - return ReportEntity( - id: reportId, - title: reportTitle, - date: reportDate, - type: ReportType(rawValue: reportCategory) ?? .transportation, - progress: ReportProgress(rawValue: reportStatus) ?? .received, - content: reportContent, - location: LocationEntity( - longitude: longitude, - latitude: latitude, - address: reportLocation), - photoUrls: reportImageUrls ?? []) + return try toReportEntity(date: reportDate) } func toReportEntity(date: String?) throws -> ReportEntity { guard let reportId else { throw NetworkError.decodingError } return ReportEntity( id: reportId, title: reportTitle, date: date, type: ReportType(rawValue: reportCategory) ?? .transportation, progress: ReportProgress(rawValue: reportStatus) ?? .received, content: reportContent, location: LocationEntity( longitude: longitude, latitude: latitude, address: reportLocation), photoUrls: reportImageUrls ?? []) }Projects/DataSource/Sources/Repository/ReportRepository.swift (1)
17-29: 에러 처리 및 로깅을 개선하세요.현재 구현에서 여러 에러 상황이 조용히 무시됩니다:
- Line 20: 응답이
nil일 때 빈 배열을 반환합니다.- Line 24:
try?를 사용하여 개별 보고서 변환 실패를 무시합니다.디버깅과 모니터링을 위해 에러를 로깅하거나, 중요한 실패의 경우 에러를 전파하는 것을 고려하세요.
개선 제안:
func fetchReports() async throws -> [ReportEntity] { let endpoint = ReportEndpoint.fetchReports - guard let response = try await networkService.request(endpoint: endpoint, type: ReportDictonaryDTO.self) - else { return [] } + guard let response = try await networkService.request(endpoint: endpoint, type: ReportDictonaryDTO.self) + else { + BitnagilLogger.log(logType: .error, message: "fetchReports: 응답이 nil입니다.") + return [] + } var reportEntities: [ReportEntity] = [] for (date, reports) in response.reportInfos { - let reportHistories = reports.compactMap({ try? $0.toReportEntity(date: date) }) + let reportHistories = reports.compactMap({ + do { + return try $0.toReportEntity(date: date) + } catch { + BitnagilLogger.log(logType: .error, message: "보고서 변환 실패: \(error)") + return nil + } + }) reportEntities += reportHistories } return reportEntities }Projects/Presentation/Sources/Report/ViewModel/ReportHistoryViewModel.swift (1)
137-139: TODO 주석을 처리하세요.에러 처리 로직이 누락되어 있습니다. 네트워크 실패나 디코딩 오류 발생 시 사용자에게 피드백을 제공하거나 로깅을 추가하는 것을 권장합니다.
에러 처리 로직을 생성하거나 이 작업을 추적할 이슈를 생성하시겠습니까?
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
Projects/DataSource/Sources/DTO/ReportDTO.swift(1 hunks)Projects/DataSource/Sources/DTO/ReportDictonaryDTO.swift(1 hunks)Projects/DataSource/Sources/Endpoint/ReportEndpoint.swift(1 hunks)Projects/DataSource/Sources/Repository/ReportRepository.swift(1 hunks)Projects/Domain/Sources/Protocol/Repository/ReportRepositoryProtocol.swift(1 hunks)Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift(1 hunks)Projects/Presentation/Sources/Report/View/ReportHistoryViewController.swift(2 hunks)Projects/Presentation/Sources/Report/ViewModel/ReportHistoryViewModel.swift(4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: choijungp
Repo: YAPP-Github/Bitnagil-iOS PR: 30
File: Projects/DataSource/Sources/NetworkService/Plugin/RefreshTokenPlugin.swift:42-43
Timestamp: 2025-07-30T03:56:18.617Z
Learning: choijungp는 현재 테스트 단계에서 RefreshTokenPlugin의 토큰 갱신 로직 디버깅을 위해 액세스 토큰과 리프레시 토큰의 실제 값을 로그에 기록하는 것을 선호함.
🧬 Code graph analysis (5)
Projects/Domain/Sources/Protocol/Repository/ReportRepositoryProtocol.swift (1)
Projects/DataSource/Sources/Repository/ReportRepository.swift (1)
fetchReports(17-29)
Projects/DataSource/Sources/Endpoint/ReportEndpoint.swift (2)
Projects/DataSource/Sources/Repository/ReportRepository.swift (2)
fetchReports(17-29)fetchReportDetail(31-37)Projects/Presentation/Sources/Report/ViewModel/ReportDetailViewModel.swift (1)
fetchReportDetail(38-58)
Projects/DataSource/Sources/Repository/ReportRepository.swift (2)
Projects/DataSource/Sources/NetworkService/NetworkService.swift (1)
request(25-48)Projects/DataSource/Sources/DTO/ReportDTO.swift (2)
toReportEntity(23-37)toReportEntity(39-53)
Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift (1)
Projects/Shared/Sources/DIContainer/DIContainer.swift (2)
register(14-16)resolve(18-25)
Projects/Presentation/Sources/Report/View/ReportHistoryViewController.swift (2)
Projects/Presentation/Sources/MyPage/View/MypageView.swift (4)
tableView(135-137)tableView(139-141)tableView(143-154)tableView(156-180)Projects/Shared/Sources/DIContainer/DIContainer.swift (1)
resolve(18-25)
🔇 Additional comments (4)
Projects/Domain/Sources/Protocol/Repository/ReportRepositoryProtocol.swift (1)
11-13: LGTM!프로토콜에
fetchReports()메서드가 올바르게 추가되었으며, 문서화도 잘 되어 있습니다.Projects/DataSource/Sources/Endpoint/ReportEndpoint.swift (1)
9-9: LGTM!
fetchReports엔드포인트가 올바르게 추가되었습니다. GET 메서드와 적절한 경로 설정이 잘 구성되어 있습니다.Also applies to: 16-16, 23-24, 32-32
Projects/Presentation/Sources/Report/View/ReportHistoryViewController.swift (1)
320-340: LGTM!테이블뷰 행 선택 처리가 올바르게 구현되었습니다. DI 컨테이너를 통한 의존성 해결과 네비게이션 로직이 프로젝트의 기존 패턴과 일관되게 작성되었습니다.
Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift (1)
131-136: LGTM!
ReportHistoryViewModel에 대한 의존성 주입 설정이 올바르게 업데이트되었습니다.ReportRepositoryProtocol을 주입하는 방식이 파일 내 다른 뷰모델 등록과 일관되게 구현되었습니다.
| // | ||
| // ReportDictonaryDTO.swift | ||
| // DataSource | ||
| // | ||
| // Created by 최정인 on 11/21/25. | ||
| // | ||
|
|
||
| struct ReportDictonaryDTO: Decodable { | ||
| let reportInfos: [String: [ReportDTO]] | ||
| } |
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.
파일명과 타입명의 오타를 수정하세요.
파일명 ReportDictonaryDTO.swift와 구조체명 ReportDictonaryDTO에 오타가 있습니다. "Dictonary"는 "Dictionary"로 수정되어야 합니다.
다음과 같이 수정하세요:
- 파일명을
ReportDictionaryDTO.swift로 변경 - 구조체명을
ReportDictionaryDTO로 변경 - 이 타입을 사용하는 모든 곳에서 이름 업데이트 필요 (예:
ReportRepository.swiftLine 19,ReportEndpoint.swift)
🤖 Prompt for AI Agents
In Projects/DataSource/Sources/DTO/ReportDictonaryDTO.swift lines 1–10 the file
and struct name have a typo ("Dictonary" → "Dictionary"); rename the file to
ReportDictionaryDTO.swift and update the struct declaration to struct
ReportDictionaryDTO: Decodable { let reportInfos: [String: [ReportDTO]] }, then
search and replace all usages/imports across the codebase (e.g.,
ReportRepository.swift at around line 19, ReportEndpoint.swift and any tests or
references) to the new type name to ensure compilation.
| private func filterReports() { | ||
| let selectedProgress = selectedProgressSubject.value | ||
| let selectedCategory = selectedCategorySubject.value | ||
|
|
||
| var filteredReports = reports | ||
| if let selectedProgress { | ||
| filteredReports = filteredReports.filter({ $0.progress == selectedProgress }) | ||
| } | ||
| if let selectedCategory { | ||
| filteredReports = filteredReports.filter({ $0.type == selectedCategory }) | ||
| } | ||
| reportSubject.send(filteredReports) | ||
| } |
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
필터링 로직의 잠재적 문제를 확인하세요.
현재 구현에서 selectedProgressSubject.value를 사용하고 있지만, filterProgress 메서드에서 이 값이 업데이트되지 않아 진행 상태 필터링이 의도대로 작동하지 않을 수 있습니다.
다음 스크립트로 selectedProgressSubject가 설정되는 위치를 확인하세요:
🏁 Script executed:
#!/bin/bash
# selectedProgressSubject.send 호출을 찾아 올바르게 업데이트되는지 확인
rg -n "selectedProgressSubject\.send" --type swiftLength of output: 0
추가 검증이 필요합니다. selectedProgressSubject의 전체 사용 패턴을 확인하겠습니다.
🏁 Script executed:
#!/bin/bash
# selectedProgressSubject의 모든 사용 위치 확인
rg -n "selectedProgressSubject" --type swift -B2 -A2Length of output: 2071
🏁 Script executed:
#!/bin/bash
# filterProgress 메서드 존재 여부 확인
rg -n "filterProgress" --type swift -B2 -A2Length of output: 2222
🏁 Script executed:
#!/bin/bash
# ReportHistoryViewModel.swift 파일의 전체 내용 확인
find . -name "ReportHistoryViewModel.swift" -type f | head -1 | xargs catLength of output: 5081
filterProgress 메서드에서 selectedProgressSubject 업데이트 누락
filterProgress 메서드(87-99줄)에서 선택된 진행 상태를 업데이트하지 않습니다. filterCategory 메서드(84줄)는 selectedCategorySubject.send(currentType)을 호출하여 선택된 카테고리를 업데이트하지만, filterProgress는 이에 해당하는 selectedProgressSubject.send() 호출이 없습니다.
결과적으로 filterReports(104줄)에서 selectedProgressSubject.value를 읽어도 항상 nil이므로 진행 상태 필터링이 작동하지 않습니다.
수정: filterProgress 메서드 98줄 후에 선택된 진행 상태를 업데이트하는 로직을 추가하세요.
🤖 Prompt for AI Agents
In Projects/Presentation/Sources/Report/ViewModel/ReportHistoryViewModel.swift
around lines 103–115, filterReports reads selectedProgressSubject.value but
filterProgress (lines ~87–99) never updates that subject; add a call to
selectedProgressSubject.send(currentProgress) (or the actual progress variable
used in filterProgress) immediately after the currentProgress is determined
(after line 98) so the selectedProgressSubject reflects the chosen progress and
filterReports can filter correctly.
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.
@taipaise 확인해 주셔서 감사합니다! 오늘 작업에서 selectedProgressSubject.send() 호출을 추가하시면 진행 상태 필터링이 정상적으로 작동할 것입니다. 구현하시면서 궁금하신 점이 있으시면 언제든지 말씀해 주세요. 😊
taipaise
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.
고생하셨습니다! 오늘 마무리 지어보는걸로!!
| private func filterReports() { | ||
| let selectedProgress = selectedProgressSubject.value | ||
| let selectedCategory = selectedCategorySubject.value | ||
|
|
||
| var filteredReports = reports | ||
| if let selectedProgress { | ||
| filteredReports = filteredReports.filter({ $0.progress == selectedProgress }) | ||
| } | ||
| if let selectedCategory { | ||
| filteredReports = filteredReports.filter({ $0.type == selectedCategory }) | ||
| } | ||
| reportSubject.send(filteredReports) | ||
| } |
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.
확인했고 오늘 작업에서 구현하겠습니다
🌁 Background
제보 히스토리 화면과 API를 연동했어용 ~
👩💻 Contents
fetchReports)📝 Review Note
이 PR 역시 신뢰와 믿음. 이 필요합니다 .
문제가 있다면 바 ~~~~ 로 수정하겟심다 !!!!
감사함니다 !!!!!!!
📣 Related Issue
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선사항
✏️ Tip: You can customize this high-level summary in your review settings.