@@ -13,7 +13,10 @@ import os
1313struct RandomPoseCarouselFeature {
1414 enum SlideDirection { case previous, next, none }
1515
16- private enum CancelID { case poseRequest }
16+ private enum CancelID : Hashable {
17+ case poseRequest
18+ case scrap( PoseID )
19+ }
1720
1821 @ObservableState
1922 struct State {
@@ -43,7 +46,7 @@ struct RandomPoseCarouselFeature {
4346
4447 // Internal Actions
4548 case poseResponse( Result < Pose , Error > )
46- case scrapResponse( PoseID , Result < Void , Error > )
49+ case scrapResponse( Pose , Result < Void , Error > )
4750 case flushResources
4851
4952 // Delegate Actions
@@ -63,10 +66,7 @@ struct RandomPoseCarouselFeature {
6366 switch action {
6467 // MARK: - Lifecycle & View Actions
6568 case . onAppear:
66- if state. currentPose != nil {
67- return . none
68- }
69-
69+ guard state. currentPose == nil else { return . none }
7070 state. isLoading = true
7171 return . run { [ count = state. activePeopleCount] send in
7272 await send ( . poseResponse( Result { try await poseClient. initializeRandomPose ( peopleCount: count) } ) )
@@ -105,16 +105,17 @@ struct RandomPoseCarouselFeature {
105105 // MARK: - Scrap Logic (Optimistic)
106106 case . onTapScrap:
107107 guard var pose = state. currentPose else { return . none }
108+ let originalPose = pose
108109 pose. isScrapped. toggle ( )
109110 state. currentPose = pose
110111
111- let trackingEffect : Effect < Action > = . run { _ in analytics. logEvent ( event: PoseAnalyticsEvent . poseBookmark) }
112- let scrapEffect : Effect < Action > = . run { [ id = pose. id, pose] send in
113- await send ( . delegate( . poseUpdated( pose) ) )
114- await send ( . scrapResponse( id, Result { try await poseClient. scrapPose ( poseID: id) } ) )
112+ let scrapEffect : Effect < Action > = . run { [ originalPose, updatedPose = pose] send in
113+ await send ( . delegate( . poseUpdated( updatedPose) ) )
114+ await send ( . scrapResponse( originalPose, Result { try await poseClient. scrapPose ( poseID: originalPose. id) } ) )
115115 }
116+ . cancellable ( id: CancelID . scrap ( pose. id) , cancelInFlight: true )
116117
117- return . merge ( trackingEffect , scrapEffect)
118+ return scrapEffect
118119
119120 // MARK: - Internal Actions
120121 case let . poseResponse( . success( pose) ) :
@@ -127,18 +128,18 @@ struct RandomPoseCarouselFeature {
127128 Logger . presentation. error ( " Random Pose Fetching Failed: \( error) " )
128129 return . none
129130
130- case let . scrapResponse( id, . failure( error) ) :
131+ case . scrapResponse( _, . success) :
132+ return . run { _ in analytics. logEvent ( PoseAnalyticsEvent . poseBookmark) }
133+
134+ case let . scrapResponse( originalPose, . failure( error) ) :
131135 if error is CancellationError { return . none }
136+ Logger . presentation. error ( " Error occured while scrapping pose: ID- \( id) / Error: \( error) " )
132137
133- if var pose = state. currentPose, pose. id == id {
134- pose. isScrapped. toggle ( )
135- state. currentPose = pose
136- return . send( . delegate( . poseUpdated( pose) ) )
138+ if state. currentPose? . id == originalPose. id {
139+ state. currentPose = originalPose
140+ return . send( . delegate( . poseUpdated( originalPose) ) )
137141 }
138- Logger . presentation. error ( " Error occured while scrapping pose: ID- \( id) / Error: \( error) " )
139- return . none
140142
141- case . scrapResponse:
142143 return . none
143144
144145 // MARK: - Navigation
0 commit comments