Skip to content

Commit

Permalink
Merge pull request #1 from yodle/add-cardholder-name
Browse files Browse the repository at this point in the history
Add cardholder name
  • Loading branch information
martinrybak committed Nov 18, 2015
2 parents 9726410 + bd65809 commit 121f328
Show file tree
Hide file tree
Showing 40 changed files with 1,831 additions and 1,598 deletions.
14 changes: 14 additions & 0 deletions CardIOCardholderNameTextFieldDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// CardIOConfigurableTextFieldDelegate.h
// See the file "LICENSE.md" for the full license governing this code.
//

#import "CardIOConfigurableTextFieldDelegate.h"

@interface CardIOCardholderNameTextFieldDelegate : CardIOConfigurableTextFieldDelegate {

}

+(BOOL)isValidCardholderName:(NSString*)cardholderName;

@end
24 changes: 24 additions & 0 deletions CardIOCardholderNameTextFieldDelegate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// CardIOCardholderNameTextFieldDelegate.m
// See the file "LICENSE.md" for the full license governing this code.
//

#import "CardIOCardholderNameTextFieldDelegate.h"

@implementation CardIOCardholderNameTextFieldDelegate

-(id) init {
if ((self = [super init])) {
// Globalization: alphanumeric, space, hyphen are all definitely okay;
// there's no compelling reason for us to get fussy here.
self.numbersOnly = NO;
self.maxLength = 175; // PayPal REST APIs accept max of 175 chars for cardholder name
}
return self;
}

+(BOOL)isValidCardholderName:(NSString*)cardholderName {
return [cardholderName length] > 0;
}

