2
\$\begingroup\$

The User story is as follows:

Users are allowed to get "verified", so other users know they have passed a background check.

After tapping "get verified" button, or the "verification badge" displayed on another users profile, they will be redirected to a view that will either prompt the current user to get verified, indicate that current user has already been verified, or indicate the user they selected is already verified. In code, this logic is initiated by calling the method checkStatus.

The process to get verified requires the user to first upload their ID (2 attempts to successfully upload), and agree to a background check. These steps are carried with the use of a UIPageViewController.

This is my code to determine what stage the current user is in the verification process, what page to segue to, and what view to display. I think the way my logic is set up is pretty messy, and am looking for advice to make it more clean and concise. Any advice is appreciated. I left some comments that could help reading the code as well. Its nothing complex, but think the code could be improved, I wrote this pretty quickly.

- (void)checkStatus {
    if (![self isCurrentUserEqualToBriefUser]) {
        // Current user tapped on verification badge of another user.
        // Still check progress of current user to enable/disable button to get verified.
        // If current user is verified that display type will overried dispaly indicating other person is verified.
        [self setupViewWithAppearance:AppearanceTypeTheyreVerified];
    }
    if (![self isUserVerified]) {
        [self checkProgress];
    }
}

- (BOOL)isUserVerified {
    // When user completes verification, Core Data is updated with date of verification. If `isVerificationDateValid` is nil, or invalid, they are not verified.
    if ([CoreDataUser currentUser].isVerificationDateValid) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([self isCurrentUserEqualToBriefUser]) {
                [self setupViewWithAppearance:AppearanceTypeYoureVerified];
            }
            [self setPermissionToContinue:NO];
            [self removeLoadingAnimation];
        });
        return YES;
    }
    return NO;
}

- (void)checkProgress {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.view setUserInteractionEnabled:NO];
    });
    RequestTask *task = [[VerificationDataManager sharedInstance] getVerificationStatus:^(NSDictionary *results, NSError *error) {
        if (results) {
            // Check if user failed background check
            if ([results valueForKey:kVerificationIsBackgroundCheckSuccessful] != nil) {
                if ([results[kVerificationIsBackgroundCheckSuccessful] boolValue] == NO) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if ([self isCurrentUserEqualToBriefUser]) {
                            [self setupViewWithAppearance:AppearanceTypeGetVerified];
                        }
                        [self setPermissionToContinue:NO];
                        [self removeLoadingAnimation];
                    });
                    return;
                }
            }
            // get status of ID and backround check
            if (![self isIdUploadInProgress:results]) {
                [self isBackgroundCheckInProgress:results];
            }
        } else if (error) {
            if (error.code == 204) {
                // 204 error  means no object exist. so user isnt verified yet.
                dispatch_async(dispatch_get_main_queue(), ^{
                    if ([self isCurrentUserEqualToBriefUser]) {
                        [self setupViewWithAppearance:AppearanceTypeGetVerified];
                    }
                    [self setPermissionToContinue:YES];
                    [self removeLoadingAnimation];
                });
            } else {
                // Actual error.
                VerifyPageViewController *parent = (VerifyPageViewController *)[self parentViewController];
                [parent dismissViewControllerAnimated:YES completion:nil];
                [self setPermissionToContinue:NO];
                [self removeLoadingAnimation];
            }
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.view setUserInteractionEnabled:YES];
        });
    }];
    [RequestsDispatcher performSingleRequest:task];
}

- (BOOL)isIdUploadInProgress:(NSDictionary *)results {
    VerifyPageViewController *parent = (VerifyPageViewController *)[self parentViewController];
    if ([results valueForKey:kVerificationIsIdVerified] == nil) {
        // key does not exist so has not attempted to submit ID yet.
        [parent nextPageAtIndex:2];
        return YES;
    } else {
        // key does exist, but ID not verified so check how many attempts were performed.
        if ([results[kVerificationIsIdVerified] boolValue] == NO) {
            // 2 attempts max
            int idAttemptCount = [[results objectForKey:kIdUploadAttempts] intValue];
            if (idAttemptCount > 1) {
                // reached max ID upload attempts.
                // set isIDSubmitting to YES, so page 7 shows proper related error.
                // Maybe use state machine with enums in data manager instead.
                [VerificationDataManager sharedInstance].isIdSumitting = YES; 
                [parent nextPageAtIndex:7];
            } else {
                // segue to ID upload page.
                [parent nextPageAtIndex:2];
            }
            return YES;
        }
    }
    return NO;
}

- (BOOL)isBackgroundCheckInProgress:(NSDictionary *)results {
    if ([results valueForKey:kVerificationIsBackgroundCheckSuccessful] == nil) {
        // key doesnt exist, so havnt perfomred backgorund check yet.
        VerifyPageViewController *parent = (VerifyPageViewController *)[self parentViewController];
        [parent nextPageAtIndex:4];
        return YES;
    } else {
        // already check for backgroundcheck failure and
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([self isCurrentUserEqualToBriefUser]) {
                [self setupViewWithAppearance:AppearanceTypeGetVerified];
            }
            [self setPermissionToContinue:NO];
            [self removeLoadingAnimation];
        });
        return NO;
    }
}
\$\endgroup\$
0
\$\begingroup\$

It's good that you are getting that feeling that something isn't right. You are violating the single responsibility principle. Your view controller should only be responsible for it's view hierarchy, not the data that drives the view hierarchy.

You should create a data model/context to encapsulate the logic around the user verification status. You can observe changes in that model to update your UI.

  1. Create a data model and optionally a context around that data.
    @interface User

    @property (nonatomic, readonly) BOOL idUploading;
    @property (nonatomic, readonly) BOOL idUploaded;
    @property (nonatomic, readonly) BOOL verified;

    @end

The implementation of the data model/context updates the properties based on the verification status.

  1. Now you can observe the data model to update page view controller using Key Value Observing.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.