Skip to content

Commit

Permalink
task: add support for cart items (#32)
Browse files Browse the repository at this point in the history
* deps: upgrade ios/android sdk dependencies

* deps: upgrade rexml

* Pass empty connectionOptions and values for cartItems for now

* Update Podfile.lock

* Add missing cartItems optional props

* Pass missing cartItems parameters to Gr4vyActivity

* Remove connectionOptions

* Pass rest of cartItems props

* Remove unnecessary util getObjectOptionalValue

* Fix ws vulnerability

* Remove EXTRA_CONNECTION_OPTIONS

* Upgrade to latest iOS sdk

* Fix discountAmount and taxAmount

* Update README

* Upgrade gr4vy-ios pod to 2.2.1

* Use string array instead of Arrays.asList for optional props

* Update type checking and populating the map

---------

Co-authored-by: Douglas Eggleton <[email protected]>
  • Loading branch information
luca-gr4vy and douglaseggleton authored Jul 1, 2024
1 parent 0cf78c1 commit 8acbe03
Show file tree
Hide file tree
Showing 13 changed files with 141 additions and 43 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ The options passed to `showPaymentSheet` via the configuration object are as fol
| `metadata` | `null` | An optional object of key/values for transaction metadata. All values should be a string. |
| `paymentSource` | `null` | `installment`, `moto`, `recurring` - Can be used to signal that Embed is used to capture the first transaction for a subscription or an installment. When used, `store` is implied to be `true` and `display` is implied to be `supportsTokenization`. This means that payment options that do not support tokenization are automatically hidden. |
| `applePayMerchantId` | `null` | The Apple merchant ID to be used for Apple Pay transactions. |
| `cartItems` | `null` | An optional array of cart item objects, each object must define a `name`, `quantity`, and `unitAmount`. |
| `cartItems` | `null` | An optional array of cart item objects, each object must define a `name`, `quantity`, and `unitAmount`. Other optional properties are `discountAmount`, `taxAmount`, `externalIdentifier`, `sku`, `productUrl`, `imageUrl`, `categories` and `productType`. |
| `theme` | `null` | Theme customisation options [See Theming Options](https://docs.gr4vy.com/guides/payments/embed/theming#theme-options). The SDK also contains an additional two properties within the `colors` object: `headerBackground` and `headerText`. These are used for the navigation background and foreground colors. |
| `locale` | `null` | An optional locale, this consists of a `ISO 639 Language Code` followed by an optional `ISO 3166 Country Code`, e.g. `en`, `en-gb` or `pt-br`. |
| `statementDescriptor` | `null` | An optional object with information about the purchase to construct the statement information the buyer will see in their bank statement. Please note support for these fields varies across payment service providers and underlying banks, so Gr4vy can only ensure a best effort approach for each supported platform. <br />As an example, most platforms will only support a concatenation of `name` and `description` fields, truncated to a length of 22 characters. <br />The object can contain `name`, `description`, `phoneNumber`, `city` and `url` keys, with string values. `phoneNumber` should be in E164 format. Gr4vy recommends avoiding characters outside the alphanumeric range and the dot (`.`) to ensure wide compatibility. |
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ dependencies {
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+"

implementation "com.github.gr4vy:gr4vy-android:v1.6.3"
implementation "com.github.gr4vy:gr4vy-android:v1.7.4"
}

if (isNewArchitectureEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,24 @@ public static <T> T coalesce(T... items) {
return null;
}

public static void setOptionalValue(ReadableMap source, WritableMap target, String key) {
if (source.hasKey(key)) {
if (!source.isNull(key)) {
switch (source.getType(key)) {
case Number:
target.putInt(key, source.getInt(key));
break;
case String:
target.putString(key, source.getString(key));
break;
case Array:
target.putArray(key, source.getArray(key));
break;
}
}
}
}

public EmbedReactNativeModule(ReactApplicationContext context) {
super(context);

Expand Down Expand Up @@ -120,6 +138,22 @@ private static WritableArray convertCartItemsToJson(ReadableArray cartItemsArray
cartItemWritableMap.putString("name", cartItemMap.getString("name"));
cartItemWritableMap.putInt("quantity", cartItemMap.getInt("quantity"));
cartItemWritableMap.putInt("unitAmount", cartItemMap.getInt("unitAmount"));

String[] optionalProps = new String[] {
"discountAmount",
"taxAmount",
"externalIdentifier",
"sku",
"productUrl",
"imageUrl",
"categories",
"productType"
};
for (String prop : optionalProps) {
setOptionalValue(cartItemMap, cartItemWritableMap, prop);
}


cartItemsWritableArray.pushMap(cartItemWritableMap);
}
return cartItemsWritableArray;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableArray;

import org.json.JSONArray;
import org.json.JSONObject;
Expand All @@ -20,6 +21,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;

import static com.gr4vy.embedreactnative.EmbedReactNativeModule.coalesce;
import static com.gr4vy.embedreactnative.EmbedReactNativeModule.EXTRA_GR4VY_ID;
Expand All @@ -45,8 +47,6 @@
import static com.gr4vy.embedreactnative.EmbedReactNativeModule.EXTRA_PAYMENT_SOURCE;
import static com.gr4vy.embedreactnative.EmbedReactNativeModule.EXTRA_CART_ITEMS;

import java.util.HashMap;

public class Gr4vyActivity extends ComponentActivity implements Gr4vyResultHandler {
private Gr4vySDK gr4vySDK;
private final ActivityResultRegistry activityResultRegistry = this.getActivityResultRegistry();
Expand Down Expand Up @@ -186,9 +186,38 @@ protected static List<CartItem> convertCartItems(String cartItemsJson) {
for (int i = 0; i < cartItemsJsonArray.length(); i++) {
JSONObject cartItemJsonObject = cartItemsJsonArray.getJSONObject(i);
String name = cartItemJsonObject.getString("name");
int quantity = cartItemJsonObject.getInt("quantity");
int unitAmount = cartItemJsonObject.getInt("unitAmount");
CartItem cartItem = new CartItem(name, quantity, unitAmount);
Integer quantity = cartItemJsonObject.getInt("quantity");
Integer unitAmount = cartItemJsonObject.getInt("unitAmount");
Integer discountAmount = (Integer) cartItemJsonObject.opt("discountAmount");
Integer taxAmount = (Integer) cartItemJsonObject.opt("taxAmount");
String externalIdentifier = (String) cartItemJsonObject.opt("externalIdentifier");
String sku = (String) cartItemJsonObject.opt("sku");
String productUrl = (String) cartItemJsonObject.opt("productUrl");
String imageUrl = (String) cartItemJsonObject.opt("imageUrl");
String productType = (String) cartItemJsonObject.opt("productType");

JSONArray categoriesArray = (JSONArray) cartItemJsonObject.opt("categories");
List<String> categories = null;
if (categoriesArray != null) {
categories = new ArrayList<String>();
for (int j = 0; j < categoriesArray.length(); j++) {
categories.add(categoriesArray.getString(j));
}
}

CartItem cartItem = new CartItem(
name,
quantity,
unitAmount,
discountAmount,
taxAmount,
externalIdentifier,
sku,
productUrl,
imageUrl,
categories,
productType
);
cartItemList.add(cartItem);
}
} catch (JSONException e) {
Expand Down Expand Up @@ -284,6 +313,7 @@ public void onStart() {
requireSecurityCode,
shippingDetailsId,
merchantAccountId,
null, // TODO: pass connectionOptions
debugMode);

sdkLaunched = true;
Expand Down
2 changes: 1 addition & 1 deletion example/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ GEM
nap (1.1.0)
netrc (0.11.0)
public_suffix (4.0.7)
rexml (3.2.5)
rexml (3.2.8)
ruby-macho (2.5.1)
typhoeus (1.4.0)
ethon (>= 0.9.0)
Expand Down
2 changes: 1 addition & 1 deletion example/android/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ GEM
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.2.5)
rexml (3.2.8)
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
Expand Down
2 changes: 1 addition & 1 deletion example/ios/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ GEM
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.2.5)
rexml (3.2.8)
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
Expand Down
10 changes: 5 additions & 5 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ PODS:
- FlipperKit/FlipperKitNetworkPlugin
- fmt (6.2.1)
- glog (0.3.5)
- gr4vy-embed-react-native (1.0.0):
- gr4vy-ios (= 1.6.1)
- gr4vy-embed-react-native (1.1.0):
- gr4vy-ios (= 2.2.1)
- React-Core
- gr4vy-ios (1.6.1)
- gr4vy-ios (2.2.1)
- hermes-engine (0.71.8):
- hermes-engine/Pre-built (= 0.71.8)
- hermes-engine/Pre-built (0.71.8)
Expand Down Expand Up @@ -627,8 +627,8 @@ SPEC CHECKSUMS:
FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
gr4vy-embed-react-native: fa2c871707b970da45a94af0611e1c0ddeb70929
gr4vy-ios: e983133ec0e3beed759e3ee07aeca7bb480c8b10
gr4vy-embed-react-native: 04bd89611a599568cada061b531d0e08439bde22
gr4vy-ios: 9553ba573977441f837de5df83f855582d813401
hermes-engine: 47986d26692ae75ee7a17ab049caee8864f855de
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
nodejs-mobile-react-native: e35e7ed7ecfca168f168983e9557f1c5278d864b
Expand Down
4 changes: 3 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
},
"resolutions": {
"braces": "^3.0.3",
"tar": "^6.2.1"
"tar": "^6.2.1",
"ws": "^7.5.10",
"react-native/ws": "^6.2.3"
}
}
18 changes: 9 additions & 9 deletions example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5335,18 +5335,18 @@ write-file-atomic@^2.3.0:
imurmurhash "^0.1.4"
signal-exit "^3.0.2"

ws@^6.2.2:
version "6.2.2"
resolved "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e"
integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==
ws@^6.2.2, ws@^7, ws@^7.5.1, ws@^7.5.10:
version "7.5.10"
resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9"
integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==

ws@^6.2.3:
version "6.2.3"
resolved "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz#ccc96e4add5fd6fedbc491903075c85c5a11d9ee"
integrity sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==
dependencies:
async-limiter "~1.0.0"

ws@^7, ws@^7.5.1:
version "7.5.9"
resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==

xcode@^2.0.0:
version "2.1.0"
resolved "https://registry.npmjs.org/xcode/-/xcode-2.1.0.tgz#bab64a7e954bb50ca8d19da7e09531c65a43ecfe"
Expand Down
2 changes: 1 addition & 1 deletion gr4vy-embed-react-native.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Pod::Spec.new do |s|
s.source_files = "ios/**/*.{h,m,mm,swift}"

s.dependency "React-Core"
s.dependency "gr4vy-ios", "1.6.1"
s.dependency "gr4vy-ios", "2.2.1"

# Don't install the dependencies when we run `pod install` in the old architecture.
if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
Expand Down
Loading

0 comments on commit 8acbe03

Please sign in to comment.