@end
4 changes: 4 additions & 0 deletions CardIO_Public_API/CardIOCreditCardInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ typedef NS_ENUM(NSInteger, CardIOCreditCardType) {
/// @note May be nil, if postal code information was not requested.
@property(nonatomic, copy, readwrite) NSString *postalCode;

/// Cardholder Name.
/// @note May be nil, if cardholder name was not requested.
@property(nonatomic, copy, readwrite) NSString *cardholderName;

/// Was the card number scanned (as opposed to entered manually)?
@property(nonatomic, assign, readwrite) BOOL scanned;

Expand Down
3 changes: 3 additions & 0 deletions CardIO_Public_API/CardIOPaymentViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@
/// Set to YES if you need to collect the billing postal code. Defaults to NO.
@property(nonatomic, assign, readwrite) BOOL collectPostalCode;

/// Set to YES if you need to collect the cardholder name. Defaults to NO.
@property(nonatomic, assign, readwrite) BOOL collectCardholderName;

/// Set to NO if you don't want the camera to try to scan the card expiration.
/// Applies only if collectExpiry is also YES.
/// Defaults to YES.
Expand Down
3,229 changes: 1,651 additions & 1,578 deletions Classes/CardIOBundle.m

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Classes/CardIOContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
@property(nonatomic, assign, readwrite) BOOL collectCVV;
@property(nonatomic, assign, readwrite) BOOL collectExpiry;
@property(nonatomic, assign, readwrite) BOOL collectPostalCode;
@property(nonatomic, assign, readwrite) BOOL collectCardholderName;
@property(nonatomic, assign, readwrite) BOOL disableManualEntryButtons;
@property(nonatomic, assign, readwrite) BOOL keepStatusBarStyle;
@property(nonatomic, assign, readwrite) UIBarStyle navigationBarStyle;
Expand Down
6 changes: 4 additions & 2 deletions Classes/CardIOCreditCardInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,14 @@ - (NSString *)redactedCardNumber {
}

- (NSString *)description {
return [NSString stringWithFormat:@"{%@ %@; expiry: %lu/%lu%@%@}",
return [NSString stringWithFormat:@"{%@ %@; expiry: %lu/%lu%@%@%@}",
[[self class] displayStringForCardType:self.cardType usingLanguageOrLocale:@"en"],
[self redactedCardNumber],
(unsigned long)self.expiryMonth,
(unsigned long)self.expiryYear,
([self.cvv length] ? [NSString stringWithFormat:@"; cvv: %@", self.cvv] : @""),
([self.postalCode length] ? [NSString stringWithFormat:@"; postal code: %@", self.postalCode] : @"")];
([self.postalCode length] ? [NSString stringWithFormat:@"; postal code: %@", self.postalCode] : @""),
([self.cardholderName length] ? [NSString stringWithFormat:@"; cardholder name: %@", self.cardholderName] : @"")];
}

- (CardIOCreditCardType)cardType {
Expand All @@ -97,6 +98,7 @@ - (CardIOCreditCardInfo *)copyWithZone:(NSZone *)zone {
theCopy.expiryYear = self.expiryYear;
theCopy.cvv = self.cvv;
theCopy.postalCode = self.postalCode;
theCopy.cardholderName = self.cardholderName;
theCopy.scanned = self.scanned;
theCopy.cardImage = [self.cardImage copy];
return theCopy;
Expand Down
2 changes: 2 additions & 0 deletions Classes/CardIODataEntryViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
@property(nonatomic, assign, readwrite) BOOL collectExpiry;
@property(nonatomic, assign, readwrite) BOOL collectCVV;
@property(nonatomic, assign, readwrite) BOOL collectPostalCode;
@property(nonatomic, assign, readwrite) BOOL collectCardholderName;
@property(nonatomic, strong, readwrite) UITextField *expiryTextField;
@property(nonatomic, strong, readwrite) UITextField *numberTextField;
@property(nonatomic, strong, readwrite) UITextField *cvvTextField;
@property(nonatomic, strong, readwrite) UITextField *postalCodeTextField;
@property(nonatomic, strong, readwrite) UITextField *cardholderNameTextField;

+ (BOOL)cardExpiryIsValid:(CardIOCreditCardInfo *)info;

Expand Down
58 changes: 57 additions & 1 deletion Classes/CardIODataEntryViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#import "CardIONumbersTextFieldDelegate.h"
#import "CardIOCVVTextFieldDelegate.h"
#import "CardIOPostalCodeTextFieldDelegate.h"
#import "CardIOCardholderNameTextFieldDelegate.h"
#import "CardIOCreditCardNumber.h"
#import "CardIORowBasedTableViewSection.h"
#import "CardIOSectionBasedTableViewDelegate.h"
Expand Down Expand Up @@ -50,6 +51,7 @@ - (NSString *)cvvPlaceholder;
@property(nonatomic, strong, readwrite) CardIOExpiryTextFieldDelegate* expiryTextFieldDelegate;
@property(nonatomic, strong, readwrite) CardIOCVVTextFieldDelegate *cvvRowTextFieldDelegate;
@property(nonatomic, strong, readwrite) CardIOPostalCodeTextFieldDelegate *postalCodeRowTextFieldDelegate;
@property(nonatomic, strong, readwrite) CardIOCardholderNameTextFieldDelegate *cardholderNameRowTextFieldDelegate;
@property(nonatomic, assign, readwrite) CGSize notificationSize;
@property(nonatomic, strong, readwrite) CardIOContext *context;
@property(nonatomic, assign, readwrite) CardIOCreditCardType cardTypeForLogo;
Expand Down Expand Up @@ -149,6 +151,7 @@ - (void)viewDidLoad {
self.collectExpiry = pvc.collectExpiry;
self.collectCVV = pvc.collectCVV;
self.collectPostalCode = pvc.collectPostalCode;
self.collectCardholderName = pvc.collectCardholderName;

self.scrollView = [[UIScrollView alloc] initWithFrame:self.relevantViewFrame];

Expand Down Expand Up @@ -318,6 +321,33 @@ - (void)viewDidLoad {
[rows addObject:postalCodeRow];
}

if(self.collectCardholderName) {
CardIOMultipleFieldTableViewCell *cardholderNameRow = [[CardIOMultipleFieldTableViewCell alloc] init];
cardholderNameRow.backgroundColor = kColorDefaultCell;
cardholderNameRow.numberOfFields = 1;
cardholderNameRow.hiddenLabels = YES;
cardholderNameRow.textAlignment = [CardIOLocalizer textAlignmentForLanguageOrLocale:self.context.languageOrLocale];

NSString *cardholderNameText = CardIOLocalizedString(@"entry_cardholder_name", self.context.languageOrLocale); // Cardholder Name
[cardholderNameRow.labels addObject:cardholderNameText];

self.cardholderNameTextField = [cardholderNameRow.textFields lastObject];
[self.visibleTextFields addObject:self.cardholderNameTextField];

self.cardholderNameRowTextFieldDelegate = [[CardIOCardholderNameTextFieldDelegate alloc] init];
self.cardholderNameTextField.placeholder = cardholderNameText;
self.cardholderNameTextField.delegate = self.cardholderNameRowTextFieldDelegate;
self.cardholderNameTextField.text = self.cardInfo.cardholderName;
self.cardholderNameTextField.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
self.cardholderNameTextField.clearButtonMode = UITextFieldViewModeNever;
self.cardholderNameTextField.text = @"";
self.cardholderNameTextField.textAlignment = [CardIOLocalizer textAlignmentForLanguageOrLocale:self.context.languageOrLocale];
self.cardholderNameTextField.autocorrectionType = UITextAutocorrectionTypeNo;
self.cardholderNameTextField.autocapitalizationType = UITextAutocapitalizationTypeWords;

[rows addObject:cardholderNameRow];
}

CardIORowBasedTableViewSection *infoSection = [[CardIORowBasedTableViewSection alloc] init];
infoSection.rows = rows;
[sections addObject:infoSection];
Expand Down Expand Up @@ -415,6 +445,12 @@ - (void)viewDidAppear:(BOOL)animated {
name:UITextFieldTextDidChangeNotification
object:self.postalCodeTextField];
}
if(self.collectCardholderName) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(cardholderNameDidChange:)
name:UITextFieldTextDidChangeNotification
object:self.cardholderNameTextField];
}

[self layoutForCurrentOrientation];

Expand Down Expand Up @@ -544,11 +580,13 @@ - (void)viewDidUnload {
self.expiryTextFieldDelegate = nil;
self.cvvRowTextFieldDelegate = nil;
self.postalCodeRowTextFieldDelegate = nil;
self.cardholderNameRowTextFieldDelegate = nil;

self.expiryTextField = nil;
self.numberTextField = nil;
self.cvvTextField = nil;
self.postalCodeTextField = nil;
self.cardholderNameTextField = nil;

self.visibleTextFields = nil;

Expand Down Expand Up @@ -771,6 +809,7 @@ - (void)done {

self.cardInfo.cvv = self.cvvTextField.text;
self.cardInfo.postalCode = [self.postalCodeTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
self.cardInfo.cardholderName = self.cardholderNameTextField.text;

CardIOPaymentViewController *pvc = (CardIOPaymentViewController *)self.navigationController;
[pvc.paymentDelegate userDidProvideCreditCardInfo:self.cardInfo inPaymentViewController:pvc];
Expand Down Expand Up @@ -929,12 +968,29 @@ - (void)postalCodeDidChange:(id)sender {
[self validate];
}

- (void)cardholderNameDidChange:(id)sender {
self.cardInfo.cardholderName = self.cardholderNameTextField.text;

if([CardIOCardholderNameTextFieldDelegate isValidCardholderName:self.cardInfo.cardholderName]) {
[self advanceToNextEmptyFieldFrom:self.cardholderNameTextField];
self.cardholderNameTextField.textColor = [CardIOTableViewCell defaultDetailTextLabelColorForCellStyle:[CardIOTableViewCell defaultCellStyle]];
} else if(self.cardholderNameTextField.text.length >= 175) {
// probably won't reach this case, since length == 175 is the only validation rule, but we'll leave it here for consitency and for future enhancements.
self.cardholderNameTextField.textColor = [UIColor redColor];
} else {
self.cardholderNameTextField.textColor = [CardIOTableViewCell defaultDetailTextLabelColorForCellStyle:[CardIOTableViewCell defaultCellStyle]];
}

[self validate];
}

- (BOOL)validate {
BOOL numberIsValid = !self.manualEntry || [CardIOCreditCardNumber isValidNumber:self.cardInfo.cardNumber];
BOOL expiryIsValid = !self.expiryTextField || [[self class] cardExpiryIsValid:self.cardInfo];
BOOL cvvIsValid = !self.cvvTextField || [CardIOCVVTextFieldDelegate isValidCVV:self.cardInfo.cvv forNumber:self.cardInfo.cardNumber];
BOOL postalCodeIsValid = !self.postalCodeTextField || [CardIOPostalCodeTextFieldDelegate isValidPostalCode:self.cardInfo.postalCode];
BOOL isValid = numberIsValid && expiryIsValid && cvvIsValid && postalCodeIsValid;
BOOL cardholderNameIsValid = !self.cardholderNameTextField || [CardIOCardholderNameTextFieldDelegate isValidCardholderName:self.cardInfo.cardholderName];
BOOL isValid = numberIsValid && expiryIsValid && cvvIsValid && postalCodeIsValid && cardholderNameIsValid;
self.navigationItem.rightBarButtonItem.enabled = isValid;

return isValid;
Expand Down
12 changes: 10 additions & 2 deletions Classes/CardIOPaymentViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ - (void)viewWillAppear:(BOOL)animated {
}

// Write console message for confused developers who have given us confusing directives
if (self.suppressScanConfirmation && (self.collectExpiry || self.collectCVV || self.collectPostalCode)) {
if (self.suppressScanConfirmation && (self.collectExpiry || self.collectCVV || self.collectPostalCode || self.collectCardholderName)) {
NSMutableString *collect = [NSMutableString string];
if (self.collectExpiry) {
[collect appendString:@"collectExpiry"];
Expand All @@ -148,6 +148,12 @@ - (void)viewWillAppear:(BOOL)animated {
}
[collect appendString:@"collectPostalCode"];
}
if (self.collectCardholderName) {
if ([collect length]) {
[collect appendString:@"/"];
}
[collect appendString:@"collectCardholderName"];
}
NSLog(@"Warning: suppressScanConfirmation blocks %@.", collect);
}
}
Expand Down Expand Up @@ -334,7 +340,7 @@ - (void)didReceiveForegroundingNotification:(NSNotification *)notification {
#define DESCRIBE_BOOL(property) (self.property ? "; " #property : "")

- (NSString *)description {
return [NSString stringWithFormat:@"{delegate: %@; %s%s%s%s%s%s%s%s%s%s%s%s%s%s}"
return [NSString stringWithFormat:@"{delegate: %@; %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}"
,self.paymentDelegate
,DESCRIBE_BOOL(keepStatusBarStyle)
,DESCRIBE_BOOL(disableBlurWhenBackgrounding)
Expand All @@ -344,6 +350,7 @@ - (NSString *)description {
,DESCRIBE_BOOL(collectExpiry)
,DESCRIBE_BOOL(collectCVV)
,DESCRIBE_BOOL(collectPostalCode)
,DESCRIBE_BOOL(collectCardholderName)
,DESCRIBE_BOOL(scanExpiry)
,DESCRIBE_BOOL(useCardIOLogo)
,DESCRIBE_BOOL(disableManualEntryButtons)
Expand Down Expand Up @@ -381,6 +388,7 @@ - (void)set##prop_uc:(t)prop_lc { \
CONTEXT_PASSTHROUGH_READWRITE(BOOL, disableBlurWhenBackgrounding, DisableBlurWhenBackgrounding)
CONTEXT_PASSTHROUGH_READWRITE(BOOL, collectCVV, CollectCVV)
CONTEXT_PASSTHROUGH_READWRITE(BOOL, collectPostalCode, CollectPostalCode)
CONTEXT_PASSTHROUGH_READWRITE(BOOL, collectCardholderName, CollectCardholderName)
CONTEXT_PASSTHROUGH_READWRITE(BOOL, collectExpiry, CollectExpiry)
CONTEXT_PASSTHROUGH_READWRITE(BOOL, scanExpiry, ScanExpiry)
CONTEXT_PASSTHROUGH_READWRITE(BOOL, useCardIOLogo, UseCardIOLogo)
Expand Down
6 changes: 6 additions & 0 deletions Classes/RootViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ @interface RootViewController ()
@property(nonatomic, strong, readwrite) IBOutlet UISwitch *expirySwitch;
@property(nonatomic, strong, readwrite) IBOutlet UISwitch *cvvSwitch;
@property(nonatomic, strong, readwrite) IBOutlet UISwitch *zipSwitch;
@property(nonatomic, strong, readwrite) IBOutlet UISwitch *nameSwitch;
@property(nonatomic, strong, readwrite) IBOutlet UILabel *outcomeLabel;
@property(nonatomic, strong, readwrite) IBOutlet UIImageView *cardImageView;
@property(nonatomic, strong, readwrite) IBOutlet UISwitch *processSwitch;
Expand Down Expand Up @@ -79,6 +80,7 @@ - (IBAction)scan {
paymentVC.collectExpiry = self.expirySwitch.on;
paymentVC.collectCVV = self.cvvSwitch.on;
paymentVC.collectPostalCode = self.zipSwitch.on;
paymentVC.collectCardholderName = self.nameSwitch.on;
paymentVC.disableManualEntryButtons = self.disableManualEntrySwitch.on;
paymentVC.useCardIOLogo = self.useCardIOLogoSwitch.on;
paymentVC.allowFreelyRotatingCardGuide = NO;
Expand Down Expand Up @@ -183,6 +185,7 @@ - (void)displayI18nCardIOPaymentViewController {
self.i18nCardIOPaymentViewController.collectExpiry = YES;
self.i18nCardIOPaymentViewController.collectCVV = YES;
self.i18nCardIOPaymentViewController.collectPostalCode = YES;
self.i18nCardIOPaymentViewController.collectCardholderName = YES;
self.i18nCardIOPaymentViewController.disableManualEntryButtons = NO;
self.i18nCardIOPaymentViewController.useCardIOLogo = NO;
self.i18nCardIOPaymentViewController.languageOrLocale = language;
Expand Down Expand Up @@ -420,6 +423,9 @@ - (void)userDidProvideCreditCardInfo:(CardIOCreditCardInfo *)info inPaymentViewC
if(self.zipSwitch.on) {
[resultStr appendFormat:@"Postal Code: %@\n", info.postalCode];
}
if(self.nameSwitch.on) {
[resultStr appendFormat:@"Cardholder Name: %@\n", info.cardholderName];
}

#if CARDIO_DEBUG
[self setOutcomeText:resultStr image:info.cardImage];
Expand Down
Loading

0 comments on commit 121f328

Please sign in to comment.