From 9984398dd888d7edaaf83876fab8c78b1e38cf60 Mon Sep 17 00:00:00 2001 From: Tharindu Kumarasiri Date: Thu, 8 Aug 2024 00:58:41 +0530 Subject: [PATCH] Payment Modal added --- payment_sdk/src/components/PaymentModal.tsx | 185 ++++++++++++++++++ payment_sdk/src/context/KomojuProvider.tsx | 1 + payment_sdk/src/context/MainStateProvider.tsx | 36 +++- payment_sdk/src/util/types.ts | 1 + 4 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 payment_sdk/src/components/PaymentModal.tsx diff --git a/payment_sdk/src/components/PaymentModal.tsx b/payment_sdk/src/components/PaymentModal.tsx new file mode 100644 index 0000000..2a382cd --- /dev/null +++ b/payment_sdk/src/components/PaymentModal.tsx @@ -0,0 +1,185 @@ +import React, { Dispatch, SetStateAction, useContext } from "react"; + +import { + TouchableOpacity, + Modal, + View, + Image, + StyleSheet, + Alert, + Keyboard, +} from "react-native"; + +import { t } from "i18next"; + +import { Actions, DispatchContext, StateContext } from "@context/state"; +import { useTheme } from "@context/ThemeContext"; + +import { + paymentFailedCtaText, + paymentSuccessCtaText, + ThemeModes, +} from "@util/constants"; +import { ResponseScreenStatuses, ThemeSchemeType } from "@util/types"; + +import closeIcon from "@assets/images/close.png"; +import closeDMIcon from "@assets/images/close_dm.png"; + +import { resizeFonts, responsiveScale, WINDOW_HEIGHT } from "@theme/scalling"; +import { useCurrentTheme } from "@theme/useCurrentTheme"; + +import KomojuText from "./KomojuText"; +import ResponseScreen from "./ResponseScreen"; +import SheetContent from "./SheetContent"; + +type PaymentModalProps = { + modalVisible: boolean; + setModalVisible: Dispatch>; + onDismiss?: () => void; +}; + +const PaymentModal = ({ + modalVisible, + setModalVisible, + onDismiss, +}: PaymentModalProps) => { + const { paymentState } = useContext(StateContext); + const dispatch = useContext(DispatchContext); + + const theme = useCurrentTheme(); + const styles = getStyles(theme); + const { mode } = useTheme(); + + const closeSheet = (showAlert = true) => { + Keyboard.dismiss(); + + if (showAlert) { + // showing an alert when user try to close the SDK modal + Alert.alert(`${t("CANCEL_PAYMENT")}?`, "", [ + { + text: t("NO"), + style: "cancel", + }, + { + text: t("YES"), + onPress: () => { + // invoking client provided onDismiss() callback when closing the SDK modal + onDismiss && onDismiss(); + setModalVisible(false); + }, + }, + ]); + } else { + // invoking client provided callback when closing the SDK modal + onDismiss && onDismiss(); + setModalVisible(false); + } + }; + + const getCtaText = () => { + switch (paymentState) { + case ResponseScreenStatuses.SUCCESS: + return paymentSuccessCtaText; + case ResponseScreenStatuses.FAILED: + return paymentFailedCtaText; + default: + return ""; + } + }; + + const ctaOnPress = () => { + switch (paymentState) { + case ResponseScreenStatuses.SUCCESS: + return closeSheet(false); + case ResponseScreenStatuses.FAILED: + return dispatch({ + type: Actions.SET_PAYMENT_STATE, + payload: "", + }); + default: + return ""; + } + }; + + const onCloseModal = () => { + closeSheet( + !( + paymentState === ResponseScreenStatuses.SUCCESS || + // TODO: Fix this type error + // @ts-expect-error - Property 'COMPLETE' does not exist on type 'ResponseScreenStatuses'. + paymentState === ResponseScreenStatuses.COMPLETE + ) + ); + }; + + return ( + + + + + + PAYMENT_OPTIONS + + + + + { + // TODO: Fix this type error + // @ts-expect-error - Property 'COMPLETE' does not exist on type 'ResponseScreenStatuses'. + paymentState && paymentState !== ResponseScreenStatuses.COMPLETE ? ( + + ) : ( + + ) + } + + + ); +}; + +const getStyles = (theme: ThemeSchemeType) => { + return StyleSheet.create({ + container: { + flex: 1, + backgroundColor: theme.WHITE50, + }, + bottomSheetContainer: { + height: WINDOW_HEIGHT - 85, + width: "100%", + backgroundColor: theme.BACKGROUND_COLOR, + }, + line: { + flexDirection: "row", + alignItems: "center", + marginVertical: responsiveScale(20), + marginHorizontal: responsiveScale(16), + }, + headerLabel: { + fontSize: resizeFonts(18), + fontWeight: "bold", + flex: 1, + alignItems: "center", + textAlign: "center", + color: theme.TEXT_COLOR, + }, + crossBtn: { + position: "absolute", + right: 0, + padding: responsiveScale(10), + fontSize: resizeFonts(16), + }, + }); +}; + +export default PaymentModal; diff --git a/payment_sdk/src/context/KomojuProvider.tsx b/payment_sdk/src/context/KomojuProvider.tsx index d52cdee..ec4a834 100644 --- a/payment_sdk/src/context/KomojuProvider.tsx +++ b/payment_sdk/src/context/KomojuProvider.tsx @@ -15,6 +15,7 @@ export const KomojuProvider = (props: KomojuProviderIprops) => { publicKey={props.publicKey} payment_methods={props?.payment_methods} language={props?.language} + useBottomSheet={props?.useBottomSheet} > {props.children} diff --git a/payment_sdk/src/context/MainStateProvider.tsx b/payment_sdk/src/context/MainStateProvider.tsx index 902a317..2e93934 100644 --- a/payment_sdk/src/context/MainStateProvider.tsx +++ b/payment_sdk/src/context/MainStateProvider.tsx @@ -4,12 +4,14 @@ import React, { useEffect, useMemo, useRef, + useState, } from "react"; import { Alert, Linking } from "react-native"; import i18next from "i18next"; +import PaymentModal from "@components/PaymentModal"; import Sheet, { SheetRefProps } from "@components/Sheet"; import payForSession from "@services/payForSessionService"; @@ -32,6 +34,7 @@ import { Actions, DispatchContext, KomojuContext } from "./state"; export const MainStateProvider = (props: KomojuProviderIprops) => { const dispatch = useContext(DispatchContext); + const [modalVisible, setModalVisible] = useState(false); const sheetRef = useRef(null); // ref to hold client provided onComplete callback @@ -53,6 +56,21 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { }; }, []); + const openPaymentSheet = () => { + if (props?.useBottomSheet) { + sheetRef?.current?.open(); + } else { + setModalVisible(true); + } + }; + + const closePaymentSheet = () => { + // TODO: Fix this type error + // @ts-expect-error - Object is possibly 'null'. + sheetRef?.current?.close(false); + setModalVisible(false); + }; + // when payment is success global state is rest and invoking the success screen const onPaymentSuccess = () => { dispatch({ @@ -122,9 +140,7 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { // validating the session data and closing the payment gateway if data is not valid if (validateSessionResponse(sessionData)) { - // TODO: Fix this type error - // @ts-expect-error - Object is possibly 'null'. - sheetRef?.current?.close(false); + closePaymentSheet(); Alert.alert("Error", "Invalid Session"); } else { // if explicitly language is not set. set to the localization from session @@ -253,7 +269,7 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { sessionId, }), }); - sheetRef?.current?.open(); + openPaymentSheet(); }, [props] ); @@ -267,9 +283,17 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { const initializeKomoju = useCallback((params: InitPrams) => {}, []); const renderPaymentUI = useMemo(() => { - const UI = ; + const UI = props?.useBottomSheet ? ( + + ) : ( + + ); return UI; - }, [sheetRef]); + }, [sheetRef, modalVisible]); const renderChildren = useMemo(() => props?.children, [props.children]); diff --git a/payment_sdk/src/util/types.ts b/payment_sdk/src/util/types.ts index caa215a..f46503b 100644 --- a/payment_sdk/src/util/types.ts +++ b/payment_sdk/src/util/types.ts @@ -4,6 +4,7 @@ export type InitPrams = { publicKey: string; payment_methods?: Array; language?: LanguageTypes; + useBottomSheet?: boolean; }; export type CreatePaymentFuncType = {