1.0.12 • Published 2 years ago

gapp-payment-method v1.0.12

Weekly downloads
-
License
MIT
Repository
-
Last release
2 years ago

Payment Method GApp Flow

Mobile GApp Flow for Payment Method

Installation

npm install serino-mobile-gapp-payment-method-flow --registry http://miniapp.serino.com:4873/

Changelogs

See the Change logs

Dependecies

  • npm install axios

(PaymentMethodGAppFlow) DataLoad Props

PropRequiredTypeDescription
dataNoarray of objectlist of payment method data. Applicable for dataloadType=json-stab
axiosNoAxiosInstanceset axios instance. Applicable for dataloadType=network-service
endpointsNoobjectlist of endpoints. Applicable for dataloadType=network-service or network-service-config
baseUrlNostringbaseurl for getAll endpoint. Applicable for dataloadType=network-service-config
methodNoGET,POST,PUT,DELETEApplicable for dataloadType=network-service-config
requestParamsNoobjectApplicable for dataloadType=network-service-config
requestPostDataNoobjectApplicable for dataloadType=network-service-config
cancelRequestNoApplicable for dataloadType=network-service-config
timeoutNoApplicable for dataloadType=network-service-config
AppKeyNoApplicable for dataloadType=network-service-config
tokenNoApplicable for dataloadType=network-service-config
tokenTypeNoApplicable for dataloadType=network-service-config
headerNoobjectApplicable for dataloadType=network-service-config
validateCardUrlNostringApplicable for dataloadType=network-service or network-service-config
cardValidationtokenNostringApplicable for dataloadType=network-service ornetwork-service-config

(PaymentMethodGAppFlow) DataIn Props

PropRequiredTypeDescription
dataLoadTypeYesjson-stab,network-service,network-service-configchoices what dataLoad should be apply
constructDataNofunctionfunction that reconstruct payment method list. should return list.
initialRouteNameNostringinitialRouteName for StackNavigator
screensNoarray of objectsmodify mini-app and gapp. able to use with the combination of Stack
isCardValidateNobooleanactivating server request to validate card form.

(dataLoad > endpoints) Props

PropRequiredTypeDescription
getAllNostringendpoint for payment method list api

(dataIn > screens) Props

PropRequiredTypeDescription
keyNostringmini-app key
stackNameNostringStack name
stackOptionsNoobjectStack options
dataLoadNoobjectmini-app dataLoad. to modify initial and gapp dataLoad
dataInNoobjectmini-app dataIn. to modify initial and gapp dataIn
dataOutNofunctionmini-app dataOut. to modify initial and gapp dataOut

Example

Run the following commands

npm run boostrap:setup project by installing all dependencies and pods. npm run example run start: start the Metro server for the example app. npm run example run android: run the example app on Android. npm run example run ios: run the example app on iOS.

Example (dataLoad='json-stab')

gateway-payment-list.json

{
  "status": 200,
  "message": "Success",
  "data": [
    {
      "id": 1,
      "name": "Credit/Debit Card",
      "description": "Pay using your Visa or Master Debit/Credit Cards",
      "type": "online",
      "merchant_processors": [
        {
          "id": 2,
          "priority_level": 0,
          "processor": {
            "name": "Maya - Credit/Debit Card",
            "description": "Pay using Credit/Debit Card via Maya",
            "type": "checkout",
            "icon_url": "https://someimage.com/maya_icon.png",
            "banner_url": "https://someimage.com/maya_banner.png"
          }
        },
        {
          "id": 3,
          "priority_level": 1,
          "processor": {
            "name": "MetroBank - MasterCard",
            "description": "Pay using Credit/Debit Master Card",
            "type": "checkout",
            "icon_url": "https://someimage.com/maya_icon.png",
            "banner_url": "https://someimage.com/maya_banner.png"
          }
        }
      ]
    },
    {
      "id": 2,
      "name": "E-Wallets",
      "description": "Pay using your E-Wallet accounts in partner banks",
      "type": "online",
      "merchant_processors": [
        {
          "id": 4,
          "priority_level": 0,
          "processor": {
            "name": "Maya - eWallet",
            "description": "Pay using Maya Account",
            "type": "checkout",
            "icon_url": "https://someimage.com/maya_icon.png",
            "banner_url": "https://someimage.com/maya_banner.png"
          }
        },
        {
          "id": 5,
          "priority_level": 1,
          "processor": {
            "name": "BDO",
            "description": "Pay using BDO",
            "type": "checkout",
            "icon_url": "https://someimage.com/bdo_icon.png",
            "banner_url": "https://someimage.com/bdo_banner.png"
          }
        }
      ]
    },
    {
      "id": 3,
      "name": "Cash",
      "description": "Pay using Cash on Delivery",
      "type": "cash",
      "merchant_processors": []
    }
  ]
}

