Skip to content

Commit

Permalink
Merge pull request #332 from Adyen/session
Browse files Browse the repository at this point in the history
Session iOS
  • Loading branch information
descorp authored Jan 5, 2024
2 parents 195939f + f53fb0f commit 54800cd
Show file tree
Hide file tree
Showing 23 changed files with 293 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ class SessionHelperModule(context: ReactApplicationContext?) : BaseModule(contex
return builder.build()
}

override fun getName(): String {
return "SessionHelper"
}
override fun getName(): String = COMPONENT_NAME

override fun onFinished(result: SessionPaymentResult) {
throw NotImplementedError("This Module have no events")
Expand All @@ -63,4 +61,8 @@ class SessionHelperModule(context: ReactApplicationContext?) : BaseModule(contex
promise.resolve(RedirectComponent.getReturnUrl(reactApplicationContext))
}

companion object {
private const val COMPONENT_NAME = "SessionHelper"
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ class ApplePayModuleMock(context: ReactApplicationContext?) : BaseModule(context
throw MethodNotImplementedException("This method is not implemented for Android")
}

override fun getName(): String {
return COMPONENT_NAME
}
override fun getName(): String = COMPONENT_NAME

companion object {
private const val COMPONENT_NAME = "AdyenApplePay"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ class DropInModule(context: ReactApplicationContext?) : BaseModule(context),
@ReactMethod
fun removeListeners(count: Int?) { /* No JS events expected */ }

override fun getName(): String {
return COMPONENT_NAME
}
override fun getName(): String = COMPONENT_NAME

@ReactMethod
fun open(paymentMethodsData: ReadableMap?, configuration: ReadableMap) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ import org.json.JSONException
class GooglePayModule(context: ReactApplicationContext?) : BaseModule(context),
CheckoutProxy.ComponentEventListener {

override fun getName(): String {
return COMPONENT_NAME
}
override fun getName(): String = COMPONENT_NAME

@ReactMethod
fun addListener(eventName: String?) { /* No JS events expected */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ import org.json.JSONException

class InstantModule(context: ReactApplicationContext?) : BaseModule(context), CheckoutProxy.ComponentEventListener {

override fun getName(): String {
return COMPONENT_NAME
}
override fun getName(): String = COMPONENT_NAME

@ReactMethod
fun addListener(eventName: String?) { /* No JS events expected */ }
Expand Down
2 changes: 1 addition & 1 deletion example/ios/AdyenExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "set -e\n\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
shellScript = "set -e\n\nexport NODE_BINARY=/usr/local/adyen/nodejs/bin/node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
};
232049820C171C0417A4BE52 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
Expand Down
54 changes: 22 additions & 32 deletions example/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,34 @@ import {
DarkTheme,
DefaultTheme,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import {createNativeStackNavigator} from '@react-navigation/native-stack';

import { Button, Alert, useColorScheme } from 'react-native';
import {Button, Alert, useColorScheme} from 'react-native';
import CseView from './Views/CseView';
import SettingView from './Views/SettingsView';
import Result from './Views/ResultView';
import SessionsCheckout from './Views/Checkout/SessionsCheckout';
import AdvancedCheckout from './Views/Checkout/AdvancedCheckout';
import Home from './Views/HomeView';
import AppContextProvider from './Utilities/AppContext';
import { DEFAULT_CONFIGURATION } from './Configuration';
import {DEFAULT_CONFIGURATION} from './Configuration';

const Stack = createNativeStackNavigator();

const SettingsButton = ({ navigation }) => {
const SettingsButton = ({navigation}) => {
return (
<Button onPress={() => navigation.navigate(Page.Settings)} title="Edit" />
);
};

export const Page = {
SessionsCheckout: 'SessionsCheckout',
AdvancedCheckout: 'AdvancedCheckout',
Settings: 'Settings',
Home: 'Home',
SessionsCheckout: 'SessionsCheckout',
AdvancedCheckout: 'AdvancedCheckout',
Settings: 'Settings',
CustomCard: 'CustomCard',
Result: 'Result'
}
Result: 'Result',
};

const App = () => {
const isDarkMode = useColorScheme() === 'dark';
Expand All @@ -52,39 +53,28 @@ const App = () => {
>
<NavigationContainer theme={isDarkMode ? DarkTheme : DefaultTheme}>
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen
name={Page.SessionsCheckout}
component={SessionsCheckout}
options={({ navigation }) => ({
title: 'Sessions',
headerRight: (props) => (
<SettingsButton navigation={navigation} {...props} />
name={Page.Home}
component={Home}
options={({navigation}) => ({
headerRight: () => (
<SettingsButton navigation={navigation} />
),
})}
/>
<Stack.Screen
name={Page.SessionsCheckout}
component={SessionsCheckout}
options={() => ({title: 'Sessions Checkout' })}
/>
<Stack.Screen
name={Page.AdvancedCheckout}
component={AdvancedCheckout}
options={({ navigation }) => ({
title: 'Advanced',
headerRight: (props) => (
<SettingsButton navigation={navigation} {...props} />
),
})}
options={() => ({title: 'Advanced Checkout' })}
/>
<Stack.Screen name={Page.Settings} component={SettingView} />
<Stack.Screen name={Page.Result} component={Result} />
<Stack.Screen
name={Page.CustomCard}
component={CseView}
options={({ navigation }) => ({
title: 'Custom Card Integration',
headerRight: (props) => (
<SettingsButton navigation={navigation} {...props} />
),
})}
/>
<Stack.Screen name={Page.CustomCard} component={CseView} />
</Stack.Navigator>
</NavigationContainer>
</AppContextProvider>
Expand Down
4 changes: 2 additions & 2 deletions example/src/Utilities/Styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const Styles = StyleSheet.create({
alignItems: 'stretch',
flex: 1,
justifyContent: 'center',
gap: 8
},
horizontalContent: {
alignItems: 'center',
Expand Down Expand Up @@ -56,8 +55,9 @@ const Styles = StyleSheet.create({
backgroundColor: '#009D6E',
borderRadius: 5,
padding: 8,
marginVertical: 4,
marginLeft: 8,
marginRight: 8
marginRight: 8,
},
btnContainer: {
flexDirection: 'row',
Expand Down
20 changes: 2 additions & 18 deletions example/src/Views/Checkout/AdvancedCheckout.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-check

import React, { useEffect, useCallback, useState } from 'react';
import { SafeAreaView, Alert, View, Text, useColorScheme } from 'react-native';
import { SafeAreaView, Alert, ActivityIndicator } from 'react-native';
import { AdyenCheckout, ErrorCode, ResultCode } from '@adyen/react-native';
import ApiClient from '../../Utilities/APIClient';
import { checkoutConfiguration, useAppContext } from '../../Utilities/AppContext';
Expand Down Expand Up @@ -138,7 +138,7 @@ const AdvancedCheckout = ({ navigation }) => {
<PaymentMethods />
</AdyenCheckout>
) : (
<NoPaymentMethodsView />
<ActivityIndicator size='large' style={Styles.page} />
)}
</SafeAreaView>
);
Expand All @@ -155,20 +155,4 @@ const isSuccess = (
code === ResultCode.presentToShopper;
};

const NoPaymentMethodsView = () => {
const isDarkMode = useColorScheme() === 'dark';
return (
<View>
<Text
style={[
Styles.centeredText,
isDarkMode ? Styles.textDark : Styles.textLight,
]}
>
No Payment methods
</Text>
</View>
);
};

export default AdvancedCheckout;
6 changes: 4 additions & 2 deletions example/src/Views/Checkout/PaymentMethodsView.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
TouchableHighlight,
Image,
Text,
useColorScheme,
} from 'react-native';
import Styles from '../../Utilities/Styles';
import { ENVIRONMENT } from '../../Configuration';
Expand All @@ -19,6 +20,7 @@ const PaymentMethods = () => {
const storedPaymentMethods = paymentMethodsResponse?.storedPaymentMethods;

const isNotReady = paymentMethodsResponse === undefined;
const isDarkMode = useColorScheme() === 'dark';

const subtitle = (/** @type {import('@adyen/react-native').StoredPaymentMethod} */ pm) => {
switch (pm.type) {
Expand All @@ -44,7 +46,7 @@ const PaymentMethods = () => {

{storedPaymentMethods ? (
<View>
<Text> Stored payments </Text>
<Text style={isDarkMode ? Styles.textDark : Styles.textLight}> Stored payments </Text>
{storedPaymentMethods.map((p) => {
const iconName = p.type === 'scheme' ? 'card' : p.type;
return (
Expand All @@ -63,7 +65,7 @@ const PaymentMethods = () => {
</View>
) : (<View />)}

<Text> Components </Text>
<Text style={isDarkMode ? Styles.textDark : Styles.textLight}> Components </Text>
{regularPaymentMethods.map((p) => {
const iconName = p.type === 'scheme' ? 'card' : p.type;
return (
Expand Down
2 changes: 1 addition & 1 deletion example/src/Views/Checkout/SessionsCheckout.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ const SessionsCheckout = ({navigation}) => {
<PaymentMethods />
</AdyenCheckout>
) : (
<ActivityIndicator style={Styles.content} />
<ActivityIndicator size='large' style={Styles.page} />
)}
</SafeAreaView>
);
Expand Down
2 changes: 1 addition & 1 deletion example/src/Views/SettingsView.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ const SettingFormView = ({ navigation: { goBack } }) => {
onChangeText={setShopperReference}
/>
<View style={Styles.centeredButton}>
<Button title="Save payment methods" onPress={handleOnPress} />
<Button title="Save" onPress={handleOnPress} />
</View>
</View>
);
Expand Down
19 changes: 17 additions & 2 deletions ios/AdyenModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ @interface RCT_EXTERN_MODULE(AdyenApplePay, NSObject)
@interface RCT_EXTERN_MODULE(AdyenGooglePay, NSObject)

RCT_EXTERN_METHOD(open:(NSDictionary *)paymentMethods
configuration:(NSDictionary *)configuration)
configuration:(NSDictionary *)configuration)

@end

Expand All @@ -62,4 +62,19 @@ @interface RCT_EXTERN_MODULE(AdyenCSE, NSObject)
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)

@end
@end

@interface RCT_EXTERN_MODULE(SessionHelper, NSObject)

RCT_EXTERN_METHOD(createSession:(NSDictionary *)sessionModelJSON
configuration:(NSDictionary *)configurationJSON
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(getReturnURL:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(hide:(nonnull NSNumber *)success
event:(NSDictionary *)event)

@end
2 changes: 1 addition & 1 deletion ios/CSE/AdyenCSE.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal final class AdyenCSE: NSObject {
let encryptedBin = try CardEncryptor.encrypt(bin: formattedBin as String, with: publicKey as String)
resolver(encryptedBin)
} catch {
rejecter(Constant.errorMessage, nil, error)
rejecter("AdyenCSE", Constant.errorMessage, error)
}
}

Expand Down
28 changes: 9 additions & 19 deletions ios/Components/ApplePayModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import React
@objc(AdyenApplePay)
internal final class ApplePayModule: BaseModule {

override func supportedEvents() -> [String]! { [ Events.didSubmit.rawValue, Events.didFail.rawValue ] }
override func supportedEvents() -> [String]! { Events.allCases.map(\.rawValue) }

@objc
func hide(_ success: NSNumber, event: NSDictionary) {
Expand All @@ -23,32 +23,22 @@ internal final class ApplePayModule: BaseModule {
func open(_ paymentMethodsDict: NSDictionary, configuration: NSDictionary) {
let parser = RootConfigurationParser(configuration: configuration)
let applePayParser = ApplepayConfigurationParser(configuration: configuration)
let paymentMethod: ApplePayPaymentMethod
let clientKey: String
let payment: Payment
let applepayConfig: Adyen.ApplePayComponent.Configuration
do {
paymentMethod = try parsePaymentMethod(from: paymentMethodsDict, for: ApplePayPaymentMethod.self)
clientKey = try fetchClientKey(from: parser)
payment = try fetchPayment(from: parser)
applepayConfig = try applePayParser.buildConfiguration(payment: payment)
} catch {
return sendEvent(error: error)
}

guard let apiContext = try? APIContext(environment: parser.environment, clientKey: clientKey) else { return }

// TODO: add analyticsConfiguration: AnalyticsConfiguration()
let context = AdyenContext(apiContext: apiContext, payment: payment)
let applePayComponent: Adyen.ApplePayComponent
let applePayComponent: ApplePayComponent
do {
let paymentMethod = try parsePaymentMethod(from: paymentMethodsDict, for: ApplePayPaymentMethod.self)
let context = try parser.fetchContext()
guard let payment = context.payment else { throw NativeModuleError.noPayment }
let applepayConfig = try applePayParser.buildConfiguration(payment: payment)
applePayComponent = try Adyen.ApplePayComponent(paymentMethod: paymentMethod,
context: context,
configuration: applepayConfig)
} catch {
return sendEvent(error: error)
}

currentComponent = applePayComponent
SessionHelperModule.sessionListener = self
applePayComponent.delegate = BaseModule.session ?? self
present(component: applePayComponent)
}

Expand Down
Loading

0 comments on commit 54800cd

Please sign in to comment.