Skip to content

Comments

Style/#63 NoTreatmentView 구현#68

Merged
wotjs020708 merged 14 commits intodevelopfrom
style/#63-notreatmentView
Jan 18, 2026
Merged

Style/#63 NoTreatmentView 구현#68
wotjs020708 merged 14 commits intodevelopfrom
style/#63-notreatmentView

Conversation

@wotjs020708
Copy link
Contributor

@wotjs020708 wotjs020708 commented Jan 15, 2026

🔗 연결된 이슈

📄 작업 내용

  • 작업하다 보니까 정리가 인되서 파일 분리를 하였습니다
Model/ - enum 같은 모델들이 들어가는 파일
View/ - View들이 들어가는 파일
ViewModel/ - ViewModel, viewModelExtension 들어가는 파일

현재 화면 흐름이 부모뷰에서 자식뷰들이 상태에 따라 바뀌어지는 구조 입니다.
그래서 이걸 뷰 별로 ViewModel을 만들어서 관리를 할까 고민을 했는데
그것 보다는 ViewModel을 Extension해서 파일로 관리하는게 좋을거 같아서 같아서 분리 했습니다.
부모뷰: NotreatmentView
자식뷰: TreatmentSElectedCatagory, TargetDdaySettinView 등...

구현 내용 IPhone 16 pro IPhone 13 mini
GIF
시술 카테고리 선택
목표 디테일 설정

💻 주요 코드 설명

NoTreatment.swif
-enum을 활용하여 뷰에서 내부 자시규만 교체

switch viewModel.state {
                    case .tretmentSelectedCatagory:
                        TreatmentSelectedCatagory(viewModel: viewModel)
                            .id(viewModel .state)
                    case .targetDdaySetting:
                        //TODO: 목표 디데이 설정
                        TargetDdaySettingView(dDayState: $viewModel.dDay, year: $viewModel.year, month: $viewModel.month, day: $viewModel.day)
                            .id(viewModel .state)
                    case .treatmentfilter:
                        //TODO: 시술 필터링
                        EmptyView()
                    case .downTimeSetting:
                        //TODO: 다운타임 설정
                        EmptyView()
                    }
                }

수정 사항

👀 기타 더 이야기해볼 점

나머지도 마무리하고 올릴게요

@wotjs020708 wotjs020708 requested a review from a team January 15, 2026 17:42
@wotjs020708 wotjs020708 self-assigned this Jan 15, 2026
@wotjs020708 wotjs020708 requested review from soseoyo12, sum130 and y-eonee and removed request for a team January 15, 2026 17:42
@wotjs020708 wotjs020708 linked an issue Jan 15, 2026 that may be closed by this pull request
1 task
@wotjs020708 wotjs020708 added the Style UI 구현 label Jan 15, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

NoTreatment 다단계 흐름(시술 카테고리 → D‑Day 설정 → 필터 → 다운타임) 관련한 새로운 모델·뷰모델·뷰 추가와 공통 입력 컴포넌트(DateTextBox, CherrishTextField) 레이아웃 조정, 앱 진입점 루트 뷰 변경이 포함됩니다.

Changes

Cohort / File(s) Summary
모델: NoTreatment 흐름
Cherrish-iOS/.../NoTreatment/Model/NoTreatment.swift
NoTreatment enum 추가(Identifiable, CaseIterable) 및 next()/previous() 네비게이션 메서드 추가.
모델: 시술 카테고리
Cherrish-iOS/.../NoTreatment/Model/TreatmentCategory.swift
TreatmentCategory enum 추가(6개 케이스, Identifiable, localized title).
뷰모델
Cherrish-iOS/.../NoTreatment/ViewModel/NoTreatmentViewModel.swift
NoTreatmentViewModel 추가: @Published 상태들(treatmentCatagory, dDay, year/month/day 등), canProceed, next()/previous(), 날짜 유효성 검사 헬퍼.
뷰: NoTreatment 화면
Cherrish-iOS/.../NoTreatment/View/NoTreatmentView.swift
NoTreatmentView 추가: 진행바, 상태 기반 뷰 전환, TreatmentSelectedCategory 서브뷰(2열 그리드), 다음/이전 네비게이션 바인딩.
뷰 컴포넌트: D‑Day 설정
Cherrish-iOS/.../Calendar/Treatment/Components/TargetDdaySettingView.swift
TargetDdaySettingViewDdayState enum 추가(선택 칩, 상태별 메시지, DateTextBox 바인딩).
공통 컴포넌트: DateTextBox
Cherrish-iOS/.../Global/Components/CherrishTextBox/DateTextBox.swift
외부 HStack spacing을 14로 변경, 내부 HStack spacing 0 및 소폭 trailing Spacer 추가로 날짜 필드 간격 조정.
공통 컴포넌트: CherrishTextField
Cherrish-iOS/.../Global/Components/CherrishTextField/CherrishTextField.swift
CherrishTextFieldStyle.horizontalPadding 제거; TextField를 내부 HStack으로 래핑하고 placeholder에 fixedSize() 적용하여 레이아웃 변경.
앱 진입점
Cherrish-iOS/.../App/Cherrish_iOSApp.swift
WindowGroup의 초기 루트 뷰를 NoTreatmentView(및 뷰모델)로 변경.

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sum130
  • soseoyo12
  • y-eonee
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 'Style/#63 NoTreatmentView 구현'으로, 변경사항의 핵심인 NoTreatmentView 구현과 관련 컴포넌트 추가를 명확히 설명하고 있습니다.
Description check ✅ Passed PR 설명이 작업 내용(파일 구조 분리, NoTreatmentView 구현), 코드 예시, 스크린샷을 포함하여 변경사항과 직접적으로 관련된 내용을 담고 있습니다.
Linked Issues check ✅ Passed 연결된 이슈 #63은 '시술 카테고리 선택' 화면 구현을 요구하며, PR은 TreatmentCategory enum, TreatmentSelectedCategory 뷰, NoTreatmentView 등을 통해 Figma 기반의 UI를 구현했습니다.
Out of Scope Changes check ✅ Passed DateTextBox와 CherrishTextField의 레이아웃 조정은 TargetDdaySettingView의 UI 구현을 위한 필요한 변경이며, NoTreatmentView 구현 범위 내 모두 관련성이 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch style/#63-notreatmentView

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 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

📥 Commits

Reviewing files that changed from the base of the PR and between b13a523 and 81726f2.

📒 Files selected for processing (5)
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentView.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/NoTreatmentViewModel.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishTextBox/DateTextBox.swift
  • Cherrish-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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 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

📥 Commits

Reviewing files that changed from the base of the PR and between 81726f2 and 3b12bf2.

📒 Files selected for processing (5)
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/TargetDdaySettingView.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/NoTreatment.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/TreatmentCategory.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
  • Cherrish-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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 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

📥 Commits

Reviewing files that changed from the base of the PR and between 3b12bf2 and aed0cbf.

📒 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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 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.titletitle: 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의 catagorycategory로 수정해야 합니다. 또한 viewModel.treatmentCatagorytreatmentCategory로 일괄 수정하세요.

♻️ 제안 수정
-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

📥 Commits

Reviewing files that changed from the base of the PR and between aed0cbf and 70a3a1f.

📒 Files selected for processing (3)
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/Model/NoTreatment.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/NoTreatment/View/NoTreatmentView.swift
  • Cherrish-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입니다.

CaseIterableIdentifiable 프로토콜을 활용한 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이 아직 미구현 상태인데 canProceedtrue를 반환합니다. 개발 중에는 괜찮지만, 릴리즈 전에 적절한 검증 로직을 추가하세요.

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.

@wotjs020708 wotjs020708 changed the title Style/#63 NoTreatmentView 구현(나머지도 마무리해서 올릴게요) Style/#63 NoTreatmentView 구현 Jan 16, 2026
Copy link
Contributor

@sum130 sum130 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리뷰 한 번 확인해주세요~

Copy link
Contributor

@y-eonee y-eonee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿 수고하셨습니다 ~~ 리뷰 한번만 봐주세요!!

style: style.placeholderFont ,
color: style.placeholderColor
)
).fixedSize()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런게 있군요...

Copy link
Contributor

@soseoyo12 soseoyo12 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다~~

Comment on lines +68 to +73
switch state {
case .yes:
TypographyText("언제까지 회복이 완료되면 좋을까요?", style: .title1_sb_18, color: .gray1000)
case .no:
TypographyText("대략적인 회복 목표일을 정해볼까요?", style: .title1_sb_18, color: .gray1000)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 분기처리를 해줄수도 있군요,,,,

var isLast: Bool { self == Self.allCases.last }
}

// MARK: - Navigation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주석빼주세영

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 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: 오타 수정 필요: treatmentCatagorytreatmentCategory

변수명에 오타가 있습니다. 일관성을 위해 올바른 철자로 수정해주세요.

✏️ 제안하는 수정
-    `@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에서 treatmentCatagorytreatmentCategory로 수정해야 합니다. 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
                             }
                         )
                     )

Comment on lines +26 to +83
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)
}

}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

Comment on lines +51 to +56
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
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

@wotjs020708 wotjs020708 merged commit c9d66cf into develop Jan 18, 2026
1 check passed
@wotjs020708 wotjs020708 deleted the style/#63-notreatmentView branch January 18, 2026 12:19
Kimgyuilli pushed a commit that referenced this pull request Jan 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Style] 시술 카테고리 선택

4 participants