From 7735cfe7b022c0ad283ed14299c522be29fc5e3c Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Sun, 11 Sep 2022 22:53:20 +0200
Subject: [PATCH] Present VerifyContact from Contact

---
 Examples/xx-messenger/Package.swift           |  3 ++
 .../AppFeature/AppEnvironment+Live.swift      |  4 ++
 .../ContactFeature/ContactFeature.swift       | 37 +++++++++++++++---
 .../Sources/ContactFeature/ContactView.swift  | 18 +++++++++
 .../VerifyContactFeature.swift                |  9 ++++-
 .../VerifyContactView.swift                   |  4 +-
 .../ContactFeatureTests.swift                 | 39 +++++++++++++++++++
 .../VerifyContactFeatureTests.swift           |  4 +-
 8 files changed, 110 insertions(+), 8 deletions(-)

diff --git a/Examples/xx-messenger/Package.swift b/Examples/xx-messenger/Package.swift
index 8c7a1c90..3951efb5 100644
--- a/Examples/xx-messenger/Package.swift
+++ b/Examples/xx-messenger/Package.swift
@@ -81,6 +81,7 @@ let package = Package(
         .target(name: "RestoreFeature"),
         .target(name: "SendRequestFeature"),
         .target(name: "UserSearchFeature"),
+        .target(name: "VerifyContactFeature"),
         .target(name: "WelcomeFeature"),
         .product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
         .product(name: "ComposablePresentation", package: "swift-composable-presentation"),
@@ -101,6 +102,7 @@ let package = Package(
       dependencies: [
         .target(name: "AppCore"),
         .target(name: "SendRequestFeature"),
+        .target(name: "VerifyContactFeature"),
         .product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
         .product(name: "ComposablePresentation", package: "swift-composable-presentation"),
         .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"),
@@ -228,6 +230,7 @@ let package = Package(
       name: "VerifyContactFeature",
       dependencies: [
         .product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
+        .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"),
       ]
     ),
     .testTarget(
diff --git a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
index 5267fcc3..beb07300 100644
--- a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
+++ b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
@@ -7,6 +7,7 @@ import RegisterFeature
 import RestoreFeature
 import SendRequestFeature
 import UserSearchFeature
+import VerifyContactFeature
 import WelcomeFeature
 import XXMessengerClient
 import XXModels
@@ -41,6 +42,9 @@ extension AppEnvironment {
           mainQueue: mainQueue,
           bgQueue: bgQueue
         )
+      },
+      verifyContact: {
+        VerifyContactEnvironment()
       }
     )
 
diff --git a/Examples/xx-messenger/Sources/ContactFeature/ContactFeature.swift b/Examples/xx-messenger/Sources/ContactFeature/ContactFeature.swift
index 9f6ef294..9d7a03d8 100644
--- a/Examples/xx-messenger/Sources/ContactFeature/ContactFeature.swift
+++ b/Examples/xx-messenger/Sources/ContactFeature/ContactFeature.swift
@@ -3,6 +3,7 @@ import ComposableArchitecture
 import ComposablePresentation
 import Foundation
 import SendRequestFeature
+import VerifyContactFeature
 import XCTestDynamicOverlay
 import XXClient
 import XXMessengerClient
@@ -16,7 +17,8 @@ public struct ContactState: Equatable {
     importUsername: Bool = true,
     importEmail: Bool = true,
     importPhone: Bool = true,
-    sendRequest: SendRequestState? = nil
+    sendRequest: SendRequestState? = nil,
+    verifyContact: VerifyContactState? = nil
   ) {
     self.id = id
     self.dbContact = dbContact
@@ -25,6 +27,7 @@ public struct ContactState: Equatable {
     self.importEmail = importEmail
     self.importPhone = importPhone
     self.sendRequest = sendRequest
+    self.verifyContact = verifyContact
   }
 
   public var id: Data
@@ -34,6 +37,7 @@ public struct ContactState: Equatable {
   @BindableState public var importEmail: Bool
   @BindableState public var importPhone: Bool
   public var sendRequest: SendRequestState?
+  public var verifyContact: VerifyContactState?
 }
 
 public enum ContactAction: Equatable, BindableAction {
@@ -43,6 +47,9 @@ public enum ContactAction: Equatable, BindableAction {
   case sendRequestTapped
   case sendRequestDismissed
   case sendRequest(SendRequestAction)
+  case verifyContactTapped
+  case verifyContactDismissed
+  case verifyContact(VerifyContactAction)
   case binding(BindingAction<ContactState>)
 }
 
@@ -52,13 +59,15 @@ public struct ContactEnvironment {
     db: DBManagerGetDB,
     mainQueue: AnySchedulerOf<DispatchQueue>,
     bgQueue: AnySchedulerOf<DispatchQueue>,
-    sendRequest: @escaping () -> SendRequestEnvironment
+    sendRequest: @escaping () -> SendRequestEnvironment,
+    verifyContact: @escaping () -> VerifyContactEnvironment
   ) {
     self.messenger = messenger
     self.db = db
     self.mainQueue = mainQueue
     self.bgQueue = bgQueue
     self.sendRequest = sendRequest
+    self.verifyContact = verifyContact
   }
 
   public var messenger: Messenger
@@ -66,6 +75,7 @@ public struct ContactEnvironment {
   public var mainQueue: AnySchedulerOf<DispatchQueue>
   public var bgQueue: AnySchedulerOf<DispatchQueue>
   public var sendRequest: () -> SendRequestEnvironment
+  public var verifyContact: () -> VerifyContactEnvironment
 }
 
 #if DEBUG
@@ -75,7 +85,8 @@ extension ContactEnvironment {
     db: .unimplemented,
     mainQueue: .unimplemented,
     bgQueue: .unimplemented,
-    sendRequest: { .unimplemented }
+    sendRequest: { .unimplemented },
+    verifyContact: { .unimplemented }
   )
 }
 #endif
@@ -135,10 +146,19 @@ public let contactReducer = Reducer<ContactState, ContactAction, ContactEnvironm
     state.sendRequest = nil
     return .none
 
-  case .sendRequest(_):
+  case .verifyContactTapped:
+    if let marshaled = state.dbContact?.marshaled {
+      state.verifyContact = VerifyContactState(
+        xxContact: .live(marshaled)
+      )
+    }
+    return .none
+
+  case .verifyContactDismissed:
+    state.verifyContact = nil
     return .none
 
-  case .binding(_):
+  case .binding(_), .sendRequest(_), .verifyContact(_):
     return .none
   }
 }
@@ -150,3 +170,10 @@ public let contactReducer = Reducer<ContactState, ContactAction, ContactEnvironm
   action: /ContactAction.sendRequest,
   environment: { $0.sendRequest() }
 )
