1.0.10 • Published 1 year ago

gapp-checkout v1.0.10

Weekly downloads
-
License
MIT
Repository
-
Last release
1 year ago

Checkout GApp Flow

GApp Flow for Checkout

Installation

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

Changelogs

See the Change logs

Dependecies

  • npm install axios
  • npm install crypto-js

(CheckoutGAppFlow) DataLoad Props

PropRequiredTypeDescription
axiosOrderNoAxiosInstanceset axios instance for order api. Applicable for dataloadType=network-service
axiosCheckoutNoAxiosInstanceset axios instance for checkout api. Applicable for dataloadType=network-service
endpointsNoobjectendpoint for checkout api. Applicable for dataloadType=network-service or network-service-config
baseUrlNoobjectbaseurl for getAll endpoint. Applicable for dataloadType=network-service-config
payloadNoobjectpayload request. Applicable for dataloadType=network-service or network-service-config
requestParamsNoobjectApplicable 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

(CheckoutGAppFlow) DataIn Props

PropRequiredTypeDescription
dataLoadTypeYesnetwork-service,network-service-configchoices what dataLoad should be apply
constructOrderPayloadYesfunctionfunction that reconstruct order payload. should return details.
constructCheckoutPayloadNofunctionfunction that reconstruct checkout payload. should return details.
initialRouteNameNostringinitialRouteName for StackNavigator
screensNoarray of objectsmodify mini-app and gapp. able to use with the combination of Stack

(dataLoad > baseUrl) Props

PropRequiredTypeDescription
orderNostringbase url for order. Applicable for dataloadType=network-service-config
checkoutNostringbase url for checkout. Applicable for dataloadType=network-service-config

(dataLoad > endpoints) Props

PropRequiredTypeDescription
postOrderNostringendpoint for order. Applicable for dataloadType=network-service-config
postCheckoutNostringendpoint for checkout. Applicable for dataloadType=network-service-config

(dataLoad > payload) Props

PropRequiredTypeDescription
payeeYesstringcustomer full name
first_nameYesstringcustomer first name
last_nameYesstringcustomer last name
contact_numberYesstringcustomer contact number
emailYesstringcustomer email
regionYesstringregion
barangayYesstringbarangay
streetYesstringstreet
building_nameYesstringbuilding name
landmarkYesstringnearest landmark
payment_methodYesstringpayment method
subtotalYesnumberorder subtotal
discountYesnumbervoucher discount
shopee_feeYesnumbershopee fee
delivery_feeYesnumberdelivery fee
total_amountYesnumbertotal amount
itemsYesarray of objectorder items
merchant_transaction_referenceYesstringmerchant transaction reference
merchant_processor_idYesnumbermerchant processor id
processorYesobjectprocessor
any property nameNoanythe res payload values.

(dataLoad > payload > items) Props

PropRequiredTypeDescription
nameYesstringproduct name
descriptionYesstringproduct description
quantityYesnumberproduct quantity
priceYesnumberprod'
uct price
any property nameNoanythe res payload values.

(dataLoad > payload > processor) Props

PropRequiredTypeDescription
tokenYesstringprocessor token
redirect_urlYesstringprocessor redirect url

(dataLoad > payload > processor > redirect_url) Props

PropRequiredTypeDescription
successYesstringprocessor success redirect url
failureYesstringprocessor failure redirect url
cancelYesstringprocessor cancel redirect url

(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

useViewModel returned value

    'customer-details':{
      dataIn: {
        fullName, // payload > payee
        firstName, // payload > first_name
        lastName, // payload > last_name
        contactNumber, // payload > contact_number
        email,
        region,
        city,
        barangay,
        street,
        buildingName, // payload > building_name
        landmark,
      }
    },
    'order-items': {
      dataIn: {
        items, // order items
      },
    },
    'payment-method': {
      dataIn: {
        label, // payload > payment_method; payment method label
      },
    },
    'order-summary': {
      dataIn: {
        subTotal, // payload > subtotal
        voucherDiscount, // payload > discount
        shopperFee, // payload > shopee_fee
        deliveryFee, // payload > delivery_fee
        grandTotal, // payload > total_amount
      },
    },
    'submit-order': {
      dataIn: {
        disabled, // true or false
        loading, // true or false
      },
      dataOut, // function to apply order & checkout api
    }

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 (dataLoadType="network-service")

axiosCheckout.tsx

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

const onRequest = (config: AxiosRequestConfig): AxiosRequestConfig => {
  const token = '';
  config.headers.Authorization = `Bearer ${token}`;
  config.headers['x-public-key'] = '';

  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);
};

