Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
172f819
chore: #39 의존성 주입
y-eonee Jan 13, 2026
e0c5a26
chore: #39 Test용 코드 삭제
y-eonee Jan 13, 2026
f4b0f5b
feat: #39 현재 달의 일정 개수 가져오는 유스케이스 추가
y-eonee Jan 13, 2026
c7683c9
feat: #39 현재 달의 모든 Date 가져오는 익스텐션
y-eonee Jan 13, 2026
4f32eab
chore: #39 탭바 폴더링 위치 변경
y-eonee Jan 13, 2026
3d550a6
feat: #39 캘린더 현재 달의 일정 가져오기 + isSelected + 달 변경 구현
y-eonee Jan 13, 2026
0f67b57
chore: #39 폴더링 변경
y-eonee Jan 13, 2026
34116d9
feat: #39 dateformatter 익스텐션 추가
y-eonee Jan 13, 2026
71796e5
chore: #39 의존성 주입
y-eonee Jan 13, 2026
25c9cdf
feat: #39 오늘 받을 시술 불러오기 유스케이스 작성
y-eonee Jan 13, 2026
d695b1c
refactor: #39 interface에 async throws 추가
y-eonee Jan 13, 2026
44cc400
feat: #39 오늘받을 시술 리스트 스크롤뷰 구현
y-eonee Jan 13, 2026
bcb66a3
chore: #39 Entity 파일 삭제
y-eonee Jan 13, 2026
87e9a3b
style: #39 그라디언트 컴포넌트
y-eonee Jan 14, 2026
bbbcb6c
chore: #39 폴더링
y-eonee Jan 14, 2026
ac539de
style: #39 라인 겹쳐서 얇게 보이는 것 수정
y-eonee Jan 14, 2026
fd3b812
feat: #39 일정 리스트 스크롤 및 그라디언트 구현
y-eonee Jan 14, 2026
4556388
feat: #39 시술 선택되었을 때 기능 구현
y-eonee Jan 14, 2026
a686431
feat: #39 calendar-dialy dto
y-eonee Jan 15, 2026
71fd7c9
refactor: #39 procedure 엔티티 수정
y-eonee Jan 15, 2026
aa33cb9
chore: #39 목데이터 수정
y-eonee Jan 15, 2026
67e2024
feat: #39 각 시술 터치 시 캘린더에 다운타임 그려짐 구현
y-eonee Jan 15, 2026
c27eb9f
chore: #39 mock 데이터 추가
y-eonee Jan 15, 2026
d40f3c1
feat: #39 시술 선택상태에서 다시 선택 시 기본캘린더로 돌아옴
y-eonee Jan 15, 2026
892897c
feat: #39 상단 스크롤 시 그라데이션 구현
y-eonee Jan 15, 2026
3f9f88c
refactor: #39 버튼 아이콘 넣을 수 있도록 수정
y-eonee Jan 15, 2026
128b93e
feat: #39 다운타임이 없는 경우
y-eonee Jan 15, 2026
279251b
feat: #39 엠티뷰
y-eonee Jan 15, 2026
82f09c0
chore: #39 목데이터 수정
y-eonee Jan 15, 2026
8e0c0b8
add: #39 이미지 추가
y-eonee Jan 15, 2026
e828e9d
style: #39 자잘한 UI 수정
y-eonee Jan 15, 2026
9bc58f9
chore: #39 Debug 삭제
y-eonee Jan 15, 2026
31d4059
chore: #39 주석 석제
y-eonee Jan 15, 2026
579ce19
chore: #39 쓸모없는 코드 삭제
y-eonee Jan 15, 2026
284abac
refactor: #39 코드래빗 리뷰 반영
y-eonee Jan 16, 2026
4157d00
refactor: #39 버튼 binding 다시 수정
y-eonee Jan 16, 2026
4d0617c
refactor: #39 버튼 파라미터 수정
y-eonee Jan 18, 2026
3c1bf91
fix: #39 빌드 오류수정
y-eonee Jan 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "0.000",
"blue" : "0xFF",
"green" : "0xFF",
"red" : "0xFF"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "0.000",
"blue" : "0xFF",
"green" : "0xFF",
"red" : "0xFF"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "illustration_noschedule.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions Cherrish-iOS/Cherrish-iOS/Data/DataDependencyAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ final class DataDependencyAssembler: DependencyAssembler {
}

func assemble() {
DIContainer.shared.register(type: TestInterface.self) {
return DefaultTestRepository(networkService: self.networkService)
DIContainer.shared.register(type: CalendarInterface.self) {
return MockCalendarRepository()
Comment on lines +18 to +19
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

Mock 레포지토리가 항상 주입되어 실제 데이터 경로가 차단됩니다.

현재 구성은 릴리즈에서도 목 데이터가 노출될 수 있습니다. 빌드 설정이나 플래그로 분기해 주세요.

🐛 제안 수정
 DIContainer.shared.register(type: CalendarInterface.self) {
-    return MockCalendarRepository()
+    `#if` DEBUG
+    return MockCalendarRepository()
+    `#else`
+    return DefaultCalendarRepository()
+    `#endif`
 }
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/DataDependencyAssembler.swift` around lines 18
- 19, DataDependencyAssembler currently always registers MockCalendarRepository
for CalendarInterface which can leak mocks into release builds; change the
registration in DIContainer.shared.register(type: CalendarInterface.self) to
conditionally register MockCalendarRepository only for debug/testing builds and
register the real implementation (e.g., RealCalendarRepository or
ProductionCalendarRepository) for release by using a build configuration flag or
compiler directive (e.g., `#if` DEBUG) around the registration so
MockCalendarRepository is not injected in production.

}

DIContainer.shared.register(type: HomeInterface.self) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// CalendarDailyResponseDTO.swift
// Cherrish-iOS
//
// Created by 이나연 on 1/15/26.
//

import Foundation

struct CalendarDailyResponseDTO: Decodable {
let eventCount: Int
let events: [EventResponseDTO]
}

struct EventResponseDTO: Decodable {
let type: String
let id: Int
let procedureId: Int
let name: String
let scheduledAt: String
let downtimeDays: Int
let sensitiveDays: [String]
let cautionDays: [String]
let recoveryDays: [String]
}

extension CalendarDailyResponseDTO {
func toEntity() {

}
Comment on lines +27 to +30
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

toEntity()가 비어 있어 변환이 누락됩니다.

현재는 호출해도 아무 동작을 하지 않습니다. 실제 변환 로직을 구현하거나, 아직 미사용이라면 제거/fatalError("Not implemented") 등으로 조기 탐지를 권장합니다.

🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Model/CalendarDailyResponseDTO.swift` around
lines 27 - 30, toEntity()가 비어 있어 DTO를 엔티티로 변환하지 못합니다; CalendarDailyResponseDTO의
toEntity() 구현부를 열어 응답 필드들을 대응되는 엔티티 타입(예: CalendarDailyEntity 또는 기존 도메인 모델)에 매핑해
반환하도록 구현하거나, 아직 사용되지 않는다면 함수 본문을 제거하거나 호출 시 즉시 발견되도록 fatalError("Not
implemented")로 대체하세요; 참조할 식별자는 CalendarDailyResponseDTO::toEntity()이며 변환 시 DTO의
날짜·타입·내용 등 각 프로퍼티를 엔티티의 동일/적절한 프로퍼티로 할당하도록 작성하세요.

}
120 changes: 120 additions & 0 deletions Cherrish-iOS/Cherrish-iOS/Data/Repository/CalendarRepository.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//
// CalendarRepository.swift
// Cherrish-iOS
//
// Created by 이나연 on 1/13/26.
//

import Foundation

struct DefaultCalendarRepository: CalendarInterface {
func fetchProcedureCountOfMonth(year: Int, month: Int) -> [Int : Int] {
return [:]
}

func fetchTodayProcedureList(date: String) -> [ProcedureEntity] {
return []
}
}

struct MockCalendarRepository: CalendarInterface {
func fetchProcedureCountOfMonth(year: Int, month: Int) -> [Int : Int] {
return [
1: 2,
7: 5,
15: 1,
23: 3,
31: 6
]
Comment on lines +21 to +28
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

month 파라미터 무시로 잘못된 날짜 카운트가 표시될 수 있습니다.

항상 31일을 포함하는 고정 딕셔너리는 30일/2월 같은 달에서 존재하지 않는 날짜에 카운트를 표시할 수 있습니다. year/month에 맞춰 필터링하거나 더미를 동적으로 생성해 주세요.

🐛 제안 수정
 func fetchProcedureCountOfMonth(year: Int, month: Int) -> [Int : Int] {
-    return [
+    let base: [Int: Int] = [
     ]
+    let calendar = Calendar.current
+    let date = calendar.date(from: DateComponents(year: year, month: month)) ?? Date()
+    let range = calendar.range(of: .day, in: .month, for: date) ?? 1..<32
+    return base.filter { range.contains($0.key) }
 }
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/CalendarRepository.swift` around
lines 21 - 28, The hard-coded dictionary in
fetchProcedureCountOfMonth(year:month:) ignores the month parameter and can
return counts for invalid days (e.g., Feb/30). Replace the static map with logic
that computes the number of days for the given year/month (using Calendar and
DateComponents), then build and return a dictionary containing only valid day
keys (1...daysInMonth) populated either from real data or generated/dummy counts
as needed; ensure any seed data is filtered by day <= daysInMonth before
returning.

}

func fetchTodayProcedureList(date: String) -> [ProcedureEntity] {
return [
ProcedureEntity(
procedureId: 1,
name: "레이저 토닝",
downtimeDays: 7,
sensitiveDays: [
"2026-01-15",
"2026-01-16",
"2026-01-17"
],
cautionDays: [
"2026-01-18",
"2026-01-19"
],
recoveryDays: [
"2026-01-20",
"2026-01-21"
]
),
ProcedureEntity(
procedureId: 2,
name: "보톡스",
downtimeDays: 3,
sensitiveDays: [
"2026-01-15"
],
cautionDays: [
"2026-01-16"
],
recoveryDays: [
"2026-01-17"
]
),
ProcedureEntity(
procedureId: 3,
name: "필러",
downtimeDays: 5,
sensitiveDays: [
"2026-01-15",
"2026-01-16"
],
cautionDays: [
"2026-01-17",
"2026-01-18"
],
recoveryDays: [
"2026-01-19"
]
),
ProcedureEntity(
procedureId: 4,
name: "IPL 레이저",
downtimeDays: 2,
sensitiveDays: [
"2026-01-15"
],
cautionDays: [
"2026-01-16"
],
recoveryDays: []
),
ProcedureEntity(
procedureId: 5,
name: "윤곽 주사",
downtimeDays: 4,
sensitiveDays: [
"2026-01-15",
"2026-01-16"
],
cautionDays: [
"2026-01-17"
],
recoveryDays: [
"2026-01-18"
]
),
ProcedureEntity(
procedureId: 6,
name: "피부 스케일링",
downtimeDays: 0,
sensitiveDays: [
"2026-01-15"
],
cautionDays: [],
recoveryDays: []
)
]
Comment on lines +31 to +118
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

date 파라미터를 무시해 어떤 날짜에서도 동일 목록이 반환됩니다.

현재 구현은 선택 날짜와 무관하게 항상 동일한 시술 목록을 반환합니다. 캘린더 UI 테스트 시에도 날짜별 상태를 구분할 수 없으므로, 날짜에 따라 필터링하거나 date→list 매핑을 쓰는 방식이 안전합니다.

🐛 제안 수정
 func fetchTodayProcedureList(date: String) -> [ProcedureEntity] {
-    return [
+    let all: [ProcedureEntity] = [
         ProcedureEntity(
             procedureId: 1,
             name: "레이저 토닝",
             downtimeDays: 7,
             sensitiveDays: [
                 "2026-01-15",
                 "2026-01-16",
                 "2026-01-17"
             ],
             cautionDays: [
                 "2026-01-18",
                 "2026-01-19"
             ],
             recoveryDays: [
                 "2026-01-20",
                 "2026-01-21"
             ]
         ),
         // ... 이하 동일
         ProcedureEntity(
             procedureId: 6,
             name: "피부 스케일링",
             downtimeDays: 0,
             sensitiveDays: [
                 "2026-01-15"
             ],
             cautionDays: [],
             recoveryDays: []
         )
     ]
+    return all.filter {
+        $0.sensitiveDays.contains(date)
+        || $0.cautionDays.contains(date)
+        || $0.recoveryDays.contains(date)
+    }
 }
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/CalendarRepository.swift` around
lines 31 - 118, fetchTodayProcedureList currently ignores its date parameter and
always returns the same hard-coded ProcedureEntity array; change it to use the
date argument to decide which procedures apply (either by filtering each
ProcedureEntity's sensitiveDays/cautionDays/recoveryDays for the given date or
by replacing the hard-coded list with a date→[ProcedureEntity] mapping and
returning mapping[date] ?? []). Locate fetchTodayProcedureList and update its
logic to consider the input date (and use ProcedureEntity properties
sensitiveDays/cautionDays/recoveryDays) so callers get a date-specific list;
ensure the function still returns [ProcedureEntity] when no entry exists (e.g.,
return empty array).

}
}
20 changes: 0 additions & 20 deletions Cherrish-iOS/Cherrish-iOS/Data/Repository/TestRepository.swift

This file was deleted.

10 changes: 7 additions & 3 deletions Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ final class DomainDependencyAssembler: DependencyAssembler {
func assemble() {
preAssembler.assemble()

guard let testRepository = DIContainer.shared.resolve(type: TestInterface.self) else {
guard let calendarRepository = DIContainer.shared.resolve(type: CalendarInterface.self) else {
return
}
Comment on lines +20 to 22
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

CalendarInterface 해결 실패 시 조용히 반환됨

CalendarInterface 해결이 실패하면 use case들이 등록되지 않고 조용히 반환됩니다. 이로 인해 런타임에 디버깅하기 어려운 문제가 발생할 수 있습니다. 실패 시 로깅을 추가하는 것을 고려해주세요.

♻️ 제안하는 수정
-        guard let calendarRepository = DIContainer.shared.resolve(type: CalendarInterface.self) else {
+        guard let calendarRepository = DIContainer.shared.resolve(type: CalendarInterface.self) else {
+            CherrishLogger.error("Failed to resolve CalendarInterface")
             return
         }
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift` around
lines 20 - 22, The guard in DomainDependencyAssembler where you call
DIContainer.shared.resolve(type: CalendarInterface.self) silently returns on
failure; update that branch to log the resolution failure (include the type name
and any context) instead of returning quietly—e.g., use your app logger (or
assertionFailure/print if no logger) inside the else branch before returning so
failures to resolve CalendarInterface are visible; locate the guard around
calendarRepository in DomainDependencyAssembler and add the logging/diagnostic
there.


DIContainer.shared.register(type: TestUseCase.self) {
return DefaultTestUseCase(repository: testRepository)
DIContainer.shared.register(type: FetchProcedureCountOfMonth.self) {
return DefaultFetchProcedureCountOfMonth(repository: calendarRepository)
}
Comment on lines +24 to 26
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

등록 시점에 캡처된 calendarRepository는 stale 상태가 될 수 있습니다.

calendarRepositoryassemble() 호출 시점에 resolve되어 클로저에 캡처됩니다. DI 컨테이너가 재조립되면 이전 인스턴스가 계속 사용됩니다.

PresentationDependencyAssembler와 동일한 패턴으로, 클로저 내부에서 lazy resolve하는 것이 안전합니다.

♻️ Lazy resolve 패턴 적용
-        guard let calendarRepository = DIContainer.shared.resolve(type: CalendarInterface.self) else {
-            return
-        }
-        
         DIContainer.shared.register(type: FetchProcedureCountOfMonth.self) {
+            guard let calendarRepository = DIContainer.shared.resolve(type: CalendarInterface.self) else {
+                CherrishLogger.error(CherrishError.DIFailedError)
+                fatalError("CalendarInterface DI resolve failed")
+            }
             return DefaultFetchProcedureCountOfMonth(repository: calendarRepository)
         }
         
         // ... homeRepository 처리 ...
     
         DIContainer.shared.register(type: FetchTodayProcedureList.self) {
+            guard let calendarRepository = DIContainer.shared.resolve(type: CalendarInterface.self) else {
+                CherrishLogger.error(CherrishError.DIFailedError)
+                fatalError("CalendarInterface DI resolve failed")
+            }
             return DefaultFetchTodayProcedure(repository: calendarRepository)
         }

Also applies to: 36-38

🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift` around
lines 24 - 26, 현재 assemble()에서 calendarRepository를 미리 resolve해 클로저에 캡처하고 있어 DI
재조립 시 stale 인스턴스를 참조할 수 있습니다; DIContainer.shared.register(...) 호출에서
FetchProcedureCountOfMonth/DefaultFetchProcedureCountOfMonth 등록 시 클로저 내부에서
calendarRepository를 직접 resolve 하도록 변경하여 lazy resolve 패턴을 적용하고 동일한 패턴을 36-38번지의
다른 등록들에도 적용하세요 (참조 심볼: assemble(), DIContainer.shared.register,
calendarRepository, FetchProcedureCountOfMonth,
DefaultFetchProcedureCountOfMonth).


guard let homeRepository = DIContainer.shared.resolve(type: HomeInterface.self) else {
Expand All @@ -32,5 +32,9 @@ final class DomainDependencyAssembler: DependencyAssembler {
DIContainer.shared.register(type: FetchDashboardData.self) {
return DefaultFetchDashboardData(repository: homeRepository)
}

DIContainer.shared.register(type: FetchTodayProcedureList.self) {
return DefaultFetchTodayProcedure(repository: calendarRepository)
}
}
}
13 changes: 13 additions & 0 deletions Cherrish-iOS/Cherrish-iOS/Domain/Interface/CalendarInterface.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// CalendarInterface.swift
// Cherrish-iOS
//
// Created by 이나연 on 1/13/26.
//

import Foundation

protocol CalendarInterface {
func fetchProcedureCountOfMonth(year: Int, month: Int) -> [Int : Int]
func fetchTodayProcedureList(date: String) -> [ProcedureEntity]
}
Comment on lines +10 to +13
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

인터페이스와 유스케이스 간 async/throws 시그니처 불일치

CalendarInterface의 메서드들은 동기/비에러이지만, 이를 사용하는 FetchProcedureCountOfMonthFetchTodayProcedureList 유스케이스는 async throws로 선언되어 있습니다. 실제 네트워크 호출이 필요한 경우 인터페이스를 async throws로 변경하거나, 현재처럼 동기 구현이면 유스케이스도 동기로 맞춰주세요.

♻️ 비동기 호출이 필요한 경우 인터페이스 수정안
 protocol CalendarInterface {
-    func fetchProcedureCountOfMonth(year: Int, month: Int) -> [Int : Int]
-    func fetchTodayProcedureList(date: String) -> [ProcedureEntity]
+    func fetchProcedureCountOfMonth(year: Int, month: Int) async throws -> [Int : Int]
+    func fetchTodayProcedureList(date: String) async throws -> [ProcedureEntity]
 }
📝 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.

Suggested change
protocol CalendarInterface {
func fetchProcedureCountOfMonth(year: Int, month: Int) -> [Int : Int]
func fetchTodayProcedureList(date: String) -> [ProcedureEntity]
}
protocol CalendarInterface {
func fetchProcedureCountOfMonth(year: Int, month: Int) async throws -> [Int : Int]
func fetchTodayProcedureList(date: String) async throws -> [ProcedureEntity]
}
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Domain/Interface/CalendarInterface.swift` around
lines 10 - 13, The CalendarInterface methods are synchronous but the use cases
FetchProcedureCountOfMonth and FetchTodayProcedureList are declared async
throws; update the API to be consistent: either change CalendarInterface's
method signatures fetchProcedureCountOfMonth(year:month:) and
fetchTodayProcedureList(date:) to async throws if they may perform network/async
work (propagate errors) or change the use case declarations to synchronous
non-throwing variants to match the current implementation; pick the async throws
route if fetching can fail or is asynchronous, and ensure all conforming
implementations and callers (use case types) are updated accordingly.

12 changes: 0 additions & 12 deletions Cherrish-iOS/Cherrish-iOS/Domain/Interface/TestInterface.swift

This file was deleted.

8 changes: 0 additions & 8 deletions Cherrish-iOS/Cherrish-iOS/Domain/Model/Entity.swift

This file was deleted.

Loading