From aad544cd6ca3591117c33306ca6f4b1525bcf8d9 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Wed, 7 Sep 2022 12:04:13 +0200
Subject: [PATCH] Fetch db contact in ContactFeature

---
 .../ContactFeature/ContactFeature.swift       |  14 +++
 .../Sources/ContactFeature/ContactView.swift  | 115 +++++++++++++++++-
 .../ContactFeatureTests.swift                 |  30 +++++
 3 files changed, 158 insertions(+), 1 deletion(-)

diff --git a/Examples/xx-messenger/Sources/ContactFeature/ContactFeature.swift b/Examples/xx-messenger/Sources/ContactFeature/ContactFeature.swift
index 80fbcc81..6624bb2c 100644
--- a/Examples/xx-messenger/Sources/ContactFeature/ContactFeature.swift
+++ b/Examples/xx-messenger/Sources/ContactFeature/ContactFeature.swift
@@ -24,6 +24,7 @@ public struct ContactState: Equatable {
 
 public enum ContactAction: Equatable {
   case start
+  case dbContactFetched(XXModels.Contact?)
 }
 
 public struct ContactEnvironment {
@@ -58,8 +59,21 @@ extension ContactEnvironment {
 
 public let contactReducer = Reducer<ContactState, ContactAction, ContactEnvironment>
 { state, action, env in
+  enum DBFetchEffectID {}
+
   switch action {
   case .start:
+    return try! env.db().fetchContactsPublisher(.init(id: [state.id]))
+      .assertNoFailure()
+      .map(\.first)
+      .map(ContactAction.dbContactFetched)
+      .subscribe(on: env.bgQueue)
+      .receive(on: env.mainQueue)
+      .eraseToEffect()
+      .cancellable(id: DBFetchEffectID.self, cancelInFlight: true)
+
+  case .dbContactFetched(let contact):
+    state.dbContact = contact
     return .none
   }
 }
diff --git a/Examples/xx-messenger/Sources/ContactFeature/ContactView.swift b/Examples/xx-messenger/Sources/ContactFeature/ContactView.swift
index a050747e..0d985c62 100644
--- a/Examples/xx-messenger/Sources/ContactFeature/ContactView.swift
+++ b/Examples/xx-messenger/Sources/ContactFeature/ContactView.swift
@@ -1,5 +1,8 @@
+import AppCore
 import ComposableArchitecture
 import SwiftUI
+import XXClient
+import XXModels
 
 public struct ContactView: View {
   public init(store: Store<ContactState, ContactAction>) {
@@ -9,13 +12,123 @@ public struct ContactView: View {
   let store: Store<ContactState, ContactAction>
 
   struct ViewState: Equatable {
-    init(state: ContactState) {}
+    var dbContact: XXModels.Contact?
+    var xxContact: XXClient.Contact?
+
+    init(state: ContactState) {
+      dbContact = state.dbContact
+      xxContact = state.xxContact
+    }
   }
 
   public var body: some View {
     WithViewStore(store.scope(state: ViewState.init)) { viewStore in
       Form {
+        Section {
+          if let dbContact = viewStore.dbContact {
+            Label(dbContact.username ?? "", systemImage: "person")
+            Label(dbContact.email ?? "", systemImage: "envelope")
+            Label(dbContact.phone ?? "", systemImage: "phone")
+          } else {
+            Text("Contact not saved locally")
+          }
+        } header: {
+          Text("Local data")
+        }
+
+        Section {
+          Label(viewStore.xxContact?.username ?? "", systemImage: "person")
+          Label(viewStore.xxContact?.email ?? "", systemImage: "envelope")
+          Label(viewStore.xxContact?.phone ?? "", systemImage: "phone")
+        } header: {
+          Text("Facts")
+        }
+
+        Section {
+          switch viewStore.dbContact?.authStatus {
+          case .none, .stranger:
+            HStack {
+              Text("Stranger")
+              Spacer()
+              Image(systemName: "person.fill.questionmark")
+            }
+
+          case .requesting:
+            HStack {
+              Text("Sending auth request")
+              Spacer()
+              ProgressView()
+            }
+
+          case .requested:
+            HStack {
+              Text("Request sent")
+              Spacer()
+              Image(systemName: "paperplane")
+            }
+
+          case .requestFailed:
+            HStack {
+              Text("Sending request failed")
+              Spacer()
+              Image(systemName: "xmark.diamond.fill")
+                .foregroundColor(.red)
+            }
+
+          case .verificationInProgress:
+            HStack {
+              Text("Verification is progress")
+              Spacer()
+              ProgressView()
+            }
+
+          case .verified:
+            HStack {
+              Text("Verified")
+              Spacer()
+              Image(systemName: "person.fill.checkmark")
+            }
+
+          case .verificationFailed:
+            HStack {
+              Text("Verification failed")
+              Spacer()
+              Image(systemName: "xmark.diamond.fill")
+                .foregroundColor(.red)
+            }
+
+          case .confirming:
+            HStack {
+              Text("Confirming auth request")
+              Spacer()
+              ProgressView()
+            }
+
+          case .confirmationFailed:
+            HStack {
+              Text("Confirmation failed")
+              Spacer()
+              Image(systemName: "xmark.diamond.fill")
+                .foregroundColor(.red)
+            }
+
+          case .friend:
+            HStack {
+              Text("Friend")
+              Spacer()
+              Image(systemName: "person.fill.checkmark")
+            }
 
+          case .hidden:
+            HStack {
+              Text("Hidden")
+              Spacer()
+              Image(systemName: "eye.slash")
+            }
+          }
+        } header: {
+          Text("Auth status")
+        }
       }
       .navigationTitle("Contact")
     }
diff --git a/Examples/xx-messenger/Tests/ContactFeatureTests/ContactFeatureTests.swift b/Examples/xx-messenger/Tests/ContactFeatureTests/ContactFeatureTests.swift
index 4711a132..5145acce 100644
--- a/Examples/xx-messenger/Tests/ContactFeatureTests/ContactFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/ContactFeatureTests/ContactFeatureTests.swift
@@ -1,5 +1,8 @@
+import Combine
 import ComposableArchitecture
+import CustomDump
 import XCTest
+import XXModels
 @testable import ContactFeature
 
 final class ContactFeatureTests: XCTestCase {
@@ -12,6 +15,33 @@ final class ContactFeatureTests: XCTestCase {
       environment: .unimplemented
     )
 
+    var dbDidFetchContacts: [XXModels.Contact.Query] = []
+    let dbContactsPublisher = PassthroughSubject<[XXModels.Contact], Error>()
+
+    store.environment.mainQueue = .immediate
+    store.environment.bgQueue = .immediate
+    store.environment.db.run = {
+      var db: Database = .failing
+      db.fetchContactsPublisher.run = { query in
+        dbDidFetchContacts.append(query)
+        return dbContactsPublisher.eraseToAnyPublisher()
+      }
+      return db
+    }
+
     store.send(.start)
+
+    XCTAssertNoDifference(dbDidFetchContacts, [
+      .init(id: ["contact-id".data(using: .utf8)!])
+    ])
+
+    let dbContact = XXModels.Contact(id: "contact-id".data(using: .utf8)!)
+    dbContactsPublisher.send([dbContact])
+
+    store.receive(.dbContactFetched(dbContact)) {
+      $0.dbContact = dbContact
+    }
+
+    dbContactsPublisher.send(completion: .finished)
   }
 }
-- 
GitLab