Skip to content
Snippets Groups Projects
Commit 2e60cdc1 authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Migrate VerifyContactFeature to ReducerProtocol

parent c5e278cd
No related branches found
No related tags found
2 merge requests!126Migrate example app to ComposableArchitecture's ReducerProtocol,!102Release 1.0.0
import AppCore
import ComposableArchitecture
import Foundation
import XCTestDynamicOverlay
import XXClient
import XXMessengerClient
import XXModels
public struct VerifyContactComponent: ReducerProtocol {
public struct State: Equatable {
public enum Result: Equatable {
case success(Bool)
case failure(String)
}
public init(
contact: XXClient.Contact,
isVerifying: Bool = false,
result: Result? = nil
) {
self.contact = contact
self.isVerifying = isVerifying
self.result = result
}
public var contact: XXClient.Contact
public var isVerifying: Bool
public var result: Result?
}
public enum Action: Equatable {
case verifyTapped
case didVerify(State.Result)
}
public init() {}
@Dependency(\.appDependencies.messenger) var messenger: Messenger
@Dependency(\.appDependencies.dbManager.getDB) var db: DBManagerGetDB
@Dependency(\.appDependencies.mainQueue) var mainQueue: AnySchedulerOf<DispatchQueue>
@Dependency(\.appDependencies.bgQueue) var bgQueue: AnySchedulerOf<DispatchQueue>
public func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
switch action {
case .verifyTapped:
state.isVerifying = true
state.result = nil
return Effect.result { [state] in
func updateStatus(_ status: XXModels.Contact.AuthStatus) throws {
try db().bulkUpdateContacts.callAsFunction(
.init(id: [try state.contact.getId()]),
.init(authStatus: status)
)
}
do {
try updateStatus(.verificationInProgress)
let result = try messenger.verifyContact(state.contact)
try updateStatus(result ? .verified : .verificationFailed)
return .success(.didVerify(.success(result)))
} catch {
try? updateStatus(.verificationFailed)
return .success(.didVerify(.failure(error.localizedDescription)))
}
}
.subscribe(on: bgQueue)
.receive(on: mainQueue)
.eraseToEffect()
case .didVerify(let result):
state.isVerifying = false
state.result = result
return .none
}
}
}
import AppCore
import ComposableArchitecture
import Foundation
import XCTestDynamicOverlay
import XXClient
import XXMessengerClient
import XXModels
public struct VerifyContactState: Equatable {
public enum Result: Equatable {
case success(Bool)
case failure(String)
}
public init(
contact: XXClient.Contact,
isVerifying: Bool = false,
result: Result? = nil
) {
self.contact = contact
self.isVerifying = isVerifying
self.result = result
}
public var contact: XXClient.Contact
public var isVerifying: Bool
public var result: Result?
}
public enum VerifyContactAction: Equatable {
case verifyTapped
case didVerify(VerifyContactState.Result)
}
public struct VerifyContactEnvironment {
public init(
messenger: Messenger,
db: DBManagerGetDB,
mainQueue: AnySchedulerOf<DispatchQueue>,
bgQueue: AnySchedulerOf<DispatchQueue>
) {
self.messenger = messenger
self.db = db
self.mainQueue = mainQueue
self.bgQueue = bgQueue
}
public var messenger: Messenger
public var db: DBManagerGetDB
public var mainQueue: AnySchedulerOf<DispatchQueue>
public var bgQueue: AnySchedulerOf<DispatchQueue>
}
#if DEBUG
extension VerifyContactEnvironment {
public static let unimplemented = VerifyContactEnvironment(
messenger: .unimplemented,
db: .unimplemented,
mainQueue: .unimplemented,
bgQueue: .unimplemented
)
}
#endif
public let verifyContactReducer = Reducer<VerifyContactState, VerifyContactAction, VerifyContactEnvironment>
{ state, action, env in
switch action {
case .verifyTapped:
state.isVerifying = true
state.result = nil
return Effect.result { [state] in
func updateStatus(_ status: XXModels.Contact.AuthStatus) throws {
try env.db().bulkUpdateContacts.callAsFunction(
.init(id: [try state.contact.getId()]),
.init(authStatus: status)
)
}
do {
try updateStatus(.verificationInProgress)
let result = try env.messenger.verifyContact(state.contact)
try updateStatus(result ? .verified : .verificationFailed)
return .success(.didVerify(.success(result)))
} catch {
try? updateStatus(.verificationFailed)
return .success(.didVerify(.failure(error.localizedDescription)))
}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
case .didVerify(let result):
state.isVerifying = false
state.result = result
return .none
}
}
......@@ -2,20 +2,20 @@ import ComposableArchitecture
import SwiftUI
public struct VerifyContactView: View {
public init(store: Store<VerifyContactState, VerifyContactAction>) {
public init(store: StoreOf<VerifyContactComponent>) {
self.store = store
}
let store: Store<VerifyContactState, VerifyContactAction>
let store: StoreOf<VerifyContactComponent>
struct ViewState: Equatable {
var username: String?
var email: String?
var phone: String?
var isVerifying: Bool
var result: VerifyContactState.Result?
var result: VerifyContactComponent.State.Result?
init(state: VerifyContactState) {
init(state: VerifyContactComponent.State) {
username = try? state.contact.getFact(.username)?.value
email = try? state.contact.getFact(.email)?.value
phone = try? state.contact.getFact(.phone)?.value
......@@ -89,11 +89,10 @@ public struct VerifyContactView: View {
public struct VerifyContactView_Previews: PreviewProvider {
public static var previews: some View {
VerifyContactView(store: Store(
initialState: VerifyContactState(
initialState: VerifyContactComponent.State(
contact: .unimplemented("contact-data".data(using: .utf8)!)
),
reducer: .empty,
environment: ()
reducer: EmptyReducer()
))
}
}
......
......@@ -5,31 +5,30 @@ import XXClient
import XXModels
@testable import VerifyContactFeature
final class VerifyContactFeatureTests: XCTestCase {
final class VerifyContactComponentTests: XCTestCase {
func testVerify() {
var contact = XXClient.Contact.unimplemented("contact-data".data(using: .utf8)!)
let contactId = "contact-id".data(using: .utf8)!
contact.getIdFromContact.run = { _ in contactId }
let store = TestStore(
initialState: VerifyContactState(
initialState: VerifyContactComponent.State(
contact: contact
),
reducer: verifyContactReducer,
environment: .unimplemented
reducer: VerifyContactComponent()
)
var didVerifyContact: [XXClient.Contact] = []
var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = []
var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = []
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.messenger.verifyContact.run = { contact in
store.dependencies.appDependencies.mainQueue = .immediate
store.dependencies.appDependencies.bgQueue = .immediate
store.dependencies.appDependencies.messenger.verifyContact.run = { contact in
didVerifyContact.append(contact)
return true
}
store.environment.db.run = {
store.dependencies.appDependencies.dbManager.getDB.run = {
var db: Database = .unimplemented
db.bulkUpdateContacts.run = { query, assignments in
didBulkUpdateContactsWithQuery.append(query)
......@@ -66,24 +65,23 @@ final class VerifyContactFeatureTests: XCTestCase {
contact.getIdFromContact.run = { _ in contactId }
let store = TestStore(
initialState: VerifyContactState(
initialState: VerifyContactComponent.State(
contact: contact
),
reducer: verifyContactReducer,
environment: .unimplemented
reducer: VerifyContactComponent()
)
var didVerifyContact: [XXClient.Contact] = []
var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = []
var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = []
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.messenger.verifyContact.run = { contact in
store.dependencies.appDependencies.mainQueue = .immediate
store.dependencies.appDependencies.bgQueue = .immediate
store.dependencies.appDependencies.messenger.verifyContact.run = { contact in
didVerifyContact.append(contact)
return false
}
store.environment.db.run = {
store.dependencies.appDependencies.dbManager.getDB.run = {
var db: Database = .unimplemented
db.bulkUpdateContacts.run = { query, assignments in
didBulkUpdateContactsWithQuery.append(query)
......@@ -120,11 +118,10 @@ final class VerifyContactFeatureTests: XCTestCase {
contact.getIdFromContact.run = { _ in contactId }
let store = TestStore(
initialState: VerifyContactState(
initialState: VerifyContactComponent.State(
contact: contact
),
reducer: verifyContactReducer,
environment: .unimplemented
reducer: VerifyContactComponent()
)
struct Failure: Error {}
......@@ -133,10 +130,10 @@ final class VerifyContactFeatureTests: XCTestCase {
var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = []
var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = []
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.messenger.verifyContact.run = { _ in throw error }
store.environment.db.run = {
store.dependencies.appDependencies.mainQueue = .immediate
store.dependencies.appDependencies.bgQueue = .immediate
store.dependencies.appDependencies.messenger.verifyContact.run = { _ in throw error }
store.dependencies.appDependencies.dbManager.getDB.run = {
var db: Database = .unimplemented
db.bulkUpdateContacts.run = { query, assignments in
didBulkUpdateContactsWithQuery.append(query)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment