Commit ed8451d8 by Dima Bart

Merge pull request #165 from Shopify/feature/refactor-routing

Refactor BUYClient to remove creation and management of routes
parents d956de37 f8ef0de0
//
// BUYClient+RoutingTests.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import <XCTest/XCTest.h>
#import "BUYClient+Routing.h"
@interface BUYClient_RoutingTests : XCTestCase
@property (strong, nonatomic) BUYClient *client;
@end
@implementation BUYClient_RoutingTests
#pragma mark - Setup -
- (void)setUp
{
[super setUp];
self.client = [[BUYClient alloc] initWithShopDomain:@"_DOMAIN_" apiKey:@"_API_KEY_" appId:@"_APP_ID_"];
}
#pragma mark - Test Routes -
- (void)testRoutes
{
NSString *identifier = @"_ID_";
NSString *token = @"_TOKEN_";
NSDictionary *parameters = @{ @"param" : @"value" };
XCTAssertEqualObjects(
[self.client urlForAPI].absoluteString,
@"https://_DOMAIN_/api"
);
XCTAssertEqualObjects(
[self.client urlForApps].absoluteString,
@"https://_DOMAIN_/api/apps/_APP_ID_"
);
XCTAssertEqualObjects(
[self.client urlForShop].absoluteString,
@"https://_DOMAIN_/meta.json"
);
XCTAssertEqualObjects(
[self.client urlForProductListingsWithParameters:parameters].absoluteString,
@"https://_DOMAIN_/api/apps/_APP_ID_/product_listings.json?param=value"
);
XCTAssertEqualObjects(
[self.client urlForCollectionListingsWithParameters:parameters].absoluteString,
@"https://_DOMAIN_/api/apps/_APP_ID_/collection_listings.json?param=value"
);
XCTAssertEqualObjects(
[self.client urlForCheckouts].absoluteString,
@"https://_DOMAIN_/api/checkouts.json"
);
XCTAssertEqualObjects(
[self.client urlForCheckoutsWithToken:token].absoluteString,
@"https://_DOMAIN_/api/checkouts/_TOKEN_.json"
);
XCTAssertEqualObjects(
[self.client urlForCheckoutsProcessingWithToken:token].absoluteString,
@"https://_DOMAIN_/api/checkouts/_TOKEN_/processing.json"
);
XCTAssertEqualObjects(
[self.client urlForCheckoutsCompletionWithToken:token].absoluteString,
@"https://_DOMAIN_/api/checkouts/_TOKEN_/complete.json"
);
XCTAssertEqualObjects(
[self.client urlForCheckoutsShippingRatesWithToken:token parameters:parameters].absoluteString,
@"https://_DOMAIN_/api/checkouts/_TOKEN_/shipping_rates.json?param=value"
);
XCTAssertEqualObjects(
[self.client urlForCheckoutsUsingGiftCard].absoluteString,
@"https://_DOMAIN_/api/checkouts/gift_cards.json"
);
XCTAssertEqualObjects(
[self.client urlForCheckoutsUsingGiftCardWithToken:token].absoluteString,
@"https://_DOMAIN_/api/checkouts/_TOKEN_/gift_cards.json"
);
XCTAssertEqualObjects(
[self.client urlForCheckoutsUsingGiftCard:@999 token:token].absoluteString,
@"https://_DOMAIN_/api/checkouts/_TOKEN_/gift_cards/999.json"
);
XCTAssertEqualObjects(
[self.client urlForCustomers].absoluteString,
@"https://_DOMAIN_/api/customers.json"
);
XCTAssertEqualObjects(
[self.client urlForCustomersOrders].absoluteString,
@"https://_DOMAIN_/api/customers/orders.json"
);
XCTAssertEqualObjects(
[self.client urlForCustomersWithID:identifier].absoluteString,
@"https://_DOMAIN_/api/customers/_ID_.json"
);
XCTAssertEqualObjects(
[self.client urlForCustomersActivationWithID:identifier parameters:parameters].absoluteString,
@"https://_DOMAIN_/api/customers/_ID_/activate.json?param=value"
);
XCTAssertEqualObjects(
[self.client urlForCustomersToken].absoluteString,
@"https://_DOMAIN_/api/customers/customer_token.json"
);
XCTAssertEqualObjects(
[self.client urlForCustomersTokenRenewalWithID:identifier].absoluteString,
@"https://_DOMAIN_/api/customers/_ID_/customer_token/renew.json"
);
XCTAssertEqualObjects(
[self.client urlForCustomersPasswordRecovery].absoluteString,
@"https://_DOMAIN_/api/customers/recover.json"
);
XCTAssertEqualObjects(
[self.client urlForCustomersPasswordResetWithID:identifier parameters:parameters].absoluteString,
@"https://_DOMAIN_/api/customers/_ID_/reset.json?param=value"
);
}
@end
......@@ -34,17 +34,12 @@
#import "BUYShopifyErrorCodes.h"
#import "BUYAccountCredentials.h"
#import "BUYClient+Customers.h"
#import "BUYClient+Internal.h"
#import "BUYApplePayToken.h"
#import "BUYApplePayTestToken.h"
NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
@interface BUYClient ()
+ (BUYStatus)statusForStatusCode:(NSUInteger)statusCode error:(NSError *)error;
@end
@interface BUYClient_Test : BUYClient
@end
......@@ -169,22 +164,22 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
- (void)testStatusCodeConversions
{
BUYStatus status = [BUYClient statusForStatusCode:412 error:nil];
BUYStatus status = [self.client statusForStatusCode:412 error:nil];
XCTAssertEqual(BUYStatusPreconditionFailed, status);
status = [BUYClient statusForStatusCode:404 error:nil];
status = [self.client statusForStatusCode:404 error:nil];
XCTAssertEqual(BUYStatusNotFound, status);
status = [BUYClient statusForStatusCode:0 error:[NSError errorWithDomain:@"" code:-1 userInfo:nil]];
status = [self.client statusForStatusCode:0 error:[NSError errorWithDomain:@"" code:-1 userInfo:nil]];
XCTAssertEqual(BUYStatusFailed, status);
status = [BUYClient statusForStatusCode:424 error:nil];
status = [self.client statusForStatusCode:424 error:nil];
XCTAssertEqual(BUYStatusFailed, status);
status = [BUYClient statusForStatusCode:202 error:nil];
status = [self.client statusForStatusCode:202 error:nil];
XCTAssertEqual(BUYStatusProcessing, status);
status = [BUYClient statusForStatusCode:200 error:nil];
status = [self.client statusForStatusCode:200 error:nil];
XCTAssertEqual(BUYStatusComplete, status);
}
......
......@@ -44,7 +44,7 @@ extern NSString * const BUYFakeCustomerToken;
@property (nonatomic, strong) NSString *giftCardCode2;
@property (nonatomic, strong) NSString *giftCardCode3;
@property (nonatomic, strong) NSString *giftCardCodeExpired;
@property (nonatomic, strong) NSString *giftCardIdExpired;
@property (nonatomic, strong) NSNumber *giftCardIdExpired;
@property (nonatomic, strong) NSString *giftCardCodeInvalid;
@property (nonatomic, strong) NSString *discountCodeValid;
@property (nonatomic, strong) NSString *discountCodeExpired;
......
......@@ -517,7 +517,7 @@
return [OHHTTPStubsResponse responseWithKey:@"testRemovingInvalidGiftCardFromCheckout_2"];
}];
BUYGiftCard *giftCard = [[BUYGiftCard alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @"000" }];
BUYGiftCard *giftCard = [[BUYGiftCard alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @(000) }];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
[self.client removeGiftCard:giftCard fromCheckout:_checkout completion:^(BUYCheckout *checkout, NSError *error) {
XCTAssertNotNil(error);
......
......@@ -65,6 +65,8 @@ FOUNDATION_EXPORT const unsigned char BuyVersionString[];
#import <Buy/BUYClient.h>
#import <Buy/BUYClient+Customers.h>
#import <Buy/BUYClient+Checkout.h>
#import <Buy/BUYClient+Storefront.h>
#import <Buy/BUYClient+Checkout.h>
#import <Buy/BUYError.h>
#import <Buy/BUYError+BUYAdditions.h>
#import <Buy/BUYManagedObject.h>
......
......@@ -113,7 +113,7 @@ typedef void (^BUYDataOrdersBlock)(NSArray <BUYOrder*> * _Nullable orders, NSErr
*
* @return the associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)recoverPasswordForCustomer:(NSString *)email callback:(BUYDataCheckoutStatusBlock)block;
- (NSURLSessionDataTask *)recoverPasswordForCustomer:(NSString *)email callback:(BUYDataStatusBlock)block;
/**
* PUT /api/customers/:customer_id/customer_token/renew
......
//
// BUYClient_Internal.h
// BUYClient+Internal.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -27,16 +27,20 @@
#import "BUYClient.h"
#import "BUYSerializable.h"
extern NSString *const kShopifyError;
static NSString * const BUYShopifyErrorDomain = @"shopify";
static NSString * const BUYClientVersionString = @"1.3";
static NSString * const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token";
@interface BUYClient (Internal)
- (NSURLSessionDataTask *)postRequestForURL:(NSURL *)url object:(id <BUYSerializable>)object completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDataTask *)putRequestForURL:(NSURL *)url object:(id<BUYSerializable>)object completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDataTask *)getRequestForURL:(NSURL *)url completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDataTask *)deleteRequestForURL:(NSURL *)url completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLComponents *)URLComponentsForAPIPath:(NSString *)apiPath appendingPath:(NSString *)appendingPath queryItems:(NSDictionary*)queryItems;
- (NSURLSessionDataTask *)postRequestForURL:(NSURL *)url object:(id <BUYSerializable>)object completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDataTask *)putRequestForURL:(NSURL *)url object:(id<BUYSerializable>)object completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDataTask *)patchRequestForURL:(NSURL *)url object:(id <BUYSerializable>)object completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler;
- (BUYStatus)statusForStatusCode:(NSUInteger)statusCode error:(NSError *)error;
- (NSError *)errorFromJSON:(NSDictionary *)json response:(NSURLResponse *)response;
@end
//
// BUYClient+Routing.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "BUYClient.h"
@interface BUYClient (Routing)
- (NSURL *)urlForAPI;
- (NSURL *)urlForApps;
- (NSURL *)urlForShop;
- (NSURL *)urlForProductListingsWithParameters:(NSDictionary *)parameters;
- (NSURL *)urlForCollectionListingsWithParameters:(NSDictionary *)parameters;
- (NSURL *)urlForCheckouts;
- (NSURL *)urlForCheckoutsWithToken:(NSString *)token;
- (NSURL *)urlForCheckoutsProcessingWithToken:(NSString *)token;
- (NSURL *)urlForCheckoutsCompletionWithToken:(NSString *)token;
- (NSURL *)urlForCheckoutsShippingRatesWithToken:(NSString *)token parameters:(NSDictionary *)parameters;
- (NSURL *)urlForCheckoutsUsingGiftCard;
- (NSURL *)urlForCheckoutsUsingGiftCardWithToken:(NSString *)token;
- (NSURL *)urlForCheckoutsUsingGiftCard:(NSNumber *)giftCardID token:(NSString *)token;
- (NSURL *)urlForCustomers;
- (NSURL *)urlForCustomersOrders;
- (NSURL *)urlForCustomersWithID:(NSString *)identifier;
- (NSURL *)urlForCustomersActivationWithID:(NSString *)identifier parameters:(NSDictionary *)parameters;
- (NSURL *)urlForCustomersToken;
- (NSURL *)urlForCustomersTokenRenewalWithID:(NSString *)customerID;
- (NSURL *)urlForCustomersPasswordRecovery;
- (NSURL *)urlForCustomersPasswordResetWithID:(NSString *)identifier parameters:(NSDictionary *)parameters;
@end
//
// BUYClient+Routing.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "BUYClient+Routing.h"
#pragma mark - NSURL (Private Routing) -
@implementation NSURL (PrivateRouting)
+ (instancetype)URLWithFormat:(NSString *)format, ...
{
va_list list;
va_start(list, format);
NSString *URLString = [[NSString alloc] initWithFormat:format arguments:list];
va_end(list);
return [[NSURL alloc] initWithString:URLString];
}
- (NSURL *)appendFormat:(NSString *)format, ...
{
va_list list;
va_start(list, format);
NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:list];
va_end(list);
NSURL *trimmedURL = [self removeExtension];
if (formattedString.length > 0) {
return [trimmedURL URLByAppendingPathComponent:formattedString];
}
return trimmedURL;
}
- (NSURL *)appendPath:(NSString *)path
{
return [self appendFormat:path];
}
- (NSURL *)appendIdentifier:(NSNumber *)identifier
{
return [self appendFormat:@"%@", identifier];
}
- (NSURL *)appendParameters:(NSDictionary *)parameters
{
NSURLComponents *components = [NSURLComponents componentsWithURL:self resolvingAgainstBaseURL:NO];
NSMutableArray *queryItems = [NSMutableArray new];
[parameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
[queryItems addObject:[NSURLQueryItem queryItemWithName:key value:[NSString stringWithFormat:@"%@", value]]];
}];
[components setQueryItems:queryItems];
return components.URL;
}
- (NSURL *)appendExtension {
return [self URLByAppendingPathExtension:@"json"];
}
- (NSURL *)removeExtension {
return [self URLByDeletingPathExtension];
}
@end
#pragma mark - BUYClient (Routing) -
@implementation BUYClient (Routing)
#pragma mark - API -
- (NSURL *)urlForShopDomain
{
return [NSURL URLWithFormat:@"https://%@", self.shopDomain];
}
- (NSURL *)urlForAPI
{
return [[self urlForShopDomain] appendPath:@"/api"];
}
- (NSURL *)urlForApps
{
return [[self urlForAPI] appendFormat:@"/apps/%@", self.appId];
}
#pragma mark - Storefront -
- (NSURL *)urlForShop
{
return [[[self urlForShopDomain] appendPath:@"/meta"] appendExtension];
}
- (NSURL *)urlForProductListingsWithParameters:(NSDictionary *)parameters
{
return [[[[self urlForApps] appendPath:@"/product_listings"] appendExtension] appendParameters:parameters];
}
- (NSURL *)urlForCollectionListingsWithParameters:(NSDictionary *)parameters
{
return [[[[self urlForApps] appendPath:@"/collection_listings"] appendExtension] appendParameters:parameters];
}
#pragma mark - Checkout -
- (NSURL *)urlForCheckouts
{
return [[[self urlForAPI] appendPath:@"/checkouts"] appendExtension];
}
- (NSURL *)urlForCheckoutsWithToken:(NSString *)token
{
return [self _urlForCheckoutsAction:@"" withToken:token];
}
- (NSURL *)urlForCheckoutsProcessingWithToken:(NSString *)token
{
return [self _urlForCheckoutsAction:@"/processing" withToken:token];
}
- (NSURL *)urlForCheckoutsCompletionWithToken:(NSString *)token
{
return [self _urlForCheckoutsAction:@"/complete" withToken:token];
}
- (NSURL *)urlForCheckoutsShippingRatesWithToken:(NSString *)token parameters:(NSDictionary *)parameters
{
return [[self _urlForCheckoutsAction:@"/shipping_rates" withToken:token] appendParameters:parameters];
}
- (NSURL *)urlForCheckoutsUsingGiftCard
{
return [[[self urlForCheckouts] appendPath:@"/gift_cards"] appendExtension];
}
- (NSURL *)urlForCheckoutsUsingGiftCardWithToken:(NSString *)token
{
return [[[[self urlForCheckouts] appendPath:token] appendPath:@"/gift_cards"] appendExtension];
}
- (NSURL *)urlForCheckoutsUsingGiftCard:(NSNumber *)giftCardID token:(NSString *)token
{
return [[[self urlForCheckoutsUsingGiftCardWithToken:token] appendIdentifier:giftCardID] appendExtension];
}
#pragma mark - Customers -
- (NSURL *)urlForCustomers
{
return [[[self urlForAPI] appendPath:@"/customers"] appendExtension];
}
- (NSURL *)urlForCustomersOrders
{
return [[[self urlForCustomers] appendPath:@"/orders"] appendExtension];
}
- (NSURL *)urlForCustomersWithID:(NSString *)identifier
{
return [[[self urlForCustomers] appendPath:identifier] appendExtension];
}
- (NSURL *)urlForCustomersActivationWithID:(NSString *)identifier parameters:(NSDictionary *)parameters
{
return [[[[self urlForCustomersWithID:identifier] appendPath:@"/activate"] appendParameters:parameters] appendExtension];
}
- (NSURL *)urlForCustomersToken
{
return [[[self urlForCustomers] appendPath:@"/customer_token"] appendExtension];
}
- (NSURL *)urlForCustomersTokenRenewalWithID:(NSString *)customerID
{
return [[[self urlForCustomersWithID:customerID] appendPath:@"/customer_token/renew"] appendExtension];
}
- (NSURL *)urlForCustomersPasswordRecovery
{
return [[[self urlForCustomers] appendPath:@"/recover"] appendExtension];
}
- (NSURL *)urlForCustomersPasswordResetWithID:(NSString *)identifier parameters:(NSDictionary *)parameters
{
return [[[[self urlForCustomersWithID:identifier] appendPath:@"/reset"] appendExtension] appendParameters:parameters];
}
#pragma mark - Utilities -
- (NSURL *)_urlForCheckoutsAction:(NSString *)action withToken:(NSString *)token
{
return [[[[self urlForCheckouts] appendPath:token] appendPath:action] appendExtension];
}
@end
//
// BUYClient+Storefront.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "BUYClient.h"
NS_ASSUME_NONNULL_BEGIN
@class BUYShop;
@class BUYCollection;
@class BUYProduct;
/**
* The sort order for products in a collection
*/
typedef NS_ENUM(NSUInteger, BUYCollectionSort) {
/**
* Sort products by best selling using the order set in the shop's admin
*/
BUYCollectionSortCollectionDefault,
/**
* Sort products by best selling
*/
BUYCollectionSortBestSelling,
/**
* Sort products by title, ascending
*/
BUYCollectionSortTitleAscending,
/**
* Sort products by title, descending
*/
BUYCollectionSortTitleDescending,
/**
* Sort products by price (first variant), ascending
*/
BUYCollectionSortPriceAscending,
/**
* Sort products by price (first variant), descending
*/
BUYCollectionSortPriceDescending,
/**
* Sort products by creation date, ascending
*/
BUYCollectionSortCreatedAscending,
/**
* Sort products by creation date, descending
*/
BUYCollectionSortCreatedDescending
};
/**
* Return block containing a BUYShop and/or an NSError
*
* @param shop A BUYShop object
* @param error Optional NSError
*/
typedef void (^BUYDataShopBlock)(BUYShop * _Nullable shop, NSError * _Nullable error);
/**
* Return block containing a list of BUYCollection objects and/or an NSError
*
* @param collections An array of BUYCollection objects
* @param error Optional NSError
*/
typedef void (^BUYDataCollectionsBlock)(NSArray<BUYCollection *> * _Nullable collections, NSError * _Nullable error);
/**
* Return block containing a BUYProduct and/or an NSError
*
* @param product A BUYProduct
* @param error Optional NSError
*/
typedef void (^BUYDataProductBlock)(BUYProduct * _Nullable product, NSError * _Nullable error);
/**
* Return block containing a list of BUYProduct objects and/or an NSError
*
* @param products An array of BUYProduct objects
* @param error Optional NSError
*/
typedef void (^BUYDataProductsBlock)(NSArray<BUYProduct *> * _Nullable products, NSError * _Nullable error);
/**
* Return block containing list of collections
*
* @param collections An array of BUYCollection objects
* @param error Optional NSError
*/
typedef void (^BUYDataCollectionsListBlock)(NSArray<BUYCollection *> * _Nullable collections, NSUInteger page, BOOL reachedEnd, NSError * _Nullable error);
/**
* Return block containing a list of BUYProduct objects, the page requested, a boolean to determine whether the end of the list has been reach and/or an optional NSError
*
* @param products An array of BUYProduct objects
* @param page Index of the page requested
* @param reachedEnd Boolean indicating whether additional pages exist
* @param error An optional NSError
*/
typedef void (^BUYDataProductListBlock)(NSArray<BUYProduct *> * _Nullable products, NSUInteger page, BOOL reachedEnd, NSError * _Nullable error);
@interface BUYClient (Storefront)
/**
* Fetches the shop's metadata (from /meta.json).
*
* @param block (^BUYDataShopBlock)(BUYShop *shop, NSError *error);
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)getShop:(BUYDataShopBlock)block;
/**
* Fetches a single page of products for the shop.
*
* @param page Page to request. Pages start at 1.
* @param block (^BUYDataProductListBlock)(NSArray *products, NSUInteger page, BOOL reachedEnd, NSError *error);
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)getProductsPage:(NSUInteger)page completion:(BUYDataProductListBlock)block;
/**
* Fetches a single product by the ID of the product.
*
* @param productId Product ID
* @param block (^BUYDataProductBlock)(BUYProduct *product, NSError *error);
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)getProductById:(NSString *)productId completion:(BUYDataProductBlock)block;
/**
* Fetches a list of product by the ID of each product.
*
* @param productIds An array of `NSString` objects with Product IDs to fetch
* @param block (^BUYDataProductsBlock)(NSArray *products, NSError *error);
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)getProductsByIds:(NSArray *)productIds completion:(BUYDataProductsBlock)block;
/**
* Fetches the collections on the shop
*
* @param block (^BUYDataCollectionsBlock)(NSArray *collections, NSError *error)
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)getCollections:(BUYDataCollectionsBlock)block;
/**
* Fetches collections based off page
*
* @param page Index of the page requested
* @param block (^BUYDataCollectionsBlock)(NSArray *collections, NSError *error)
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)getCollectionsPage:(NSUInteger)page completion:(BUYDataCollectionsListBlock)block;
/**
* Fetches the products in the given collection with the collection's
* default sort order set in the shop's admin
*
* @param page Index of the page requested
* @param collectionId The `collectionId` found in the BUYCollection object to fetch the products from
* @param block (NSArray *products, NSUInteger page, BOOL reachedEnd, NSError *error)
*
* @return the associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)getProductsPage:(NSUInteger)page inCollection:(NSNumber *)collectionId completion:(BUYDataProductListBlock)block;
/**
* Fetches the products in the given collection with a given sort order
*
* @param page Index of the page requested
* @param collectionId The `collectionId` found in the BUYCollection object to fetch the products from
* @param sortOrder The sort order that overrides the default collection sort order
* @param block (NSArray *products, NSUInteger page, BOOL reachedEnd, NSError *error)
*
* @return the associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)getProductsPage:(NSUInteger)page inCollection:(NSNumber *)collectionId sortOrder:(BUYCollectionSort)sortOrder completion:(BUYDataProductListBlock)block;
@end
NS_ASSUME_NONNULL_END
//
// BUYClient+Storefront.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "BUYClient+Storefront.h"
#import "BUYClient+Internal.h"
#import "BUYClient+Routing.h"
#import "BUYShop.h"
#import "BUYCollection.h"
#import "BUYProduct.h"
#import "BUYAssert.h"
#import "BUYShopifyErrorCodes.h"
static NSString * const BUYProductsKey = @"product_listings";
static NSString * const BUYCollectionsKey = @"collection_listings";
@implementation BUYClient (Storefront)
#pragma mark - Utilities -
- (BOOL)hasReachedEndOfPage:(NSArray *)lastFetchedObjects
{
return [lastFetchedObjects count] < self.pageSize;
}
#pragma mark - API -
- (NSURLSessionDataTask *)getShop:(BUYDataShopBlock)block
{
return [self getRequestForURL:[self urlForShop] completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
BUYShop *shop = nil;
if (json && !error) {
shop = [self.modelManager insertShopWithJSONDictionary:json];
}
block(shop, error);
}];
}
- (NSURLSessionDataTask *)getProductsPage:(NSUInteger)page completion:(BUYDataProductListBlock)block
{
NSURL *route = [self urlForProductListingsWithParameters:@{
@"limit" : @(self.pageSize),
@"page" : @(page),
}];
return [self getRequestForURL:route completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSArray *products = nil;
if (json && !error) {
products = [self.modelManager insertProductsWithJSONArray:json[BUYProductsKey]];
}
block(products, page, [self hasReachedEndOfPage:products] || error, error);
}];
}
- (NSURLSessionDataTask *)getProductById:(NSString *)productId completion:(BUYDataProductBlock)block;
{
BUYAssert(productId, @"Failed to get product by ID. Product ID must not be nil.");
return [self getProductsByIds:@[productId] completion:^(NSArray *products, NSError *error) {
if (products.count > 0) {
block(products[0], error);
} else {
if (!error) {
error = [NSError errorWithDomain:BUYShopifyErrorDomain code:BUYShopifyError_InvalidProductID userInfo:@{ NSLocalizedDescriptionKey : @"Product ID is not valid. Confirm the product ID on your shop's admin and also ensure that the visibility is on for the Mobile App channel." }];
}
block(nil, error);
}
}];
}
- (NSURLSessionDataTask *)getProductsByIds:(NSArray *)productIds completion:(BUYDataProductsBlock)block
{
BUYAssert(productIds, @"Failed to get product by IDs. Product IDs array must not be nil.");
NSURL *route = [self urlForProductListingsWithParameters:@{
@"product_ids" : [productIds componentsJoinedByString:@","],
}];
return [self getRequestForURL:route completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSArray *products = nil;
if (json && !error) {
products = [self.modelManager insertProductsWithJSONArray:json[BUYProductsKey]];
}
if (!error && products.count == 0) {
error = [NSError errorWithDomain:BUYShopifyErrorDomain code:BUYShopifyError_InvalidProductID userInfo:@{ NSLocalizedDescriptionKey : @"Product IDs are not valid. Confirm the product IDs on your shop's admin and also ensure that the visibility is on for the Mobile App channel." }];
}
block(products, error);
}];
}
- (NSURLSessionDataTask *)getCollections:(BUYDataCollectionsBlock)block
{
return [self getCollectionsPage:1 completion:^(NSArray<BUYCollection *> *collections, NSUInteger page, BOOL reachedEnd, NSError *error) {
block(collections, error);
}];
}
- (NSURLSessionDataTask *)getCollectionsPage:(NSUInteger)page completion:(BUYDataCollectionsListBlock)block
{
NSURL *route = [self urlForCollectionListingsWithParameters:@{
@"limit" : @(self.pageSize),
@"page" : @(page),
}];
return [self getRequestForURL:route completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSArray *collections = nil;
if (json && !error) {
collections = [self.modelManager buy_objectsWithEntityName:[BUYCollection entityName] JSONArray:json[BUYCollectionsKey]];
}
block(collections, page, [self hasReachedEndOfPage:collections], error);
}];
}
- (NSURLSessionDataTask *)getProductsPage:(NSUInteger)page inCollection:(NSNumber *)collectionId completion:(BUYDataProductListBlock)block
{
return [self getProductsPage:page inCollection:collectionId sortOrder:BUYCollectionSortCollectionDefault completion:block];
}
- (NSURLSessionDataTask *)getProductsPage:(NSUInteger)page inCollection:(NSNumber *)collectionId sortOrder:(BUYCollectionSort)sortOrder completion:(BUYDataProductListBlock)block
{
BUYAssert(collectionId, @"Failed to get products page. Invalid collectionID.");
NSURL *route = [self urlForProductListingsWithParameters:@{
@"collection_id" : collectionId,
@"limit" : @(self.pageSize),
@"page" : @(page),
@"sort_by" : [BUYCollection sortOrderParameterForCollectionSort:sortOrder]
}];
return [self getRequestForURL:route completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSArray *products = nil;
if (json && !error) {
products = [self.modelManager buy_objectsWithEntityName:[BUYProduct entityName] JSONArray:json[BUYProductsKey]];
}
block(products, page, [self hasReachedEndOfPage:products] || error, error);
}];
}
@end
//
// BUYAuthenticatedResponse.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2016 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import <Foundation/Foundation.h>
@interface BUYAuthenticatedResponse : NSObject
@property (nonatomic, copy, readonly) NSString *accessToken;
@property (nonatomic, copy, readonly) NSDate *expiry;
@property (nonatomic, copy, readonly) NSString *customerID;
+ (BUYAuthenticatedResponse *)responseWithJSON:(NSDictionary *)json;
@end
//
// BUYAuthenticatedResponse.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2016 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "BUYAuthenticatedResponse.h"
#import "NSDateFormatter+BUYAdditions.h"
@implementation BUYAuthenticatedResponse
+ (BUYAuthenticatedResponse *)responseWithJSON:(NSDictionary *)json
{
return [[[self class] alloc] initWithJSON:json];
}
- (instancetype)initWithJSON:(NSDictionary *)json
{
self = [super init];
if (self) {
NSDateFormatter *formatter = [NSDateFormatter dateFormatterForPublications];
NSDictionary *access = json[@"customer_access_token"];
_accessToken = access[@"access_token"];
_expiry = [formatter dateFromString:access[@"expires_at"]];
_customerID = [NSString stringWithFormat:@"%@", access[@"customer_id"]];
}
return self;
}
@end
......@@ -25,7 +25,7 @@
//
#import <Buy/_BUYCollection.h>
#import "BUYClient.h"
#import "BUYClient+Storefront.h"
@interface BUYCollection : _BUYCollection {}
......
......@@ -31,7 +31,7 @@
#import "BUYApplePayHelpers.h"
#import "BUYApplePayAdditions.h"
#import "BUYShop.h"
#import "BUYClient+Checkout.h"
#import "BUYClient+CheckoutHelpers.h"
NSString *const BUYApplePayPaymentProviderId = @"BUYApplePayPaymentProviderId";
......
......@@ -28,7 +28,7 @@
NS_ASSUME_NONNULL_BEGIN
@interface BUYClient (Checkout)
@interface BUYClient (CheckoutHelpers)
- (NSURLSessionDataTask *)handleCheckout:(BUYCheckout *)checkout completion:(BUYDataCheckoutBlock)completion;
......
......@@ -24,9 +24,9 @@
// THE SOFTWARE.
//
#import "BUYClient+Checkout.h"
#import "BUYClient+CheckoutHelpers.h"
@implementation BUYClient (Checkout)
@implementation BUYClient (CheckoutHelpers)
- (NSURLSessionDataTask *)handleCheckout:(BUYCheckout *)checkout completion:(BUYDataCheckoutBlock)completion
{
......
......@@ -26,7 +26,7 @@
#import "BUYWebCheckoutPaymentProvider.h"
#import "BUYCheckout.h"
#import "BUYClient+Checkout.h"
#import "BUYClient+CheckoutHelpers.h"
@import SafariServices;
......
......@@ -36,6 +36,11 @@
#import "BUYCartLineItem.h"
#import "BUYCheckout.h"
#import "BUYCheckoutAttribute.h"
#import "BUYClient+Test.h"
#import "BUYClient.h"
#import "BUYClient+Customers.h"
#import "BUYClient+Storefront.h"
#import "BUYClient+Checkout.h"
#import "BUYCollection.h"
#import "BUYCreditCard.h"
#import "BUYCustomer.h"
......
......@@ -27,7 +27,8 @@
#import "BUYApplePayHelpers.h"
#import "BUYAddress.h"
#import "BUYApplePayAdditions.h"
#import "BUYClient.h"
#import "BUYClient+Checkout.h"
#import "BUYClient+Storefront.h"
#import "BUYCheckout.h"
#import "BUYError.h"
#import "BUYModelManager.h"
......
//
// BUYStoreController.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import WebKit;
#import "BUYLineItem.h"
#import "BUYProduct.h"
#import "BUYProductVariant.h"
#import "BUYStoreViewController.h"
#import "BUYError.h"
#import "BUYOrder.h"
#import "BUYShopifyErrorCodes.h"
#import "BUYClient+Storefront.h"
#import "BUYClient+Checkout.h"
@interface BUYStoreViewController () <WKNavigationDelegate, WKScriptMessageHandler>
@end
@implementation BUYStoreViewController {
NSURL *_url;
WKWebView *_webView;
UIBarButtonItem *_backButton;
UIBarButtonItem *_forwardButton;
BOOL _skippingAppCheckout;
NSURLRequest *_checkoutRequest;
}
@dynamic delegate;
- (instancetype)initWithClient:(BUYClient *)client url:(NSURL *)url
{
self = [super initWithClient:client];
if (self) {
_url = url;
}
return self;
}
- (instancetype)initWithClient:(BUYClient *)client
{
self = [super initWithClient:client];
if (self) {
_url = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", client.shopDomain]];
}
return self;
}
- (void)loadView
{
WKWebViewConfiguration *configuration = [self webViewConfiguration];
_webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
_webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
_webView.navigationDelegate = self;
self.view = _webView;
_backButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"back"] style:UIBarButtonItemStylePlain target:_webView action:@selector(goBack)];
_forwardButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"forward"] style:UIBarButtonItemStylePlain target:_webView action:@selector(goForward)];
UIBarButtonItem *shareButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(shareTapped)];
UIBarButtonItem *flexible = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
self.toolbarItems = @[_backButton, flexible, _forwardButton, flexible, shareButton, flexible, flexible, flexible];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[_webView loadRequest:[NSURLRequest requestWithURL:_url]];
[self updateButtons];
}
#pragma mark - Button Presses
- (void)updateButtons
{
_backButton.enabled = [_webView canGoBack];
_forwardButton.enabled = [_webView canGoForward];
}
- (void)shareTapped
{
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[_webView.URL] applicationActivities:nil];
activityViewController.excludedActivityTypes = @[UIActivityTypeAddToReadingList, UIActivityTypeAssignToContact, UIActivityTypePrint, UIActivityTypeSaveToCameraRoll];
[self presentViewController:activityViewController animated:YES completion:nil];
}
#pragma mark - Web View Navigation Delegate Methods
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSString *currentUrlString = [[[navigationAction request] URL] absoluteString];
BOOL checkoutLink = [currentUrlString containsString:@"/checkout"] || [currentUrlString containsString:@"/sessions"];
BOOL thankYouPage = [currentUrlString containsString:@"thank_you"];
if (checkoutLink && thankYouPage == NO) {
if (_skippingAppCheckout) {
decisionHandler(WKNavigationActionPolicyAllow);
}
else {
decisionHandler(WKNavigationActionPolicyCancel);
[self presentCheckoutMethodSelectionMenuWithCheckoutRequest:[navigationAction request]];
}
}
else {
_skippingAppCheckout = NO;
decisionHandler(WKNavigationActionPolicyAllow);
}
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
[self updateButtons];
}
- (void)reloadHomePage
{
[_webView loadRequest:[NSURLRequest requestWithURL:_url]];
}
#pragma mark - Checkout Methods
- (void)presentCheckoutMethodSelectionMenuWithCheckoutRequest:(NSURLRequest *)request
{
_checkoutRequest = request;
if ([self.delegate respondsToSelector:@selector(controller:shouldProceedWithCheckoutType:)]) {
[self.delegate controller:self shouldProceedWithCheckoutType:^(BUYCheckoutType type) {
switch (type) {
case BUYCheckoutTypeNormal:
[self checkoutWithNormalCheckout];
break;
case BUYCheckoutTypeApplePay:
[self checkoutWithApplePay];
break;
default:
break;
}
}];
}
else {
[self checkoutWithNormalCheckout];
}
}
- (void)getProduct:(NSString *)productId withVariantId:(NSString *)variantId completion:(void (^)(BUYProductVariant *variant, NSError *error))completion;
{
[self.client getProductById:productId completion:^(BUYProduct *product, NSError *error) {
BUYProductVariant *selectedVariant = nil;
if (error == nil) {
for (BUYProductVariant *variant in product.variants) {
if ([variant.identifier isEqual:@([variantId longLongValue])]) {
selectedVariant = variant;
break;
}
}
}
else {
NSLog(@"Failed to fetch variant: %@", error);
}
completion(selectedVariant, error);
}];
}
#pragma mark - Checkout Selection Delegate Methods
- (void)checkoutWithApplePay
{
[_webView evaluateJavaScript:@"\
var cartRequest = new XMLHttpRequest();\
cartRequest.open(\"GET\", \"/cart.json\", false);\
cartRequest.onreadystatechange = function() {\
if (cartRequest.readyState == 4 && cartRequest.status == 200) {\
window.webkit.messageHandlers.nativeApp.postMessage(JSON.parse(cartRequest.responseText));\
}\
};\
cartRequest.send(null);"
completionHandler:^(id response, NSError *error) {
}];
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
NSDictionary *json = message.body;
NSString *cartToken = json[@"token"];
if (cartToken) {
[self startCheckoutWithCartToken:cartToken];
}
else {
NSError *error = [NSError errorWithDomain:BUYShopifyError code:BUYShopifyError_CartFetchError userInfo:nil];
[self.delegate controller:self failedToCreateCheckout:error];
}
}
- (void)checkoutWithNormalCheckout
{
_skippingAppCheckout = YES;
[_webView loadRequest:_checkoutRequest];
}
#pragma mark - Checkout Completion Handling
- (void)checkoutCompleted:(BUYCheckout *)checkout status:(BUYStatus)status
{
if (status == BUYStatusComplete) {
[self.client getCheckout:checkout completion:^(BUYCheckout *updatedCheckout, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (updatedCheckout.order.statusURL) {
[_webView loadRequest:[NSURLRequest requestWithURL:updatedCheckout.order.statusURL]];
}
else {
NSLog(@"Couldn't redirect to thank you page: %@ (url: %@)", updatedCheckout, updatedCheckout.order.statusURL);
}
});
}];
}
else {
NSError *error = [NSError errorWithDomain:BUYShopifyError code:status userInfo:@{@"checkout": checkout}];
[self.delegate controller:self failedToCompleteCheckout:checkout withError:error];
}
}
#pragma mark - Web View Configuration
- (WKWebViewConfiguration *)webViewConfiguration
{
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
configuration.userContentController = [self userContentConfiguration];
configuration.processPool = [self processPool];
return configuration;
}
- (WKProcessPool *)processPool
{
static WKProcessPool *pool = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
pool = [[WKProcessPool alloc] init];
});
return pool;
}
- (WKUserContentController *)userContentConfiguration
{
//Register our native bridge
WKUserContentController *contentController = [WKUserContentController new];
[contentController addScriptMessageHandler:self name:@"nativeApp"];
return contentController;
}
@end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment