Newer
Older
import XXClient
import XXMessengerClient
import XXModels
public struct MyContactState: Equatable {
}
public init(
contact: XXModels.Contact? = nil,
focusedField: Field? = nil,
email: String = "",
emailConfirmationID: String? = nil,
emailConfirmationCode: String = "",
isRegisteringEmail: Bool = false,
isConfirmingEmail: Bool = false,
phoneConfirmationID: String? = nil,
phoneConfirmationCode: String = "",
isRegisteringPhone: Bool = false,
isConfirmingPhone: Bool = false,
alert: AlertState<MyContactAction>? = nil
) {
self.contact = contact
self.focusedField = focusedField
self.email = email
self.emailConfirmationID = emailConfirmationID
self.emailConfirmationCode = emailConfirmationCode
self.isRegisteringEmail = isRegisteringEmail
self.isConfirmingEmail = isConfirmingEmail
self.isUnregisteringEmail = isUnregisteringEmail
self.phoneConfirmationID = phoneConfirmationID
self.phoneConfirmationCode = phoneConfirmationCode
self.isRegisteringPhone = isRegisteringPhone
self.isConfirmingPhone = isConfirmingPhone
self.isUnregisteringPhone = isUnregisteringPhone
}
public var contact: XXModels.Contact?
@BindableState public var focusedField: Field?
@BindableState public var email: String
@BindableState public var emailConfirmationID: String?
@BindableState public var emailConfirmationCode: String
@BindableState public var isRegisteringEmail: Bool
@BindableState public var isConfirmingEmail: Bool
@BindableState public var isUnregisteringEmail: Bool
@BindableState public var phoneConfirmationID: String?
@BindableState public var phoneConfirmationCode: String
@BindableState public var isRegisteringPhone: Bool
@BindableState public var isConfirmingPhone: Bool
@BindableState public var isUnregisteringPhone: Bool
@BindableState public var isLoadingFacts: Bool
public var alert: AlertState<MyContactAction>?
public enum MyContactAction: Equatable, BindableAction {
case contactFetched(XXModels.Contact?)
case registerEmailTapped
case unregisterEmailTapped
case registerPhoneTapped
case didFail(String)
case alertDismissed
}
public struct MyContactEnvironment {
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 MyContactEnvironment {
public static let unimplemented = MyContactEnvironment(
messenger: .unimplemented,
db: .unimplemented,
mainQueue: .unimplemented,
bgQueue: .unimplemented
)
}
#endif
public let myContactReducer = Reducer<MyContactState, MyContactAction, MyContactEnvironment>
{ state, action, env in
return Effect
.catching { try env.messenger.e2e.tryGet().getContact().getId() }
.tryMap { try env.db().fetchContactsPublisher(.init(id: [$0])) }
.flatMap { $0 }
.assertNoFailure()
.map(\.first)
.map(MyContactAction.contactFetched)
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
.cancellable(id: DBFetchEffectID.self, cancelInFlight: true)
case .contactFetched(let contact):
state.contact = contact
return .none
case .registerEmailTapped:
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
state.focusedField = nil
state.isRegisteringEmail = true
return Effect.run { [state] subscriber in
do {
let ud = try env.messenger.ud.tryGet()
let fact = Fact(type: .email, value: state.email)
let confirmationID = try ud.sendRegisterFact(fact)
subscriber.send(.set(\.$emailConfirmationID, confirmationID))
} catch {
subscriber.send(.didFail(error.localizedDescription))
}
subscriber.send(.set(\.$isRegisteringEmail, false))
subscriber.send(completion: .finished)
return AnyCancellable {}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
case .confirmEmailTapped:
guard let confirmationID = state.emailConfirmationID else { return .none }
state.focusedField = nil
state.isConfirmingEmail = true
return Effect.run { [state] subscriber in
do {
let ud = try env.messenger.ud.tryGet()
try ud.confirmFact(confirmationId: confirmationID, code: state.emailConfirmationCode)
let contactId = try env.messenger.e2e.tryGet().getContact().getId()
if var dbContact = try env.db().fetchContacts(.init(id: [contactId])).first {
dbContact.email = state.email
try env.db().saveContact(dbContact)
}
subscriber.send(.set(\.$email, ""))
subscriber.send(.set(\.$emailConfirmationID, nil))
subscriber.send(.set(\.$emailConfirmationCode, ""))
} catch {
subscriber.send(.didFail(error.localizedDescription))
}
subscriber.send(.set(\.$isConfirmingEmail, false))
subscriber.send(completion: .finished)
return AnyCancellable {}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
guard let email = state.contact?.email else { return .none }
state.isUnregisteringEmail = true
return Effect.run { [state] subscriber in
do {
let ud: UserDiscovery = try env.messenger.ud.tryGet()
let fact = Fact(type: .email, value: email)
try ud.removeFact(fact)
let contactId = try env.messenger.e2e.tryGet().getContact().getId()
if var dbContact = try env.db().fetchContacts(.init(id: [contactId])).first {
dbContact.email = nil
try env.db().saveContact(dbContact)
}
} catch {
subscriber.send(.didFail(error.localizedDescription))
}
subscriber.send(.set(\.$isUnregisteringEmail, false))
subscriber.send(completion: .finished)
return AnyCancellable {}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
state.focusedField = nil
state.isRegisteringPhone = true
return Effect.run { [state] subscriber in
do {
let ud = try env.messenger.ud.tryGet()
let fact = Fact(type: .phone, value: state.phone)
let confirmationID = try ud.sendRegisterFact(fact)
subscriber.send(.set(\.$phoneConfirmationID, confirmationID))
} catch {
subscriber.send(.didFail(error.localizedDescription))
}
subscriber.send(.set(\.$isRegisteringPhone, false))
subscriber.send(completion: .finished)
return AnyCancellable {}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
case .confirmPhoneTapped:
guard let confirmationID = state.phoneConfirmationID else { return .none }
state.focusedField = nil
state.isConfirmingPhone = true
return Effect.run { [state] subscriber in
do {
let ud = try env.messenger.ud.tryGet()
try ud.confirmFact(confirmationId: confirmationID, code: state.phoneConfirmationCode)
let contactId = try env.messenger.e2e.tryGet().getContact().getId()
if var dbContact = try env.db().fetchContacts(.init(id: [contactId])).first {
dbContact.phone = state.phone
try env.db().saveContact(dbContact)
}
subscriber.send(.set(\.$phone, ""))
subscriber.send(.set(\.$phoneConfirmationID, nil))
subscriber.send(.set(\.$phoneConfirmationCode, ""))
} catch {
subscriber.send(.didFail(error.localizedDescription))
}
subscriber.send(.set(\.$isConfirmingPhone, false))
subscriber.send(completion: .finished)
return AnyCancellable {}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
guard let phone = state.contact?.phone else { return .none }
state.isUnregisteringPhone = true
return Effect.run { [state] subscriber in
do {
let ud: UserDiscovery = try env.messenger.ud.tryGet()
let fact = Fact(type: .phone, value: phone)
try ud.removeFact(fact)
let contactId = try env.messenger.e2e.tryGet().getContact().getId()
if var dbContact = try env.db().fetchContacts(.init(id: [contactId])).first {
dbContact.phone = nil
try env.db().saveContact(dbContact)
}
} catch {
subscriber.send(.didFail(error.localizedDescription))
}
subscriber.send(.set(\.$isUnregisteringPhone, false))
subscriber.send(completion: .finished)
return AnyCancellable {}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
return Effect.run { subscriber in
do {
let contactId = try env.messenger.e2e.tryGet().getContact().getId()
if var dbContact = try env.db().fetchContacts(.init(id: [contactId])).first {
let facts = try env.messenger.ud.tryGet().getFacts()
dbContact.username = facts.get(.username)?.value
dbContact.email = facts.get(.email)?.value
dbContact.phone = facts.get(.phone)?.value
try env.db().saveContact(dbContact)
}
} catch {
subscriber.send(.didFail(error.localizedDescription))
}
subscriber.send(.set(\.$isLoadingFacts, false))
subscriber.send(completion: .finished)
return AnyCancellable {}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
case .didFail(let failure):
state.alert = .error(failure)
return .none
case .alertDismissed:
state.alert = nil
return .none