Skip to content

Commit

Permalink
Merge pull request #50 from degica/task/MOB-38
Browse files Browse the repository at this point in the history
Payment Modal added
  • Loading branch information
tharindu-rhino authored Aug 8, 2024
2 parents 4cb3d51 + 9984398 commit 773eed2
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 6 deletions.
185 changes: 185 additions & 0 deletions payment_sdk/src/components/PaymentModal.tsx
Original file line number Diff line number Diff line change
@@ -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<SetStateAction<boolean>>;
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 (
<Modal
animationType="slide"
presentationStyle="overFullScreen"
visible={modalVisible}
onRequestClose={onCloseModal}
>
<TouchableOpacity onPress={onCloseModal} style={styles.container} />

<View style={styles.bottomSheetContainer}>
<View style={styles.line}>
<KomojuText style={styles.headerLabel}>PAYMENT_OPTIONS</KomojuText>
<TouchableOpacity style={styles.crossBtn} onPress={onCloseModal}>
<Image
source={mode === ThemeModes.light ? closeIcon : closeDMIcon}
/>
</TouchableOpacity>
</View>
{
// TODO: Fix this type error
// @ts-expect-error - Property 'COMPLETE' does not exist on type 'ResponseScreenStatuses'.
paymentState && paymentState !== ResponseScreenStatuses.COMPLETE ? (
<ResponseScreen
status={paymentState}
onPress={ctaOnPress}
onPressLabel={getCtaText()}
/>
) : (
<SheetContent />
)
}
</View>
</Modal>
);
};

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;
1 change: 1 addition & 0 deletions payment_sdk/src/context/KomojuProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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}
</MainStateProvider>
Expand Down
36 changes: 30 additions & 6 deletions payment_sdk/src/context/MainStateProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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<SheetRefProps>(null);
// ref to hold client provided onComplete callback
Expand All @@ -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({
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -253,7 +269,7 @@ export const MainStateProvider = (props: KomojuProviderIprops) => {
sessionId,
}),
});
sheetRef?.current?.open();
openPaymentSheet();
},
[props]
);
Expand All @@ -267,9 +283,17 @@ export const MainStateProvider = (props: KomojuProviderIprops) => {
const initializeKomoju = useCallback((params: InitPrams) => {}, []);

const renderPaymentUI = useMemo(() => {
const UI = <Sheet ref={sheetRef} onDismiss={onUserCancel} />;
const UI = props?.useBottomSheet ? (
<Sheet ref={sheetRef} onDismiss={onUserCancel} />
) : (
<PaymentModal
modalVisible={modalVisible}
setModalVisible={setModalVisible}
onDismiss={onUserCancel}
/>
);
return UI;
}, [sheetRef]);
}, [sheetRef, modalVisible]);

const renderChildren = useMemo(() => props?.children, [props.children]);

Expand Down
1 change: 1 addition & 0 deletions payment_sdk/src/util/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type InitPrams = {
publicKey: string;
payment_methods?: Array<PaymentType>;
language?: LanguageTypes;
useBottomSheet?: boolean;
};

export type CreatePaymentFuncType = {
Expand Down

0 comments on commit 773eed2

Please sign in to comment.