From 1f170097b2f6621ea6b1df04762d780a36282f3d Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Wed, 8 Jun 2022 12:57:11 +0200
Subject: [PATCH] Present MyIdentityView from SessionView

---
 Example/example-app/Package.swift             |  2 +
 .../example-app/Sources/AppFeature/App.swift  |  5 ++-
 .../MyIdentityFeature/MyIdentityFeature.swift |  8 +++-
 .../MyIdentityFeature/MyIdentityView.swift    |  2 +-
 .../SessionFeature/SessionFeature.swift       | 40 +++++++++++++++++--
 .../Sources/SessionFeature/SessionView.swift  | 25 ++++++++++++
 .../SessionFeatureTests.swift                 | 22 ++++++++++
 7 files changed, 97 insertions(+), 7 deletions(-)

diff --git a/Example/example-app/Package.swift b/Example/example-app/Package.swift
index cb8aead7..0c0ef222 100644
--- a/Example/example-app/Package.swift
+++ b/Example/example-app/Package.swift
@@ -62,6 +62,7 @@ let package = Package(
       dependencies: [
         .target(name: "ErrorFeature"),
         .target(name: "LandingFeature"),
+        .target(name: "MyIdentityFeature"),
         .target(name: "SessionFeature"),
         .product(
           name: "ElixxirDAppsSDK",
@@ -157,6 +158,7 @@ let package = Package(
       name: "SessionFeature",
       dependencies: [
         .target(name: "ErrorFeature"),
+        .target(name: "MyIdentityFeature"),
         .product(
           name: "ComposableArchitecture",
           package: "swift-composable-architecture"
diff --git a/Example/example-app/Sources/AppFeature/App.swift b/Example/example-app/Sources/AppFeature/App.swift
index 341cb46c..06477b12 100644
--- a/Example/example-app/Sources/AppFeature/App.swift
+++ b/Example/example-app/Sources/AppFeature/App.swift
@@ -3,6 +3,7 @@ import ComposableArchitecture
 import ElixxirDAppsSDK
 import ErrorFeature
 import LandingFeature
+import MyIdentityFeature
 import SessionFeature
 import SwiftUI
 
@@ -44,7 +45,9 @@ extension AppEnvironment {
       session: SessionEnvironment(
         getClient: { clientSubject.value },
         bgScheduler: bgScheduler,
-        mainScheduler: mainScheduler
+        mainScheduler: mainScheduler,
+        makeId: UUID.init,
+        myIdentity: MyIdentityEnvironment()
       )
     )
   }
diff --git a/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift b/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift
index a9b97361..fb4c7200 100644
--- a/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift
+++ b/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift
@@ -1,7 +1,13 @@
 import ComposableArchitecture
 
 public struct MyIdentityState: Equatable {
-  public init() {}
+  public init(
+    id: UUID
+  ) {
+    self.id = id
+  }
+
+  public var id: UUID
 }
 
 public enum MyIdentityAction: Equatable {}
diff --git a/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift b/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift
index 4061024b..c50941b6 100644
--- a/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift
+++ b/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift
@@ -24,7 +24,7 @@ public struct MyIdentityView_Previews: PreviewProvider {
   public static var previews: some View {
     NavigationView {
       MyIdentityView(store: .init(
-        initialState: .init(),
+        initialState: .init(id: UUID()),
         reducer: .empty,
         environment: ()
       ))
diff --git a/Example/example-app/Sources/SessionFeature/SessionFeature.swift b/Example/example-app/Sources/SessionFeature/SessionFeature.swift
index 0756f738..f3ba9326 100644
--- a/Example/example-app/Sources/SessionFeature/SessionFeature.swift
+++ b/Example/example-app/Sources/SessionFeature/SessionFeature.swift
@@ -2,24 +2,28 @@ import Combine
 import ComposableArchitecture
 import ElixxirDAppsSDK
 import ErrorFeature
+import MyIdentityFeature
 
 public struct SessionState: Equatable {
   public init(
     id: UUID,
     networkFollowerStatus: NetworkFollowerStatus? = nil,
     isNetworkHealthy: Bool? = nil,
-    error: ErrorState? = nil
+    error: ErrorState? = nil,
+    myIdentity: MyIdentityState? = nil
   ) {
     self.id = id
     self.networkFollowerStatus = networkFollowerStatus
     self.isNetworkHealthy = isNetworkHealthy
     self.error = error
+    self.myIdentity = myIdentity
   }
 
   public var id: UUID
   public var networkFollowerStatus: NetworkFollowerStatus?
   public var isNetworkHealthy: Bool?
   public var error: ErrorState?
+  public var myIdentity: MyIdentityState?
 }
 
 public enum SessionAction: Equatable {
@@ -31,23 +35,32 @@ public enum SessionAction: Equatable {
   case monitorNetworkHealth(Bool)
   case didUpdateNetworkHealth(Bool?)
   case didDismissError
+  case presentMyIdentity
+  case didDismissMyIdentity
   case error(ErrorAction)
+  case myIdentity(MyIdentityAction)
 }
 
 public struct SessionEnvironment {
   public init(
     getClient: @escaping () -> Client?,
     bgScheduler: AnySchedulerOf<DispatchQueue>,
-    mainScheduler: AnySchedulerOf<DispatchQueue>
+    mainScheduler: AnySchedulerOf<DispatchQueue>,
+    makeId: @escaping () -> UUID,
+    myIdentity: MyIdentityEnvironment
   ) {
     self.getClient = getClient
     self.bgScheduler = bgScheduler
     self.mainScheduler = mainScheduler
+    self.makeId = makeId
+    self.myIdentity = myIdentity
   }
 
   public var getClient: () -> Client?
   public var bgScheduler: AnySchedulerOf<DispatchQueue>
   public var mainScheduler: AnySchedulerOf<DispatchQueue>
+  public var makeId: () -> UUID
+  public var myIdentity: MyIdentityEnvironment
 }
 
 public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironment>
@@ -129,17 +142,36 @@ public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironm
     state.error = nil
     return .none
 
-  case .error(_):
+  case .presentMyIdentity:
+    if state.myIdentity == nil {
+      state.myIdentity = MyIdentityState(id: env.makeId())
+    }
+    return .none
+
+  case .didDismissMyIdentity:
+    state.myIdentity = nil
+    return .none
+
+  case .error(_), .myIdentity(_):
     return .none
   }
 }
+.presenting(
+  myIdentityReducer,
+  state: .keyPath(\.myIdentity),
+  id: .keyPath(\.?.id),
+  action: /SessionAction.myIdentity,
+  environment: \.myIdentity
+)
 
 #if DEBUG
 extension SessionEnvironment {
   public static let failing = SessionEnvironment(
     getClient: { .failing },
     bgScheduler: .failing,
-    mainScheduler: .failing
+    mainScheduler: .failing,
+    makeId: { fatalError() },
+    myIdentity: .failing
   )
 }
 #endif
diff --git a/Example/example-app/Sources/SessionFeature/SessionView.swift b/Example/example-app/Sources/SessionFeature/SessionView.swift
index 395cfcb1..9f3c419b 100644
--- a/Example/example-app/Sources/SessionFeature/SessionView.swift
+++ b/Example/example-app/Sources/SessionFeature/SessionView.swift
@@ -2,6 +2,7 @@ import ComposableArchitecture
 import ComposablePresentation
 import ElixxirDAppsSDK
 import ErrorFeature
+import MyIdentityFeature
 import SwiftUI
 
 public struct SessionView: View {
@@ -49,6 +50,18 @@ public struct SessionView: View {
         } header: {
           Text("Network health")
         }
+
+        Section {
+          Button {
+            viewStore.send(.presentMyIdentity)
+          } label: {
+            HStack {
+              Text("My identity")
+              Spacer()
+              Image(systemName: "chevron.forward")
+            }
+          }
+        }
       }
       .navigationTitle("Session")
       .task {
@@ -64,6 +77,18 @@ public struct SessionView: View {
         },
         content: ErrorView.init(store:)
       )
+      .background(
+        NavigationLinkWithStore(
+          store.scope(
+            state: \.myIdentity,
+            action: SessionAction.myIdentity
+          ),
+          onDeactivate: {
+            viewStore.send(.didDismissMyIdentity)
+          },
+          destination: MyIdentityView.init(store:)
+        )
+      )
     }
   }
 }
diff --git a/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift b/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift
index 2ada840d..02039168 100644
--- a/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift
+++ b/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift
@@ -1,6 +1,7 @@
 import ComposableArchitecture
 import ElixxirDAppsSDK
 import ErrorFeature
+import MyIdentityFeature
 import XCTest
 @testable import SessionFeature
 
@@ -155,4 +156,25 @@ final class SessionFeatureTests: XCTestCase {
       $0.error = nil
     }
   }
+
+  func testPresentingMyIdentity() {
+    let newId = UUID()
+
+    var env = SessionEnvironment.failing
+    env.makeId = { newId }
+
+    let store = TestStore(
+      initialState: SessionState(id: UUID()),
+      reducer: sessionReducer,
+      environment: env
+    )
+
+    store.send(.presentMyIdentity) {
+      $0.myIdentity = MyIdentityState(id: newId)
+    }
+
+    store.send(.didDismissMyIdentity) {
+      $0.myIdentity = nil
+    }
+  }
 }
-- 
GitLab