Feat/#114 시술 필터 API 연결 , 다운 타임 설정 구현#122
Conversation
📝 WalkthroughWalkthrough시술 필터링 API 연계 및 다운타임 설정을 위한 도메인/데이터/프레젠테이션 계층의 모델·유스케이스·리포지토리·뷰/뷰모델 변경을 도입합니다. 구체적으로 새로운 DTO·API 엔드포인트·리포지토리 메서드·유스케이스 추가와 뷰/뷰모델의 바인딩·상태/검증 로직 변경이 포함됩니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant TreatmentView
participant TreatmentViewModel
participant FetchTreatmentsUseCase
participant TreatmentRepository
participant TreatmentAPI
participant Server
participant ProcedureDTO
participant TreatmentEntity
User->>TreatmentView: 뷰 로드 / 검색 요청
TreatmentView->>TreatmentViewModel: fetchTreatments(id?, keyword?)
TreatmentViewModel->>FetchTreatmentsUseCase: execute(id?, keyword?)
FetchTreatmentsUseCase->>TreatmentRepository: fetchTreatment(id?, keyword?)
TreatmentRepository->>TreatmentAPI: 요청: fetchProcedures(userId, id, text)
TreatmentAPI->>Server: GET /api/procedures?...
Server-->>TreatmentAPI: JSON (ProceduresResponseDTO)
TreatmentAPI-->>TreatmentRepository: 데이터 전달
TreatmentRepository->>ProcedureDTO: 디코딩
ProcedureDTO->>TreatmentEntity: toEntity()
TreatmentRepository-->>FetchTreatmentsUseCase: [TreatmentEntity]
FetchTreatmentsUseCase-->>TreatmentViewModel: [TreatmentEntity]
TreatmentViewModel-->>TreatmentView: `@Published` 업데이트 (뷰 갱신)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~35 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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.
Actionable comments posted: 11
🤖 Fix all issues with AI agents
In `@Cherrish-iOS/Cherrish-iOS/Data/DataDependencyAssembler.swift`:
- Around line 38-39: Remove the unnecessary blank lines introduced in
DataDependencyAssembler.swift to restore original formatting and consistency;
locate the extra empty lines around the DataDependencyAssembler declaration (or
within its surrounding top-level declarations) and delete them so the file has
no redundant blank lines while preserving existing code structure and spacing
elsewhere.
In `@Cherrish-iOS/Cherrish-iOS/Data/Network/EndPoint/TreatmentAPI.swift`:
- Around line 66-74: In the .fetchProcedures case in TreatmentAPI (where params
is built), avoid adding keyword when text is empty or only whitespace; instead
trim text with text.trimmingCharacters(in: .whitespacesAndNewlines) and only set
params["keyword"] when the trimmed string is not empty, leaving params unset for
blank inputs so no empty "keyword=" query is sent.
In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/TreatmentRepository.swift`:
- Around line 38-40: The mock TreatmentRepository's fetchTreatment(id: Int?,
keyword: String?) currently returns an empty array causing blank UI/previews;
update fetchTreatment(id:keyword:) in TreatmentRepository to return a small set
of representative TreatmentEntity instances (e.g., one or two sample
TreatmentEntity objects with realistic title, description, id and any required
fields) when running in mock or preview mode so previews and QA show data;
ensure the sample data covers cases like lookup by id and simple keyword
filtering (use TreatmentEntity's initializer and any existing sample factory
helpers if present).
In `@Cherrish-iOS/Cherrish-iOS/Domain/Interface/TreatmentInterface.swift`:
- Around line 10-13: Rename the protocol method fetchTreatment to the plural
form fetchTreatments to reflect its array return type and improve consistency
with fetchCategories; update the TreatmentInterface protocol declaration
(replace func fetchTreatment(id: Int?, keyword: String?) async throws ->
[TreatmentEntity] with func fetchTreatments(id: Int?, keyword: String?) async
throws -> [TreatmentEntity]) and then propagate that rename to all conforming
types, callers, and any tests that reference fetchTreatment so signatures and
call sites use TreatmentInterface.fetchTreatments and the TreatmentEntity return
type consistently.
In `@Cherrish-iOS/Cherrish-iOS/Domain/Model/TreatmentEntity.swift`:
- Around line 16-20: updateDowntime currently assigns value directly to
setDowntime allowing out-of-range values; change updateDowntime(_ value: Int) to
validate against the entity's downtimeMin and downtimeMax (or the UI bounds like
CherrishPicker 1...30) and either clamp the input into the valid range or ignore
invalid values before assigning to setDowntime, e.g., compute validated =
min(max(value, downtimeMin), downtimeMax) and set setDowntime = validated (or
return/throw on invalid input) so the domain model invariants are preserved.
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentFilterView.swift`:
- Around line 14-22: The search button is currently disabled because
TreatmentSearchBarTextField is instantiated with isDisabled: true; change this
to isDisabled: false to enable the button and update the enter handler (the
closure passed as enter that calls await viewModel.fetchTreatments()) to guard
against empty searchText — e.g., check viewModel.searchText is non‑empty before
calling fetchTreatments(), or add that check inside viewModel.fetchTreatments()
itself; reference TreatmentSearchBarTextField, viewModel.searchText, and the
enter closure/viewModel.fetchTreatments() when making the change.
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentView.swift`:
- Line 13: The view declares `@StateObject` var viewModel: TreatmentViewModel but
the reviewer questions ownership intent; if the view should observe an
externally provided, replaceable instance switch to `@ObservedObject` for
viewModel in TreatmentView so updates propagate without owning it, otherwise if
the view must own and instantiate the TreatmentViewModel initialize it
explicitly in the view's initializer using _viewModel =
StateObject(wrappedValue: ...) to ensure correct lifecycle; locate the
TreatmentView and TreatmentViewModel symbols and apply the appropriate change
based on whether the instance is injected or constructed inside the view.
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/NoTreatment/NoTreatmentViewModel.swift`:
- Around line 63-69: In NoTreatmentViewModel’s fetchCategories() replace the
empty catch with explicit error handling: on failure (from
fetchCategoriesUseCase.execute()) reset or set a safe default for the categories
property (e.g., [] or a single “failed to load” category), set an error state
property (e.g., categoriesError or isCategoriesLoadingFailed) or message so the
UI can render an error/empty state, and ensure these state updates happen on the
main actor/queue; keep fetchCategories()’s signature but populate the error
state and default categories so the UI doesn’t silently remain in a previous
state.
- Around line 72-77: The fetchNoTreatments() method currently calls
fetchTreatmentsUseCase.execute(id: selectedCategory?.id, keyword: "") which may
send an empty string to the server; change the call to pass nil instead of an
empty string when the keyword is empty (e.g., compute a local keywordParam =
keyword.isEmpty ? nil : keyword) so execute receives nil for no filter, and
update the invocation of fetchTreatmentsUseCase.execute(id:
selectedCategory?.id, keyword: keywordParam); ensure this logic is applied
inside fetchNoTreatments() and any related caller that constructs the keyword
parameter.
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/Treatment/TreatmentViewModel.swift`:
- Around line 51-58: The fetchTreatments() call currently passes searchText
directly to fetchTreatmentsUseCase.execute, which may send an empty string to
the server; update fetchTreatments() to detect an empty searchText and pass nil
instead (e.g., let keyword = searchText.isEmpty ? nil : searchText) when calling
fetchTreatmentsUseCase.execute(id: nil, keyword: keyword) and keep the existing
error fallback that sets treatments = []; ensure references: fetchTreatments(),
searchText, fetchTreatmentsUseCase.execute(id:keyword:), and treatments are
updated accordingly.
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift`:
- Around line 56-58: The guard that resolves FetchTreatmentsUseCase via
DIContainer.shared.resolve currently returns silently on failure; update it to
mirror the other guards by logging an error when resolution fails (e.g., use the
same logger or logging function used elsewhere in
PresentationDependencyAssembler) and then return. Locate the guard referencing
FetchTreatmentsUseCase and DIContainer.shared.resolve(type:
FetchTreatmentsUseCase.self), add an error log message including the type name
to aid debugging, and keep the subsequent return behavior unchanged.
|
|
||
|
|
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
단순 포맷팅 변경입니다.
불필요한 빈 줄이 추가되었습니다. 코드 품질에 영향은 없으나, 일관성을 위해 제거를 고려해 주세요.
♻️ 빈 줄 제거
DIContainer.shared.register(type: TreatmentInterface.self) {
return DefaultTreatmentRepository(networkService: self.networkService, userDefaultService: self.userDefaultService)
}
-
-
}📝 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.
| DIContainer.shared.register(type: TreatmentInterface.self) { | |
| return DefaultTreatmentRepository(networkService: self.networkService, userDefaultService: self.userDefaultService) | |
| } | |
| } |
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/DataDependencyAssembler.swift` around lines 38
- 39, Remove the unnecessary blank lines introduced in
DataDependencyAssembler.swift to restore original formatting and consistency;
locate the extra empty lines around the DataDependencyAssembler declaration (or
within its surrounding top-level declarations) and delete them so the file has
no redundant blank lines while preserving existing code structure and spacing
elsewhere.
| case .fetchProcedures(_, let id, let text): | ||
| var params: [String: Any] = [:] | ||
| if let id = id { | ||
| params["worryId"] = id | ||
| } | ||
| if let text = text { | ||
| params["keyword"] = "\(text)" | ||
| } | ||
| return params |
There was a problem hiding this comment.
빈 검색어도 쿼리로 전송됨
text가 빈 문자열이면 keyword=가 전송됩니다. 백엔드가 빈 키워드를 필터로 해석하면 전체 결과가 비워질 수 있으니 공백/빈 문자열은 제외하는 게 안전합니다.
🔧 제안 수정안
case .fetchProcedures(_, let id, let text):
var params: [String: Any] = [:]
if let id = id {
params["worryId"] = id
}
- if let text = text {
- params["keyword"] = "\(text)"
- }
- return params
+ if let text = text?.trimmingCharacters(in: .whitespacesAndNewlines),
+ !text.isEmpty {
+ params["keyword"] = text
+ }
+ return params.isEmpty ? nil : params🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Network/EndPoint/TreatmentAPI.swift` around
lines 66 - 74, In the .fetchProcedures case in TreatmentAPI (where params is
built), avoid adding keyword when text is empty or only whitespace; instead trim
text with text.trimmingCharacters(in: .whitespacesAndNewlines) and only set
params["keyword"] when the trimmed string is not empty, leaving params unset for
blank inputs so no empty "keyword=" query is sent.
| func fetchTreatment(id: Int?, keyword: String?) async throws -> [TreatmentEntity] { | ||
| return [] | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Mock 데이터가 비어 있어 UI/미리보기에서 공백 화면 가능성
Mock 저장소가 항상 빈 배열을 반환하면 검색/필터 UI가 빈 상태로만 보여 QA/미리보기에서 흐름 확인이 어렵습니다. 필요하다면 최소 샘플 데이터를 제공하는 방향을 고려해 주세요.
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/TreatmentRepository.swift` around
lines 38 - 40, The mock TreatmentRepository's fetchTreatment(id: Int?, keyword:
String?) currently returns an empty array causing blank UI/previews; update
fetchTreatment(id:keyword:) in TreatmentRepository to return a small set of
representative TreatmentEntity instances (e.g., one or two sample
TreatmentEntity objects with realistic title, description, id and any required
fields) when running in mock or preview mode so previews and QA show data;
ensure the sample data covers cases like lookup by id and simple keyword
filtering (use TreatmentEntity's initializer and any existing sample factory
helpers if present).
| protocol TreatmentInterface { | ||
| func fetchCategories() async throws -> [TreatmentCategoryEntity] | ||
| func fetchTreatment(id: Int?, keyword: String?) async throws -> [TreatmentEntity] | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
LGTM! 프로토콜 확장이 깔끔합니다.
새로운 fetchTreatment 메서드가 기존 fetchCategories와 일관된 async/throws 패턴을 따르고 있습니다. 선택적 파라미터를 통해 유연한 필터링이 가능합니다.
사소한 제안: 메서드가 배열을 반환하므로 fetchTreatments (복수형)으로 이름을 변경하면 일관성이 향상될 수 있습니다.
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Domain/Interface/TreatmentInterface.swift` around
lines 10 - 13, Rename the protocol method fetchTreatment to the plural form
fetchTreatments to reflect its array return type and improve consistency with
fetchCategories; update the TreatmentInterface protocol declaration (replace
func fetchTreatment(id: Int?, keyword: String?) async throws ->
[TreatmentEntity] with func fetchTreatments(id: Int?, keyword: String?) async
throws -> [TreatmentEntity]) and then propagate that rename to all conforming
types, callers, and any tests that reference fetchTreatment so signatures and
call sites use TreatmentInterface.fetchTreatments and the TreatmentEntity return
type consistently.
| var setDowntime: Int? | ||
|
|
||
| mutating func updateDowntime(_ value: Int) { | ||
| setDowntime = value | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# TreatmentEntity.swift 파일 위치 찾기
find . -name "TreatmentEntity.swift" -type fRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 132
🏁 Script executed:
# 파일이 발견되면 내용 확인
find . -name "TreatmentEntity.swift" -type f -exec wc -l {} \;Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 135
🏁 Script executed:
# updateDowntime와 setDowntime 사용처 검색
rg -n --type=swift "\.updateDowntime\(|setDowntime\s*=" -C 2Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 2667
🏁 Script executed:
# TreatmentEntity.swift의 downtime 관련 모든 속성 확인
rg -n --type=swift "downtime" -iRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 12636
🏁 Script executed:
cat -n ./Cherrish-iOS/Cherrish-iOS/Domain/Model/TreatmentEntity.swiftRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 641
🏁 Script executed:
head -n 220 ./Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/DowntimeBottomSheetView.swift | tail -n 100Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 3288
🏁 Script executed:
# DowntimeBottomSheetView에서 selectedDowntime과 downtimeMin/Max 관계 확인
rg -A 10 -B 10 "CherrishPicker.*selectedDowntime" ./Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/DowntimeBottomSheetView.swiftRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 697
🏁 Script executed:
cat ./Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/DowntimeBottomSheetView.swift | head -n 180Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 5830
🏁 Script executed:
# CherrishPicker의 정의 확인
find . -name "*.swift" -type f -exec grep -l "struct CherrishPicker" {} \;Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 149
🏁 Script executed:
cat ./Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swiftRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 3270
updateDowntime 메서드에서 범위 검증 필요
updateDowntime이 입력값을 검증 없이 그대로 할당하므로, downtimeMin과 downtimeMax 범위를 벗어난 값이 저장될 수 있습니다. 특히:
updateDowntime(0)호출 시downtimeMin > 0이면 범위 위반- UI의 CherrishPicker가 1...30 고정이므로
downtimeMax를 초과할 수 있음
도메인 모델의 불변성을 보장하려면 최소한의 범위 검증이 필요합니다.
🔧 제안 수정안
mutating func updateDowntime(_ value: Int) {
- setDowntime = value
+ let clamped = min(max(value, downtimeMin), downtimeMax)
+ setDowntime = clamped
}🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Domain/Model/TreatmentEntity.swift` around lines 16
- 20, updateDowntime currently assigns value directly to setDowntime allowing
out-of-range values; change updateDowntime(_ value: Int) to validate against the
entity's downtimeMin and downtimeMax (or the UI bounds like CherrishPicker
1...30) and either clamp the input into the valid range or ignore invalid values
before assigning to setDowntime, e.g., compute validated = min(max(value,
downtimeMin), downtimeMax) and set setDowntime = validated (or return/throw on
invalid input) so the domain model invariants are preserved.
| @EnvironmentObject private var calendarCoordinator: CalendarCoordinator | ||
| @EnvironmentObject private var tabBarCoordinator: TabBarCoordinator | ||
| @ObservedObject var viewModel: TreatmentViewModel | ||
| @StateObject var viewModel: TreatmentViewModel |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
@StateObject 소유권 의도 확인 필요
외부에서 주입되는 인스턴스가 교체될 수 있다면 @ObservedObject가 안전합니다. 뷰 소유가 의도라면 초기화 경로를 명확히 해주세요.
🔧 명시적 소유권 초기화 예시
- `@StateObject` var viewModel: TreatmentViewModel
+ `@StateObject` private var viewModel: TreatmentViewModel
+
+ init(viewModel: TreatmentViewModel) {
+ _viewModel = StateObject(wrappedValue: viewModel)
+ }🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentView.swift`
at line 13, The view declares `@StateObject` var viewModel: TreatmentViewModel but
the reviewer questions ownership intent; if the view should observe an
externally provided, replaceable instance switch to `@ObservedObject` for
viewModel in TreatmentView so updates propagate without owning it, otherwise if
the view must own and instantiate the TreatmentViewModel initialize it
explicitly in the view's initializer using _viewModel =
StateObject(wrappedValue: ...) to ensure correct lifecycle; locate the
TreatmentView and TreatmentViewModel symbols and apply the appropriate change
based on whether the instance is injected or constructed inside the view.
| func fetchCategories() async { | ||
| do { | ||
| categories = try await fetchCategoriesUseCase.execute() | ||
| } catch { | ||
|
|
||
| } | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
카테고리 로딩 실패 처리 방식 개선 고려
에러 발생 시 UI가 이전 상태를 유지할 수 있어, 기본값 초기화나 오류 상태 전달을 고려해 주세요.
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/NoTreatment/NoTreatmentViewModel.swift`
around lines 63 - 69, In NoTreatmentViewModel’s fetchCategories() replace the
empty catch with explicit error handling: on failure (from
fetchCategoriesUseCase.execute()) reset or set a safe default for the categories
property (e.g., [] or a single “failed to load” category), set an error state
property (e.g., categoriesError or isCategoriesLoadingFailed) or message so the
UI can render an error/empty state, and ensure these state updates happen on the
main actor/queue; keep fetchCategories()’s signature but populate the error
state and default categories so the UI doesn’t silently remain in a previous
state.
| func fetchNoTreatments() async { | ||
| do { | ||
| treatments = try await fetchTreatmentsUseCase.execute(id: selectedCategory?.id, keyword: "") | ||
| } catch { | ||
| treatments = [] | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
keyword 빈 문자열 처리 계약 확인 필요
서버가 빈 문자열을 필터로 취급할 수 있으니, 비어있으면 nil로 전달하는지 확인 권장합니다.
🔧 예시 수정안
- treatments = try await fetchTreatmentsUseCase.execute(id: selectedCategory?.id, keyword: "")
+ treatments = try await fetchTreatmentsUseCase.execute(id: selectedCategory?.id, keyword: nil)🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/NoTreatment/NoTreatmentViewModel.swift`
around lines 72 - 77, The fetchNoTreatments() method currently calls
fetchTreatmentsUseCase.execute(id: selectedCategory?.id, keyword: "") which may
send an empty string to the server; change the call to pass nil instead of an
empty string when the keyword is empty (e.g., compute a local keywordParam =
keyword.isEmpty ? nil : keyword) so execute receives nil for no filter, and
update the invocation of fetchTreatmentsUseCase.execute(id:
selectedCategory?.id, keyword: keywordParam); ensure this logic is applied
inside fetchNoTreatments() and any related caller that constructs the keyword
parameter.
| @MainActor | ||
| func fetchTreatments() async { | ||
| do { | ||
| treatments = try await fetchTreatmentsUseCase.execute(id: nil, keyword: searchText) | ||
| } catch { | ||
| treatments = [] | ||
| } | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
검색어 비어 있을 때 keyword 처리 확인 필요
서버가 ""를 필터로 해석하면 초기 로드가 비어질 수 있습니다. 계약상 nil이 맞는지 확인 후 처리 분기 권장합니다.
🔧 예시 수정안
- treatments = try await fetchTreatmentsUseCase.execute(id: nil, keyword: searchText)
+ let keyword = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
+ treatments = try await fetchTreatmentsUseCase.execute(
+ id: nil,
+ keyword: keyword.isEmpty ? nil : keyword
+ )🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/Treatment/TreatmentViewModel.swift`
around lines 51 - 58, The fetchTreatments() call currently passes searchText
directly to fetchTreatmentsUseCase.execute, which may send an empty string to
the server; update fetchTreatments() to detect an empty searchText and pass nil
instead (e.g., let keyword = searchText.isEmpty ? nil : searchText) when calling
fetchTreatmentsUseCase.execute(id: nil, keyword: keyword) and keep the existing
error fallback that sets treatments = []; ensure references: fetchTreatments(),
searchText, fetchTreatmentsUseCase.execute(id:keyword:), and treatments are
updated accordingly.
| guard let fetchTreatmentsUseCase = DIContainer.shared.resolve(type: FetchTreatmentsUseCase.self) else { | ||
| return | ||
| } |
There was a problem hiding this comment.
DI 해상 실패 시 로그 누락
다른 guard 구문은 실패 시 에러 로깅을 남기는데, 여기만 조용히 return 합니다. 원인 파악이 어려워질 수 있으니 동일한 로깅 패턴을 적용하는 편이 좋습니다.
🔧 제안 수정안
guard let fetchTreatmentsUseCase = DIContainer.shared.resolve(type: FetchTreatmentsUseCase.self) else {
+ CherrishLogger.error(CherrishError.DIFailedError)
return
}🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift`
around lines 56 - 58, The guard that resolves FetchTreatmentsUseCase via
DIContainer.shared.resolve currently returns silently on failure; update it to
mirror the other guards by logging an error when resolution fails (e.g., use the
same logger or logging function used elsewhere in
PresentationDependencyAssembler) and then return. Locate the guard referencing
FetchTreatmentsUseCase and DIContainer.shared.resolve(type:
FetchTreatmentsUseCase.self), add an error log message including the type name
to aid debugging, and keep the subsequent return behavior unchanged.
|
|
||
|
|
| struct ProcedureDTO: Decodable { | ||
| let id: Int | ||
| let name: String | ||
| let worries: [TreatmentCategoryResponseDTO] | ||
| let minDowntimeDays: Int | ||
| let maxDowntimeDays: Int | ||
| } | ||
|
|
||
| struct ProceduresResponseDTO: Decodable { | ||
| let procedures: [ProcedureDTO] | ||
| } |
There was a problem hiding this comment.
dto간 위계를 생각하면 responsedto가 위에 있는게 좋을 것 같아요
| var basePath: String { | ||
| switch self { | ||
| case .fetchCategories: | ||
| return "/api" | ||
|
|
||
| case .fetchProcedures: | ||
| return "/api" |
There was a problem hiding this comment.
걍 return "/api" 해줘도 되지않아여?
|
|
||
| func fetchTreatment(id: Int?, keyword: String?) async throws -> [TreatmentEntity] { | ||
| let userId: Int = userDefaultService.load(key: .userID) ?? 1 | ||
| let response = try await networkService.request(TreatmentAPI.fetchProcedures(userId: userId,id: id, text: keyword), decodingType: ProceduresResponseDTO.self) |
| } | ||
|
|
||
| struct MockTreatmentRepository: TreatmentInterface { | ||
| func fetchTreatment(id: Int?, keyword: String?) async throws -> [TreatmentEntity] { |
| do { | ||
| categories = try await fetchCategoriesUseCase.execute() | ||
| } catch { | ||
|
|
There was a problem hiding this comment.
CherrishLogger.error(error) 추가해주세욤
| do { | ||
| treatments = try await fetchTreatmentsUseCase.execute(id: selectedCategory?.id, keyword: "") | ||
| } catch { | ||
| treatments = [] |
| @@ -9,19 +9,22 @@ import SwiftUI | |||
| import Combine | |||
| do { | ||
| treatments = try await fetchTreatmentsUseCase.execute(id: nil, keyword: searchText) | ||
| } catch { | ||
| treatments = [] |
|
|
||
| DIContainer.shared.register(type: NoTreatmentViewModel.self) { | ||
| return NoTreatmentViewModel(fetchCategoriesUseCase: fetchTreatmentCategoriesUseCase) | ||
| return NoTreatmentViewModel(fetchCategoriesUseCase: fetchTreatmentCategoriesUseCase, fetchTreatmentsUseCase: fetchTreatmentsUseCase) |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/DownTimeSettingView.swift`:
- Around line 36-46: The ForEach currently uses id: \.self which is brittle when
treatment properties (like setDowntime) change; switch to a stable identifier
(e.g., treatment.id or another unique immutable property) and update the ForEach
to use id: \.id (or the chosen property) so SwiftUI can reliably track rows;
also ensure Treatment model conforms to Identifiable or expose that stable key
and change any comparisons (such as selectedTreatment == treatment) to compare
identifiers (selectedTreatment?.id == treatment.id) so selection and animations
remain stable when setDowntime changes.
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentFilterView.swift`:
- Around line 55-58: Remove the nested Task inside the SwiftUI .task modifier in
TreatmentFilterView and call viewModel.fetchTreatments() directly so
cancellation propagates; replace the inner Task { try await
viewModel.fetchTreatments() } with a direct await inside .task, e.g. use do {
try await viewModel.fetchTreatments() } catch { /* handle or log error via
viewModel or a logger */ } to perform proper error handling while keeping the
.task lifecycle semantics unchanged.
♻️ Duplicate comments (2)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/Treatment/TreatmentViewModel.swift (1)
51-58: 빈 검색어는 nil로 정규화 필요
공백/빈 문자열이 그대로 전달되면 서버가 필터로 해석해 초기 로드가 비어질 수 있습니다.🔧 수정 제안
- treatments = try await fetchTreatmentsUseCase.execute(id: nil, keyword: searchText) + let keyword = searchText.trimmingCharacters(in: .whitespacesAndNewlines) + treatments = try await fetchTreatmentsUseCase.execute( + id: nil, + keyword: keyword.isEmpty ? nil : keyword + )Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentView.swift (1)
13-13: @StateObject 소유권 의도 재확인 필요
외부 주입 인스턴스를 교체 가능하게 유지해야 한다면@ObservedObject가 안전합니다. 뷰가 소유하는 것이 맞다면 초기화를 명시하세요.🔧 수정 제안(뷰가 소유하는 경우)
- `@StateObject` var viewModel: TreatmentViewModel + `@StateObject` private var viewModel: TreatmentViewModel + + init(viewModel: TreatmentViewModel) { + _viewModel = StateObject(wrappedValue: viewModel) + }
| ForEach(treatments, id: \.self) { treatment in | ||
| TreatmentRowView( | ||
| displayMode: .completeBoxView, | ||
| treatmentEntity: treatment, | ||
| isSelected: .constant( | ||
| selectedTreatment == treatment | ||
|
|
||
| ), | ||
| isCompleted: .constant( | ||
| treatment.setDowntime == nil ? false : true | ||
| ), |
There was a problem hiding this comment.
ForEach 식별자에 \.self 사용은 변경 시 UI 불안정 위험
setDowntime 변경으로 해시/동등성이 바뀌면 셀 식별자가 흔들려 선택 상태/애니메이션이 깨질 수 있습니다. 안정적인 id를 사용하세요.
🔧 수정 제안
- ForEach(treatments, id: \.self) { treatment in
+ ForEach(treatments, id: \.id) { treatment in
TreatmentRowView(
displayMode: .completeBoxView,
treatmentEntity: treatment,
isSelected: .constant(
- selectedTreatment == treatment
+ selectedTreatment?.id == treatment.id
),🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/DownTimeSettingView.swift`
around lines 36 - 46, The ForEach currently uses id: \.self which is brittle
when treatment properties (like setDowntime) change; switch to a stable
identifier (e.g., treatment.id or another unique immutable property) and update
the ForEach to use id: \.id (or the chosen property) so SwiftUI can reliably
track rows; also ensure Treatment model conforms to Identifiable or expose that
stable key and change any comparisons (such as selectedTreatment == treatment)
to compare identifiers (selectedTreatment?.id == treatment.id) so selection and
animations remain stable when setDowntime changes.
| .task { | ||
| Task { | ||
| try await viewModel.fetchTreatments() | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
.task 내부 중첩 Task 제거 권장
중첩 Task는 뷰 생명주기 취소 전파가 끊길 수 있어 비정상 동작 위험이 있습니다. .task에서 직접 await + 오류 처리로 정리하세요.
🔧 수정 제안
- .task {
- Task {
- try await viewModel.fetchTreatments()
- }
- }
+ .task {
+ do {
+ try await viewModel.fetchTreatments()
+ } catch {
+ // 필요 시 에러 처리/로깅
+ }
+ }🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentFilterView.swift`
around lines 55 - 58, Remove the nested Task inside the SwiftUI .task modifier
in TreatmentFilterView and call viewModel.fetchTreatments() directly so
cancellation propagates; replace the inner Task { try await
viewModel.fetchTreatments() } with a direct await inside .task, e.g. use do {
try await viewModel.fetchTreatments() } catch { /* handle or log error via
viewModel or a logger */ } to perform proper error handling while keeping the
.task lifecycle semantics unchanged.
| HStack(alignment: .top, spacing: 0) { | ||
| TypographyText( | ||
| "실제 다운타임 및 회복 과정은 개인에 따라 다를 수 있습니다.", | ||
| "◎", |
| .id(viewModel.step) | ||
| } | ||
| .ignoresSafeArea(.keyboard,edges: .bottom) | ||
| .ignoresSafeArea(.keyboard ,edges: .bottom) |

🔗 연결된 이슈
📄 작업 내용
💻 주요 코드 설명
TreatmentEntity