Payment Method Screen

import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import { Button, Text } from 'react-native-paper';
import { PaymentMethodGAppFlow } from 'serino-mobile-gapp-payment-method-flow';

import { MyNavigator } from '../App';
/*
 * from App.tsx:
 * import { createNativeStackNavigator } from '@react-navigation/native-stack'
 * export const MyNavigator = createNativeStackNavigator();
 */

import { GlobalContext } from '../context/GlobalContext';

import { MethodSelectionAccordion } from 'serino-mapp-payment-method';
import JSONStab from '../json-stab/gateway-payment-list.json';

const PaymentMethodFlow = ({ navigation }: any) => {
  const context: any = React.useContext(GlobalContext);

  const [selectedPaymentMethod, setSelectedPaymentMethod] = React.useState(
    Boolean(context.paymentMethod)
      ? context.paymentMethod
      : {
          id: 1,
          text: 'Credit/Debit Card',
          value: 'Credit/Debit Card',
        }
  );
  const dataLoadType = 'json-stab';

  const data = JSONStab.data;

  const screens = [
    // mini-app index 0
    {
      stackName: 'PaymentMethod',
      stackOptions: {
        title: 'Payment Method',
      },
    },
    // mini-app index 1
    {
      stackName: 'CardDetails',
      stackOptions: {
        title: 'Debit/Credit Card Details',
      },
    },
  ];

  const constructData = (item: any) => {
    return item.map((i: any) => ({
      id: i.id,
      text: i.name,
      value: i.name,
      subText: i.description,
      descriptionText: '', // i.description,
      isExpanded: i.expanded || false,
      child:
        (i.merchant_processors || []).length > 0
          ? i.merchant_processors?.map((d: any) => ({
              id: d.id,
              text: d.processor.name,
              value: d.processor.name,
              subText: d.processor.description,
              descriptionText: '', //d.description,
              imageUri: d.processor.icon_url || undefined,
            }))
          : undefined,
    }));
  };

  const handleDataOut = (values: any) => {
    const paymentMethodDetails = values.paymentMethod?.id
      ? values.paymentMethod
      : selectedPaymentMethod;

    // set selected payment method
    setSelectedPaymentMethod(paymentMethodDetails);

    // If selected payment method is debit or credit card
    if (values.paymentMethod.id === 1) {
      console.log('values.paymentMethod.id', values.paymentMethod.id);
      // navigation.navigate('CardDetails');
      navigation.navigate('PaymentMethodFlow', { screen: 'CardDetails' });
    }
  };

  React.useLayoutEffect(() => {
    navigation.setOptions({
      headerShown: false,
    });
  }, [navigation]);

  return (
    <View style={styles.container}>
      <PaymentMethodGAppFlow
        dataLoad={{ data }}
        dataIn={{
          dataLoadType,
          constructData,
          StackNavigator: MyNavigator,
          initialRouteName: 'PaymentMethod',
          screens,
        }}
        dataOut={handleDataOut}
      >
        {/* mini-app index 0 */}
        <MethodSelectionAccordion
          key="payment-method-accordion-list"
          dataLoad={[]}
          dataIn={{
            selectedPaymentMethod,
          }}
          dataOut={() => {}}
        />
        {/* mini-app index 1 */}
        <MApp2 key="card-form-details" dataOut={() => {}} />
      </PaymentMethodGAppFlow>
      <Button
        mode="contained"
        onPress={() => {
          // context purpose: (simulate checkout gapp flow)
          context.setContext &&
            context.setContext({
              ...context,
              paymentMethod: selectedPaymentMethod,
            });
          navigation.goBack();
        }}
      >
        Confirm
      </Button>
    </View>
  );
};
export default PaymentMethodFlow;

const MApp2 = (props: any) => {
  return (
    <View>
      <Text>Card Details</Text>
      <Button
        onPress={() =>
          props?.dataOut({
            cardNumber:
              '************' +
              '4012001037167778'.replace(/-/g, '').substring(12),
            paymentTokenId: '1234',
          })
        }
      >
        Send Card details
      </Button>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  box: {
    width: 60,
    height: 60,
    marginVertical: 20,
  },
});

Example (dataLoad='network-service')

axiosGateway.ts

import axios, { AxiosResponse, AxiosError, AxiosRequestConfig } from 'axios';

const onRequest = (config: AxiosRequestConfig): AxiosRequestConfig => {
  // You can add token here
  // const token = '';
  // config.headers.Authorization = `Bearer ${token}`;

  return config;
};

const onRequestError = (error: AxiosError): Promise<AxiosError> => {
  return Promise.reject(error);
};

const onResponse = (response: AxiosResponse) => {
  return response.data;
};

const onResponseError = (error: AxiosError): Promise<AxiosError> => {
  return Promise.reject(error.response.data);
};

const instance = axios.create({
  baseURL: 'http://',
});

instance.interceptors.request.use(onRequest, onRequestError);
instance.interceptors.response.use(onResponse, onResponseError);

export default instance;

Payment Method

import * as React from 'react';

import { StyleSheet, View } from 'react-native';
import { MethodSelectionAccordion } from 'serino-mobile-mapp-payment-method';

import { PaymentMethodGAppFlow } from 'serino-mobile-gapp-payment-method-flow';
import { Text } from 'react-native-paper';
import { MyNavigator } from '../App';
import axios from '../library/axiosGateway';

const PaymentMethodFlow = ({ navigation }: any) => {
  const [selectedPaymentMethod, setSelectedPaymentMethod] = React.useState({
    id: 0,
    text: '',
    value: '',
  });

  const public_key = 'pk-8c6axxxx-xxxx-xxxx-xxxx-xxxxxx120002';

  const screens = [
    // mini-app index 0
    {
      stackName: 'PaymentMethod',
      stackOptions: {
        title: 'Payment Method',
      },
    },
    // mini-app index 1
    {
      stackName: 'CardDetails',
      stackOptions: {
        title: 'Debit/Credit Card Details',
      },
    },
  ];

  const constructData = (item: any) => {
    return item.map((i: any) => ({
      id: i.id,
      text: i.name,
      value: i.name,
      subText: i.description,
      descriptionText: '', // i.description,
      isExpanded: i.expanded || false,
      child: i.merchant_processors?.map((d: any) => ({
        id: d.id,
        text: d.name,
        value: d.name,
        subText: d.description,
        descriptionText: '', //d.description,
        imageUri: d.icon_url || undefined,
      })),
    }));
  };

  const handleDataOut = (values: any) => {
    const paymentMethodDetails = values.paymentMethod?.id
      ? values.paymentMethod
      : selectedPaymentMethod;

    // set selected payment method
    setSelectedPaymentMethod(paymentMethodDetails);

    // If selected payment method is debit or credit card
    if (values.paymentMethod.id === 1) {
      console.log('values.paymentMethod.id', values.paymentMethod.id);
      navigation.navigate('PaymentMethodFlow', { screen: 'CardDetails' });
    }
  };

  React.useLayoutEffect(() => {
    navigation.setOptions({
      headerShown: false,
    });
  }, [navigation]);

  return (
    <View style={styles.container}>
      <PaymentMethodGAppFlow
        dataLoad={{
          axios,
          endpoints: {
            getAll: `/api/public/merchants/${public_key}/mode-of-payments`,
          },
        }}
        dataIn={{
          dataLoadType: 'network-service',
          constructData,
          StackNavigator: MyNavigator,
          initialRouteName: 'PaymentMethod',
          screens,
        }}
        dataOut={handleDataOut}
      >
        {/* mini-app index 0 */}
        <MethodSelectionAccordion
          key="payment-method-accordion-list"
          dataLoad={[]}
          dataIn={{
            selectedPaymentMethod,
          }}
          dataOut={(value: any) => {}}
        />
        {/* mini-app index 1 */}
        <Text>Card Details</Text>
      </PaymentMethodGAppFlow>
    </View>
  );
};
export default PaymentMethodFlow;

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  box: {
    width: 60,
    height: 60,
    marginVertical: 20,
  },
});

Example (dataLoad='network-service-config')

import * as React from 'react';

import { StyleSheet, View } from 'react-native';
import MethodSelectionAccordion from '../payment-method-v3/MethodSelectionAccordion/MethodSelectionAccordion';

import { PaymentMethodGAppFlow } from 'serino-mobile-gapp-payment-method-flow';
import { Text } from 'react-native-paper';
import { MyNavigator } from '../App';

const PaymentMethodFlow = ({ navigation }: any) => {
  const [selectedPaymentMethod, setSelectedPaymentMethod] = React.useState({
    id: 1,
    text: 'Credit/Debit Card',
    value: 'Credit/Debit Card',
  });

  const public_key = 'pk-8c6axxxx-xxxx-xxxx-xxxx-xxxxxx120002';

  const screens = [
    // mini-app index 0
    {
      stackName: 'PaymentMethod',
      stackOptions: {
        title: 'Payment Method',
      },
    },
    // mini-app index 1
    {
      stackName: 'CardDetails',
      stackOptions: {
        title: 'Debit/Credit Card Details',
      },
    },
  ];

  const constructData = (item: any) => {
    return item.map((i: any) => ({
      id: i.id,
      text: i.name,
      value: i.name,
      subText: i.description,
      descriptionText: '', // i.description,
      isExpanded: i.expanded || false,
      child: i.merchant_processors?.map((d: any) => ({
        id: d.id,
        text: d.name,
        value: d.name,
        subText: d.description,
        descriptionText: '', //d.description,
        imageUri: d.icon_url || undefined,
      })),
    }));
  };

  const handleDataOut = (values: any) => {
    const paymentMethodDetails = values.paymentMethod?.id
      ? values.paymentMethod
      : selectedPaymentMethod;

    // set selected payment method
    setSelectedPaymentMethod(paymentMethodDetails);

    // If selected payment method is debit or credit card
    if (values.paymentMethod.id === 1) {
      console.log('values.paymentMethod.id', values.paymentMethod.id);
      // navigation.navigate('CardDetails');
      navigation.navigate('PaymentMethodFlow', { screen: 'CardDetails' });
    }
  };

  React.useLayoutEffect(() => {
    navigation.setOptions({
      headerShown: false,
    });
  }, [navigation]);

  return (
    <View style={styles.container}>
      <PaymentMethodGAppFlow
        dataLoad={{
          baseUrl: 'http://',
          endpoints: {
            getAll: `/api/public/merchants/${public_key}/mode-of-payments`,
          },
        }}
        dataIn={{
          dataLoadType: 'network-service-config',
          constructData,
          StackNavigator: MyNavigator,
          initialRouteName: 'PaymentMethod',
          screens,
        }}
        dataOut={handleDataOut}
      >
        {/* mini-app index 0 */}
        <MethodSelectionAccordion
          key="payment-method-accordion-list"
          dataLoad={[]}
          dataIn={{
            selectedPaymentMethod,
          }}
          dataOut={(value: any) => {}}
        />
        {/* mini-app index 1 */}
        <Text>Card Details</Text>
      </PaymentMethodGAppFlow>
    </View>
  );
};
export default PaymentMethodFlow;

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  box: {
    width: 60,
    height: 60,
    marginVertical: 20,
  },
});

License

MIT

1.0.12

2 years ago

1.0.11

2 years ago

1.0.10

2 years ago

1.0.9

2 years ago

1.0.8

2 years ago

1.0.7

2 years ago

1.0.6

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago