-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
ManagePledgePaymentMethodViewModel.swift
150 lines (123 loc) · 4.73 KB
/
ManagePledgePaymentMethodViewModel.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import Foundation
import KsApi
import Prelude
import ReactiveExtensions
import ReactiveSwift
public struct ManagePledgePaymentMethodViewData: Equatable {
public let backingState: Backing.Status
public let expirationDate: String?
public let lastFour: String?
public let creditCardType: CreditCardType?
public let paymentType: PaymentType?
}
public protocol ManagePledgePaymentMethodViewModelInputs {
/// Call to configure payment method section the values from a backing
func configureWith(data: ManagePledgePaymentMethodViewData)
/// Call when the "Fix" button is tapped
func fixButtonTapped()
}
public protocol ManagePledgePaymentMethodViewModelOutputs {
/// Emits the card's image.
var cardImageName: Signal<String, Never> { get }
/// Emits a formatted accessibility string containing the card type, number and last four digits
var cardNumberAccessibilityLabel: Signal<String, Never> { get }
/// Emits a formatted string containing the card's last four digits with the format: Ending in 8844.
var cardNumberTextShortStyle: Signal<String, Never> { get }
/// Emits the formatted card's expirationdate.
var expirationDateText: Signal<String, Never> { get }
/// Emits whether the Fix button is hidden
var fixButtonHidden: Signal<Bool, Never> { get }
/// Emits when the fix button was tapped
var notifyDelegateFixButtonTapped: Signal<Void, Never> { get }
}
public protocol ManagePledgePaymentMethodViewModelType {
var inputs: ManagePledgePaymentMethodViewModelInputs { get }
var outputs: ManagePledgePaymentMethodViewModelOutputs { get }
}
public final class ManagePledgePaymentMethodViewModel: ManagePledgePaymentMethodViewModelInputs,
ManagePledgePaymentMethodViewModelOutputs, ManagePledgePaymentMethodViewModelType {
public init() {
self.cardImageName = self.configureWithDataSignal
.map { ($0.paymentType, $0.creditCardType) }
.map(imageName(for:creditCardType:))
.skipNil()
let paymentType = self.configureWithDataSignal
.map(\.paymentType)
.skipNil()
let cardType = self.configureWithDataSignal
.map(\.creditCardType)
.skipNil()
let lastFour = self.configureWithDataSignal
.map(\.lastFour)
.skipNil()
self.cardNumberAccessibilityLabel = Signal.combineLatest(
paymentType,
cardType,
lastFour
)
.map {
[$0.0.accessibilityLabel, $0.1.description, Strings.Card_ending_in_last_four(last_four: $0.2)]
.compact()
.joined(separator: ", ")
}
self.cardNumberTextShortStyle = lastFour
.map { Strings.Ending_in_last_four(last_four: $0) }
self.expirationDateText = self.configureWithDataSignal
.map(\.expirationDate)
.skipNil()
.map { String($0.dropLast(3)) }
.map(formatted(dateString:))
.map { Strings.Credit_card_expiration(expiration_date: $0) }
self.fixButtonHidden = self.configureWithDataSignal
.map { $0.backingState != .errored }
self.notifyDelegateFixButtonTapped = self.fixButtonTappedSignal
}
fileprivate let (configureWithDataSignal, configureWithDataObserver)
= Signal<ManagePledgePaymentMethodViewData, Never>.pipe()
public func configureWith(data: ManagePledgePaymentMethodViewData) {
self.configureWithDataObserver.send(value: data)
}
fileprivate let (fixButtonTappedSignal, fixButtonTappedObserver) = Signal<Void, Never>.pipe()
public func fixButtonTapped() {
self.fixButtonTappedObserver.send(value: ())
}
public let cardImageName: Signal<String, Never>
public let cardNumberAccessibilityLabel: Signal<String, Never>
public let cardNumberTextShortStyle: Signal<String, Never>
public let expirationDateText: Signal<String, Never>
public let fixButtonHidden: Signal<Bool, Never>
public let notifyDelegateFixButtonTapped: Signal<Void, Never>
public var inputs: ManagePledgePaymentMethodViewModelInputs { return self }
public var outputs: ManagePledgePaymentMethodViewModelOutputs { return self }
}
private func imageName(for paymentType: PaymentType?, creditCardType: CreditCardType?) -> String? {
switch paymentType {
case .creditCard:
return creditCardType?.imageName
case .applePay:
return "icon--apple-pay"
case .googlePay:
return "icon--google-pay"
case nil:
return nil
}
}
private func formatted(dateString: String) -> String {
let date = toDate(dateString: dateString)
return Format.date(
secondsInUTC: date.timeIntervalSince1970,
template: "MM-yyyy",
timeZone: UTCTimeZone
)
}
private func toDate(dateString: String) -> Date {
// Always use UTC timezone here this date should be timezone agnostic
guard let date = Format.date(
from: dateString,
dateFormat: "yyyy-MM",
timeZone: UTCTimeZone
) else {
fatalError("Unable to parse date format")
}
return date
}