Conversation
📝 WalkthroughWalkthrough치료(Treatment) UI 컴포넌트와 데이터 모델을 새로 추가하고, 아이콘 자산 카탈로그의 Contents.json 파일들에 렌더링 속성 및 새 SVG 자산을 추가했습니다. Changes
Sequence Diagram(s)(생성 조건 미충족 — 생략) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
업데이트된 기존 섹션개요치료(Treatment) 컴포넌트 기능을 구현합니다. 새로운 데이터 모델, UI 컴포넌트, 표시 모드 열거형을 추가하고 아이콘 자산의 렌더링 속성을 설정합니다. 변경 사항
예상 코드 리뷰 노력🎯 3 (Moderate) | ⏱️ ~25분 관련 PR 목록
제안된 리뷰어
🚥 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: 6
🤖 Fix all issues with AI agents
In
@Cherrish-iOS/Cherrish-iOS/Assets.xcassets/cherrishIcon/check_circular_gray.imageset/Contents.json:
- Around line 1-12: 이 Contents.json의 images 항목(특히 "filename":
"check_circular_gray.svg"가 있는 이미지 오브젝트)에 "template-rendering-intent": "original"
속성을 명시적으로 추가해 일관성을 맞추세요; 다른 이미지셋인 check_circular.imageset에서 사용한 것과 동일한 키/값을 추가하면
됩니다.
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentModel.swift:
- Around line 10-15: The TreatmentModel struct should conform to Identifiable
(and optionally Hashable) so it can be used directly in SwiftUI ForEach and
collections; update TreatmentModel to adopt Identifiable and Hashable and add a
stable unique identifier property (e.g., let id = UUID() or a provided id
initializer) so instances are uniquely identifiable in lists and can be used as
set/dictionary keys.
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift:
- Around line 89-141: TreatmentCheckBoxView and TreatmentCompleteBoxView
duplicate the same layout (VStack/HStack structure, paddings, fixed height,
background and overlay); extract the shared container into a reusable view or
modifier (e.g., TreatmentCardContainer or a View extension) that accepts
content, isSelected state and tap action, then refactor both
TreatmentCheckBoxView and TreatmentCompleteBoxView to compose that container and
only provide their differing inner content (texts, icons, and any specific
bindings) so layout logic is centralized and duplicated code is removed.
- Around line 74-77: The delete Image(.deletebox) in TreatmentRowView lacks an
accessibility label and button trait; update the UI so VoiceOver users know its
purpose by either replacing the tappable Image(.deletebox) with a Button that
calls action() (preserving Image(.deletebox) as the label) or, if keeping the
Image with .onTapGesture, add .accessibilityLabel("Delete treatment") (use a
localized string) and .accessibilityAddTraits(.isButton) to the Image, ensuring
the label text is localized and clearly describes the delete action.
- Around line 37-43: In the .completeBoxView branch the optional isCompleted may
be nil which currently renders nothing; update TreatmentRowView so
.completeBoxView forces a non‑nil binding (e.g., use guard let isCompleted =
isCompleted else { fatalError("completeBoxView requires isCompleted binding") })
before calling TreatmentCompleteBoxView(treatmentModel, isSelected: $isSelected,
isCompleted: isCompleted) { action() } to fail fast in development and prevent
silent empty views.
In @Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Array+.swift:
- Around line 10-14: The extension method joinedWithSeparator() currently
hardcodes " | " as the separator; either rename it to something explicit like
joinedWithPipe() or make it generic by adding a separator parameter (e.g., func
joinedWithSeparator(_ separator: String = " | ") -> String) so callers can
supply a custom separator while preserving the default; update call sites to use
the new API and adjust documentation/comments accordingly.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
Cherrish-iOS/Cherrish-iOS/Assets.xcassets/cherrishIcon/check_circular_gray.imageset/check_circular_gray.svgis excluded by!**/*.svg
📒 Files selected for processing (7)
Cherrish-iOS/Cherrish-iOS/Assets.xcassets/cherrishIcon/check_circular.imageset/Contents.jsonCherrish-iOS/Cherrish-iOS/Assets.xcassets/cherrishIcon/check_circular_gray.imageset/Contents.jsonCherrish-iOS/Cherrish-iOS/Assets.xcassets/cherrishIcon/clock.imageset/Contents.jsonCherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentDisplayMode.swiftCherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentModel.swiftCherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swiftCherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Array+.swift
🔇 Additional comments (5)
Cherrish-iOS/Cherrish-iOS/Assets.xcassets/cherrishIcon/check_circular.imageset/Contents.json (1)
11-14: LGTM!
template-rendering-intent: "original"설정이 적절합니다. 체크 아이콘이 원본 색상 그대로 렌더링됩니다.Cherrish-iOS/Cherrish-iOS/Assets.xcassets/cherrishIcon/clock.imageset/Contents.json (1)
11-14: LGTM!
template-rendering-intent: "template"설정으로 시계 아이콘이 SwiftUI의foregroundColor에 따라 틴트 색상이 적용됩니다. UI 아이콘에 적합한 설정입니다.Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentDisplayMode.swift (1)
10-14: LGTM!열거형 정의가 깔끔하고 세 가지 디스플레이 모드를 명확하게 구분하고 있습니다.
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift (2)
136-139:action()과isSelected.toggle()호출 순서를 확인해 주세요.현재
action()이isSelected.toggle()이전에 호출됩니다. 만약 부모 뷰의action클로저가 업데이트된isSelected값에 의존한다면, 이전(stale) 값을 참조하게 됩니다.♻️ 상태 업데이트 후 action 호출 제안
.onTapGesture { - action() isSelected.toggle() + action() }
205-211: 완료된 항목의 선택 상태 보호 로직이 적절합니다.
isCompleted가 true일 때isSelected.toggle()을 방지하는 로직은 올바릅니다. 다만 Lines 136-139에서 언급한action()과toggle()순서 문제가 이 부분에도 동일하게 적용됩니다.
| { | ||
| "images" : [ | ||
| { | ||
| "filename" : "check_circular_gray.svg", | ||
| "idiom" : "universal" | ||
| } | ||
| ], | ||
| "info" : { | ||
| "author" : "xcode", | ||
| "version" : 1 | ||
| } | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
일관성을 위해 template-rendering-intent 속성 추가를 권장합니다.
check_circular.imageset에는 "template-rendering-intent": "original" 속성이 명시되어 있지만, 이 파일에는 누락되어 있습니다. 기본값이 "original"이므로 기능상 문제는 없지만, 명시적으로 설정하면 일관성이 향상됩니다.
♻️ 권장 수정 사항
{
"images" : [
{
"filename" : "check_circular_gray.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
- }
+ },
+ "properties" : {
+ "template-rendering-intent" : "original"
+ }
}📝 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.
| { | |
| "images" : [ | |
| { | |
| "filename" : "check_circular_gray.svg", | |
| "idiom" : "universal" | |
| } | |
| ], | |
| "info" : { | |
| "author" : "xcode", | |
| "version" : 1 | |
| } | |
| } | |
| { | |
| "images" : [ | |
| { | |
| "filename" : "check_circular_gray.svg", | |
| "idiom" : "universal" | |
| } | |
| ], | |
| "info" : { | |
| "author" : "xcode", | |
| "version" : 1 | |
| }, | |
| "properties" : { | |
| "template-rendering-intent" : "original" | |
| } | |
| } |
🤖 Prompt for AI Agents
In
@Cherrish-iOS/Cherrish-iOS/Assets.xcassets/cherrishIcon/check_circular_gray.imageset/Contents.json
around lines 1 - 12, 이 Contents.json의 images 항목(특히 "filename":
"check_circular_gray.svg"가 있는 이미지 오브젝트)에 "template-rendering-intent": "original"
속성을 명시적으로 추가해 일관성을 맞추세요; 다른 이미지셋인 check_circular.imageset에서 사용한 것과 동일한 키/값을 추가하면
됩니다.
| struct TreatmentModel { | ||
| let name: String | ||
| let benefits: [String] | ||
| let downtimeMin: Int | ||
| let downtimeMax: Int | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
SwiftUI 리스트 호환성을 위해 Identifiable 프로토콜 채택을 고려해 주세요.
이 모델이 ForEach 등에서 사용될 경우, Identifiable 프로토콜을 채택하면 더 편리하게 사용할 수 있습니다. 또한 Hashable을 채택하면 Set이나 딕셔너리 키로도 활용 가능합니다.
♻️ 제안된 개선안
-struct TreatmentModel {
+struct TreatmentModel: Identifiable, Hashable {
+ let id: UUID = UUID()
let name: String
let benefits: [String]
let downtimeMin: Int
let downtimeMax: Int
}🤖 Prompt for AI Agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentModel.swift
around lines 10 - 15, The TreatmentModel struct should conform to Identifiable
(and optionally Hashable) so it can be used directly in SwiftUI ForEach and
collections; update TreatmentModel to adopt Identifiable and Hashable and add a
stable unique identifier property (e.g., let id = UUID() or a provided id
initializer) so instances are uniquely identifiable in lists and can be used as
set/dictionary keys.
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift
Outdated
Show resolved
Hide resolved
| Image(.deletebox) | ||
| .onTapGesture { | ||
| action() | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
삭제 버튼 접근성 개선을 고려해 주세요.
Image(.deletebox)에 접근성 레이블이 없어 VoiceOver 사용자가 버튼의 목적을 알기 어렵습니다.
♻️ 접근성 레이블 추가 제안
Image(.deletebox)
+ .accessibilityLabel("삭제")
.onTapGesture {
action()
}🤖 Prompt for AI Agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift
around lines 74 - 77, The delete Image(.deletebox) in TreatmentRowView lacks an
accessibility label and button trait; update the UI so VoiceOver users know its
purpose by either replacing the tappable Image(.deletebox) with a Button that
calls action() (preserving Image(.deletebox) as the label) or, if keeping the
Image with .onTapGesture, add .accessibilityLabel("Delete treatment") (use a
localized string) and .accessibilityAddTraits(.isButton) to the Image, ensuring
the label text is localized and clearly describes the delete action.
| private struct TreatmentCheckBoxView: View { | ||
| let treatmentModel: TreatmentModel | ||
| @Binding var isSelected: Bool | ||
| let action: () -> Void | ||
|
|
||
| init(_ treatmentModel: TreatmentModel, isSelected: Binding<Bool>, action: @escaping () -> Void) { | ||
| self.treatmentModel = treatmentModel | ||
| self._isSelected = isSelected | ||
| self.action = action | ||
| } | ||
|
|
||
| fileprivate var body: some View { | ||
| VStack { | ||
| HStack { | ||
| Text(treatmentModel.name) | ||
| .typography(.title1_sb_18) | ||
| Spacer() | ||
| } | ||
| HStack(spacing: 0) { | ||
| Text(treatmentModel.benefits.joinedWithSeparator()) | ||
| .typography(.body3_r_12) | ||
| .foregroundStyle(.gray700) | ||
| Spacer() | ||
| } | ||
|
|
||
|
|
||
| Spacer() | ||
| HStack(spacing: 0){ | ||
| Spacer() | ||
| Image(.clock) | ||
| .foregroundStyle(.gray700) | ||
| Text("다운타임*\(treatmentModel.downtimeMin)-\(treatmentModel.downtimeMax)일") | ||
| .font(.pretendard(.medium, size: 13)) | ||
| .foregroundStyle(.gray700) | ||
| } | ||
| } | ||
| .padding(.vertical, 12) | ||
| .padding(.horizontal, 14) | ||
| .frame(height: 100) | ||
| .background { | ||
| RoundedRectangle(cornerRadius: 10) | ||
| .foregroundStyle(isSelected ? .gray300 : Color.white) | ||
| } | ||
| .overlay{ | ||
| RoundedRectangle(cornerRadius: 10) | ||
| .stroke(.gray500, lineWidth: 1) | ||
| } | ||
| .onTapGesture { | ||
| action() | ||
| isSelected.toggle() | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
TreatmentCheckBoxView와 TreatmentCompleteBoxView 간 중복 코드 리팩토링을 고려해 주세요.
두 뷰가 동일한 레이아웃 구조(VStack, HStack, padding, frame height 100, background, overlay)를 공유하고 있습니다. 향후 유지보수를 위해 공통 레이아웃을 추출하는 것을 고려해 주세요.
현재 구현도 동작에는 문제가 없으므로, 컴포넌트가 더 복잡해질 때 리팩토링을 진행해도 됩니다.
Also applies to: 143-213
🤖 Prompt for AI Agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift
around lines 89 - 141, TreatmentCheckBoxView and TreatmentCompleteBoxView
duplicate the same layout (VStack/HStack structure, paddings, fixed height,
background and overlay); extract the shared container into a reusable view or
modifier (e.g., TreatmentCardContainer or a View extension) that accepts
content, isSelected state and tap action, then refactor both
TreatmentCheckBoxView and TreatmentCompleteBoxView to compose that container and
only provide their differing inner content (texts, icons, and any specific
bindings) so layout logic is centralized and duplicated code is removed.
There was a problem hiding this comment.
중복코드가 좀 있는 거 같긴해서,, 생각해볼만한 거 같아요
There was a problem hiding this comment.
제 생각에 아까 enum 나눈걸로 backgroundColor 같은 것들을 switch case로 작성해서 중복코드를 줄이는게 좋을 것 같아요
| extension Array where Element == String { | ||
| func joinedWithSeparator() -> String { | ||
| self.joined(separator: " | ") | ||
| } | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
함수명 개선 또는 파라미터화를 고려해 주세요.
joinedWithSeparator()라는 이름은 일반적인 구분자를 사용할 것처럼 보이지만, 실제로는 " | "로 하드코딩되어 있습니다. 재사용성과 명확성을 위해 다음 중 하나를 고려해 주세요:
♻️ 제안된 개선안
옵션 1: 더 명확한 함수명 사용
extension Array where Element == String {
- func joinedWithSeparator() -> String {
+ func joinedWithPipeSeparator() -> String {
self.joined(separator: " | ")
}
}옵션 2: 파라미터화하여 범용성 확보
extension Array where Element == String {
- func joinedWithSeparator() -> String {
- self.joined(separator: " | ")
+ func joinedWithSeparator(_ separator: String = " | ") -> String {
+ self.joined(separator: separator)
}
}📝 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.
| extension Array where Element == String { | |
| func joinedWithSeparator() -> String { | |
| self.joined(separator: " | ") | |
| } | |
| } | |
| extension Array where Element == String { | |
| func joinedWithPipeSeparator() -> String { | |
| self.joined(separator: " | ") | |
| } | |
| } |
| extension Array where Element == String { | |
| func joinedWithSeparator() -> String { | |
| self.joined(separator: " | ") | |
| } | |
| } | |
| extension Array where Element == String { | |
| func joinedWithSeparator(_ separator: String = " | ") -> String { | |
| self.joined(separator: separator) | |
| } | |
| } |
🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Array+.swift around
lines 10 - 14, The extension method joinedWithSeparator() currently hardcodes "
| " as the separator; either rename it to something explicit like
joinedWithPipe() or make it generic by adding a separator parameter (e.g., func
joinedWithSeparator(_ separator: String = " | ") -> String) so callers can
supply a custom separator while preserving the default; update call sites to use
the new API and adjust documentation/comments accordingly.
| Text(treatmentModel.name) | ||
| .typography(.body1_r_14) | ||
| .foregroundStyle(.gray800) | ||
| Spacer() | ||
| .frame(width: 12) | ||
| Text("|") | ||
| .font(.pretendard(.regular, size: 13)) | ||
| .foregroundStyle(.gray600) | ||
| Spacer() | ||
| .frame(width: 12) | ||
| Text("다운타임*\(treatmentModel.downtimeMin)-\(treatmentModel.downtimeMax)일") | ||
| .typography(.body1_r_14) | ||
| .foregroundStyle(.gray700) |
There was a problem hiding this comment.
텍스트 viewBuilder로 적용해주세요~
| HStack(spacing: 0) { | ||
| Text(treatmentModel.benefits.joinedWithSeparator()) | ||
| .typography(.body3_r_12) | ||
| .foregroundStyle(.gray700) |
There was a problem hiding this comment.
색상도 전부 .gray700으로 넣을 수 있습니다~
| private struct TreatmentCheckBoxView: View { | ||
| let treatmentModel: TreatmentModel | ||
| @Binding var isSelected: Bool | ||
| let action: () -> Void | ||
|
|
||
| init(_ treatmentModel: TreatmentModel, isSelected: Binding<Bool>, action: @escaping () -> Void) { | ||
| self.treatmentModel = treatmentModel | ||
| self._isSelected = isSelected | ||
| self.action = action | ||
| } | ||
|
|
||
| fileprivate var body: some View { | ||
| VStack { | ||
| HStack { | ||
| Text(treatmentModel.name) | ||
| .typography(.title1_sb_18) | ||
| Spacer() | ||
| } | ||
| HStack(spacing: 0) { | ||
| Text(treatmentModel.benefits.joinedWithSeparator()) | ||
| .typography(.body3_r_12) | ||
| .foregroundStyle(.gray700) | ||
| Spacer() | ||
| } | ||
|
|
||
|
|
||
| Spacer() | ||
| HStack(spacing: 0){ | ||
| Spacer() | ||
| Image(.clock) | ||
| .foregroundStyle(.gray700) | ||
| Text("다운타임*\(treatmentModel.downtimeMin)-\(treatmentModel.downtimeMax)일") | ||
| .font(.pretendard(.medium, size: 13)) | ||
| .foregroundStyle(.gray700) | ||
| } | ||
| } | ||
| .padding(.vertical, 12) | ||
| .padding(.horizontal, 14) | ||
| .frame(height: 100) | ||
| .background { | ||
| RoundedRectangle(cornerRadius: 10) | ||
| .foregroundStyle(isSelected ? .gray300 : Color.white) | ||
| } | ||
| .overlay{ | ||
| RoundedRectangle(cornerRadius: 10) | ||
| .stroke(.gray500, lineWidth: 1) | ||
| } | ||
| .onTapGesture { | ||
| action() | ||
| isSelected.toggle() | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
중복코드가 좀 있는 거 같긴해서,, 생각해볼만한 거 같아요
y-eonee
left a comment
There was a problem hiding this comment.
컴포넌트 중복 코드 줄이는 걸로 다시 수정해보는게 좋을 것 같아요 수고하셨습니당
There was a problem hiding this comment.
이 부분은 서버에서 받아오게 될텐데..
제 생각에는 프레젠테이션보단 도메인에 이 엔티티를 위치시키는게 좋을 것 같아요
도메인 레이어에
struct TreatmentEntity { ... }
extension TreatmentEntity {
func toEntity() -> TreatmentEntity {
~~~
}
요렇게 작성해주는 게 좋을 것 같아요
| var isCompleted: Binding<Bool>? | ||
| let action: () -> Void | ||
|
|
||
| init(displayMode: TreatmentDisplayMode, treatmentModel: TreatmentModel, isSelected: Binding<Bool>, isCompleted: Binding<Bool>? = nil, action: @escaping () -> Void) { |
| private struct TreatmentCheckBoxView: View { | ||
| let treatmentModel: TreatmentModel | ||
| @Binding var isSelected: Bool | ||
| let action: () -> Void | ||
|
|
||
| init(_ treatmentModel: TreatmentModel, isSelected: Binding<Bool>, action: @escaping () -> Void) { | ||
| self.treatmentModel = treatmentModel | ||
| self._isSelected = isSelected | ||
| self.action = action | ||
| } | ||
|
|
||
| fileprivate var body: some View { | ||
| VStack { | ||
| HStack { | ||
| Text(treatmentModel.name) | ||
| .typography(.title1_sb_18) | ||
| Spacer() | ||
| } | ||
| HStack(spacing: 0) { | ||
| Text(treatmentModel.benefits.joinedWithSeparator()) | ||
| .typography(.body3_r_12) | ||
| .foregroundStyle(.gray700) | ||
| Spacer() | ||
| } | ||
|
|
||
|
|
||
| Spacer() | ||
| HStack(spacing: 0){ | ||
| Spacer() | ||
| Image(.clock) | ||
| .foregroundStyle(.gray700) | ||
| Text("다운타임*\(treatmentModel.downtimeMin)-\(treatmentModel.downtimeMax)일") | ||
| .font(.pretendard(.medium, size: 13)) | ||
| .foregroundStyle(.gray700) | ||
| } | ||
| } | ||
| .padding(.vertical, 12) | ||
| .padding(.horizontal, 14) | ||
| .frame(height: 100) | ||
| .background { | ||
| RoundedRectangle(cornerRadius: 10) | ||
| .foregroundStyle(isSelected ? .gray300 : Color.white) | ||
| } | ||
| .overlay{ | ||
| RoundedRectangle(cornerRadius: 10) | ||
| .stroke(.gray500, lineWidth: 1) | ||
| } | ||
| .onTapGesture { | ||
| action() | ||
| isSelected.toggle() | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
제 생각에 아까 enum 나눈걸로 backgroundColor 같은 것들을 switch case로 작성해서 중복코드를 줄이는게 좋을 것 같아요
| self._isCompleted = isCompleted | ||
| self.action = action | ||
| } | ||
| fileprivate var body: some View { |
There was a problem hiding this comment.
사실 이미 구조체에서 private을 사용해서 크게 의미는 없지만 명시적으로 사용했습니다.
| let action: () -> Void | ||
| init(_ treatmentModel: TreatmentModel, isSelected: Binding<Bool>, isCompleted: Binding<Bool>, action: @escaping () -> Void) { |
| Text(treatmentModel.benefits.joinedWithSeparator()) | ||
| .typography(.body3_r_12) | ||
| .foregroundStyle(.gray700) |
| } | ||
|
|
||
|
|
| enum TreatmentDisplayMode { | ||
| case summary | ||
| case checkBoxView | ||
| case completeBoxView |
There was a problem hiding this comment.
summary가 젤 기본 타입인가요? 네이밍을 수정해야할듯 ...
case 네이밍을 .default, .check, .complete 이런식으로 고치는게 좋을 것 같아요
sum130
left a comment
There was a problem hiding this comment.
다른 분들이 언급해주신 거랑 기기대응 적용해주세용! 수고하셨습니당~~
| enum TreatmentDisplayMode { | ||
| case summary | ||
| case checkBoxView | ||
| case completeBoxView |
| private struct TreatmentCheckBoxView: View { | ||
| let treatmentModel: TreatmentModel | ||
| @Binding var isSelected: Bool | ||
| let action: () -> Void | ||
|
|
||
| init(_ treatmentModel: TreatmentModel, isSelected: Binding<Bool>, action: @escaping () -> Void) { | ||
| self.treatmentModel = treatmentModel | ||
| self._isSelected = isSelected | ||
| self.action = action | ||
| } | ||
|
|
||
| fileprivate var body: some View { | ||
| VStack { | ||
| HStack { | ||
| Text(treatmentModel.name) | ||
| .typography(.title1_sb_18) | ||
| Spacer() | ||
| } | ||
| HStack(spacing: 0) { | ||
| Text(treatmentModel.benefits.joinedWithSeparator()) | ||
| .typography(.body3_r_12) | ||
| .foregroundStyle(.gray700) | ||
| Spacer() | ||
| } | ||
|
|
||
|
|
||
| Spacer() | ||
| HStack(spacing: 0){ | ||
| Spacer() | ||
| Image(.clock) | ||
| .foregroundStyle(.gray700) | ||
| Text("다운타임*\(treatmentModel.downtimeMin)-\(treatmentModel.downtimeMax)일") | ||
| .font(.pretendard(.medium, size: 13)) | ||
| .foregroundStyle(.gray700) | ||
| } | ||
| } | ||
| .padding(.vertical, 12) | ||
| .padding(.horizontal, 14) | ||
| .frame(height: 100) | ||
| .background { | ||
| RoundedRectangle(cornerRadius: 10) | ||
| .foregroundStyle(isSelected ? .gray300 : Color.white) | ||
| } | ||
| .overlay{ | ||
| RoundedRectangle(cornerRadius: 10) | ||
| .stroke(.gray500, lineWidth: 1) | ||
| } | ||
| .onTapGesture { | ||
| action() | ||
| isSelected.toggle() | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@Cherrish-iOS/Cherrish-iOS/Domain/Model/TreatmentEntity.swift`:
- Around line 10-15: Update TreatmentEntity to conform to Codable and
Identifiable (or Hashable) so it can be decoded from server responses and used
in SwiftUI ForEach; e.g. change the declaration to "struct TreatmentEntity:
Codable, Identifiable" and add a stable id property (for example "let id =
UUID()") and implement a CodingKeys enum that excludes the id so decoding uses
only the server fields (name, benefits, downtimeMin, downtimeMax);
alternatively, if you prefer not to add an id, conform to Hashable instead by
adding ": Codable, Hashable" to the struct.
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift`:
- Around line 123-125: The if-statement spacing is inconsistent: add a single
space before each opening brace in the conditional statements so Swift style is
consistent (e.g., change "if isCompletedView{" to "if isCompletedView {" and
likewise for other occurrences around the TreatmentRowView body at the
conditions using isCompletedView and any other ifs on lines ~151 and ~175);
update the curly-brace spacing in TreatmentRowView's conditional blocks to match
Swift style throughout.
- Around line 85-87: In TreatmentRowView.swift update the padding call that
currently reads .padding(.trailing,10) to include a space after the comma so it
matches the file's formatting style (i.e., change .padding(.trailing,10) to
.padding(.trailing, 10)) ensuring consistency with the adjacent .padding calls
in the TreatmentRowView modifier chain.
- Around line 119-132: The Text styling in TreatmentRowView is inconsistent:
treatmentEntity.name uses .typography(.title1_sb_18) without a color while the
benefits line uses .foregroundStyle(.gray700) directly; update the title Text
(treatmentEntity.name) to use the same styling approach as the benefits (prefer
the project convention: either wrap with TypographyText or apply the .gray700()
extension) and replace the direct .foregroundStyle(.gray700) on
treatmentEntity.benefits.joinedWithSeparator() with the same consistent pattern
(e.g., .gray700() or TypographyText) so both lines use the same styling API.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
Cherrish-iOS/Cherrish-iOS/Domain/Model/TreatmentEntity.swiftCherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift
🧰 Additional context used
🧬 Code graph analysis (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift (4)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
body(9-17)Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Color.swift (7)
gray800(41-43)gray600(33-35)gray700(37-39)green1(53-55)gray300(21-23)green2(57-59)gray500(29-31)Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Font+.swift (1)
typography(60-65)Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Array+.swift (1)
joinedWithSeparator(11-13)
🔇 Additional comments (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift (3)
161-167: 탭 동작 로직을 확인해 주세요.
isCompleted가true일 때action()은 호출되지만isSelected는 토글되지 않습니다. 완료된 항목에서action()만 호출되는 것이 의도된 동작인지 확인이 필요합니다.
171-185: LGTM!
DownTimeLabel뷰가 프로젝트의 스타일링 패턴(.gray700()확장,TypographyText)을 잘 따르고 있습니다.
103-116: Swift 문법 오류: trailing comma를 제거해 주세요.Line 109에서
action:@escaping() -> Void,뒤에 trailing comma가 있어 컴파일 에러가 발생할 수 있습니다.🐛 제안된 수정안
init( _ treatmentEntity: TreatmentEntity, isSelected: Binding<Bool>, isCompleted: Binding<Bool>, isCompletedView: Bool = false, - action: `@escaping` () -> Void, - ) { + action: `@escaping` () -> Void + ) { self.treatmentEntity = treatmentEntity self._isSelected = isSelected self._isCompleted = isCompleted self.isCompletedView = isCompletedView self.action = action - - } + }Likely an incorrect or invalid review comment.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| struct TreatmentEntity { | ||
| let name: String | ||
| let benefits: [String] | ||
| let downtimeMin: Int | ||
| let downtimeMax: Int | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
프로토콜 준수 추가를 고려해 주세요.
서버에서 데이터를 받아올 경우 Codable 준수가 필요하며, SwiftUI의 ForEach에서 사용하려면 Identifiable 또는 Hashable 준수가 권장됩니다.
♻️ 제안된 수정안
-struct TreatmentEntity {
+struct TreatmentEntity: Identifiable, Hashable, Codable {
+ let id: UUID = UUID()
let name: String
let benefits: [String]
let downtimeMin: Int
let downtimeMax: Int
}🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Domain/Model/TreatmentEntity.swift` around lines 10
- 15, Update TreatmentEntity to conform to Codable and Identifiable (or
Hashable) so it can be decoded from server responses and used in SwiftUI
ForEach; e.g. change the declaration to "struct TreatmentEntity: Codable,
Identifiable" and add a stable id property (for example "let id = UUID()") and
implement a CodingKeys enum that excludes the id so decoding uses only the
server fields (name, benefits, downtimeMin, downtimeMax); alternatively, if you
prefer not to add an id, conform to Hashable instead by adding ": Codable,
Hashable" to the struct.
| .padding(.leading, 17) | ||
| .padding(.trailing,10) | ||
| .padding(.vertical, 7) |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
패딩 값 포맷팅을 일관성 있게 수정해 주세요.
.trailing,10에서 쉼표 뒤에 공백이 누락되어 있습니다.
♻️ 제안된 수정안
.padding(.leading, 17)
- .padding(.trailing,10)
+ .padding(.trailing, 10)
.padding(.vertical, 7)📝 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.
| .padding(.leading, 17) | |
| .padding(.trailing,10) | |
| .padding(.vertical, 7) | |
| .padding(.leading, 17) | |
| .padding(.trailing, 10) | |
| .padding(.vertical, 7) |
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift`
around lines 85 - 87, In TreatmentRowView.swift update the padding call that
currently reads .padding(.trailing,10) to include a space after the comma so it
matches the file's formatting style (i.e., change .padding(.trailing,10) to
.padding(.trailing, 10)) ensuring consistency with the adjacent .padding calls
in the TreatmentRowView modifier chain.
| HStack { | ||
| Text(treatmentEntity.name) | ||
| .typography(.title1_sb_18) | ||
| Spacer() | ||
| if isCompletedView{ | ||
| Image(isCompleted ? .checkCircular : .checkCircularGray) | ||
| } | ||
| } | ||
| HStack(spacing: 0) { | ||
| Text(treatmentEntity.benefits.joinedWithSeparator()) | ||
| .typography(.body3_r_12) | ||
| .foregroundStyle(.gray700) | ||
| Spacer() | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
텍스트 스타일링 방식의 일관성을 고려해 주세요.
Line 120의 Text(treatmentEntity.name)에 색상이 적용되지 않았고, Line 130에서는 .foregroundStyle(.gray700)을 직접 사용하고 있습니다. 다른 곳에서는 TypographyText나 .gray700() 확장을 사용하고 있어 일관성이 떨어집니다.
♻️ 제안된 수정안
HStack {
Text(treatmentEntity.name)
.typography(.title1_sb_18)
+ .gray800()
Spacer()
if isCompletedView{
Image(isCompleted ? .checkCircular : .checkCircularGray)
}
}
HStack(spacing: 0) {
Text(treatmentEntity.benefits.joinedWithSeparator())
.typography(.body3_r_12)
- .foregroundStyle(.gray700)
+ .gray700()
Spacer()
}🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift`
around lines 119 - 132, The Text styling in TreatmentRowView is inconsistent:
treatmentEntity.name uses .typography(.title1_sb_18) without a color while the
benefits line uses .foregroundStyle(.gray700) directly; update the title Text
(treatmentEntity.name) to use the same styling approach as the benefits (prefer
the project convention: either wrap with TypographyText or apply the .gray700()
extension) and replace the direct .foregroundStyle(.gray700) on
treatmentEntity.benefits.joinedWithSeparator() with the same consistent pattern
(e.g., .gray700() or TypographyText) so both lines use the same styling API.
| if isCompletedView{ | ||
| Image(isCompleted ? .checkCircular : .checkCircularGray) | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Swift 코드 스타일: 중괄호 앞에 공백을 추가해 주세요.
여러 곳에서 { 앞에 공백이 누락되어 있습니다 (Lines 123, 151, 175).
♻️ 제안된 수정안
- if isCompletedView{
+ if isCompletedView {
Image(isCompleted ? .checkCircular : .checkCircularGray)
}- .overlay{
+ .overlay {
if isCompleted {- HStack(spacing: 0){
+ HStack(spacing: 0) {
Spacer()Also applies to: 151-160, 175-175
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift`
around lines 123 - 125, The if-statement spacing is inconsistent: add a single
space before each opening brace in the conditional statements so Swift style is
consistent (e.g., change "if isCompletedView{" to "if isCompletedView {" and
likewise for other occurrences around the TreatmentRowView body at the
conditions using isCompletedView and any other ifs on lines ~151 and ~175);
update the curly-brace spacing in TreatmentRowView's conditional blocks to match
Swift style throughout.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift`:
- Around line 103-116: The init initializer formatting is inconsistent: remove
the trailing comma after the last parameter in the parameter list and reformat
the initializer body to match project style (align braces and use the same
indentation level as surrounding initializers); specifically adjust the init(_
treatmentEntity: TreatmentEntity, isSelected: Binding<Bool>, isCompleted:
Binding<Bool>, isCompletedView: Bool = false, action: `@escaping` () -> Void)
signature to drop the trailing comma and re-indent the assignments to
treatmentEntity, _isSelected, _isCompleted, isCompletedView and action so they
align with other inits in the file.
♻️ Duplicate comments (4)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift (4)
85-87: 쉼표 뒤 공백 누락.
.padding(.trailing,10)에서 쉼표 뒤에 공백이 누락되어 있습니다.♻️ 제안된 수정안
.padding(.leading, 17) - .padding(.trailing,10) + .padding(.trailing, 10) .padding(.vertical, 7)
123-125: 중괄호 앞에 공백을 추가해 주세요.Swift 스타일 가이드에 따라
{앞에 공백이 필요합니다.♻️ 제안된 수정안
- if isCompletedView{ + if isCompletedView { Image(isCompleted ? .checkCircular : .checkCircularGray) }- .overlay{ + .overlay { if isCompleted {Also applies to: 151-160
175-175: 중괄호 앞에 공백을 추가해 주세요.
HStack(spacing: 0){에서{앞에 공백이 필요합니다.♻️ 제안된 수정안
- HStack(spacing: 0){ + HStack(spacing: 0) { Spacer()
119-132: 텍스트 스타일링 일관성을 확인해 주세요.
- Line 120:
Text(treatmentEntity.name)에 색상이 적용되지 않았습니다.- Line 130:
.foregroundStyle(.gray700)대신.gray700()확장 사용을 고려해 주세요.다른 곳에서는
TypographyText나.gray700()확장을 사용하고 있어 일관성이 떨어집니다.♻️ 제안된 수정안
HStack { Text(treatmentEntity.name) .typography(.title1_sb_18) + .gray800() Spacer()HStack(spacing: 0) { Text(treatmentEntity.benefits.joinedWithSeparator()) .typography(.body3_r_12) - .foregroundStyle(.gray700) + .gray700() Spacer() }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift
🔇 Additional comments (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift (1)
10-43: LGTM! 깔끔한 컴포넌트 구조입니다.
displayMode에 따른 분기 처리가 명확하고,isCompleted의 nil 처리를.constant(false)로 해결한 방식이 적절합니다.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| init( | ||
| _ treatmentEntity: TreatmentEntity, | ||
| isSelected: Binding<Bool>, | ||
| isCompleted: Binding<Bool>, | ||
| isCompletedView: Bool = false, | ||
| action: @escaping () -> Void, | ||
| ) { | ||
| self.treatmentEntity = treatmentEntity | ||
| self._isSelected = isSelected | ||
| self._isCompleted = isCompleted | ||
| self.isCompletedView = isCompletedView | ||
| self.action = action | ||
|
|
||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
init 포맷팅 스타일을 정리해 주세요.
- Line 109: 마지막 파라미터 뒤의 trailing comma는 Swift 코드 스타일에서 일반적이지 않습니다.
- Lines 110-116: init 본문의 들여쓰기가 다른 곳과 일관성이 없습니다.
♻️ 제안된 수정안
init(
_ treatmentEntity: TreatmentEntity,
isSelected: Binding<Bool>,
isCompleted: Binding<Bool>,
isCompletedView: Bool = false,
- action: `@escaping` () -> Void,
- ) {
- self.treatmentEntity = treatmentEntity
- self._isSelected = isSelected
- self._isCompleted = isCompleted
- self.isCompletedView = isCompletedView
- self.action = action
-
- }
+ action: `@escaping` () -> Void
+ ) {
+ self.treatmentEntity = treatmentEntity
+ self._isSelected = isSelected
+ self._isCompleted = isCompleted
+ self.isCompletedView = isCompletedView
+ self.action = action
+ }🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/Treatment/TreatmentRowView.swift`
around lines 103 - 116, The init initializer formatting is inconsistent: remove
the trailing comma after the last parameter in the parameter list and reformat
the initializer body to match project style (align braces and use the same
indentation level as surrounding initializers); specifically adjust the init(_
treatmentEntity: TreatmentEntity, isSelected: Binding<Bool>, isCompleted:
Binding<Bool>, isCompletedView: Bool = false, action: `@escaping` () -> Void)
signature to drop the trailing comma and re-indent the assignments to
treatmentEntity, _isSelected, _isCompleted, isCompletedView and action so they
align with other inits in the file.
| .padding(.leading, 17) | ||
| .padding(.trailing,10) | ||
| .padding(.vertical, 7) |
Feat/#28 TreatmentRow 컴포넌트 구현
🔗 연결된 이슈
📄 작업 내용
💻 주요 코드 설명
컴포넌트 케이스로 구별
배열 사이에 "|" 넣기 구현