@@ -28,6 +28,12 @@ import SharedUtil
2828public 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를 구성합니다.
0 commit comments