Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cardholder name #1

Merged
merged 6 commits into from
Nov 18, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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])) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The extra set of parentheses is not strictly required.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's their style on all of the other textFieldDelegate files.

// 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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be defined as a constant?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it should be a constant, but, again, this is strictly following their style (of not using constants). I think I'll do what Dan did, and after this branch gets merged, make another PR for Card.io that cleans up their code and implements constants.

}
return self;
}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does it check for max length?

}

@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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CardIOCardholderNameTextFieldDelegate is used in conjunction with UITextFieldTextDidChangeNotification?

[[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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This 175 was also defined in CardIOCardholderNameTextFieldDelegate.m. Is there a way to reuse?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They define the max length for Expiry as 7 in both of the same places. I figured following their style was better than being potentially confusing with more organized code.

// 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