# iOS Card Field Spec
### Initialization
In order to create a contract around our card field UI, they would first create a client object, and pass that client object to a UI components type.
```swift=
/// Contains the shared data the SDK would need for each payment method
/// in order to function properly
public struct CoreConfig {
let clientId: String
let currency: Currency ( enum )
let locale: ?
others?
}
```
Using a shared configuration object, a new instance of a `CardClient` can be created
```swift=
public class CardClient {
public init(config: CoreConfig) {
...
}
public func capture(order: OrderRequest,
completion: (Result<CaptureResponse, CaptureError>) -> Void) {
// Capture with order object
}
public func capture(orderID: String,
completion: (Result<CaptureResponse, CaptureError>) -> Void) {
// Capture with order ID
}
}
```
### UI Types
We want to provide some discrete types that a merchant could use to check out, but want to be flexible enough that a merchant could pass any object conforming to some interface
```swift=
public protocol: CardField {
// used to ensure we are validating on the right fields
var component: .cardNumber / .cvv / .expiry { get }
// literal text of the field
var text: String? { get }
// called when the API request validating the text field resolves
func validationStatusChanged( .passed / .failed )
}
```
Our internal implementations would conform to the same protocol
```swift=
@IBDesignable
public class CardNumberField: UITextField, CardField {
public var component = .cardNumber
public init(font: UIFont = <some default font>,
textColor: UIColor = <some default text color>) {
...
}
public func validationStatusChanged( .passed / .failed ) {
/// Update UI if failed validation?
}
}
public class CardCVVField: UITextField, CardField { ... }
public class CardExpiryField: UITextField, CardField { ... }
```
# Mobile Card Field UI Spec
Per the [multi-child component conversation](https://github.com/paypal/paypal-sdk-spec/discussions/11), this is a possible implementation of the second solution:
```swift=
public class CardFieldComponent {
public internal(set) fields: [CardField]
public init(cardClient: CardClient,
createOrder: { },
onError: { },
onApprove: { }) {
...
}
public func add(fields: CardField...) { ... }
public func submit() { ... }
}
```
Using this approach, the initial validation (before a validation API request is made) would ensure that the component object has all of the field types that are required before performing the capture request.
### Merchant Integration Steps
The following is a possible merchant integration, where all of the fields and values are implemented in a merchant's view controller
```swift=
import PayPalCard
class SomeMerchantViewController: UIViewController {
let cardNumberField = CardNumberField()
let cvvField = CardCVVField()
let expiryField = CardExpiryField()
let coreConfig = CoreConfig(clientId:"11222333", currency: .usd, ?)
lazy var cardClient: CardClient = CardClient(config: coreConfig)
lazy var cardFieldComponent: CardFieldComponent = {
return CardFieldComponent(
cardClient: cardClient,
createOrder: { actions in
actions.create(request: OrderRequest())
//or
actions.create(orderId: "123")
},
onApprove: { approvalData in
...
},
onError: { error in
...
}
)
}()
override func viewDidLoad() {
super.viewDidLoad()
setupCardUI()
}
func setupCardUI() {
view.addSubview(cardNumberField)
view.addSubview(cvvField)
view.addSubview(expiryField)
NSLayoutConstraint.activate([
<assign UI constraints for each of their card fields>
])
cardFieldComponent.add(cardNumberField, cvvField, expiryField)
}
func submitButtonTapped() {
cardFieldComponent.submit()
}
}
```
### Open Questions:
1. Closures vs Delegates:
- The above is implemented using approve / error / create closures. 1:1 communication between objects on iOS is often faciliatated using the delegation pattern. Do we want to continue using closures for the sake of continuity with other platforms, or would we want to migrate to using delegates for the familiarity on iOS?
2. Who controls the communication defined by the closure / delegates:
- The above implementation assumes the CardFieldComponent would consume the approve / create / error callbacks. Is that the right object to handle that, or should the callbacks / delegate be moved to the CardClient instead?
3. Is the above implementation sufficiently easy to use / intuitive for a merchant?
----
# iOS Card Field Spec
This spec defines the way a merchant would use the card
A brief overview of this integration and who it is for along with any prereqs.
## Integration
What types of integrations are available (orders/vault/etc)? Include basic code snippets and steps.
## API Reqs
Outline the API calls that the SDK will need to make and why.
## Blockers and Questions
What blockers exist based on current API documentation?
## Comments
All other comments and items for tracking.