+.presenting(
+  verifyContactReducer,
+  state: .keyPath(\.verifyContact),
+  id: .notNil(),
+  action: /ContactAction.verifyContact,
+  environment: { $0.verifyContact() }
+)
diff --git a/Examples/xx-messenger/Sources/ContactFeature/ContactView.swift b/Examples/xx-messenger/Sources/ContactFeature/ContactView.swift
index 1cd8fa2e..86202f15 100644
--- a/Examples/xx-messenger/Sources/ContactFeature/ContactView.swift
+++ b/Examples/xx-messenger/Sources/ContactFeature/ContactView.swift
@@ -3,6 +3,7 @@ import ComposableArchitecture
 import ComposablePresentation
 import SendRequestFeature
 import SwiftUI
+import VerifyContactFeature
 import XXClient
 import XXModels
 
@@ -114,6 +115,15 @@ public struct ContactView: View {
                 Image(systemName: "chevron.forward")
               }
             }
+            Button {
+              viewStore.send(.verifyContactTapped)
+            } label: {
+              HStack {
+                Text("Verify contact")
+                Spacer()
+                Image(systemName: "chevron.forward")
+              }
+            }
           } header: {
             Text("Auth")
           }
@@ -131,6 +141,14 @@ public struct ContactView: View {
         onDeactivate: { viewStore.send(.sendRequestDismissed) },
         destination: SendRequestView.init(store:)
       ))
+      .background(NavigationLinkWithStore(
+        store.scope(
+          state: \.verifyContact,
+          action: ContactAction.verifyContact
+        ),
+        onDeactivate: { viewStore.send(.verifyContactDismissed) },
+        destination: VerifyContactView.init(store:)
+      ))
     }
   }
 }
diff --git a/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactFeature.swift b/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactFeature.swift
index c657dd72..a64c43c4 100644
--- a/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactFeature.swift
+++ b/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactFeature.swift
@@ -1,8 +1,15 @@
 import ComposableArchitecture
 import XCTestDynamicOverlay
+import XXClient
 
 public struct VerifyContactState: Equatable {
-  public init() {}
+  public init(
+    xxContact: XXClient.Contact
+  ) {
+    self.xxContact = xxContact
+  }
+
+  public var xxContact: XXClient.Contact
 }
 
 public enum VerifyContactAction: Equatable {
diff --git a/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactView.swift b/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactView.swift
index ff2d76b2..fff1ad51 100644
--- a/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactView.swift
+++ b/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactView.swift
@@ -27,7 +27,9 @@ public struct VerifyContactView: View {
 public struct VerifyContactView_Previews: PreviewProvider {
   public static var previews: some View {
     VerifyContactView(store: Store(
-      initialState: VerifyContactState(),
+      initialState: VerifyContactState(
+        xxContact: .unimplemented("contact-data".data(using: .utf8)!)
+      ),
       reducer: .empty,
       environment: ()
     ))
diff --git a/Examples/xx-messenger/Tests/ContactFeatureTests/ContactFeatureTests.swift b/Examples/xx-messenger/Tests/ContactFeatureTests/ContactFeatureTests.swift
index 247abb49..260ed279 100644
--- a/Examples/xx-messenger/Tests/ContactFeatureTests/ContactFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/ContactFeatureTests/ContactFeatureTests.swift
@@ -2,6 +2,7 @@ import Combine
 import ComposableArchitecture
 import CustomDump
 import SendRequestFeature
+import VerifyContactFeature
 import XCTest
 import XXClient
 import XXModels
@@ -163,4 +164,42 @@ final class ContactFeatureTests: XCTestCase {
       $0.sendRequest = nil
     }
   }
+
+  func testVerifyContactTapped() {
+    let contactData = "contact-data".data(using: .utf8)!
+    let store = TestStore(
+      initialState: ContactState(
+        id: Data(),
+        dbContact: XXModels.Contact(
+          id: Data(),
+          marshaled: contactData
+        )
+      ),
+      reducer: contactReducer,
+      environment: .unimplemented
+    )
+
+    store.send(.verifyContactTapped) {
+      $0.verifyContact = VerifyContactState(
+        xxContact: .live(contactData)
+      )
+    }
+  }
+
+  func testVerifyContactDismissed() {
+    let store = TestStore(
+      initialState: ContactState(
+        id: "contact-id".data(using: .utf8)!,
+        verifyContact: VerifyContactState(
+          xxContact: .unimplemented("contact-data".data(using: .utf8)!)
+        )
+      ),
+      reducer: contactReducer,
+      environment: .unimplemented
+    )
+
+    store.send(.verifyContactDismissed) {
+      $0.verifyContact = nil
+    }
+  }
 }
diff --git a/Examples/xx-messenger/Tests/VerifyContactFeatureTests/VerifyContactFeatureTests.swift b/Examples/xx-messenger/Tests/VerifyContactFeatureTests/VerifyContactFeatureTests.swift
index b0f41108..212b3d0a 100644
--- a/Examples/xx-messenger/Tests/VerifyContactFeatureTests/VerifyContactFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/VerifyContactFeatureTests/VerifyContactFeatureTests.swift
@@ -5,7 +5,9 @@ import XCTest
 final class VerifyContactFeatureTests: XCTestCase {
   func testStart() {
     let store = TestStore(
-      initialState: VerifyContactState(),
+      initialState: VerifyContactState(
+        xxContact: .unimplemented("contact-data".data(using: .utf8)!)
+      ),
       reducer: verifyContactReducer,
       environment: .unimplemented
     )
-- 
GitLab