const axiosCheckout = axios.create({
  baseURL: 'https://....',
});

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

export default axiosCheckout;

Checkout Screen

import * as React from 'react';
import { Button, Text } from 'react-native-paper';
import { CheckoutGAppFlow } from 'serino-mobile-gapp-checkout-flow';
import { GlobalContext } from '../context/GlobalContext';
import axiosCart from '../library/axiosCart';
import axiosCheckout from '../library/axiosCheckout';
import axiosOrder from '../library/axiosOrder';
import OrderItems from '../components/Cart/OrderedItems';
import OrderSummary from '../components/Cart/OrderSummary';
import checkoutJsonStab from '../json-stab/place-order copy.json';

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

  const reconstructOrderPayload = (values: any) => {
    return {
      orders: [
        {
          action_to_proceed:
            values.action_to_proceed ||
            'Cancel the whole order if any item is out of stock',
          cart_id: values.cart_id || 'a89b5c67-4c19-40e0-a81b-062523a078fb',
          change_for: values.total_amount || '0',
          customer: {
            contact_number: values.contact_number || '+639876546231',
            email: values.email || 'ej.dalman@serino.com',
            first_name: values.first_name || 'Ej',
            last_name: values.last_name || 'Dalman',
            reference_1: values.reference_1 || '',
            reference_2: values.reference_2 || '',
            reference_3: values.reference_3 || '',
          },
          fulfillment_type: values.fulfillment_type || 'deliver later',
          items: values.items,
          merchant_reference_id: values.merchant_reference_id || 'market',
          notes: [{ type: 'Order Notes', notes: '' }],
          platform: 'Web',
          platform_details:
            values.platform_details ||
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36',
          promo_reference_id: '',
          reference_1: '',
          reference_2: '',
          reference_3: '',
          reservation_reference: 'branch_advance_6',
          schedule: '2023-02-28 10:30:0',
          shipping_address: {
            barangay: '',
            city: '',
            details: '',
            full_address:
              'BLK 10 LOT 10 SAMPAGUITA STREET, Bel-Air, Makati, Metro Manila, Philippines',
            landmark: '',
            latitude: 14.554729,
            longitude: 121.0244452,
            pinned_address: 'Makati, Metro Manila, Philippines',
            region: '',
            street: '',
            zip_code: '',
          },
          source: 'Central PH',
          store_reference_id: '6',
        },
      ],
      payment: {
        type: values.payment_method_type,
        option: values.payment_method,
      },
    };
  };

  const payload = {
    ...checkoutJsonStab,
    payment_method_type:
      context.paymentMethod?.parent_type || context.paymentMethod?.type,
    payment_method: context.paymentMethod?.text,
    merchant_processor_id: context.paymentMethod?.id,
    merchant_transaction_reference: 'CENTRAL03411',
    processor: {
      token: '',
      redirect_url: {
        success:
          'https://ordering.com/CENTRAL03411/payment-result?status=sucess',
        failure:
          'https://ordering.com/CENTRAL03411/payment-result?status=failure',
        cancel:
          'https://ordering.com/CENTRAL03411/payment-result?status=cancel',
      },
    },
    items: context?.cartDetails.items.map((d: any) => {
      const customData = JSON.parse(d.custom_data);
      const barcodeDetails = customData
        ? customData.find((c: any) => c.name === 'barcode')
        : {};
      return {
        barcode: barcodeDetails.value || '28400017503',
        description:
          d.itemDescription ||
          '<p>Frito Lay it all start with farm grown potatoes cooked and seasoned to perfection, Then we add just the right balanced of tangly Vinegar. So every Lays potato is perfectly crispy and delicious happiness in every bite.</p>\n<ul>\n<li>No Artificial Flavours</li>\n<li>No Preservatives</li>\n</ul>\n<p><strong>Ingredients:</strong><br />Potatoes, Vegetable Oil (Sunflower, corn and/or Canola Oil), Salt &amp; Vinegar Seasoning (Maltodextrin made from corn, Natural Flavours, Salt, Malic Acid and Vinegar).</p>',
        image:
          d.itemImage ||
          'https://qa-centralmain.s3.ap-southeast-1.amazonaws.com/thumbnails/28400017503-01_8_thumbnail.jpg',
        instructions: d.instructions || '',
        name: d.itemName || 'Lays Salt & Vinegar Potato Chips 184.2g',
        options: '',
        price: d.price ? parseFloat(d.price) : 167.95,
        quantity: d.quantity || 1,
        reference_1: '',
        reference_2: '',
        reference_3: '',
        reference_id: d.itemReferenceId || '24698',
        sku: d.itemSKU || '105146',
        type: d.itemReferenceType || 'basic_product',
        weight: 0,
        weight_price_per_unit: 0,
        weight_uom: '',
      };
    }),
  };
  const public_key = 'pk-8c6a927a-972f-11ed-a8fc-0242ac120002';

  const handleDataOut = (values: any) => {
    console.log('checkout DATAOUT', values);
  };

  const fetchCart = React.useCallback(async () => {
    try {
      const res: any = await axiosCart.get('/cart');
      context.setContext({
        ...context,
        cartDetails: {
          ...context?.cartDetails,
          items: res?.data?.data,
        },
      });
    } catch (err: any) {}
  }, []);

  // life-cycle method to get cart details
  React.useEffect(() => {
    fetchCart();
  }, []);

  return (
    <React.Fragment>
      <CheckoutGAppFlow
        dataLoad={{
          axiosCheckout: axiosCheckout,
          axiosOrder: axiosOrder,
          endpoints: {
            postOrder: '/public/create',
            postCheckout: `/api/public/merchants/${public_key}/checkout`,
          },
          payload: payload,
        }}
        dataIn={{
          dataLoadType: 'network-service',
          constructOrderPayload: reconstructOrderPayload,
        }}
        dataOut={handleDataOut}
      >
        <OrderItems key="order-items" dataIn={{ navigation }} />
        <SelectPaymentMethod
          key="payment-method"
          dataIn={{
            label: context.paymentMethod?.text
              ? context.paymentMethod.text
              : 'Select Payment Method',
          }}
          dataOut={() => {
            navigation.navigate('PaymentMethodFlow');
          }}
        />
        <OrderSummary
          key="order-summary"
          dataIn={{
            subTotal: 0,
            voucherDiscount: 0,
            showPickupDiscount: false,
            pickupDiscount: 0,
            showShopperFee: false,
            shopperFee: 0,
            showDeliveryFee: false,
            deliveryFee: 0,
          }}
        />
        <CheckoutButton
          key="submit-order"
          dataIn={{ label: 'Pay Now' }}
          dataOut={() => {}}
        />
      </CheckoutGAppFlow>
    </React.Fragment>
  );
};

const CheckoutButton = (props: any) => {
  return (
    <Button
      mode={props?.dataIn?.mode || 'contained'}
      disabled={props?.dataIn?.disabled || props?.dataIn?.loading}
      onPress={props?.dataOut}
    >
      {props?.dataIn?.loading ? 'Loading...' : props?.dataIn?.label}
    </Button>
  );
};

const SelectPaymentMethod = ({ dataIn, dataOut }: any) => {
  return (
    <React.Fragment>
      <Text>Select Payment method</Text>
      <CheckoutButton
        dataIn={{
          label: dataIn.label,
          mode: 'outlined',
        }}
        dataOut={dataOut}
      />
    </React.Fragment>
  );
};

export default Checkout;

License

MIT

1.0.10

1 year ago

1.0.9

1 year ago

1.0.7

1 year ago

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago