Conversation
📝 WalkthroughWalkthroughNoTreatment 다단계 흐름(시술 카테고리 → D‑Day 설정 → 필터 → 다운타임) 관련한 새로운 모델·뷰모델·뷰 추가와 공통 입력 컴포넌트(DateTextBox, CherrishTextField) 레이아웃 조정, 앱 진입점 루트 뷰 변경이 포함됩니다. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant NoTreatmentView as NoTreatmentView
participant ViewModel as NoTreatmentViewModel
participant TargetDday as TargetDdaySettingView
participant DateBox as DateTextBox
User->>NoTreatmentView: 진입
NoTreatmentView->>ViewModel: StateObject 초기화 / 상태 구독
rect rgba(100,150,200,0.5)
User->>NoTreatmentView: 카테고리 선택
NoTreatmentView->>ViewModel: treatmentCatagory 업데이트
NoTreatmentView->>ViewModel: next()
ViewModel->>NoTreatmentView: state 변경(published)
end
rect rgba(150,150,100,0.5)
User->>TargetDday: DdayState 선택
TargetDday->>ViewModel: dDay 바인딩 업데이트
User->>DateBox: 연/월/일 입력
DateBox->>ViewModel: year/month/day 바인딩 업데이트
ViewModel->>ViewModel: isDateTextFieldNotEmpty() 검증
User->>NoTreatmentView: 다음 클릭
NoTreatmentView->>ViewModel: next()
ViewModel->>NoTreatmentView: state 변경(published)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 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: 8
🤖 Fix all issues with AI agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swift`:
- Around line 10-24: Rename the misspelled enum case in DdayState from yse to
yes and update all references accordingly: change the declaration case yse to
case yes, adjust any switch patterns (e.g., switch self { case .yse: -> case
.yes: }) and any other usages (comparisons, initializers, or bindings) to use
.yes so the enum and its consumers remain consistent.
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentView.swift`:
- Around line 55-74: Refactor the repeated CherrishButton by computing the
button state and action from viewModel.state: create a computed property or
helper (e.g., var nextButtonState(for state: State) -> CherrishButton.State and
var nextButtonAction(for state: State) -> () -> Void) that maps cases
(.tretmentSelectedCatagory, .targetDdaySetting, .treatmentfilter,
.downTimeSetting) to the proper state (use viewModel.treatmentCatagory,
viewModel.isDateTextFieldNotEmpty()) and action (call viewModel.next() for cases
that should advance, noop otherwise), then replace the switch block with a
single CherrishButton(title: "다음", type: .next, state: .constant(computedState))
{ computedAction() } using those helpers so behavior is preserved and
duplication removed.
- Line 98: Remove the unnecessary trailing comma after the spacing parameter in
the VStack initializer inside NoTreatmentView (the line with VStack(alignment:
.leading, spacing: 0,)), changing it to VStack(alignment: .leading, spacing: 0)
to fix the syntax inconsistency.
- Around line 79-81: The VStack in NoTreatmentView is using the
.scrollIndicators(.hidden) modifier which has no effect outside a ScrollView;
remove the .scrollIndicators(.hidden) call from the VStack (the chain containing
.id(viewModel.step)) or, if hiding scroll indicators is intended, wrap the
content in a ScrollView and move .scrollIndicators(.hidden) onto that ScrollView
so the modifier is applied to the correct view.
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentViewModel.swift`:
- Around line 97-101: The current isDateTextFieldNotEmpty() only checks for
empty strings; update it to also parse year, month, and day into Ints and
validate numeric ranges (e.g., year between 2020–2100, month 1–12, day 1–31) and
return false if parsing or range checks fail; optionally enhance by validating
day against the specific month (and leap year for February) for full
correctness. Ensure you modify the isDateTextFieldNotEmpty() function and use
the existing year, month, day properties when implementing these checks.
- Around line 10-28: Enum NoTreatment contains misspelled case identifiers;
rename the cases to correct spellings in the enum declaration and all usages:
change tretmentSelectedCatagory to treatmentSelectedCategory and change
treatmentfilter to treatmentFilter (keep targetDdaySetting and downTimeSetting
as-is), then update any code that references
NoTreatment.tretmentSelectedCatagory or NoTreatment.treatmentfilter to use the
new names so compilation and lookups succeed.
- Around line 76-77: Two `@Published` optionals in NoTreatmentViewModel are
explicitly initialized to nil which is redundant; remove the "= nil"
initializers from the properties treatmentCatagory and dDay in
NoTreatmentViewModel so they rely on Swift's default nil for optionals (locate
the `@Published` var treatmentCatagory: TreatmentCatagory? and `@Published` var
dDay: DdayState? declarations and delete the trailing "= nil").
- Around line 30-55: Rename the enum TreatmentCatagory to TreatmentCategory
(keep CaseIterable and Identifiable conformance and the id: Self implementation)
and update every reference to it across the codebase (e.g., usages like
TreatmentCatagory.allCases, variable types, initializers, or switch cases). Do
not change the case names or the title property contents; only correct the enum
identifier and ensure you update import/usage sites (views, view models, tests)
so the project compiles after the rename.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (5)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swiftCherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentView.swiftCherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentViewModel.swiftCherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishTextBox/DateTextBox.swiftCherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishTextField/CherrishTextField.swift
🧰 Additional context used
🧬 Code graph analysis (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentView.swift (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
body(9-17)Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentViewModel.swift (5)
previous(65-70)previous(90-95)next(58-63)next(83-88)isDateTextFieldNotEmpty(97-101)Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Color.swift (2)
gray1000(49-51)gray700(37-39)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishTextField/CherrishTextField.swift (2)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishButton.swift (1)
textColor(89-98)Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Font+.swift (1)
typography(60-65)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swift (2)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
body(9-17)Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Color.swift (1)
gray1000(49-51)
🪛 SwiftLint (0.57.0)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentView.swift
[Warning] 39-39: TODOs should be resolved (목표 디데이 설정)
(todo)
[Warning] 43-43: TODOs should be resolved (시술 필터링)
(todo)
[Warning] 46-46: TODOs should be resolved (다운타임 설정)
(todo)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentViewModel.swift
[Warning] 76-76: Initializing an optional variable with nil is redundant
(redundant_optional_initialization)
[Warning] 77-77: Initializing an optional variable with nil is redundant
(redundant_optional_initialization)
🔇 Additional comments (4)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishTextField/CherrishTextField.swift (1)
132-141: 레이아웃 개선 LGTM!TextField를 HStack과 Spacer로 감싸 중앙 정렬을 구현한 방식이 적절합니다.
fixedSize()를 placeholder에 적용하여 intrinsic size를 유지하는 것도 올바른 접근입니다.Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishTextBox/DateTextBox.swift (1)
21-25: 레이아웃 조정 LGTM!날짜 입력 필드 간 spacing 조정과 라벨 앞 여백 추가가 적절합니다. TargetDdaySettingView에서 사용될 때 일관된 UI를 제공합니다.
Also applies to: 34-48
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swift (1)
44-61: 선택 칩 바인딩 로직 LGTM!
guard isSelected else { return }패턴으로 선택 해제를 방지하는 것이 적절합니다. 사용자가 반드시 하나의 옵션을 선택하도록 강제하는 UX입니다.Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentViewModel.swift (1)
57-70: 네비게이션 로직 LGTM!enum의 mutating 함수와 ViewModel의 navigation 메서드가 올바르게 구현되어 있습니다. 경계 검사로 첫 번째/마지막 단계를 벗어나지 않도록 보호하고 있습니다.
Also applies to: 83-95
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swift
Show resolved
Hide resolved
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
Outdated
Show resolved
Hide resolved
...h-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentView.swift
Outdated
Show resolved
Hide resolved
...h-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentView.swift
Outdated
Show resolved
Hide resolved
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentViewModel.swift
Outdated
Show resolved
Hide resolved
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentViewModel.swift
Outdated
Show resolved
Hide resolved
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentViewModel.swift
Outdated
Show resolved
Hide resolved
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentViewModel.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift`:
- Around line 10-66: The .treatmentFilter and .downTimeSetting cases in
NoTreatmentView are left as EmptyView(), breaking the flow; update
NoTreatmentView (and related view model state handling) to provide a temporary
placeholder UI or blocking behavior: replace the EmptyView() branches for
.treatmentFilter and .downTimeSetting with a minimal placeholder view (e.g., a
centered message and/or a disabled CherrishButton) or add logic in
NoTreatmentViewModel to prevent advancing (canProceed = false) while these
states are active so users cannot proceed; ensure you reference the switch on
viewModel.state inside NoTreatmentView and keep the .id(viewModel.state)
behavior so navigation/animations remain consistent.
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift`:
- Around line 32-38: Add a defensive guard in NoTreatmentViewModel.next() to
verify the state allows advancing before calling state.next() — e.g., call an
existing predicate like state.canMoveNext() or state.isNextAllowed(), and return
early if it’s false; if the State type lacks such a predicate, add a small
helper (e.g., canTransition(to: .next) or isNextAllowed()) on the state and use
it in next() to prevent invalid transitions from non-UI callers while leaving
previous()/state.previous() unchanged.
- Around line 40-50: The isDateTextFieldNotEmpty() currently only checks day is
between 1–31 and can accept invalid dates like Feb 30; after parsing yearInt,
monthInt, dayInt (and keeping the existing yearInt >= 2020 check), create
DateComponents(year: yearInt, month: monthInt, day: dayInt) and call
Calendar.current.date(from: components) — return false if that returns nil and
true otherwise; in other words replace the loose day-range check with a
Calendar.current.date(from:) validity check inside isDateTextFieldNotEmpty().
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (5)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swiftCherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/NoTreatment.swiftCherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/TreatmentCategory.swiftCherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swiftCherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift
🧰 Additional context used
🧬 Code graph analysis (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swift (2)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
body(9-17)Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Color.swift (1)
gray1000(49-51)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift (4)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
body(9-17)Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/NoTreatment.swift (2)
previous(44-49)next(37-42)Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift (2)
previous(36-38)next(32-34)Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Color.swift (2)
gray1000(49-51)gray700(37-39)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/NoTreatment.swift (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift (2)
next(32-34)previous(36-38)
🪛 SwiftLint (0.57.0)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
[Warning] 42-42: TODOs should be resolved (시술 필터링)
(todo)
[Warning] 45-45: TODOs should be resolved (다운타임 설정)
(todo)
🔇 Additional comments (8)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swift (2)
10-24: DdayState 매핑이 명확합니다.
타이틀 스위치가 모든 케이스를 커버하고 있어 구조가 깔끔합니다.
26-84: 상태 선택→날짜 입력 흐름이 자연스럽습니다.
선택 상태에 따른 문구/입력 노출이 명확하게 구성되어 있습니다.Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/TreatmentCategory.swift (1)
10-35: 카테고리 enum 정의가 간결합니다.
케이스와 타이틀 매핑이 명확해 사용하기 좋습니다.Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/NoTreatment.swift (2)
10-33: 단계 타이틀/플래그 정의가 명확합니다.
각 단계의 title/isFirst/isLast가 일관됩니다.
35-49: next/previous 경계 처리 잘 되어 있습니다.
인덱스 범위를 안전하게 체크하고 있어 안정적입니다.Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift (2)
69-123: 카테고리 선택 UI 구성 좋습니다.
그리드 구성과 선택 바인딩이 명확합니다.
125-126: 프리뷰 추가 좋습니다.
빠른 UI 검증에 도움이 됩니다.Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift (1)
10-30: canProceed 계산 로직이 상태별로 명확합니다.
단계별 진행 가능 조건이 잘 드러납니다.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
Show resolved
Hide resolved
...iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift
Show resolved
Hide resolved
...iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift
Outdated
Show resolved
Hide resolved
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/NoTreatment/View/NoTreatmentView.swift`:
- Around line 18-26: rightButtonAction에 빈 클로저가 남아 있어 의도 확인이 필요합니다:
NoTreatmentView.swift의 CherrishNavigationBar 호출에서 rightButtonAction을 사용하지 않을
계획이면 빈 클로저 대신 nil을 전달하도록 변경하고(또는 API가 nil을 허용하지 않으면 버튼 비활성화 로직 적용), 향후 구현 예정이면
rightButtonAction 내부에 TODO 주석을 추가하여 의도를 명시하세요; 또한
CherrishNavigationBar(title:viewModel.state.title, ...) 호출에서 title: 다음에 빠진 공백을
추가하여 가독성을 맞추세요.
- Around line 35-37: Several identifiers contain the misspelling "Catagory"
which must be consistently renamed to "Category": rename the enum case
treatmentSelectedCatagory -> treatmentSelectedCategory, the struct
TreatmentSelectedCatagory -> TreatmentSelectedCategory, the `@Published` var
treatmentCatagory -> treatmentCategory, and any parameter/variable names like
catagory to category; update all references (e.g., in NoTreatment.swift enum,
NoTreatmentViewModel.swift property and enum usage, and NoTreatmentView.swift
struct name and initializers) so they use the correct TreatmentCategory
type/name and rebuild to fix compiler errors from the refactor.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
🧰 Additional context used
🧬 Code graph analysis (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift (4)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
body(9-17)Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/NoTreatment.swift (2)
previous(44-49)next(37-42)Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift (2)
previous(36-38)next(32-34)Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Color.swift (2)
gray1000(49-51)gray700(37-39)
🪛 SwiftLint (0.57.0)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
[Warning] 42-42: TODOs should be resolved (시술 필터링)
(todo)
[Warning] 45-45: TODOs should be resolved (다운타임 설정)
(todo)
🔇 Additional comments (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift (3)
10-15: LGTM!
@StateObject와 의존성 주입을 위한 초기화 패턴이 올바르게 구현되어 있습니다.
69-123: LGTM!
TreatmentSelectedCatagory의 구현이 적절합니다.@ObservedObject사용,LazyVGrid레이아웃, 그리고SelectionChip의 바인딩 로직이 올바르게 구현되어 있습니다. 다만, 앞서 언급한 struct 이름의 오타("Catagory")는 수정이 필요합니다.
54-58: 버튼의 액션이 비활성화 상태에서도 실행된다는 우려는 타당하지 않습니다.CherrishButton은 line 41에서.disabled(type.isDisabled(for: state))를 사용하고 있으며,.next타입의 경우 상태가.normal일 때isDisabled()가true를 반환합니다(line 103). SwiftUI의.disabled(true)모디파이어는 버튼의 액션 실행을 완전히 차단하므로, 현재 구현은 의도된 대로 안전하게 동작합니다.Likely an incorrect or invalid review comment.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
Show resolved
Hide resolved
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift`:
- Around line 33-48: Add the missing .id(viewModel.state) modifiers to the
.treatmentFilter and .downTimeSetting switch cases to match the other branches
(maintain identity on viewModel.state for TreatmentSelectedCategory and
TargetDdaySettingView); also replace the placeholder EmptyView() TODOs for
treatmentFilter and downTimeSetting with the actual implementations before
release (ensure the new views follow the same .id(viewModel.state) pattern and
accept any required viewModel bindings/state).
♻️ Duplicate comments (4)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift (2)
10-17: "treatmentCatagory" 오타 수정 필요
treatmentCatagory는 "Category"의 오타입니다. 일관성을 위해treatmentCategory로 수정하세요.
40-52: 유효하지 않은 날짜(예: 2월 30일)가 검증을 통과할 수 있습니다.현재 코드는 일(day)을 1~31 범위로만 확인하여 각 월의 실제 일 수를 검증하지 않습니다.
Calendar.current.date(from:)를 사용하여 실제 유효한 날짜인지 확인하세요.🛠️ 제안 수정
func isDateTextFieldNotEmpty() -> Bool { guard !year.isEmpty, !month.isEmpty, !day.isEmpty else { return false } guard let yearInt = Int(year), yearInt >= 2020, let monthInt = Int(month), monthInt >= 1, monthInt <= 12, let dayInt = Int(day), dayInt >= 1, dayInt <= 31 else { return false } - return true + let components = DateComponents(year: yearInt, month: monthInt, day: dayInt) + return Calendar.current.date(from: components) != nil }Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift (2)
18-26:title:뒤에 공백 누락 및rightButtonAction확인 필요Line 19에서
title:viewModel.state.title→title: viewModel.state.title로 공백을 추가하세요. 또한rightButtonAction이 빈 클로저인데, 필요 없다면nil을 전달하거나 TODO 주석을 추가하세요.♻️ 제안 수정
CherrishNavigationBar( - title:viewModel.state.title, + title: viewModel.state.title, leftButtonAction: { viewModel.previous() }, - rightButtonAction: { - - } + rightButtonAction: nil // 또는 필요한 액션 구현 )
101-120:catagory변수명 오타 수정 필요Line 102의
catagory는category로 수정해야 합니다. 또한viewModel.treatmentCatagory도treatmentCategory로 일괄 수정하세요.♻️ 제안 수정
-ForEach(TreatmentCategory.allCases, id: \.id) { catagory in +ForEach(TreatmentCategory.allCases, id: \.id) { category in SelectionChip( - title: catagory.title, + title: category.title, isSelected: Binding( get: { - viewModel.treatmentCatagory == catagory + viewModel.treatmentCategory == category }, set: { isSelected in guard isSelected else { return } - viewModel.treatmentCatagory = catagory + viewModel.treatmentCategory = category } ) ) }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/NoTreatment.swiftCherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swiftCherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift
🧰 Additional context used
🧬 Code graph analysis (2)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/NoTreatment.swift (2)
next(37-42)previous(44-49)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/NoTreatment.swift (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift (2)
next(32-34)previous(36-38)
🪛 SwiftLint (0.57.0)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
[Warning] 42-42: TODOs should be resolved (시술 필터링)
(todo)
[Warning] 45-45: TODOs should be resolved (다운타임 설정)
(todo)
🔇 Additional comments (5)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/NoTreatment.swift (2)
10-33: LGTM! 잘 구조화된 상태 머신 enum입니다.
CaseIterable과Identifiable프로토콜을 활용한 enum 설계가 깔끔합니다.isFirst/isLast속성과title매핑이 적절합니다.
35-50: 네비게이션 로직이 안전하게 구현되어 있습니다.경계 조건 검사가 올바르게 되어 있어 out-of-bounds 오류가 발생하지 않습니다.
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift (1)
19-30: TODO 상태에서canProceed = true확인
.treatmentFilter와.downTimeSetting이 아직 미구현 상태인데canProceed가true를 반환합니다. 개발 중에는 괜찮지만, 릴리즈 전에 적절한 검증 로직을 추가하세요.Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift (2)
54-58: LGTM! 버튼 상태 바인딩이 적절합니다.
viewModel.canProceed를 활용한 버튼 활성화 로직이 깔끔하게 구현되어 있습니다.
69-123:TreatmentSelectedCategory구조가 적절합니다.2열 그리드 레이아웃과
SelectionChip바인딩 로직이 올바르게 구현되어 있습니다. 오타 수정 외에는 문제없습니다.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
Show resolved
Hide resolved
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
Outdated
Show resolved
Hide resolved
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
Outdated
Show resolved
Hide resolved
...iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift
Outdated
Show resolved
Hide resolved
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishTextBox/DateTextBox.swift
Show resolved
Hide resolved
y-eonee
left a comment
There was a problem hiding this comment.
굿 수고하셨습니다 ~~ 리뷰 한번만 봐주세요!!
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swift
Show resolved
Hide resolved
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
Outdated
Show resolved
Hide resolved
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
Show resolved
Hide resolved
.../Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
Show resolved
Hide resolved
...iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift
Show resolved
Hide resolved
...iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift
Outdated
Show resolved
Hide resolved
| style: style.placeholderFont , | ||
| color: style.placeholderColor | ||
| ) | ||
| ).fixedSize() |
| switch state { | ||
| case .yes: | ||
| TypographyText("언제까지 회복이 완료되면 좋을까요?", style: .title1_sb_18, color: .gray1000) | ||
| case .no: | ||
| TypographyText("대략적인 회복 목표일을 정해볼까요?", style: .title1_sb_18, color: .gray1000) | ||
| } |
| var isLast: Bool { self == Self.allCases.last } | ||
| } | ||
|
|
||
| // MARK: - Navigation |
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/Components/TargetDdaySettingView.swift`:
- Around line 26-83: Add a SwiftUI preview for TargetDdaySettingView so
designers/devs can quickly inspect the UI: at the bottom of the
TargetDdaySettingView.swift file, add a preview block (using `#Preview` or a
PreviewProvider) that instantiates TargetDdaySettingView with sample bindings
(e.g., dDayState: .constant(.yes), year/month/day: .constant("2026"/"01"/"15")),
ensuring it references the same DdayState enum and DateTextBox/SelectionChip
types so the view renders correctly in Xcode previews.
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift`:
- Around line 51-56: The current guard compares two DateComponents with == which
can fail due to extra fields; change the validation after creating date (the
guard using components and Calendar.current.dateComponents([...], from: date))
to compare the year/month/day fields explicitly or use
Calendar.current.isDate(_:equalTo:toGranularity:). For example, replace the
equality check with either extracting .year/.month/.day from
Calendar.current.dateComponents([.year,.month,.day], from: date) and comparing
each to yearInt/monthInt/dayInt, or call Calendar.current.isDate(date, equalTo:
Calendar.current.date(from: components)!, toGranularity: .day) so the guard
reliably verifies the same day; update the guard around components,
Calendar.current.date(from:), and the dateComponents check in
NoTreatmentViewModel accordingly.
♻️ Duplicate comments (5)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift (2)
13-13: 오타 수정 필요:treatmentCatagory→treatmentCategory변수명에 오타가 있습니다. 일관성을 위해 올바른 철자로 수정해주세요.
✏️ 제안하는 수정
- `@Published` var treatmentCatagory: TreatmentCategory? + `@Published` var treatmentCategory: TreatmentCategory?
32-34:next()에서canProceed확인 추가 권장UI 외부에서
next()가 호출될 경우를 대비하여 방어적으로canProceed를 확인하는 것이 안전합니다.♻️ 제안하는 수정
func next() { + guard canProceed else { return } state.next() }Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift (3)
19-27: 코드 스타일 및 빈 클로저 확인Line 20에서
title:뒤에 공백이 누락되어 있습니다. 또한rightButtonAction이 빈 클로저로 되어 있는데, 의도적이라면 TODO 주석을 추가해주세요.♻️ 제안하는 수정
CherrishNavigationBar( - title:viewModel.state.title, + title: viewModel.state.title, leftButtonAction: { viewModel.previous() }, rightButtonAction: { - + // TODO: 오른쪽 버튼 액션 구현 필요 시 추가 } )
47-52: TODO 항목에.id(viewModel.state)누락 및 구현 필요
.treatmentFilter와.downTimeSetting에서.id(viewModel.state)가 누락되어 다른 case와 일관성이 없습니다. 또한 해당 기능은 릴리즈 전 구현이 필요합니다.♻️ 제안하는 수정
case .treatmentFilter: //TODO: 시술 필터링 EmptyView() + .id(viewModel.state) case .downTimeSetting: //TODO: 다운타임 설정 EmptyView() + .id(viewModel.state)
76-131:treatmentCatagory오타 수정 필요Lines 116, 123에서
treatmentCatagory를treatmentCategory로 수정해야 합니다. ViewModel의 변수명 수정과 함께 일괄 변경이 필요합니다.✏️ 제안하는 수정
SelectionChip( title: category.title, isSelected: Binding( get: { - viewModel.treatmentCatagory == category + viewModel.treatmentCategory == category }, set: { isSelected in guard isSelected else { return } - viewModel.treatmentCatagory = category + viewModel.treatmentCategory = category } ) )
| struct TargetDdaySettingView: View { | ||
| @Binding var dDayState: DdayState? | ||
| @Binding var year: String | ||
| @Binding var month: String | ||
| @Binding var day: String | ||
|
|
||
| var body: some View { | ||
| VStack { | ||
| Spacer() | ||
| .frame(height: 50.adjustedH) | ||
| HStack(spacing:0){ | ||
| VStack(alignment: .leading, spacing: 0) { | ||
| TypographyText("회복을 계획할 때 고려해야 할", style: .title1_sb_18, color: .gray1000) | ||
| TypographyText("중요한 일정이 있나요?", style: .title1_sb_18, color: .gray1000) | ||
| } | ||
| Spacer() | ||
| } | ||
| .frame(height: 54.adjustedH) | ||
| Spacer() | ||
| .frame(height: 40) | ||
| HStack(spacing: 12.adjustedW) { | ||
| ForEach(DdayState.allCases, id: \.self) { state in | ||
| SelectionChip( | ||
| title: state.title, | ||
| isSelected: Binding( | ||
| get: { | ||
| dDayState == state | ||
| }, | ||
| set: {isSelected in | ||
| guard isSelected else { | ||
| return | ||
| } | ||
| dDayState = state | ||
| } | ||
| ) | ||
| ) | ||
| } | ||
| } | ||
| Spacer() | ||
| .frame(height: 56.adjustedH) | ||
| if let state = dDayState { | ||
| HStack(spacing: 0) { | ||
| switch state { | ||
| case .yes: | ||
| TypographyText("언제까지 회복이 완료되면 좋을까요?", style: .title1_sb_18, color: .gray1000) | ||
| case .no: | ||
| TypographyText("대략적인 회복 목표일을 정해볼까요?", style: .title1_sb_18, color: .gray1000) | ||
| } | ||
| Spacer() | ||
| } | ||
| Spacer() | ||
| .frame(height: 24.adjustedH) | ||
| DateTextBox(year: $year, month: $month, day: $day) | ||
| } | ||
|
|
||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
개발 편의를 위한 Preview 추가 권장
SwiftUI Preview가 없어 개발 중 UI 확인이 어렵습니다. Preview를 추가하면 개발 효율성이 향상됩니다.
♻️ Preview 추가 제안
`#Preview` {
TargetDdaySettingView(
dDayState: .constant(.yes),
year: .constant("2026"),
month: .constant("01"),
day: .constant("15")
)
}🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swift`
around lines 26 - 83, Add a SwiftUI preview for TargetDdaySettingView so
designers/devs can quickly inspect the UI: at the bottom of the
TargetDdaySettingView.swift file, add a preview block (using `#Preview` or a
PreviewProvider) that instantiates TargetDdaySettingView with sample bindings
(e.g., dDayState: .constant(.yes), year/month/day: .constant("2026"/"01"/"15")),
ensuring it references the same DdayState enum and DateTextBox/SelectionChip
types so the view renders correctly in Xcode previews.
| let components = DateComponents(year: yearInt, month: monthInt, day: dayInt) | ||
|
|
||
| guard let date = Calendar.current.date(from: components), | ||
| Calendar.current.dateComponents([.year, .month, .day], from: date) == components else { | ||
| return false | ||
| } |
There was a problem hiding this comment.
DateComponents 비교 로직에 잠재적 버그가 있습니다.
Calendar.current.dateComponents가 반환하는 DateComponents에는 추가 필드(calendar, timeZone 등)가 포함되어 있어, 수동으로 생성한 components와 == 비교 시 항상 실패할 수 있습니다.
🐛 제안하는 수정
let components = DateComponents(year: yearInt, month: monthInt, day: dayInt)
guard let date = Calendar.current.date(from: components),
- Calendar.current.dateComponents([.year, .month, .day], from: date) == components else {
+ let extractedComponents = Calendar.current.dateComponents([.year, .month, .day], from: date),
+ extractedComponents.year == yearInt,
+ extractedComponents.month == monthInt,
+ extractedComponents.day == dayInt else {
return false
}🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/ViewModel/NoTreatmentViewModel.swift`
around lines 51 - 56, The current guard compares two DateComponents with ==
which can fail due to extra fields; change the validation after creating date
(the guard using components and Calendar.current.dateComponents([...], from:
date)) to compare the year/month/day fields explicitly or use
Calendar.current.isDate(_:equalTo:toGranularity:). For example, replace the
equality check with either extracting .year/.month/.day from
Calendar.current.dateComponents([.year,.month,.day], from: date) and comparing
each to yearInt/monthInt/dayInt, or call Calendar.current.isDate(date, equalTo:
Calendar.current.date(from: components)!, toGranularity: .day) so the guard
reliably verifies the same day; update the guard around components,
Calendar.current.date(from:), and the dateComponents check in
NoTreatmentViewModel accordingly.
Style/#63 NoTreatmentView 구현
🔗 연결된 이슈
📄 작업 내용
현재 화면 흐름이 부모뷰에서 자식뷰들이 상태에 따라 바뀌어지는 구조 입니다.
그래서 이걸 뷰 별로 ViewModel을 만들어서 관리를 할까 고민을 했는데
그것 보다는 ViewModel을 Extension해서 파일로 관리하는게 좋을거 같아서 같아서 분리 했습니다.
부모뷰: NotreatmentView
자식뷰: TreatmentSElectedCatagory, TargetDdaySettinView 등...
💻 주요 코드 설명
NoTreatment.swif-
enum을 활용하여 뷰에서 내부 자시규만 교체수정 사항
👀 기타 더 이야기해볼 점
나머지도 마무리하고 올릴게요