From 5b6ce6a132c26fc4b4530a3cd70e7dadb7818520 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Fri, 21 Oct 2022 11:31:40 +0200
Subject: [PATCH] Migrate WelcomeFeature to ReducerProtocol

---
 .../WelcomeFeature/WelcomeComponent.swift     | 64 ++++++++++++++
 .../WelcomeFeature/WelcomeFeature.swift       | 83 -------------------
 .../Sources/WelcomeFeature/WelcomeView.swift  | 11 ++-
 ...ests.swift => WelcomeComponentTests.swift} | 30 +++----
 4 files changed, 82 insertions(+), 106 deletions(-)
 create mode 100644 Examples/xx-messenger/Sources/WelcomeFeature/WelcomeComponent.swift
 delete mode 100644 Examples/xx-messenger/Sources/WelcomeFeature/WelcomeFeature.swift
 rename Examples/xx-messenger/Tests/WelcomeFeatureTests/{WelcomeFeatureTests.swift => WelcomeComponentTests.swift} (60%)

diff --git a/Examples/xx-messenger/Sources/WelcomeFeature/WelcomeComponent.swift b/Examples/xx-messenger/Sources/WelcomeFeature/WelcomeComponent.swift
new file mode 100644
index 00000000..55af6703
--- /dev/null
+++ b/Examples/xx-messenger/Sources/WelcomeFeature/WelcomeComponent.swift
@@ -0,0 +1,64 @@
+import ComposableArchitecture
+import SwiftUI
+import XXMessengerClient
+
+public struct WelcomeComponent: ReducerProtocol {
+  public struct State: Equatable {
+    public init(
+      isCreatingCMix: Bool = false,
+      failure: String? = nil
+    ) {
+      self.isCreatingAccount = isCreatingCMix
+      self.failure = failure
+    }
+
+    public var isCreatingAccount: Bool
+    public var failure: String?
+  }
+
+  public enum Action: Equatable {
+    case newAccountTapped
+    case restoreTapped
+    case finished
+    case failed(String)
+  }
+
+  public init() {}
+
+  @Dependency(\.app.messenger) var messenger: Messenger
+  @Dependency(\.app.mainQueue) var mainQueue: AnySchedulerOf<DispatchQueue>
+  @Dependency(\.app.bgQueue) var bgQueue: AnySchedulerOf<DispatchQueue>
+
+  public func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
+    switch action {
+    case .newAccountTapped:
+      state.isCreatingAccount = true
+      state.failure = nil
+      return .future { fulfill in
+        do {
+          try messenger.create()
+          fulfill(.success(.finished))
+        }
+        catch {
+          fulfill(.success(.failed(error.localizedDescription)))
+        }
+      }
+      .subscribe(on: bgQueue)
+      .receive(on: mainQueue)
+      .eraseToEffect()
+
+    case .restoreTapped:
+      return .none
+
+    case .finished:
+      state.isCreatingAccount = false
+      state.failure = nil
+      return .none
+
+    case .failed(let failure):
+      state.isCreatingAccount = false
+      state.failure = failure
+      return .none
+    }
+  }
+}
diff --git a/Examples/xx-messenger/Sources/WelcomeFeature/WelcomeFeature.swift b/Examples/xx-messenger/Sources/WelcomeFeature/WelcomeFeature.swift
deleted file mode 100644
index 66e9ef1b..00000000
--- a/Examples/xx-messenger/Sources/WelcomeFeature/WelcomeFeature.swift
+++ /dev/null
@@ -1,83 +0,0 @@
-import ComposableArchitecture
-import SwiftUI
-import XXMessengerClient
-
-public struct WelcomeState: Equatable {
-  public init(
-    isCreatingCMix: Bool = false,
-    failure: String? = nil
-  ) {
-    self.isCreatingAccount = isCreatingCMix
-    self.failure = failure
-  }
-
-  public var isCreatingAccount: Bool
-  public var failure: String?
-}
-
-public enum WelcomeAction: Equatable {
-  case newAccountTapped
-  case restoreTapped
-  case finished
-  case failed(String)
-}
-
-public struct WelcomeEnvironment {
-  public init(
-    messenger: Messenger,
-    mainQueue: AnySchedulerOf<DispatchQueue>,
-    bgQueue: AnySchedulerOf<DispatchQueue>
-  ) {
-    self.messenger = messenger
-    self.mainQueue = mainQueue
-    self.bgQueue = bgQueue
-  }
-
-  public var messenger: Messenger
-  public var mainQueue: AnySchedulerOf<DispatchQueue>
-  public var bgQueue: AnySchedulerOf<DispatchQueue>
-}
-
-#if DEBUG
-extension WelcomeEnvironment {
-  public static let unimplemented = WelcomeEnvironment(
-    messenger: .unimplemented,
-    mainQueue: .unimplemented,
-    bgQueue: .unimplemented
-  )
-}
-#endif
-
-public let welcomeReducer = Reducer<WelcomeState, WelcomeAction, WelcomeEnvironment>
-{ state, action, env in
-  switch action {
-  case .newAccountTapped:
-    state.isCreatingAccount = true
-    state.failure = nil
-    return .future { fulfill in
-      do {
-        try env.messenger.create()
-        fulfill(.success(.finished))
-      }
-      catch {
-        fulfill(.success(.failed(error.localizedDescription)))
-      }
-    }
-    .subscribe(on: env.bgQueue)
-    .receive(on: env.mainQueue)
-    .eraseToEffect()
-
-  case .restoreTapped:
-    return .none
-
-  case .finished:
-    state.isCreatingAccount = false
-    state.failure = nil
-    return .none
-
-  case .failed(let failure):
-    state.isCreatingAccount = false
-    state.failure = failure
-    return .none
-  }
-}
diff --git a/Examples/xx-messenger/Sources/WelcomeFeature/WelcomeView.swift b/Examples/xx-messenger/Sources/WelcomeFeature/WelcomeView.swift
index 64396fe1..0b4597e1 100644
--- a/Examples/xx-messenger/Sources/WelcomeFeature/WelcomeView.swift
+++ b/Examples/xx-messenger/Sources/WelcomeFeature/WelcomeView.swift
@@ -3,14 +3,14 @@ import ComposableArchitecture
 import SwiftUI
 
 public struct WelcomeView: View {
-  public init(store: Store<WelcomeState, WelcomeAction>) {
+  public init(store: StoreOf<WelcomeComponent>) {
     self.store = store
   }
 
-  let store: Store<WelcomeState, WelcomeAction>
+  let store: StoreOf<WelcomeComponent>
 
   struct ViewState: Equatable {
-    init(_ state: WelcomeState) {
+    init(_ state: WelcomeComponent.State) {
       isCreatingAccount = state.isCreatingAccount
       failure = state.failure
     }
@@ -69,9 +69,8 @@ public struct WelcomeView: View {
 public struct WelcomeView_Previews: PreviewProvider {
   public static var previews: some View {
     WelcomeView(store: Store(
-      initialState: WelcomeState(),
-      reducer: .empty,
-      environment: ()
+      initialState: WelcomeComponent.State(),
+      reducer: EmptyReducer()
     ))
   }
 }
diff --git a/Examples/xx-messenger/Tests/WelcomeFeatureTests/WelcomeFeatureTests.swift b/Examples/xx-messenger/Tests/WelcomeFeatureTests/WelcomeComponentTests.swift
similarity index 60%
rename from Examples/xx-messenger/Tests/WelcomeFeatureTests/WelcomeFeatureTests.swift
rename to Examples/xx-messenger/Tests/WelcomeFeatureTests/WelcomeComponentTests.swift
index c6f23b7a..4d2391d3 100644
--- a/Examples/xx-messenger/Tests/WelcomeFeatureTests/WelcomeFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/WelcomeFeatureTests/WelcomeComponentTests.swift
@@ -2,8 +2,7 @@ import ComposableArchitecture
 import XCTest
 @testable import WelcomeFeature
 
-@MainActor
-final class WelcomeFeatureTests: XCTestCase {
+final class WelcomeComponentTests: XCTestCase {
   func testNewAccountTapped() {
     let mainQueue = DispatchQueue.test
     let bgQueue = DispatchQueue.test
@@ -11,14 +10,13 @@ final class WelcomeFeatureTests: XCTestCase {
     var didCreateMessenger = 0
 
     let store = TestStore(
-      initialState: WelcomeState(),
-      reducer: welcomeReducer,
-      environment: .unimplemented
+      initialState: WelcomeComponent.State(),
+      reducer: WelcomeComponent()
     )
 
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.messenger.create.run = { didCreateMessenger += 1 }
+    store.dependencies.app.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.dependencies.app.bgQueue = bgQueue.eraseToAnyScheduler()
+    store.dependencies.app.messenger.create.run = { didCreateMessenger += 1 }
 
     store.send(.newAccountTapped) {
       $0.isCreatingAccount = true
@@ -44,14 +42,13 @@ final class WelcomeFeatureTests: XCTestCase {
     let bgQueue = DispatchQueue.test
 
     let store = TestStore(
-      initialState: WelcomeState(),
-      reducer: welcomeReducer,
-      environment: .unimplemented
+      initialState: WelcomeComponent.State(),
+      reducer: WelcomeComponent()
     )
 
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.messenger.create.run = { throw failure }
+    store.dependencies.app.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.dependencies.app.bgQueue = bgQueue.eraseToAnyScheduler()
+    store.dependencies.app.messenger.create.run = { throw failure }
 
     store.send(.newAccountTapped) {
       $0.isCreatingAccount = true
@@ -69,9 +66,8 @@ final class WelcomeFeatureTests: XCTestCase {
 
   func testRestore() {
     let store = TestStore(
-      initialState: WelcomeState(),
-      reducer: welcomeReducer,
-      environment: .unimplemented
+      initialState: WelcomeComponent.State(),
+      reducer: WelcomeComponent()
     )
 
     store.send(.restoreTapped)
-- 
GitLab