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 ...@@ -2,20 +2,20 @@ import ComposableArchitecture
import SwiftUI import SwiftUI
public struct VerifyContactView: View { public struct VerifyContactView: View {
public init(store: Store<VerifyContactState, VerifyContactAction>) { public init(store: StoreOf<VerifyContactComponent>) {
self.store = store self.store = store
} }
let store: Store<VerifyContactState, VerifyContactAction> let store: StoreOf<VerifyContactComponent>
struct ViewState: Equatable { struct ViewState: Equatable {
var username: String? var username: String?
var email: String? var email: String?
var phone: String? var phone: String?
var isVerifying: Bool 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 username = try? state.contact.getFact(.username)?.value
email = try? state.contact.getFact(.email)?.value email = try? state.contact.getFact(.email)?.value
phone = try? state.contact.getFact(.phone)?.value phone = try? state.contact.getFact(.phone)?.value
...@@ -89,11 +89,10 @@ public struct VerifyContactView: View { ...@@ -89,11 +89,10 @@ public struct VerifyContactView: View {
public struct VerifyContactView_Previews: PreviewProvider { public struct VerifyContactView_Previews: PreviewProvider {
public static var previews: some View { public static var previews: some View {
VerifyContactView(store: Store( VerifyContactView(store: Store(
initialState: VerifyContactState( initialState: VerifyContactComponent.State(
contact: .unimplemented("contact-data".data(using: .utf8)!) contact: .unimplemented("contact-data".data(using: .utf8)!)
), ),
reducer: .empty, reducer: EmptyReducer()
environment: ()
)) ))
} }
} }
......
...@@ -5,31 +5,30 @@ import XXClient ...@@ -5,31 +5,30 @@ import XXClient
import XXModels import XXModels
@testable import VerifyContactFeature @testable import VerifyContactFeature
final class VerifyContactFeatureTests: XCTestCase { final class VerifyContactComponentTests: XCTestCase {
func testVerify() { func testVerify() {
var contact = XXClient.Contact.unimplemented("contact-data".data(using: .utf8)!) var contact = XXClient.Contact.unimplemented("contact-data".data(using: .utf8)!)
let contactId = "contact-id".data(using: .utf8)! let contactId = "contact-id".data(using: .utf8)!
contact.getIdFromContact.run = { _ in contactId } contact.getIdFromContact.run = { _ in contactId }
let store = TestStore( let store = TestStore(
initialState: VerifyContactState( initialState: VerifyContactComponent.State(
contact: contact contact: contact
), ),
reducer: verifyContactReducer, reducer: VerifyContactComponent()
environment: .unimplemented
) )
var didVerifyContact: [XXClient.Contact] = [] var didVerifyContact: [XXClient.Contact] = []
var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = [] var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = []
var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = [] var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = []
store.environment.mainQueue = .immediate store.dependencies.appDependencies.mainQueue = .immediate
store.environment.bgQueue = .immediate store.dependencies.appDependencies.bgQueue = .immediate
store.environment.messenger.verifyContact.run = { contact in store.dependencies.appDependencies.messenger.verifyContact.run = { contact in
didVerifyContact.append(contact) didVerifyContact.append(contact)
return true return true
} }
store.environment.db.run = { store.dependencies.appDependencies.dbManager.getDB.run = {
var db: Database = .unimplemented var db: Database = .unimplemented
db.bulkUpdateContacts.run = { query, assignments in db.bulkUpdateContacts.run = { query, assignments in
didBulkUpdateContactsWithQuery.append(query) didBulkUpdateContactsWithQuery.append(query)
...@@ -66,24 +65,23 @@ final class VerifyContactFeatureTests: XCTestCase { ...@@ -66,24 +65,23 @@ final class VerifyContactFeatureTests: XCTestCase {
contact.getIdFromContact.run = { _ in contactId } contact.getIdFromContact.run = { _ in contactId }
let store = TestStore( let store = TestStore(
initialState: VerifyContactState( initialState: VerifyContactComponent.State(
contact: contact contact: contact
), ),
reducer: verifyContactReducer, reducer: VerifyContactComponent()
environment: .unimplemented
) )
var didVerifyContact: [XXClient.Contact] = [] var didVerifyContact: [XXClient.Contact] = []
var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = [] var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = []
var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = [] var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = []
store.environment.mainQueue = .immediate store.dependencies.appDependencies.mainQueue = .immediate
store.environment.bgQueue = .immediate store.dependencies.appDependencies.bgQueue = .immediate
store.environment.messenger.verifyContact.run = { contact in store.dependencies.appDependencies.messenger.verifyContact.run = { contact in
didVerifyContact.append(contact) didVerifyContact.append(contact)
return false return false
} }
store.environment.db.run = { store.dependencies.appDependencies.dbManager.getDB.run = {
var db: Database = .unimplemented var db: Database = .unimplemented
db.bulkUpdateContacts.run = { query, assignments in db.bulkUpdateContacts.run = { query, assignments in
didBulkUpdateContactsWithQuery.append(query) didBulkUpdateContactsWithQuery.append(query)
...@@ -120,11 +118,10 @@ final class VerifyContactFeatureTests: XCTestCase { ...@@ -120,11 +118,10 @@ final class VerifyContactFeatureTests: XCTestCase {
contact.getIdFromContact.run = { _ in contactId } contact.getIdFromContact.run = { _ in contactId }
let store = TestStore( let store = TestStore(
initialState: VerifyContactState( initialState: VerifyContactComponent.State(
contact: contact contact: contact
), ),
reducer: verifyContactReducer, reducer: VerifyContactComponent()
environment: .unimplemented
) )
struct Failure: Error {} struct Failure: Error {}
...@@ -133,10 +130,10 @@ final class VerifyContactFeatureTests: XCTestCase { ...@@ -133,10 +130,10 @@ final class VerifyContactFeatureTests: XCTestCase {
var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = [] var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = []
var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = [] var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = []
store.environment.mainQueue = .immediate store.dependencies.appDependencies.mainQueue = .immediate
store.environment.bgQueue = .immediate store.dependencies.appDependencies.bgQueue = .immediate
store.environment.messenger.verifyContact.run = { _ in throw error } store.dependencies.appDependencies.messenger.verifyContact.run = { _ in throw error }
store.environment.db.run = { store.dependencies.appDependencies.dbManager.getDB.run = {
var db: Database = .unimplemented var db: Database = .unimplemented
db.bulkUpdateContacts.run = { query, assignments in db.bulkUpdateContacts.run = { query, assignments in
didBulkUpdateContactsWithQuery.append(query) 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