Skip to content

Commit 16b9109

Browse files
committed
refactor: separate action/states - #211
1 parent f9fc036 commit 16b9109

4 files changed

Lines changed: 540 additions & 424 deletions

File tree

Projects/Feature/Home/Interface/Sources/Home/HomeReducer.swift

Lines changed: 116 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ import SharedUtil
2828
public struct HomeReducer {
2929
let reducer: Reduce<State, Action>
3030
private let proofPhotoReducer: ProofPhotoReducer
31+
32+
/// 홈 화면에서 발생 가능한 에러
33+
public enum HomeError: Error, Equatable {
34+
case unknown
35+
case networkError
36+
}
3137

3238
@ObservableState
3339
/// 홈 화면에서 사용되는 상태 모델입니다.
@@ -37,40 +43,67 @@ public struct HomeReducer {
3743
/// let state = HomeReducer.State()
3844
/// ```
3945
public struct State: Equatable {
40-
public var cards: [GoalCardItem] = []
41-
public var isLoading: Bool = true
42-
public var mainTitle: String = "KEEPILUV"
43-
public var calendarMonthTitle: String = ""
44-
public var calendarWeeks: [[TXCalendarDateItem]] = []
45-
public var calendarDate: TXCalendarDate = .init()
46-
public var calendarSheetDate: TXCalendarDate = .init()
47-
public var goalsCache: [String: [GoalCardItem]] = [:]
48-
public var isRefreshHidden: Bool = true
49-
public var isCalendarSheetPresented: Bool = false
50-
public var pendingDeleteGoalID: Int64?
51-
public var pendingDeletePhotologID: Int64?
52-
public var hasCards: Bool { !cards.isEmpty }
53-
public let nowDate = CalendarNow()
54-
public var toast: TXToastType?
55-
public var modal: TXModalType?
56-
public var isProofPhotoPresented: Bool = false
57-
public var isAddGoalPresented: Bool = false
58-
public var isCameraPermissionAlertPresented: Bool = false
59-
public var hasUnreadNotification: Bool = false
60-
46+
// MARK: - Nested Structs
47+
48+
/// 도메인 데이터 (실제 데이터/캐시/선택값)
49+
public struct Data: Equatable {
50+
public var cards: [GoalCardItem] = []
51+
public var goalsCache: [String: [GoalCardItem]] = [:]
52+
public var calendarDate: TXCalendarDate = .init()
53+
public var calendarSheetDate: TXCalendarDate = .init()
54+
public var calendarWeeks: [[TXCalendarDateItem]] = []
55+
public var pendingDeleteGoalID: Int64?
56+
public var pendingDeletePhotologID: Int64?
57+
58+
public init() {}
59+
}
60+
61+
/// UI 상태 (화면 관련 상태)
62+
public struct UIState: Equatable {
63+
public var isLoading: Bool = true
64+
public var mainTitle: String = "KEEPILUV"
65+
public var calendarMonthTitle: String = ""
66+
public var isRefreshHidden: Bool = true
67+
public var hasUnreadNotification: Bool = false
68+
public let nowDate = CalendarNow()
69+
70+
public init() {}
71+
}
72+
73+
/// 프레젠테이션 (toast, modal, sheet 등)
74+
public struct Presentation: Equatable {
75+
public var toast: TXToastType?
76+
public var modal: TXModalType?
77+
public var isCalendarSheetPresented: Bool = false
78+
public var isProofPhotoPresented: Bool = false
79+
public var isAddGoalPresented: Bool = false
80+
public var isCameraPermissionAlertPresented: Bool = false
81+
82+
public init() {}
83+
}
84+
85+
// MARK: - State Instances
86+
87+
public var data = Data()
88+
public var ui = UIState()
89+
public var presentation = Presentation()
90+
public var proofPhoto: ProofPhotoReducer.State?
91+
92+
// MARK: - Computed Properties
93+
94+
public var hasCards: Bool { !data.cards.isEmpty }
95+
6196
public var goalSectionTitle: String {
6297
let now = CalendarNow()
6398
let today = TXCalendarDate(year: now.year, month: now.month, day: now.day)
64-
if calendarDate < today {
99+
if data.calendarDate < today {
65100
return "지난 우리 목표"
66101
}
67-
if today < calendarDate {
102+
if today < data.calendarDate {
68103
return "다음 우리 목표"
69104
}
70105
return "오늘 우리 목표"
71106
}
72-
73-
public var proofPhoto: ProofPhotoReducer.State?
74107

75108
/// 기본 상태를 생성합니다.
76109
///
@@ -86,57 +119,73 @@ public struct HomeReducer {
86119
///
87120
/// ## 사용 예시
88121
/// ```swift
89-
/// store.send(.onAppear)
122+
/// store.send(.view(.onAppear))
90123
/// ```
91124
public enum Action: BindableAction {
92-
case binding(BindingAction<State>)
93-
94-
// MARK: - Child Action
95-
case proofPhoto(ProofPhotoReducer.Action)
96-
97-
// MARK: - LifeCycle
98-
case onAppear
99-
100-
// MARK: - User Action
101-
case calendarDateSelected(TXCalendarDateItem)
102-
case weekCalendarSwipe(TXCalendar.SwipeGesture)
103-
case navigationBarAction(TXNavigationBar.Action)
104-
case monthCalendarConfirmTapped
105-
case goalCheckButtonTapped(id: Int64, isChecked: Bool)
106-
case modalConfirmTapped
107-
case yourCardTapped(GoalCardItem)
108-
case myCardTapped(GoalCardItem)
109-
case headerTapped(GoalCardItem)
110-
case floatingButtonTapped
111-
case editButtonTapped
112-
113-
// MARK: - Update State
114-
case fetchGoals
115-
case fetchGoalsCompleted([GoalCardItem], date: TXCalendarDate)
116-
case setCalendarDate(TXCalendarDate)
117-
case setCalendarSheetPresented(Bool)
118-
case showToast(TXToastType)
119-
case authorizationCompleted(id: Int64, isAuthorized: Bool)
120-
case proofPhotoDismissed
121-
case addGoalButtonTapped(GoalCategory)
122-
case cameraPermissionAlertDismissed
123-
case fetchGoalsFailed
124-
case deletePhotoLogCompleted(goalId: Int64)
125-
case deletePhotoLogFailed
126-
case fetchUnreadResponse(Bool)
127-
128-
// MARK: - Delegate
129-
case delegate(Delegate)
130-
131-
/// 홈 화면에서 외부로 전달하는 이벤트입니다.
132-
public enum Delegate {
125+
// MARK: - View (사용자 이벤트)
126+
127+
public enum View: Equatable {
128+
case onAppear
129+
case calendarDateSelected(TXCalendarDateItem)
130+
case weekCalendarSwipe(TXCalendar.SwipeGesture)
131+
case navigationBarAction(TXNavigationBar.Action)
132+
case monthCalendarConfirmTapped
133+
case goalCheckButtonTapped(id: Int64, isChecked: Bool)
134+
case modalConfirmTapped
135+
case yourCardTapped(GoalCardItem)
136+
case myCardTapped(GoalCardItem)
137+
case headerTapped(GoalCardItem)
138+
case floatingButtonTapped
139+
case editButtonTapped
140+
case addGoalButtonTapped(GoalCategory)
141+
case cameraPermissionAlertDismissed
142+
case proofPhotoDismissed
143+
}
144+
145+
// MARK: - Internal (Reducer 내부 Effect)
146+
147+
public enum Internal: Equatable {
148+
case fetchGoals
149+
case setCalendarDate(TXCalendarDate)
150+
case setCalendarSheetPresented(Bool)
151+
case authorizationCompleted(id: Int64, isAuthorized: Bool)
152+
}
153+
154+
// MARK: - Response (비동기 응답)
155+
156+
public enum Response: Equatable {
157+
case fetchGoalsResult(Result<[GoalCardItem], HomeError>, date: TXCalendarDate)
158+
case deletePhotoLogResult(Result<Int64, HomeError>)
159+
case fetchUnreadResult(Bool)
160+
case pokePartnerResult(Result<Int64, HomeError>)
161+
}
162+
163+
// MARK: - Delegate (부모에게 알림)
164+
165+
public enum Delegate: Equatable {
133166
case goToGoalDetail(id: Int64, owner: GoalDetail.Owner, verificationDate: String)
134167
case goToStatsDetail(id: Int64)
135168
case goToMakeGoal(GoalCategory)
136169
case goToEditGoalList(date: TXCalendarDate)
137170
case goToSettings
138171
case goToNotification
139172
}
173+
174+
// MARK: - Presentation (프레젠테이션 관련)
175+
176+
public enum Presentation: Equatable {
177+
case showToast(TXToastType)
178+
}
179+
180+
// MARK: - Top-level cases
181+
182+
case view(View)
183+
case `internal`(Internal)
184+
case response(Response)
185+
case delegate(Delegate)
186+
case presentation(Presentation)
187+
case proofPhoto(ProofPhotoReducer.Action)
188+
case binding(BindingAction<State>)
140189
}
141190

142191
/// 외부에서 주입한 Reduce로 HomeReducer를 구성합니다.

Projects/Feature/Home/Interface/Sources/Root/HomeCoordinator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public struct HomeCoordinator {
6666
///
6767
/// ## 사용 예시
6868
/// ```swift
69-
/// store.send(.home(.onAppear))
69+
/// store.send(.home(.view(.onAppear)))
7070
/// ```
7171
public enum Action: BindableAction {
7272
case binding(BindingAction<State>)

0 commit comments

Comments
 (0)