diff --git a/src/components/PaymentModal.tsx b/src/components/PaymentModal.tsx index de8c3f2..747cda3 100644 --- a/src/components/PaymentModal.tsx +++ b/src/components/PaymentModal.tsx @@ -1,4 +1,4 @@ -import { Dispatch, SetStateAction, useContext } from "react"; +import { Dispatch, SetStateAction } from "react"; import { TouchableOpacity, @@ -6,19 +6,9 @@ import { View, Image, StyleSheet, - Alert, - Keyboard, } from "react-native"; -import { t } from "i18next"; - -import { Actions, DispatchContext, StateContext } from "../context/state"; - -import { - paymentFailedCtaText, - paymentSuccessCtaText, -} from "../util/constants"; -import { ResponseScreenStatuses, ThemeSchemeType } from "../util/types"; +import { ThemeSchemeType } from "../util/types"; import closeIcon from "../assets/images/close.png"; @@ -28,6 +18,7 @@ import { useCurrentTheme } from "../theme/useCurrentTheme"; import KomojuText from "./KomojuText"; import ResponseScreen from "./ResponseScreen"; import SheetContent from "./SheetContent"; +import { usePaymentUiUtils } from "../hooks/usePaymentUiUtils"; type PaymentModalProps = { modalVisible: boolean; @@ -35,84 +26,25 @@ type PaymentModalProps = { onDismiss?: () => void; }; -const PaymentModal = ({ +const PaymentModal: React.FC = ({ modalVisible, setModalVisible, onDismiss, -}: PaymentModalProps) => { - const { paymentState, paymentType } = useContext(StateContext); - const dispatch = useContext(DispatchContext); +}) => { + const { + paymentState, + paymentType, + closeSheet, + getCtaText, + ctaOnPress, + shouldShowAlert, + } = usePaymentUiUtils(onDismiss); const theme = useCurrentTheme(); const styles = getStyles(theme); - 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: - case ResponseScreenStatuses.COMPLETE: - case ResponseScreenStatuses.CANCELLED: - case ResponseScreenStatuses.EXPIRED: - return paymentSuccessCtaText; - case ResponseScreenStatuses.FAILED: - return paymentFailedCtaText; - default: - return ""; - } - }; - - const ctaOnPress = () => { - switch (paymentState) { - case ResponseScreenStatuses.SUCCESS: - case ResponseScreenStatuses.COMPLETE: - case ResponseScreenStatuses.CANCELLED: - return closeSheet(false); - case ResponseScreenStatuses.EXPIRED: - return closeSheet(false); - case ResponseScreenStatuses.FAILED: - return dispatch({ - type: Actions.SET_PAYMENT_STATE, - payload: "", - }); - default: - return ""; - } - }; - - const onCloseModal = () => { - closeSheet( - !( - paymentState === ResponseScreenStatuses.SUCCESS || - paymentState === ResponseScreenStatuses.CANCELLED || - paymentState === ResponseScreenStatuses.COMPLETE || - paymentState === ResponseScreenStatuses.EXPIRED - ) - ); + const handleClose = () => { + closeSheet(shouldShowAlert(), () => setModalVisible(false)); }; return ( @@ -120,25 +52,23 @@ const PaymentModal = ({ animationType="slide" presentationStyle="overFullScreen" visible={modalVisible} - onRequestClose={onCloseModal} + onRequestClose={handleClose} > - + {!paymentState ? "PAYMENT_OPTIONS" : ""} - - + + {paymentState ? ( ctaOnPress(() => setModalVisible(false))} onPressLabel={getCtaText()} paymentType={paymentType} /> diff --git a/src/components/Sheet.tsx b/src/components/Sheet.tsx index f310599..50166ba 100644 --- a/src/components/Sheet.tsx +++ b/src/components/Sheet.tsx @@ -1,14 +1,12 @@ import React, { useCallback, useImperativeHandle, - useContext, useRef, useEffect, ForwardRefRenderFunction, } from "react"; import { - Alert, Image, StyleSheet, TouchableOpacity, @@ -19,18 +17,9 @@ import { import { useTranslation } from "react-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 { 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"; @@ -38,6 +27,7 @@ import { useCurrentTheme } from "../theme/useCurrentTheme"; import KomojuText from "./KomojuText"; import ResponseScreen from "./ResponseScreen"; import SheetContent from "./SheetContent"; +import { usePaymentUiUtils } from "../hooks/usePaymentUiUtils"; const MAX_TRANSLATE_Y = -WINDOW_HEIGHT + responsiveScale(50); @@ -67,11 +57,17 @@ const Sheet: ForwardRefRenderFunction = ( const translateYState = useRef(0); const contextState = useRef(0); - const { paymentState, paymentType } = useContext(StateContext); - const dispatch = useContext(DispatchContext); + const { + paymentState, + paymentType, + closeSheet, + getCtaText, + ctaOnPress, + shouldShowAlert, + } = usePaymentUiUtils(onDismiss); + const theme = useCurrentTheme(); const styles = getStyles(theme); - const { mode } = useTheme(); useEffect(() => { const yListener = translateY.addListener(({ value }) => { @@ -104,32 +100,9 @@ const Sheet: ForwardRefRenderFunction = ( return activeState.current; }, []); - 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"), - onPress: () => scrollTo(MAX_TRANSLATE_Y + 50), - style: "cancel", - }, - { - text: t("YES"), - onPress: () => { - // invoking client provided onDismiss() callback when closing the SDK modal - onDismiss && onDismiss(); - scrollTo(0); - }, - }, - ]); - } else { - // invoking client provided callback when closing the SDK modal - onDismiss && onDismiss(); - scrollTo(0); - } - }; + const handleClose = useCallback((forceClose = false) => { + closeSheet(shouldShowAlert() && !forceClose, () => scrollTo(0)); + }, [closeSheet, shouldShowAlert, scrollTo]); useImperativeHandle( ref, @@ -138,11 +111,11 @@ const Sheet: ForwardRefRenderFunction = ( Keyboard.dismiss(); scrollTo(MAX_TRANSLATE_Y + 50); }, - close: closeSheet, + close: handleClose, scrollTo, isActive, }), - [scrollTo, isActive] + [scrollTo, isActive, handleClose] ); const panResponder = useRef( @@ -157,7 +130,7 @@ const Sheet: ForwardRefRenderFunction = ( }, onPanResponderRelease: () => { if (translateYState.current > -WINDOW_HEIGHT / 1.5) { - closeSheet(false); + handleClose(false); } else if (translateYState.current < -WINDOW_HEIGHT / 1.5) { scrollTo(MAX_TRANSLATE_Y + 50); } @@ -165,40 +138,11 @@ const Sheet: ForwardRefRenderFunction = ( }) ).current; - const getCtaText = () => { - switch (paymentState) { - case ResponseScreenStatuses.SUCCESS: - case ResponseScreenStatuses.COMPLETE: - case ResponseScreenStatuses.CANCELLED: - return paymentSuccessCtaText; - case ResponseScreenStatuses.FAILED: - return paymentFailedCtaText; - default: - return ""; - } - }; - - const ctaOnPress = () => { - switch (paymentState) { - case ResponseScreenStatuses.SUCCESS: - case ResponseScreenStatuses.COMPLETE: - case ResponseScreenStatuses.CANCELLED: - return closeSheet(false); - case ResponseScreenStatuses.FAILED: - return dispatch({ - type: Actions.SET_PAYMENT_STATE, - payload: "", - }); - default: - return ""; - } - }; - return ( <> { - if (swipeClose) closeSheet(false); + if (swipeClose) handleClose(true); }} pointerEvents="none" style={[styles.backDrop, { opacity: active }]} @@ -210,28 +154,20 @@ const Sheet: ForwardRefRenderFunction = ( ]} > - PAYMENT_OPTIONS + + {!paymentState ? t("PAYMENT_OPTIONS") : ""} + - closeSheet( - !( - paymentState === ResponseScreenStatuses.SUCCESS || - paymentState === ResponseScreenStatuses.CANCELLED || - paymentState === ResponseScreenStatuses.COMPLETE - ) - ) - } + onPress={() => handleClose()} > - + {paymentState ? ( ctaOnPress(() => scrollTo(0))} onPressLabel={getCtaText()} paymentType={paymentType} /> diff --git a/src/hooks/usePaymentUiUtils.tsx b/src/hooks/usePaymentUiUtils.tsx new file mode 100644 index 0000000..2db1f7c --- /dev/null +++ b/src/hooks/usePaymentUiUtils.tsx @@ -0,0 +1,87 @@ +import { useCallback, useContext } from "react"; +import { Alert, Keyboard } from "react-native"; +import { useTranslation } from "react-i18next"; +import { Actions, DispatchContext, StateContext } from "../context/state"; +import { + paymentFailedCtaText, + paymentSuccessCtaText, +} from "../util/constants"; +import { ResponseScreenStatuses } from "../util/types"; + +export const usePaymentUiUtils = (onDismiss?: () => void) => { + const { t } = useTranslation(); + const { paymentState, paymentType } = useContext(StateContext); + const dispatch = useContext(DispatchContext); + + const closeSheet = useCallback((showAlert = true, onClose: () => void) => { + Keyboard.dismiss(); + + if (showAlert) { + Alert.alert(`${t("CANCEL_PAYMENT")}?`, "", [ + { + text: t("NO"), + style: "cancel", + }, + { + text: t("YES"), + onPress: () => { + onDismiss && onDismiss(); + onClose(); + }, + }, + ]); + } else { + onDismiss && onDismiss(); + onClose(); + } + }, [onDismiss, t]); + + const getCtaText = useCallback(() => { + switch (paymentState) { + case ResponseScreenStatuses.SUCCESS: + case ResponseScreenStatuses.COMPLETE: + case ResponseScreenStatuses.CANCELLED: + case ResponseScreenStatuses.EXPIRED: + return paymentSuccessCtaText; + case ResponseScreenStatuses.FAILED: + return paymentFailedCtaText; + default: + return ""; + } + }, [paymentState]); + + const ctaOnPress = useCallback((onClose: () => void) => { + switch (paymentState) { + case ResponseScreenStatuses.SUCCESS: + case ResponseScreenStatuses.COMPLETE: + case ResponseScreenStatuses.CANCELLED: + case ResponseScreenStatuses.EXPIRED: + return closeSheet(false, onClose); + case ResponseScreenStatuses.FAILED: + return dispatch({ + type: Actions.SET_PAYMENT_STATE, + payload: "", + }); + default: + return ""; + } + }, [paymentState, dispatch, closeSheet]); + + const shouldShowAlert = useCallback(() => { + return !( + paymentState === ResponseScreenStatuses.SUCCESS || + paymentState === ResponseScreenStatuses.CANCELLED || + paymentState === ResponseScreenStatuses.COMPLETE || + paymentState === ResponseScreenStatuses.EXPIRED + ); + }, [paymentState]); + + return { + paymentState, + paymentType, + closeSheet, + getCtaText, + ctaOnPress, + shouldShowAlert, + }; +}; \ No newline at end of file