diff --git a/src/assets/images/loader_animation.gif b/src/assets/images/loader_animation.gif new file mode 100644 index 0000000..d4f4377 Binary files /dev/null and b/src/assets/images/loader_animation.gif differ diff --git a/src/assets/images/lock_image.png b/src/assets/images/lock_image.png new file mode 100644 index 0000000..0cd562e Binary files /dev/null and b/src/assets/images/lock_image.png differ diff --git a/src/assets/images/success_animation.gif b/src/assets/images/success_animation.gif new file mode 100644 index 0000000..3579ee9 Binary files /dev/null and b/src/assets/images/success_animation.gif differ diff --git a/src/assets/languages/en.json b/src/assets/languages/en.json index f46ee07..033e897 100644 --- a/src/assets/languages/en.json +++ b/src/assets/languages/en.json @@ -51,6 +51,7 @@ "SESSION_EXPIRED_MSG": "This session has already expired. Please try again.", "PAYMENT_WAITING": "Awaiting Payment", "PAYMENT_WAITING_MSG": "Your payment has not been completed yet. We have e-mailed you the instructions on how to complete your purchase.", + "LOADING_TEXT": "Processing...", "PAYMENT_VIA_ALI_PAY": "Payment via Alipay", "ALI_PAY_REDIRECT_MESSAGE": "You will be redirected to Alipay to complete the payment", diff --git a/src/assets/languages/ja.json b/src/assets/languages/ja.json index ab2fc53..40f104b 100644 --- a/src/assets/languages/ja.json +++ b/src/assets/languages/ja.json @@ -51,6 +51,7 @@ "SESSION_EXPIRED_MSG": "このセッションは既に期限切れです。再度お試しください。", "PAYMENT_WAITING": "支払い待ち", "PAYMENT_WAITING_MSG": "支払いは完了していません。支払い方法の詳細をメールアドレス宛にお送りしていますのでご確認ください。", + "LOADING_TEXT": "処理...", "PAYMENT_VIA_ALI_PAY": "Alipayによる支払い", "ALI_PAY_REDIRECT_MESSAGE": "支払いを完了するには、Alipay にリダイレクトされます。", diff --git a/src/components/Button.tsx b/src/components/Button.tsx new file mode 100644 index 0000000..57adab7 --- /dev/null +++ b/src/components/Button.tsx @@ -0,0 +1,73 @@ +import { StyleSheet, Text, TouchableOpacity, Keyboard } from "react-native"; + +import { useTranslation } from "react-i18next"; + +import { ThemeSchemeType } from "../util/types"; + +import { resizeFonts, responsiveScale } from "../theme/scalling"; +import { useCurrentTheme } from "../theme/useCurrentTheme"; +import { ReactNode } from "react"; + +type Props = { + onPress: () => void; + label: string; + labelSuffix?: string; + testID?: string; + style?: object; + disabled?: boolean; + children?: ReactNode; +}; + +const Button = ({ + label, + labelSuffix, + onPress, + testID, + style, + disabled = false, + children, +}: Props) => { + const { t } = useTranslation(); + const theme = useCurrentTheme(); + const styles = getStyles(theme); + + const onSubmit = () => { + Keyboard.dismiss(); + onPress(); + }; + + return ( + + + {labelSuffix ? `${t(label)} ${labelSuffix}` : t(label)} + + {children} + + ); +}; + +export default Button; + +const getStyles = (theme: ThemeSchemeType) => { + return StyleSheet.create({ + buttonWrapper: { + backgroundColor: theme.PRIMARY_COLOR, + borderRadius: responsiveScale(8), + height: responsiveScale(50), + marginHorizontal: responsiveScale(16), + flex: 1, + justifyContent: "center", + alignItems: "center", + }, + label: { + color: "white", + fontSize: resizeFonts(16), + fontWeight: "bold", + }, + }); +}; diff --git a/src/components/Input.tsx b/src/components/Input.tsx index 626b5a8..b5b8b5a 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useContext } from "react"; import { View, @@ -13,10 +13,11 @@ import { import { useTranslation } from "react-i18next"; -import { ThemeSchemeType } from "../util/types"; +import { ResponseScreenStatuses, ThemeSchemeType } from "../util/types"; import { resizeFonts, responsiveScale } from "../theme/scalling"; import { useCurrentTheme } from "../theme/useCurrentTheme"; +import { StateContext } from "../context/state"; interface InputProps extends TextInputProps { value: string; @@ -42,6 +43,8 @@ const Input: React.FC = ({ keyboardType, ...rest }: InputProps) => { + const { loading, paymentState } = useContext(StateContext); + const { t } = useTranslation(); const theme = useCurrentTheme(); const styles = getStyles(theme); @@ -57,11 +60,14 @@ const Input: React.FC = ({ placeholderTextColor={theme.INPUT_PLACEHOLDER} style={[ styles.input, - styles.withBorder, error && styles.withErrorBorder, + (loading?.payment || + paymentState === ResponseScreenStatuses.SUCCESS) && + styles.disabledStyles, inputStyle, ]} testID={testID} + editable={!loading?.payment} {...rest} /> {error && errorText && ( @@ -99,7 +105,9 @@ const getStyles = (theme: ThemeSchemeType) => { color: theme.ERROR, zIndex: 2, }, - withBorder: {}, + disabledStyles: { + color: theme.INPUT_PLACEHOLDER, + }, }); }; diff --git a/src/components/PaymentModal.tsx b/src/components/PaymentModal.tsx index 747cda3..d88243c 100644 --- a/src/components/PaymentModal.tsx +++ b/src/components/PaymentModal.tsx @@ -1,14 +1,8 @@ import { Dispatch, SetStateAction } from "react"; -import { - TouchableOpacity, - Modal, - View, - Image, - StyleSheet, -} from "react-native"; +import { TouchableOpacity, Modal, View, Image, StyleSheet } from "react-native"; -import { ThemeSchemeType } from "../util/types"; +import { PaymentMode, sessionDataType, ThemeSchemeType } from "../util/types"; import closeIcon from "../assets/images/close.png"; @@ -34,6 +28,7 @@ const PaymentModal: React.FC = ({ const { paymentState, paymentType, + sessionData, closeSheet, getCtaText, ctaOnPress, @@ -43,6 +38,9 @@ const PaymentModal: React.FC = ({ const theme = useCurrentTheme(); const styles = getStyles(theme); + const SessionData = sessionData as sessionDataType; + const isCustomerMode = SessionData?.mode === PaymentMode.Customer; + const handleClose = () => { closeSheet(shouldShowAlert(), () => setModalVisible(false)); }; @@ -59,13 +57,13 @@ const PaymentModal: React.FC = ({ - {!paymentState ? "PAYMENT_OPTIONS" : ""} + {!paymentState || isCustomerMode ? "PAYMENT_OPTIONS" : ""} - {paymentState ? ( + {paymentState && !isCustomerMode ? ( ctaOnPress(() => setModalVisible(false))} diff --git a/src/components/ResponseScreen.tsx b/src/components/ResponseScreen.tsx index a371b42..d43d380 100644 --- a/src/components/ResponseScreen.tsx +++ b/src/components/ResponseScreen.tsx @@ -12,7 +12,7 @@ import { resizeFonts, responsiveScale } from "../theme/scalling"; import { useCurrentTheme } from "../theme/useCurrentTheme"; import KomojuText from "./KomojuText"; -import SubmitButton from "./SubmitButton"; +import Button from "./Button"; import successIcon from "../assets/images/success.png"; import errorIcon from "../assets/images/error.png"; @@ -104,7 +104,7 @@ const ResponseScreen = ({ {renderIcon} {renderMessageContent} - + ); }; -export default SubmitButton; - -const getStyles = (theme: ThemeSchemeType) => { +const getStyles = () => { return StyleSheet.create({ - buttonWrapper: { - backgroundColor: theme.PRIMARY_COLOR, - borderRadius: responsiveScale(8), - height: responsiveScale(50), - marginHorizontal: responsiveScale(16), - flex: 1, - justifyContent: "center", - alignItems: "center", + indicatorContainer: { + position: "absolute", + }, + iconLock: { + position: "absolute", + right: responsiveScale(20), + width: responsiveScale(15), + height: responsiveScale(15), + resizeMode: "contain", }, - label: { - color: "white", - fontSize: resizeFonts(16), - fontWeight: "bold", + iconAnimation: { + width: responsiveScale(30), + height: responsiveScale(30), + resizeMode: "contain", }, }); }; + +export default SubmitButton; diff --git a/src/components/sections/CardSection.tsx b/src/components/sections/CardSection.tsx index 044644f..f748535 100644 --- a/src/components/sections/CardSection.tsx +++ b/src/components/sections/CardSection.tsx @@ -60,7 +60,7 @@ const CardSection = (): JSX.Element => { if (isValid) { const cardDataObj: CardDetailsType = { - cardholderName: cardData?.cardNumber, + cardholderName: cardData?.cardholderName, cardCVV: cardData?.cardCVV, cardNumber: cardData?.cardNumber, cardExpiredDate: cardData?.cardExpiredDate, diff --git a/src/context/MainStateProvider.tsx b/src/context/MainStateProvider.tsx index b9c97b2..9ea8a47 100644 --- a/src/context/MainStateProvider.tsx +++ b/src/context/MainStateProvider.tsx @@ -56,10 +56,14 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { useMainStateUtils(); // Handle deep-links of the module - useDeepLinkHandler(setIsDeepLinkOpened); + useDeepLinkHandler(setIsDeepLinkOpened, closePaymentSheet); // Handle events when module goes foreground - useBackgroundHandler(isDeepLinkOpened, setIsDeepLinkOpened); + useBackgroundHandler( + isDeepLinkOpened, + setIsDeepLinkOpened, + closePaymentSheet + ); // Handle validations of the session const { validateSession } = useValidationHandler({ @@ -118,6 +122,7 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { createPayment, showPaymentSheetUI, initializeKomoju, + closePaymentSheet, }} > {renderChildren} diff --git a/src/context/state.ts b/src/context/state.ts index e899770..bf1e876 100644 --- a/src/context/state.ts +++ b/src/context/state.ts @@ -140,6 +140,10 @@ const defaultValue = { // TODO: Fix this type error // eslint-disable-next-line @typescript-eslint/no-unused-vars initializeKomoju: (_data: InitPrams) => {}, + /** + * Function to close the payment sheet manually. + */ + closePaymentSheet: noop, }; /** * State context for the Komoju payment system. diff --git a/src/hooks/useBackgroundHandler.tsx b/src/hooks/useBackgroundHandler.tsx index 72a7579..f377620 100644 --- a/src/hooks/useBackgroundHandler.tsx +++ b/src/hooks/useBackgroundHandler.tsx @@ -13,9 +13,12 @@ import { getTokenResult } from "../services/secureTokenService"; import payForSession from "../services/payForSessionService"; import useMainStateUtils from "./useMainStateUtils"; +let timeoutId: NodeJS.Timeout; + const useBackgroundHandler = ( isDeepLinkOpened: boolean, - setIsDeepLinkOpened: Dispatch> + setIsDeepLinkOpened: Dispatch>, + closePaymentSheet: () => void ) => { const { paymentType, tokenId, providerPropsData, sessionData } = useContext(StateContext); @@ -23,7 +26,7 @@ const useBackgroundHandler = ( const SessionData = sessionData as CreatePaymentFuncType; const { - startLoading, + startPaymentLoading, stopLoading, onPaymentAwaiting, onPaymentCancelled, @@ -44,6 +47,14 @@ const useBackgroundHandler = ( }; }, [providerPropsData, paymentType, tokenId, SessionData, isDeepLinkOpened]); + useEffect(() => { + () => { + if (timeoutId) { + clearTimeout(timeoutId); + } + }; + }, []); + const handleSessionPaymentResponse = async () => { // if this is a session flow, check until session response changes from 'pending' to 'completed' or 'error' const sessionShowPayload = { @@ -61,6 +72,9 @@ const useBackgroundHandler = ( sessionResponse.mode === PaymentMode.Customer ) { onPaymentSuccess(); + if (sessionResponse.mode === PaymentMode.Customer) { + timeoutId = setTimeout(() => closePaymentSheet(), 2000); + } } else { onPaymentAwaiting(); } // calling user passed onComplete method with session response data @@ -110,7 +124,7 @@ const useBackgroundHandler = ( const handleBackgroundStateChange = async (status: AppStateStatus) => { if (status === "active" && !isDeepLinkOpened) { - startLoading(); + startPaymentLoading(); if (paymentType === PaymentType.CREDIT) { await handleSecureTokenPaymentResponse(); diff --git a/src/hooks/useDeepLinkHandler.tsx b/src/hooks/useDeepLinkHandler.tsx index 317d62e..5cc9407 100644 --- a/src/hooks/useDeepLinkHandler.tsx +++ b/src/hooks/useDeepLinkHandler.tsx @@ -14,15 +14,18 @@ import { extractParameterFromUrl } from "../util/helpers"; import payForSession from "../services/payForSessionService"; import useMainStateUtils from "./useMainStateUtils"; +let timeoutId: NodeJS.Timeout; + const useDeepLinkHandler = ( - setIsDeepLinkOpened: Dispatch> + setIsDeepLinkOpened: Dispatch>, + closePaymentSheet: () => void ) => { const { paymentType, providerPropsData, sessionData } = useContext(StateContext); const SessionData = sessionData as CreatePaymentFuncType; const { - startLoading, + startPaymentLoading, stopLoading, onPaymentAwaiting, onPaymentCancelled, @@ -42,8 +45,16 @@ const useDeepLinkHandler = ( }; }, [paymentType, providerPropsData, sessionData]); + useEffect(() => { + () => { + if (timeoutId) { + clearTimeout(timeoutId); + } + }; + }, []); + const handleSessionPaymentResponse = async () => { - startLoading(); + startPaymentLoading(); // if this is a session flow, check until session response changes from 'pending' to 'completed' or 'error' const sessionShowPayload = { @@ -71,6 +82,9 @@ const useDeepLinkHandler = ( sessionResponse.mode === PaymentMode.Customer ) { onPaymentSuccess(); + if (sessionResponse.mode === PaymentMode.Customer) { + timeoutId = setTimeout(() => closePaymentSheet(), 2000); + } } else { onPaymentAwaiting(); } @@ -87,7 +101,7 @@ const useDeepLinkHandler = ( }; const handleSecureTokenPaymentResponse = async (token: string) => { - startLoading(); + startPaymentLoading(); const tokenResponse = await getTokenResult({ publishableKey: providerPropsData.publishableKey, diff --git a/src/hooks/useMainStateUtils.tsx b/src/hooks/useMainStateUtils.tsx index 34d54d7..1a49ff9 100644 --- a/src/hooks/useMainStateUtils.tsx +++ b/src/hooks/useMainStateUtils.tsx @@ -1,27 +1,53 @@ -import { useContext } from "react"; +import { useContext, useEffect } from "react"; import { Actions, DispatchContext, StateContext } from "../context/state"; import { - initialState, ResponseScreenStatuses, CreatePaymentFuncType, + sessionDataType, + PaymentMode, } from "../util/types"; import sessionShow from "../services/sessionShow"; +import { getInitialStateWithoutProviderPropsData } from "../util/helpers"; + +let timeoutId: NodeJS.Timeout; const useMainStateUtils = () => { const dispatch = useContext(DispatchContext); const { providerPropsData, sessionData } = useContext(StateContext); - const SessionData = sessionData as CreatePaymentFuncType; + const SessionData = sessionData as CreatePaymentFuncType & sessionDataType; - const resetGlobalStates = () => - dispatch({ - type: Actions.RESET_STATES, - payload: initialState, - }); + const isCustomerMode = SessionData?.mode === PaymentMode.Customer; + + useEffect(() => { + () => { + if (timeoutId) { + clearTimeout(timeoutId); + } + }; + }, []); + + const resetGlobalStates = (withTimeout = false) => { + if (withTimeout) { + timeoutId = setTimeout( + () => + dispatch({ + type: Actions.RESET_STATES, + payload: getInitialStateWithoutProviderPropsData(), + }), + 3000 + ); + } else { + dispatch({ + type: Actions.RESET_STATES, + payload: getInitialStateWithoutProviderPropsData(), + }); + } + }; // when payment is success global state is rest and invoking the success screen const onPaymentSuccess = () => { - resetGlobalStates(); + resetGlobalStates(isCustomerMode); dispatch({ type: Actions.SET_PAYMENT_STATE, payload: ResponseScreenStatuses.SUCCESS, @@ -37,7 +63,7 @@ const useMainStateUtils = () => { // when payment is cancelled by the user const onPaymentCancelled = () => { - resetGlobalStates(); + resetGlobalStates(isCustomerMode); dispatch({ type: Actions.SET_PAYMENT_STATE, payload: ResponseScreenStatuses.CANCELLED, @@ -80,14 +106,29 @@ const useMainStateUtils = () => { const startLoading = () => dispatch({ type: Actions.SET_LOADING, - payload: true, + payload: { + app: true, + payment: false, + }, + }); + + const startPaymentLoading = () => + dispatch({ + type: Actions.SET_LOADING, + payload: { + app: false, + payment: true, + }, }); // Hiding overlay loading indicator const stopLoading = () => dispatch({ type: Actions.SET_LOADING, - payload: false, + payload: { + app: false, + payment: false, + }, }); return { @@ -98,6 +139,7 @@ const useMainStateUtils = () => { onSessionExpired, onUserCancel, startLoading, + startPaymentLoading, stopLoading, resetGlobalStates, }; diff --git a/src/hooks/usePaymentUiUtils.tsx b/src/hooks/usePaymentUiUtils.tsx index 2db1f7c..4999693 100644 --- a/src/hooks/usePaymentUiUtils.tsx +++ b/src/hooks/usePaymentUiUtils.tsx @@ -2,86 +2,90 @@ 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 { 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 { t } = useTranslation(); + const { paymentState, paymentType, sessionData } = useContext(StateContext); + const dispatch = useContext(DispatchContext); - const closeSheet = useCallback((showAlert = true, onClose: () => void) => { - Keyboard.dismiss(); + 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]); + 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 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 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]); + 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 + return { + paymentState, + paymentType, + sessionData, + closeSheet, + getCtaText, + ctaOnPress, + shouldShowAlert, + }; +}; diff --git a/src/hooks/useSessionPayHandler.tsx b/src/hooks/useSessionPayHandler.tsx index e8ce87e..2a4dd45 100644 --- a/src/hooks/useSessionPayHandler.tsx +++ b/src/hooks/useSessionPayHandler.tsx @@ -1,4 +1,4 @@ -import { useContext } from "react"; +import { useContext, useEffect } from "react"; import { CreatePaymentFuncType, @@ -7,17 +7,29 @@ import { sessionPayProps, TokenResponseStatuses, } from "../util/types"; -import { StateContext } from "../context/state"; +import { StateContext, KomojuContext } from "../context/state"; import { openURL } from "../util/helpers"; import payForSession from "../services/payForSessionService"; import useMainStateUtils from "./useMainStateUtils"; +let timeoutId: NodeJS.Timeout; + const useSessionPayHandler = () => { const { sessionData, providerPropsData } = useContext(StateContext); + const { closePaymentSheet } = useContext(KomojuContext); + const SessionData = sessionData as CreatePaymentFuncType; + useEffect(() => { + () => { + if (timeoutId) { + clearTimeout(timeoutId); + } + }; + }, []); + const { - startLoading, + startPaymentLoading, stopLoading, onPaymentAwaiting, onPaymentFailed, @@ -30,7 +42,7 @@ const useSessionPayHandler = () => { paymentDetails, }: sessionPayProps) => { // Start of the payment handling method - startLoading(); + startPaymentLoading(); // initiate payment for the session ID with payment details const response = await payForSession({ @@ -50,6 +62,9 @@ const useSessionPayHandler = () => { response?.customer?.resource === PaymentMode.Customer ) { onPaymentSuccess(); + if (response?.customer?.resource === PaymentMode.Customer) { + timeoutId = setTimeout(() => closePaymentSheet(), 2000); + } } else if (response?.payment?.payment_details?.instructions_url) { openURL(response?.payment?.payment_details?.instructions_url); onPaymentAwaiting(); diff --git a/src/hooks/useThreeDSecureHandler.tsx b/src/hooks/useThreeDSecureHandler.tsx index 9515119..de8e8ce 100644 --- a/src/hooks/useThreeDSecureHandler.tsx +++ b/src/hooks/useThreeDSecureHandler.tsx @@ -15,11 +15,12 @@ const useThreeDSecureHandler = () => { const dispatch = useContext(DispatchContext); const { sessionData, providerPropsData } = useContext(StateContext); - const { startLoading, stopLoading, onPaymentFailed } = useMainStateUtils(); + const { startPaymentLoading, stopLoading, onPaymentFailed } = + useMainStateUtils(); const SessionData = sessionData as sessionDataType; const threeDSecurePayment = async (paymentDetails: CardDetailsType) => { - startLoading(); + startPaymentLoading(); const { month, year } = getMonthYearFromExpiry( paymentDetails?.cardExpiredDate || "" diff --git a/src/theme/defaultColorTheme.ts b/src/theme/defaultColorTheme.ts index adfc3de..59d3dc8 100644 --- a/src/theme/defaultColorTheme.ts +++ b/src/theme/defaultColorTheme.ts @@ -1,6 +1,7 @@ const darkTheme = { PRIMARY_COLOR: "#0071D7", BACKGROUND_COLOR: "#1E1E1E", + SUCCESS_COLOR: "#3CC239", ERROR: "#fc4747", TEXT_COLOR: "#fff", INPUT_BACKGROUND: "#2C2C2C", @@ -18,6 +19,7 @@ const darkTheme = { const lightTheme = { PRIMARY_COLOR: "#0B82EE", BACKGROUND_COLOR: "#FFFFFF", + SUCCESS_COLOR: "#3CC239", ERROR: "#fc5d5d", TEXT_COLOR: "#172E44", INPUT_BACKGROUND: "#FFFFFF", diff --git a/src/util/helpers.ts b/src/util/helpers.ts index b8235bb..5d6c5c5 100644 --- a/src/util/helpers.ts +++ b/src/util/helpers.ts @@ -6,6 +6,7 @@ import { CardTypes, CurrencySign, CurrencyTypes, + initialState, KonbiniType, PaymentType, sessionShowPaymentMethodType, @@ -222,3 +223,8 @@ export function fromUserFriendlyTheme( return acc; }, {} as Partial); } + +export const getInitialStateWithoutProviderPropsData = () => { + const { providerPropsData, ...stateWithoutProviderProps } = initialState; + return stateWithoutProviderProps; +}; diff --git a/src/util/types.ts b/src/util/types.ts index c9ba9de..449b5a1 100644 --- a/src/util/types.ts +++ b/src/util/types.ts @@ -240,6 +240,11 @@ export type brandType = { icon: string; }; +export type LoadingTypes = { + app?: boolean; + payment?: boolean; +}; + export type sessionDataType = { /** * Amount for the payment @@ -267,7 +272,7 @@ export type State = KonbiniDetailsType & { /** * Global loading state. to display loading animation over sdk and disable buttons. */ - loading: boolean; + loading: LoadingTypes; /** * All credit card related data */ @@ -315,7 +320,10 @@ export type sessionPayProps = { // Define the initial state export const initialState: State = { paymentType: PaymentType.CREDIT, - loading: false, + loading: { + app: false, + payment: false, + }, /** credit card payment related states start */ cardData: { @@ -363,6 +371,7 @@ export type ActionType = { type: string; payload: State[keyof State] }; export interface ThemeSchemeType { PRIMARY_COLOR: string; BACKGROUND_COLOR: string; + SUCCESS_COLOR: string; ERROR: string; TEXT_COLOR: string; INPUT_BACKGROUND: string;